From 04af1e291c0f019a2c7953cc91dfb7cfd3a04a1c Mon Sep 17 00:00:00 2001 From: Snorre Ettrup Altschul Date: Sat, 22 Feb 2025 21:38:41 +0100 Subject: [PATCH] unset --- src/cli-repl.rs | 15 +++++++++++ src/lib/environment.rs | 42 ++++++++++++++++++++++++++++- src/lib/node/call.rs | 13 ++++++--- src/lib/node/function.rs | 22 ++++++++++++--- src/lib/node/mod.rs | 18 ++++++++----- src/lib/node/string_node.rs | 38 ++++++++++++++++++++++++++ src/lib/parser/mod.rs | 53 ++++++++++++++++++++++--------------- 7 files changed, 165 insertions(+), 36 deletions(-) create mode 100644 src/lib/node/string_node.rs diff --git a/src/cli-repl.rs b/src/cli-repl.rs index 4a01e34..f00d04e 100644 --- a/src/cli-repl.rs +++ b/src/cli-repl.rs @@ -162,12 +162,27 @@ fn print(args: &Vec>, env: &mut Environment) -> Result Ok(Empty::new("")) } +fn unset(args: &Vec>, env: &mut Environment) -> Result, 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()), diff --git a/src/lib/environment.rs b/src/lib/environment.rs index 074e1e3..ab67c24 100644 --- a/src/lib/environment.rs +++ b/src/lib/environment.rs @@ -22,6 +22,9 @@ pub struct Environment { stack: Vec, stack_shadows: Vec<(EnvironmentInternalSymbolKey, Rc)>, + hidden: Vec, + disable_calls: bool, + // stack: Vec>, symbol_to_id: HashMap, id_to_symbol: HashMap, @@ -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> { - 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) } diff --git a/src/lib/node/call.rs b/src/lib/node/call.rs index bb93042..b70ef3e 100644 --- a/src/lib/node/call.rs +++ b/src/lib/node/call.rs @@ -12,15 +12,20 @@ pub struct Call { impl Node for Call { fn evaluate(&self, env: &mut Environment) -> Result, 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() { diff --git a/src/lib/node/function.rs b/src/lib/node/function.rs index 3f96121..08e16c3 100644 --- a/src/lib/node/function.rs +++ b/src/lib/node/function.rs @@ -4,7 +4,8 @@ use crate::environment::Environment; use super::{Node, NodeEnum, Precedence, symbol::Symbol}; -pub type NativeFunctionType = fn(&Vec>, env: &mut Environment) -> Result, String>; +pub type NativeFunctionType = + fn(&Vec>, env: &mut Environment) -> Result, 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, String> { - Ok(Rc::new(self.clone().into())) + fn evaluate(&self, env: &mut Environment) -> Result, 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 { diff --git a/src/lib/node/mod.rs b/src/lib/node/mod.rs index 4d32092..b1a9baf 100644 --- a/src/lib/node/mod.rs +++ b/src/lib/node/mod.rs @@ -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)] diff --git a/src/lib/node/string_node.rs b/src/lib/node/string_node.rs new file mode 100644 index 0000000..9311f6c --- /dev/null +++ b/src/lib/node/string_node.rs @@ -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 for StringNode { + fn from(value: String) -> Self { + Self { value } + } +} + +impl Node for StringNode { + fn evaluate(&self, _: &mut super::Environment) -> Result, 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 { + Rc::new(Self { value }.into()) + } + + pub fn get_value(&self) -> &String { + &self.value + } +} diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index b5a7d72..74f048b 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -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, 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, 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) {