This commit is contained in:
Snorre Ettrup Altschul 2025-02-22 21:38:41 +01:00
parent ff5855af76
commit 04af1e291c
7 changed files with 165 additions and 36 deletions

View file

@ -162,12 +162,27 @@ fn print(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>
Ok(Empty::new(""))
}
fn unset(args: &Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
for arg in args {
if let NodeEnum::StringNode(string) = arg.as_ref() {
if let Some(id) = env.str_to_id(string.get_value()) {
env.undefine(*id);
}
} else {
return Err(format!("Cannot undefine the expression {arg}"));
}
}
Ok(Empty::new(format!("Undefined {} symbols", args.len())))
}
fn main() -> Result<(), io::Error> {
let mut input = Input::new();
let mut env = Environment::new();
env.define_native_function("print", print);
env.define_native_function("unset", unset);
env.define(
"pi",
Rc::new(Constant::new(f64::consts::PI.try_into().unwrap()).into()),

View file

@ -22,6 +22,9 @@ pub struct Environment {
stack: Vec<EnvironmentInternalSymbolKey>,
stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc<NodeEnum>)>,
hidden: Vec<EnvironmentInternalSymbolKey>,
disable_calls: bool,
// stack: Vec<Vec<EnvironmentInternalSymbolKey>>,
symbol_to_id: HashMap<String, EnvironmentInternalSymbolKey>,
id_to_symbol: HashMap<EnvironmentInternalSymbolKey, String>,
@ -38,6 +41,8 @@ impl Environment {
stack_sizes: vec![],
stack: vec![],
stack_shadows: vec![],
hidden: vec![],
disable_calls: false,
symbol_to_id: HashMap::new(),
id_to_symbol: HashMap::new(),
@ -45,6 +50,34 @@ impl Environment {
}
}
pub fn hide(&mut self, key: EnvironmentInternalSymbolKey) {
match self.hidden.binary_search(&key) {
Ok(_) => {}
Err(pos) => self.hidden.insert(pos, key),
}
}
pub fn unhide(&mut self, key: EnvironmentInternalSymbolKey) {
match self.hidden.binary_search(&key) {
Ok(pos) => {
self.hidden.remove(pos);
}
Err(_) => {}
}
}
pub fn disable_calls(&mut self) {
self.disable_calls = true;
}
pub fn enable_calls(&mut self) {
self.disable_calls = false;
}
pub fn calls_disabled(&self) -> bool {
self.disable_calls
}
pub fn push_stack(&mut self) -> Result<(), String> {
if self.stack_depth == self.max_stack_depth {
self.unwind_stack();
@ -104,6 +137,10 @@ impl Environment {
self.insert_id_to_str(id, name);
}
pub fn undefine(&mut self, key: EnvironmentInternalSymbolKey) {
self.map.remove(&key);
}
pub fn define_native_function(&mut self, name: &'static str, func: NativeFunctionType) {
let f = Function::new(FunctionType::Native(name, func));
@ -111,7 +148,10 @@ impl Environment {
}
pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc<NodeEnum>> {
eprintln!("Get {key}");
if self.hidden.binary_search(key).is_ok() {
// This value is hidden, so we pretend its not defined
return None;
}
self.map.get(key)
}

View file

@ -12,15 +12,20 @@ pub struct Call {
impl Node for Call {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
if env.calls_disabled() {
return Ok(Rc::new(self.clone().into()));
}
// Evaluate callee and error if its not a function
let evaluated = self.function.evaluate(env)?;
let func = if let NodeEnum::Function(func) = evaluated.as_ref() {
func
} else {
return Err(format!(
"Cannot call {} as a function",
evaluated.as_string(Some(env))
));
// return Err(format!(
// "Cannot call {} as a function",
// evaluated.as_string(Some(env))
// ));
return Ok(Rc::new(self.clone().into()));
};
let arguments = if let NodeEnum::Set(set) = self.arguments.as_ref() {

View file

@ -4,7 +4,8 @@ use crate::environment::Environment;
use super::{Node, NodeEnum, Precedence, symbol::Symbol};
pub type NativeFunctionType = fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
pub type NativeFunctionType =
fn(&Vec<Rc<NodeEnum>>, env: &mut Environment) -> Result<Rc<NodeEnum>, String>;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum FunctionType {
@ -18,8 +19,23 @@ pub struct Function {
}
impl Node for Function {
fn evaluate(&self, _: &mut Environment) -> Result<Rc<NodeEnum>, String> {
Ok(Rc::new(self.clone().into()))
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
// Ok(Rc::new(self.clone().into()))
Ok(Rc::new(
Self {
function: match &self.function {
FunctionType::Native(_, _) => self.function.clone(),
FunctionType::UserFunction(node_enum, symbols) => {
env.disable_calls();
let evaluated = node_enum.evaluate(env)?;
env.enable_calls();
FunctionType::UserFunction(evaluated, symbols.clone())
}
},
}
.into(),
))
}
fn as_string(&self, env: Option<&Environment>) -> String {

View file

@ -16,6 +16,7 @@ use multiply::Multiply;
use set::Set;
use subtract::Subtract;
use symbol::Symbol;
use string_node::StringNode;
use crate::environment::Environment;
@ -35,12 +36,14 @@ pub mod node_ref;
pub mod set;
pub mod subtract;
pub mod symbol;
pub mod string_node;
#[enum_dispatch]
#[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)]
#[derive(Debug, Clone, PartialEq)]
pub enum NodeEnum {
Constant,
StringNode,
// Operators
Add,
@ -50,10 +53,10 @@ pub enum NodeEnum {
Exponent,
Symbol,
// NodeRef, // DEPRECATED, use Symbol
Assign,
Empty,
Function,
// Closure // IMPLEMENT THIS SO CURRYING WORKS
Call,
Bool,
@ -65,12 +68,13 @@ pub enum NodeEnum {
Greater,
GreaterEquals,
Less,
LessEquals, // Logical operators
// In,
// Where,
// Not,
// Or,
// And
LessEquals,
// Logical operators
// In,
// Where,
// Not,
// Or,
// And
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]

View file

@ -0,0 +1,38 @@
use std::rc::Rc;
use super::{Environment, Node, NodeEnum, Precedence};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct StringNode {
value: String,
}
impl From<String> for StringNode {
fn from(value: String) -> Self {
Self { value }
}
}
impl Node for StringNode {
fn evaluate(&self, _: &mut super::Environment) -> Result<Rc<super::NodeEnum>, String> {
Ok(Rc::new(self.clone().into()))
}
fn as_string(&self, _env: Option<&Environment>) -> String {
format!("\"{}\"", self.value.clone())
}
fn precedence(&self) -> Precedence {
Precedence::Primary
}
}
impl StringNode {
pub fn new(value: String) -> Rc<NodeEnum> {
Rc::new(Self { value }.into())
}
pub fn get_value(&self) -> &String {
&self.value
}
}

View file

@ -3,21 +3,7 @@ use std::{iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter};
use crate::{
environment::Environment,
node::{
NodeEnum,
add::Add,
assign::Assign,
call::Call,
comparison::{Greater, GreaterEquals, Less, LessEquals},
constant::{Constant, ConstantValue},
divide::Divide,
equals::Equals,
exponent::Exponent,
function::{Function, FunctionType},
if_else::{Bool, ElseBranchEnum, IfElse},
multiply::Multiply,
set::Set,
subtract::Subtract,
symbol::Symbol,
add::Add, assign::Assign, call::Call, comparison::{Greater, GreaterEquals, Less, LessEquals}, constant::{Constant, ConstantValue}, divide::Divide, equals::Equals, exponent::Exponent, function::{Function, FunctionType}, if_else::{Bool, ElseBranchEnum, IfElse}, multiply::Multiply, set::Set, string_node::StringNode, subtract::Subtract, symbol::Symbol, NodeEnum
},
};
@ -29,6 +15,7 @@ pub enum TokenType {
// Space,
Number(ConstantValue),
Identifier(String),
String(String),
Plus,
Minus,
@ -62,7 +49,7 @@ impl TokenType {
pub fn len(&self) -> usize {
match self {
TokenType::Number(n) => n.to_string().len(),
TokenType::Identifier(s) => s.len(),
TokenType::Identifier(s) | TokenType::String(s) => s.len(),
TokenType::Plus => 1,
TokenType::Minus => 1,
@ -174,6 +161,29 @@ impl<'a> Lexer<'a> {
tokens.push(Token(i, TokenType::Number(number)));
}
'"' => {
let mut buffer = "".to_owned();
loop {
let next = self.source.peek();
match next {
Some('"') => {
tokens.push(Token(i, TokenType::String(buffer.clone())));
self.source.next();
break;
}
Some(_) => {
buffer.push(self.source.next().unwrap());
}
None => {
return Err(LexerError::UnexpectedChar(
i,
"Unexpected End of file".to_owned(),
));
}
}
}},
// LeftArrow (->)
'-' if self.source.peek() == Some(&'>') => {
self.source.next();
@ -350,14 +360,13 @@ impl<'a> Parser<'a> {
}
fn assignment(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
let expr = self.equality();
let expr = self.equality()?;
if let Some(Token(_, TokenType::ColonEquals)) = self.tokens.peek() {
self.consume();
return Ok(Rc::new(Assign::new(expr?, self.equality()?).into()));
if self.matchType(TokenType::ColonEquals) {
return Ok(Rc::new(Assign::new(expr, self.equality()?).into()));
}
expr
Ok(expr)
}
fn equality(&mut self) -> Result<Rc<NodeEnum>, ParserError> {
@ -599,6 +608,8 @@ impl<'a> Parser<'a> {
TokenType::True => Ok(Rc::new(Bool::True.into())),
TokenType::False => Ok(Rc::new(Bool::False.into())),
TokenType::String(s) => Ok(StringNode::new(s)),
TokenType::LParen => {
// Empty set
if self.matchType(TokenType::RParen) {