From b7834b5244203d65be71b8d1b089fb4db2597404 Mon Sep 17 00:00:00 2001 From: Snorre Date: Thu, 20 Feb 2025 17:15:59 +0100 Subject: [PATCH] implemented more nodes --- src/cli-repl.rs | 27 ++-- src/lib/environment.rs | 49 +++++- src/lib/node/add.rs | 23 ++- src/lib/node/assign.rs | 17 +- src/lib/node/call.rs | 44 +++-- src/lib/node/constant.rs | 6 + src/lib/node/divide.rs | 54 ++++++- src/lib/node/empty.rs | 22 ++- src/lib/node/equals.rs | 39 +++++ src/lib/node/function.rs | 15 +- src/lib/node/mod.rs | 24 ++- src/lib/node/multiply.rs | 140 +++++++++++++++- src/lib/node/set.rs | 49 ++++++ src/lib/node/subtract.rs | 17 +- src/lib/node/symbol.rs | 39 +---- src/lib/parser/mod.rs | 342 +++++++++++++++++++++++++++++++++++---- 16 files changed, 782 insertions(+), 125 deletions(-) create mode 100644 src/lib/node/equals.rs create mode 100644 src/lib/node/set.rs diff --git a/src/cli-repl.rs b/src/cli-repl.rs index 0c86d17..a8c0a8b 100644 --- a/src/cli-repl.rs +++ b/src/cli-repl.rs @@ -2,7 +2,7 @@ use std::io::{self, StdoutLock, Write, stdout}; use libopenbirch::environment::Environment; use libopenbirch::node::Node; -use libopenbirch::parser::{Lexer, Parser}; +use libopenbirch::parser::{Lexer, Parser, ParserError}; #[cfg(feature = "async")] use termion::AsyncReader; use termion::color; @@ -133,8 +133,13 @@ impl Input { } } -fn print_err(i: usize, exp: String) { - println!("\r{}{}^", " ".repeat(i + 2), color::Fg(color::Yellow)); +fn print_err(i: usize, len: usize, exp: String) { + println!( + "\r{}{}{}", + " ".repeat(i + 3 - len), + color::Fg(color::Yellow), + "^".repeat(len) + ); println!( "\r{}{}{}", color::Fg(color::Red), @@ -154,7 +159,7 @@ fn main() -> Result<(), io::Error> { if tokens_result.is_err() { match tokens_result.err().unwrap() { - libopenbirch::parser::LexerError::UnexpectedChar(i, exp) => print_err(i, exp), + libopenbirch::parser::LexerError::UnexpectedChar(i, exp) => print_err(i, 1, exp), } continue; } @@ -163,7 +168,7 @@ fn main() -> Result<(), io::Error> { input.disable_raw(); let tokens = tokens_result.unwrap(); - let mut parser = Parser::new(tokens); + let mut parser = Parser::new(tokens, &mut env); #[cfg(debug_assertions)] input.enable_raw(); @@ -172,10 +177,10 @@ fn main() -> Result<(), io::Error> { Ok(nodes) => nodes, Err(err) => { match err { - libopenbirch::parser::ParserError::UnexpectedEndOfTokens(exp) => { - print_err(source.len(), exp) - } - libopenbirch::parser::ParserError::UnexpectedToken(i, exp) => print_err(i, exp), + ParserError::UnexpectedEndOfTokens(exp) => print_err(source.len(), 1, exp), + ParserError::UnexpectedToken(i, len, exp) + | ParserError::Unimplemented(i, len, exp) => print_err(i, len, exp), + ParserError::UnexpectedNode(i, exp) => print_err(i, 1, exp), } continue; } @@ -186,8 +191,8 @@ fn main() -> Result<(), io::Error> { for node in nodes { let evaluated = node.evaluate(&mut env); match evaluated { - Ok(result) => println!("\r\t{}", result.as_string(None)), - Err(exp) => print_err(0, exp), + Ok(result) => println!("\r\t{}", result.as_string(Some(&env))), + Err(exp) => print_err(0, 1, exp), } } diff --git a/src/lib/environment.rs b/src/lib/environment.rs index 19e47fa..14af6ed 100644 --- a/src/lib/environment.rs +++ b/src/lib/environment.rs @@ -3,4 +3,51 @@ use std::{collections::HashMap, rc::Rc}; use crate::node::NodeEnum; pub type EnvironmentInternalSymbolKey = u16; -pub type Environment = HashMap>; +// pub type Environment = HashMap>; + +pub struct Environment { + map: HashMap>, + + symbol_to_id: HashMap, + id_to_symbol: HashMap, + unique_keys: EnvironmentInternalSymbolKey +} + +impl Environment { + pub fn new() -> Self { + Self { + map: HashMap::new(), + + symbol_to_id: HashMap::new(), + id_to_symbol: HashMap::new(), + unique_keys: 0 + } + } + + pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc> { + self.map.get(key) + } + + pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc) { + self.map.insert(key, value); + } + + pub fn str_to_id(&self, value: &String) -> Option<&EnvironmentInternalSymbolKey> { + self.symbol_to_id.get(value) + } + pub fn id_to_str(&self, value: &EnvironmentInternalSymbolKey) -> Option<&String> { + self.id_to_symbol.get(value) + } + pub fn insert_str_to_id(&mut self, key: String, value: EnvironmentInternalSymbolKey) { + self.symbol_to_id.insert(key.clone(), value); + self.id_to_symbol.insert(value, key); + } + pub fn insert_id_to_str(&mut self, key: EnvironmentInternalSymbolKey, value: String) { + self.id_to_symbol.insert(key, value.clone()); + self.symbol_to_id.insert(value, key); + } + pub fn get_new_id(&mut self) -> EnvironmentInternalSymbolKey { + self.unique_keys += 1; + self.unique_keys + } +} diff --git a/src/lib/node/add.rs b/src/lib/node/add.rs index be0607b..0b86675 100644 --- a/src/lib/node/add.rs +++ b/src/lib/node/add.rs @@ -14,10 +14,26 @@ impl Node for Add { let evaluated_right = self.right.evaluate(env)?; match (evaluated_left.as_ref(), evaluated_right.as_ref()) { + // Zero rule + (NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right), + (_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => Ok(evaluated_left), + + // Constant + Constant = Constant (NodeEnum::Constant(a), NodeEnum::Constant(b)) => { Ok(Rc::new(Constant::new(a.get_value() + b.get_value()).into())) } - _ => Err(format!("Invalid Add operation: {:?}", self)), + + // Symbol + Constant we just return the same + (NodeEnum::Symbol(_), NodeEnum::Constant(_)) => { + Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())) + } + + // Constant + Symbol we switch them around so the constant is last + (NodeEnum::Constant(_), NodeEnum::Symbol(_)) => { + Ok(Rc::new(Add::new(evaluated_right, evaluated_left).into())) + } + + _ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())), } } @@ -42,10 +58,7 @@ impl Node for Add { impl Add { pub fn new(left: Rc, right: Rc) -> Self { - Self { - left, - right, - } + Self { left, right } } pub fn get_left(&self) -> Rc { diff --git a/src/lib/node/assign.rs b/src/lib/node/assign.rs index c04d58f..f2bdc14 100644 --- a/src/lib/node/assign.rs +++ b/src/lib/node/assign.rs @@ -11,8 +11,17 @@ pub struct Assign { impl Node for Assign { fn evaluate(&self, env: &mut Environment) -> Result, String> { if let NodeEnum::Symbol(symbol) = self.left.as_ref() { - env.insert(symbol.get_value(), self.right.clone()); - Ok(Empty::EMPTY.clone()) + let name = env + .id_to_str(&symbol.get_value()) + .expect("Unknown symbol") + .clone(); + let right = self.right.evaluate(env)?; + + env.insert(symbol.get_value(), right.clone()); + Ok(Empty::new(format!( + "{name} := {}", + right.as_string(Some(env)) + ))) } else { Err(format!( "Cannot assign to a {}", @@ -35,6 +44,10 @@ impl Node for Assign { } impl Assign { + pub fn new(left: Rc, right: Rc) -> Self { + Self { left, right } + } + pub fn get_left(&self) -> Rc { self.left.clone() } diff --git a/src/lib/node/call.rs b/src/lib/node/call.rs index b470c5e..0822f2a 100644 --- a/src/lib/node/call.rs +++ b/src/lib/node/call.rs @@ -7,7 +7,7 @@ use super::{Node, NodeEnum, Precedence, symbol::Symbol}; #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct Call { function: Rc, - arguments: Vec>, + arguments: Rc, } impl Node for Call { @@ -23,29 +23,34 @@ impl Node for Call { )); }; + let arguments = if let NodeEnum::Set(set) = self.arguments.as_ref() { + set.get_values() + } else { + panic!( + "This shoulnd not be possible, but call constructed with arguments of type that is not set" + ); + }; + // Check if argument counts match let fargs = func.get_arguments(); - if fargs.len() != self.arguments.len() { + if fargs.len() != arguments.len() { return Err(format!( "Error calling function. Expected {} arguments, but got {}", func.get_arguments().len(), - self.arguments.len() + arguments.len() )); } // Call function body with arguments match func.get_body() { // Pass arguments to native function - FunctionType::Native(_name, native_function) => native_function(&self.arguments), + FunctionType::Native(_name, native_function) => native_function(arguments), FunctionType::UserFunction(node_enum) => { // TODO: Push scope // Define variables - fargs - .iter() - .zip(&self.arguments) - .for_each(|(symbol, value)| { - env.insert(symbol.get_value(), value.clone()); - }); + fargs.iter().zip(arguments).for_each(|(symbol, value)| { + env.insert(symbol.get_value(), value.clone()); + }); let ev = node_enum.evaluate(env); // TODO: Pop scope // Return evaluated return value for function @@ -55,12 +60,7 @@ impl Node for Call { } fn as_string(&self, env: Option<&Environment>) -> String { - let arguments = self - .arguments - .iter() - .map(|x| x.as_string(env)) - .reduce(|a, b| a + ", " + &b) - .unwrap(); + let arguments = self.arguments.as_string(env); format!("{}({})", self.function.as_string(env), arguments) } @@ -68,3 +68,15 @@ impl Node for Call { Precedence::Call } } + +impl Call { + pub fn new(function: Rc, arguments: Rc) -> Rc { + Rc::new( + Self { + function, + arguments, + } + .into(), + ) + } +} diff --git a/src/lib/node/constant.rs b/src/lib/node/constant.rs index 3797100..00d2573 100644 --- a/src/lib/node/constant.rs +++ b/src/lib/node/constant.rs @@ -9,6 +9,12 @@ pub struct Constant { value: ConstantValue, } +impl From for Constant { + fn from(value: ConstantValue) -> Self { + Self::new(value) + } +} + impl Node for Constant { fn evaluate(&self, _: &mut super::Environment) -> Result, String> { Ok(Rc::new(self.clone().into())) diff --git a/src/lib/node/divide.rs b/src/lib/node/divide.rs index f2bcf83..1cd2ab5 100644 --- a/src/lib/node/divide.rs +++ b/src/lib/node/divide.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use super::{Node, NodeEnum, Precedence, constant::Constant}; +use super::{constant::Constant, set::Set, Node, NodeEnum, Precedence}; #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Divide { @@ -14,10 +14,55 @@ impl Node for Divide { let evaluated_right = self.right.evaluate(env)?; match (evaluated_left.as_ref(), evaluated_right.as_ref()) { + // Error if dividing by zero + (_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => { + Err("Division by Zero".into()) + } + + // Zero rule + (NodeEnum::Constant(zero), _) if zero.get_value() == 0. => { + Ok(evaluated_left) + } + + // Constant + Constant = Constant (NodeEnum::Constant(a), NodeEnum::Constant(b)) => { Ok(Rc::new(Constant::new(a.get_value() / b.get_value()).into())) } - _ => Err(format!("Invalid Divide operation: {:?}", self)), + // Symbol + Constant we just return the same + (NodeEnum::Symbol(_), NodeEnum::Constant(_)) => { + Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into())) + } + // Constant + Symbol we switch them around so the constant is last + (NodeEnum::Constant(_), NodeEnum::Symbol(_)) => { + Ok(Rc::new(Divide::new(evaluated_right, evaluated_left).into())) + } + // Divide a set with a constant + (NodeEnum::Set(s), NodeEnum::Constant(c)) => { + let old_values = s.get_values(); + let mut values = Vec::with_capacity(old_values.len()); + let c: Rc = Rc::new(c.clone().into()); + + for value in old_values.iter() { + let new_value = Divide::new(c.clone(), value.clone()); + values.push(new_value.evaluate(env)?); + } + + Ok(Set::new(values)) + } + // Divide a set with a symbol + (NodeEnum::Set(s), NodeEnum::Symbol(c)) => { + let old_values = s.get_values(); + let mut values = Vec::with_capacity(old_values.len()); + let c: Rc = Rc::new(c.clone().into()); + + for value in old_values.iter() { + let new_value = Divide::new(c.clone(), value.clone()); + values.push(new_value.evaluate(env)?); + } + + Ok(Set::new(values)) + } + _ => Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into())), } } @@ -42,10 +87,7 @@ impl Node for Divide { impl Divide { pub fn new(left: Rc, right: Rc) -> Self { - Self { - left, - right - } + Self { left, right } } pub fn get_left(&self) -> Rc { diff --git a/src/lib/node/empty.rs b/src/lib/node/empty.rs index a13607c..dc87d8e 100644 --- a/src/lib/node/empty.rs +++ b/src/lib/node/empty.rs @@ -3,14 +3,20 @@ use std::{rc::Rc, sync::LazyLock}; use super::{Environment, Node, NodeEnum, Precedence}; #[derive(Debug, Clone, PartialEq, PartialOrd)] -pub struct Empty; +pub struct Empty { + message: Option, +} + impl Node for Empty { fn evaluate(&self, _: &mut Environment) -> Result, String> { Ok(Empty::EMPTY.clone()) } fn as_string(&self, _: Option<&Environment>) -> String { - String::from("{{#VOID}}") + match &self.message { + Some(m) => m.clone(), + None => String::from("{{#VOID}}"), + } } fn precedence(&self) -> Precedence { @@ -19,5 +25,15 @@ impl Node for Empty { } impl Empty { - pub const EMPTY: LazyLock> = LazyLock::new(|| Rc::new(Empty{}.into())); + pub const EMPTY: LazyLock> = + LazyLock::new(|| Rc::new(Empty { message: None }.into())); + + pub fn new(message: impl Into) -> Rc { + Rc::new( + Self { + message: Some(message.into()), + } + .into(), + ) + } } diff --git a/src/lib/node/equals.rs b/src/lib/node/equals.rs new file mode 100644 index 0000000..e1194f8 --- /dev/null +++ b/src/lib/node/equals.rs @@ -0,0 +1,39 @@ +use std::rc::Rc; + +use super::{Environment, Node, NodeEnum, Precedence, if_else::Bool}; + +#[derive(Clone, Debug, PartialEq, PartialOrd)] +pub struct Equals { + left: Rc, + right: Rc, +} + +impl Node for Equals { + fn evaluate(&self, env: &mut Environment) -> Result, String> { + let left = self.left.evaluate(env)?; + let right = self.right.evaluate(env)?; + + match left == right { + true => Ok(Rc::new(Bool::True.into())), + false => Ok(Rc::new(Bool::False.into())), + } + } + + fn as_string(&self, env: Option<&Environment>) -> String { + format!( + "({}={})", + self.left.as_string(env), + self.right.as_string(env) + ) + } + + fn precedence(&self) -> Precedence { + Precedence::Primary + } +} + +impl Equals { + pub fn new(left: Rc, right: Rc) -> Self { + Self { left, right } + } +} diff --git a/src/lib/node/function.rs b/src/lib/node/function.rs index f4897c9..ecaa5e9 100644 --- a/src/lib/node/function.rs +++ b/src/lib/node/function.rs @@ -30,7 +30,7 @@ impl Node for Function { let args = self .arguments .iter() - .map(|x| Node::as_string(x, None)) + .map(|x| Node::as_string(x, env)) .reduce(|acc, e| format!("{acc}, {e}")) .unwrap_or("()".to_owned()); @@ -46,10 +46,15 @@ impl Node for Function { } impl Function { - // TODO: Implement new. - // pub fn new(t: FunctionType, ) -> Self { - // - // } + pub fn new(t: FunctionType, args: Vec) -> Rc { + Rc::new( + Self { + function: t, + arguments: args, + } + .into(), + ) + } pub fn get_body(&self) -> &FunctionType { &self.function diff --git a/src/lib/node/mod.rs b/src/lib/node/mod.rs index 7d68104..6db3aa4 100644 --- a/src/lib/node/mod.rs +++ b/src/lib/node/mod.rs @@ -12,6 +12,8 @@ use if_else::{Bool, IfElse}; use multiply::Multiply; use subtract::Subtract; use symbol::Symbol; +use equals::Equals; +use set::Set; use crate::environment::Environment; @@ -21,12 +23,14 @@ pub mod divide; pub mod multiply; pub mod subtract; pub mod symbol; -mod node_ref; -mod assign; -mod empty; -mod function; -mod call; -mod if_else; +pub mod node_ref; +pub mod assign; +pub mod empty; +pub mod function; +pub mod call; +pub mod if_else; +pub mod equals; +pub mod set; #[enum_dispatch] #[enum_dispatch(Debug, Clone, PartialEq, PartialOrd, ToString)] @@ -50,6 +54,14 @@ pub enum NodeEnum { Bool, IfElse, + Set, + + Equals, + // Greater, + // GreaterEquals, + // Less, + // LessEquals + // Logical operators // In, // Where, diff --git a/src/lib/node/multiply.rs b/src/lib/node/multiply.rs index ffe632a..564d4ff 100644 --- a/src/lib/node/multiply.rs +++ b/src/lib/node/multiply.rs @@ -1,6 +1,8 @@ use std::rc::Rc; -use super::{Node, NodeEnum, Precedence, constant::Constant}; +use crate::environment::Environment; + +use super::{Node, NodeEnum, Precedence, constant::Constant, set::Set}; #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Multiply { @@ -14,10 +16,70 @@ impl Node for Multiply { let evaluated_right = self.right.evaluate(env)?; match (evaluated_left.as_ref(), evaluated_right.as_ref()) { + // Zero rule + (NodeEnum::Constant(zero), _) | (_, NodeEnum::Constant(zero)) + if zero.get_value() == 0. => + { + Ok(Rc::new(Constant::new(0.).into())) + } + + // Constant + Constant = Constant (NodeEnum::Constant(a), NodeEnum::Constant(b)) => { Ok(Rc::new(Constant::new(a.get_value() * b.get_value()).into())) } - _ => Err(format!("Invalid Multiply operation: {:?}", self)), + + // Symbol + Constant we just return the same + (NodeEnum::Symbol(_), NodeEnum::Constant(_)) => Ok(Rc::new( + Multiply::new(evaluated_right, evaluated_left).into(), + )), + + // Constant + Symbol we switch them around so the constant is last + (NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new( + Multiply::new(evaluated_left, evaluated_right).into(), + )), + + // Multiply a set with a constant + (NodeEnum::Set(s), NodeEnum::Constant(c)) + | (NodeEnum::Constant(c), NodeEnum::Set(s)) => { + let old_values = s.get_values(); + let mut values = Vec::with_capacity(old_values.len()); + let c: Rc = Rc::new(c.clone().into()); + + for value in old_values.iter() { + let new_value = Multiply::new(c.clone(), value.clone()); + values.push(new_value.evaluate(env)?); + } + + Ok(Set::new(values)) + } + + // Multiply a set with a constant + (NodeEnum::Set(s), NodeEnum::Symbol(c)) | (NodeEnum::Symbol(c), NodeEnum::Set(s)) => { + let old_values = s.get_values(); + let mut values = Vec::with_capacity(old_values.len()); + let c: Rc = Rc::new(c.clone().into()); + + for value in old_values.iter() { + let new_value = Multiply::new(c.clone(), value.clone()); + values.push(new_value.evaluate(env)?); + } + + Ok(Set::new(values)) + } + + (NodeEnum::Constant(c), NodeEnum::Multiply(m)) + | (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => { + Self::collapse_nested_multiply(c, m, env)?.evaluate(env) + } + + // (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => { + // Self::move_constants_to_left(evaluated_left.clone(), evaluated_right.clone()) + // } + + // Default to returning with left and right evaluated + _ => Ok(Rc::new( + Multiply::new(evaluated_left, evaluated_right).into(), + )), } } @@ -41,13 +103,79 @@ impl Node for Multiply { } impl Multiply { - pub fn new(left: Rc, right: Rc) -> Self { - Self { - left, - right + fn collapse_nested_multiply( + constant: &Constant, + multiply: &Multiply, + env: &mut Environment, + ) -> Result, String> { + match (multiply.left.as_ref(), multiply.right.as_ref()) { + (NodeEnum::Constant(c2), _) => { + let new_const = Constant::new(constant.get_value() * c2.get_value()).into(); + Ok(Rc::new( + Multiply::new(Rc::new(new_const), multiply.right.clone()).into(), + )) + } + + (_, NodeEnum::Constant(c2)) => { + let new_const = Constant::new(constant.get_value() * c2.get_value()).into(); + Ok(Rc::new( + Multiply::new(Rc::new(new_const), multiply.right.clone()).into(), + )) + } + + (_, NodeEnum::Multiply(inner_mul)) => { + let expr = Self::collapse_nested_multiply(constant, inner_mul, env)?; + Ok(Rc::new(Multiply::new(expr, multiply.left.clone()).into())) + } + + (NodeEnum::Multiply(inner_mul), _) => { + let expr = Self::collapse_nested_multiply(constant, inner_mul, env)?; + Ok(Rc::new(Multiply::new(expr, multiply.right.clone()).into())) + } + + _ => Ok(Rc::new( + Multiply::new( + Rc::new(constant.clone().into()), + Rc::new(multiply.clone().into()), + ) + .into(), + )), } } + fn move_constants_to_left( + left: Rc, + right: Rc, + ) -> Result, String> { + match (left.as_ref(), right.as_ref()) { + // Default cases that returns + (NodeEnum::Constant(_), NodeEnum::Multiply(_)) + | (NodeEnum::Symbol(_), NodeEnum::Symbol(_)) => Ok(Self::new_rc(left, right)), + + (NodeEnum::Multiply(m), NodeEnum::Constant(c)) => Ok(Self::new_rc( + right.clone(), + Self::move_constants_to_left(m.left.clone(), m.right.clone())?, + )), + + (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => Ok(Self::new_rc( + Self::move_constants_to_left(m1.left.clone(), m1.right.clone())?, + Self::move_constants_to_left(m2.left.clone(), m2.right.clone())?, + )), + + _ => Ok(Self::new_rc(left, right)), + } + } +} + +impl Multiply { + pub fn new(left: Rc, right: Rc) -> Self { + Self { left, right } + } + + pub fn new_rc(left: Rc, right: Rc) -> Rc { + Rc::new(Self::new(left, right).into()) + } + pub fn get_left(&self) -> Rc { self.left.clone() } diff --git a/src/lib/node/set.rs b/src/lib/node/set.rs new file mode 100644 index 0000000..d37f4fb --- /dev/null +++ b/src/lib/node/set.rs @@ -0,0 +1,49 @@ +use std::rc::Rc; + +use super::{Environment, Node, NodeEnum, Precedence}; + +#[derive(Clone, Debug, PartialEq, PartialOrd)] +pub struct Set { + values: Vec>, +} + +impl Node for Set { + fn evaluate(&self, env: &mut super::Environment) -> Result, String> { + let mut values = Vec::with_capacity(self.values.len()); + + for value in self.values.iter() { + values.push(value.evaluate(env)?); + } + + Ok(Self::new(values)) + } + + fn as_string(&self, env: Option<&Environment>) -> String { + format!( + "({})", + self.values + .iter() + .map(|x| x.as_string(env)) + .reduce(|a, b| a + ", " + &b) + .unwrap() + ) + } + + fn precedence(&self) -> Precedence { + Precedence::Primary + } +} + +impl Set { + pub fn new(values: Vec>) -> Rc { + Rc::new(Self { values }.into()) + } + + pub fn get_values(&self) -> &Vec> { + &self.values + } + + pub fn set_value(&mut self, values: Vec>) { + self.values = values; + } +} diff --git a/src/lib/node/subtract.rs b/src/lib/node/subtract.rs index 70ca3bc..63c8dee 100644 --- a/src/lib/node/subtract.rs +++ b/src/lib/node/subtract.rs @@ -14,10 +14,25 @@ impl Node for Subtract { let evaluated_right = self.right.evaluate(env)?; match (evaluated_left.as_ref(), evaluated_right.as_ref()) { + // Zero rule + (NodeEnum::Constant(zero), _) if zero.get_value() == 0. => Ok(evaluated_right), + (_, NodeEnum::Constant(zero)) if zero.get_value() == 0. => Ok(evaluated_left), + + // Constant + Constant = Constant (NodeEnum::Constant(a), NodeEnum::Constant(b)) => { Ok(Rc::new(Constant::new(a.get_value() - b.get_value()).into())) } - _ => Err(format!("Invalid Add operation: {:?}", self)), + // Symbol + Constant we just return the same + (NodeEnum::Symbol(_), NodeEnum::Constant(_)) => { + Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into())) + } + // Constant + Symbol we switch them around so the constant is last + (NodeEnum::Constant(_), NodeEnum::Symbol(_)) => { + Ok(Rc::new(Subtract::new(evaluated_right, evaluated_left).into())) + } + _ => { + Ok(Rc::new(Subtract::new(evaluated_left, evaluated_right).into())) + } } } diff --git a/src/lib/node/symbol.rs b/src/lib/node/symbol.rs index 1ca8055..5ac0a8d 100644 --- a/src/lib/node/symbol.rs +++ b/src/lib/node/symbol.rs @@ -28,20 +28,12 @@ impl Node for Symbol { if let Some(value) = env.get(&self.value) { value.as_string(Some(env)) } else { - Symbol::ID_TO_STR_MAP - .lock() - .unwrap() - .get(&self.value) - .unwrap_or(&format!("{{#SYMBOL {}}}", self.value)) - .clone() + env.id_to_str(&self.value) + .cloned() + .unwrap_or(format!("{{#SYMBOL {}}}", self.value)) } } else { - Symbol::ID_TO_STR_MAP - .lock() - .unwrap() - .get(&self.value) - .unwrap_or(&format!("{{#SYMBOL {}}}", self.value)) - .clone() + format!("{{#SYMBOL {}}}", self.value) } } @@ -51,32 +43,17 @@ impl Node for Symbol { } impl Symbol { - const STR_TO_ID_MAP: LazyLock>> = - LazyLock::new(|| HashMap::new().into()); - const ID_TO_STR_MAP: LazyLock>> = - LazyLock::new(|| HashMap::new().into()); - pub fn new(value: EnvironmentInternalSymbolKey) -> Self { Self { value } } - pub fn new_from_str(str: impl Into) -> Self { + pub fn new_from_str(str: impl Into, env: &mut Environment) -> Self { let str = str.into(); - if let Some(value) = Symbol::STR_TO_ID_MAP.lock().unwrap().get(str.as_str()) { + if let Some(value) = env.str_to_id(&str) { Self::new(value.clone()) } else { - let id = Symbol::STR_TO_ID_MAP - .lock() - .unwrap() - .len() - .try_into() - .unwrap(); - Symbol::STR_TO_ID_MAP - .lock() - .unwrap() - .insert(str.clone(), id); - Symbol::ID_TO_STR_MAP.lock().unwrap().insert(id, str); - + let id = env.get_new_id(); + env.insert_str_to_id(str.clone(), id); Self::new(id) } } diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index c553034..e202386 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -1,29 +1,45 @@ -use std::{collections::HashMap, iter::Peekable, rc::Rc, slice::Iter, vec::IntoIter}; +use std::{collections::HashMap, iter::Peekable, rc::Rc, slice::Iter, str::Chars, vec::IntoIter}; -use crate::node::{ - NodeEnum, - add::Add, - constant::{Constant, ConstantValue}, - divide::Divide, - multiply::Multiply, - subtract::Subtract, +use crate::{ + environment::Environment, + node::{ + NodeEnum, + add::Add, + assign::Assign, + call::Call, + constant::{Constant, ConstantValue}, + divide::Divide, + equals::Equals, + function::{Function, FunctionType}, + multiply::Multiply, + set::Set, + subtract::Subtract, + symbol::Symbol, + }, }; #[derive(Debug)] pub struct Token(usize, TokenType); -#[derive(Debug)] +#[derive(Debug, PartialEq, Clone)] pub enum TokenType { // Space, Number(ConstantValue), + Identifier(String), Plus, Minus, Star, Slash, + Equals, + + ColonEquals, + LeftArrow, + RParen, LParen, + Comma, If, Then, @@ -31,8 +47,35 @@ pub enum TokenType { End, } +impl TokenType { + pub fn len(&self) -> usize { + match self { + TokenType::Number(n) => n.to_string().len(), + TokenType::Identifier(s) => s.len(), + + TokenType::Plus => 1, + TokenType::Minus => 1, + TokenType::Star => 1, + TokenType::Slash => 1, + TokenType::Equals => 1, + + TokenType::ColonEquals => 2, + TokenType::LeftArrow => 2, + + TokenType::RParen => 1, + TokenType::LParen => 1, + TokenType::Comma => 1, + + TokenType::If => 2, + TokenType::Then => 4, + TokenType::Else => 4, + TokenType::End => 3, + } + } +} + pub struct Lexer<'a> { - source: &'a String, + source: Peekable>, } #[derive(Debug)] @@ -42,40 +85,41 @@ pub enum LexerError { impl<'a> Lexer<'a> { pub fn new(source: &'a String) -> Self { - Self { source } + Self { + source: source.chars().peekable(), + } } pub fn lex(&'a mut self) -> Result, LexerError> { - let mut src = self.source.chars().peekable(); let mut i = 0; let mut tokens = vec![]; - while let Some(c) = src.next() { + while let Some(c) = self.source.next() { match c { // Collapse spaces into a single Space token ' ' => { - while src.peek() == Some(&' ') { - src.next(); + while self.source.peek() == Some(&' ') { + self.source.next(); i += 1; } // tokens.push(Token(i, TokenType::Space)); } // Comments with // - '/' if src.peek() == Some(&'/') => { - while src.next() != Some('\n') { + '/' if self.source.peek() == Some(&'/') => { + while self.source.next() != Some('\n') { i += 1; } } // Numbers with decimal points - '0'..'9' | '.' => { + '0'..='9' | '.' => { let mut digit = String::from(c); loop { - let d = src.peek(); + let d = self.source.peek(); let mut has_decimal = c == '.'; match d { - Some('0'..'9') => { + Some('0'..='9') => { digit.push(*d.unwrap()); - src.next(); + self.source.next(); i += 1; } #[allow(unused_assignments)] // For some reason it thinks has_decimal @@ -101,14 +145,33 @@ impl<'a> Lexer<'a> { tokens.push(Token(i, TokenType::Number(number))); } + // LeftArrow (->) + '-' if self.source.peek() == Some(&'>') => { + self.source.next(); + i += 1; + tokens.push(Token(i, TokenType::LeftArrow)); + } + '+' => tokens.push(Token(i, TokenType::Plus)), '-' => tokens.push(Token(i, TokenType::Minus)), '*' => tokens.push(Token(i, TokenType::Star)), '/' => tokens.push(Token(i, TokenType::Slash)), + '=' => tokens.push(Token(i, TokenType::Equals)), + ',' => tokens.push(Token(i, TokenType::Comma)), + + ':' if self.source.peek() == Some(&'=') => { + self.source.next(); + i += 1; + tokens.push(Token(i, TokenType::ColonEquals)); + } '(' => tokens.push(Token(i, TokenType::LParen)), ')' => tokens.push(Token(i, TokenType::RParen)), + _ if c.is_alphabetic() || c == '_' => { + tokens.push(self.lex_identifier(&mut i, c)?); + } + _ => { return Err(LexerError::UnexpectedChar( i, @@ -121,26 +184,57 @@ impl<'a> Lexer<'a> { Ok(tokens) } + + fn lex_identifier<'b>(&'b mut self, i: &mut usize, c: char) -> Result { + let mut identifier = c.to_string(); + + while let Some(c) = self.source.peek() { + if c.is_alphanumeric() || c == &'_' || c == &'\'' { + identifier.push(*c); + self.source.next(); + *i += 1; + } else { + break; + } + } + + Ok(Token( + *i, + match identifier.to_lowercase().as_str() { + "if" => TokenType::If, + "then" => TokenType::Then, + "else" => TokenType::Else, + "end" => TokenType::End, + _ => TokenType::Identifier(identifier), + }, + )) + } } pub enum ParserError { UnexpectedEndOfTokens(String), - UnexpectedToken(usize, String), + UnexpectedToken(usize, usize, String), + Unimplemented(usize, usize, String), + UnexpectedNode(usize, String), } /// Recursive descent parser -pub struct Parser { +pub struct Parser<'a> { tokens: Peekable>, + environment: &'a mut Environment, + previous: Option<&'a Token>, } type Tokens<'a> = Peekable>; -impl Parser { - pub fn new(tokens: Vec) -> Self { +impl<'a> Parser<'a> { + pub fn new(tokens: Vec, env: &'a mut Environment) -> Self { // #[cfg(debug_assertions)] - // println!("\r{tokens:#?}"); + // println!("\r{tokens:?}"); Self { tokens: tokens.into_iter().peekable(), + environment: env, + previous: None, } } @@ -155,13 +249,61 @@ impl Parser { Ok(expressions) } + #[inline] + fn matchType<'b>(&'b mut self, t: TokenType) -> bool { + if let Some(Token(_, token_type)) = self.tokens.peek() { + if *token_type == t { + self.tokens.next(); + return true; + } + } + + false + } + + #[inline] + fn matchOrErr(&mut self, t: TokenType) -> Result { + let (i, tt) = if let Some(Token(i, tt)) = self.tokens.peek() { + (*i, tt.clone()) + } else { + return Err(ParserError::UnexpectedEndOfTokens(format!( + "Expected {t:?} but found nothing instead" + ))); + }; + + if self.matchType(t.clone()) { + Ok(true) + } else { + Err(ParserError::UnexpectedToken( + i, + tt.len(), + format!("Expected {t:?} but found {tt:?} instead"), + )) + } + } + fn expression(&mut self) -> Result, ParserError> { - self.equality() + self.assignment() + } + + fn assignment(&mut self) -> Result, ParserError> { + let expr = self.equality(); + + if let Some(Token(_, TokenType::ColonEquals)) = self.tokens.peek() { + self.tokens.next(); + return Ok(Rc::new(Assign::new(expr?, self.equality()?).into())); + } + + expr } fn equality(&mut self) -> Result, ParserError> { // TODO: Implement equality - self.comparison() + let expr = self.comparison(); + if self.matchType(TokenType::Equals) { + return Ok(Rc::new(Equals::new(expr?, self.equality()?).into())); + } + expr } fn comparison(&mut self) -> Result, ParserError> { @@ -171,8 +313,7 @@ impl Parser { fn term(&mut self) -> Result, ParserError> { let expr = self.factor()?; - if let Some(Token(_, TokenType::Plus)) = self.tokens.peek() { - self.tokens.next(); + if self.matchType(TokenType::Plus) { Ok(Rc::new(Add::new(expr, self.comparison()?).into())) } else if let Some(Token(_, TokenType::Minus)) = self.tokens.peek() { self.tokens.next(); @@ -204,11 +345,83 @@ impl Parser { } fn call(&mut self) -> Result, ParserError> { - self.function() + let mut expr = self.function(); + + loop { + let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() { + (*i, x.clone()) + } else { + return expr; + }; + + if t == TokenType::LParen { + let potential_parameters = self.primary()?; + let parameters = if let NodeEnum::Set(set) = potential_parameters.as_ref() { + potential_parameters + } else { + // return Err(ParserError::UnexpectedNode( + // i, + // format!("Expected a Set here, but got a {potential_parameters:?}"), + // )); + Set::new(vec![potential_parameters]) + }; + + expr = Ok(Call::new(expr?, parameters)); + } else { + break; + } + } + + expr } fn function(&mut self) -> Result, ParserError> { - self.primary() + let error_loc = if let Some(Token(i, _)) = self.tokens.peek() { + *i + } else { + 0 + }; + + let expr = self.primary()?; + + if self.matchType(TokenType::LeftArrow) { + let right = self.equality()?; + match expr.clone().as_ref() { + NodeEnum::Symbol(symbol) => { + return Ok(Function::new( + FunctionType::UserFunction(right), + vec![symbol.clone()], + )); + } + NodeEnum::Set(set) => { + let mut symbols = vec![]; + for (i, value) in set.get_values().into_iter().enumerate() { + match value.as_ref() { + _ => { + return Err(ParserError::UnexpectedNode( + error_loc, + format!( + "Expected set of Identifiers, but argument #{i} is a {value:?}" + ), + )); + } + + NodeEnum::Symbol(symbol) => symbols.push(symbol.clone()), + } + } + + return Ok(Function::new(FunctionType::UserFunction(right), symbols)); + } + _ => { + return Err(ParserError::UnexpectedNode( + error_loc, + format!("Expected Set, got {:?}", expr), + )); + } + } + } + + Ok(expr) } fn primary(&mut self) -> Result, ParserError> { @@ -222,8 +435,73 @@ impl Parser { match token { TokenType::Number(value) => Ok(Rc::new(Constant::new(value).into())), + TokenType::Identifier(string) => Ok(Rc::new( + Symbol::new_from_str(string, self.environment).into(), + )), + TokenType::LParen => { + let expr = self.expression()?; + let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() { + (i, x) + } else { + return Err(ParserError::UnexpectedEndOfTokens( + "Unclosed right parenthesis".into(), + )); + }; + + match t { + TokenType::RParen => { + self.tokens.next(); + Ok(expr) + } + TokenType::Comma => { + let mut values = vec![expr]; + while { + if let Some(Token(_, TokenType::RParen)) = self.tokens.peek() { + self.tokens.next(); + false + } else { + true + } + } { + let (i, token) = if let Some(Token(i, x)) = self.tokens.peek() { + (i, x) + } else { + return Err(ParserError::UnexpectedEndOfTokens( + "Expected comma here".into(), + )); + }; + + if *token == TokenType::Comma { + self.tokens.next(); + } else { + return Err(ParserError::UnexpectedToken( + *i, + token.len(), + format!("Expected comma here, but got {token:?}"), + )); + } + + values.push(self.equality()?); + } + + Ok(Set::new(values)) + } + _ => Err(ParserError::Unimplemented( + *i, + t.len(), + format!("Expected either a comma or a right parenthesis here. Got {t:?}"), + )), + } + + // if t != TokenType::RParen { + // Err(ParserError::UnexpectedToken(i, t.len(), format!(""))) + // } else { + // Ok(expr) + // } + } _ => Err(ParserError::UnexpectedToken( i, + token.len(), format!("Unexpected token {token:?}"), )), }