diff --git a/src/lib/node/constant.rs b/src/lib/node/constant.rs index 64f00a2..c9a79ed 100644 --- a/src/lib/node/constant.rs +++ b/src/lib/node/constant.rs @@ -26,7 +26,11 @@ impl Node for Constant { if self.value.is_zero() { return "0".to_string(); } - + + if self.value < 1. && self.value > 0.001 { + return self.value.to_f64().to_string(); + } + self.value .to_string_radix(10, Some(8)) .trim_end_matches('0') diff --git a/src/lib/node/divide.rs b/src/lib/node/divide.rs index 5fb23a3..a8a3f0a 100644 --- a/src/lib/node/divide.rs +++ b/src/lib/node/divide.rs @@ -26,8 +26,27 @@ impl Node for Divide { } // Zero rule - (NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => { - Ok(evaluated_left) + (NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => Ok(evaluated_left), + + // Cancel out symbols and constants + (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => { + match ( + (m1.get_left().as_ref(), m1.get_right().as_ref()), + (m2.get_left().as_ref(), m2.get_right().as_ref()), + ) { + ((NodeEnum::Symbol(s1), o1), (NodeEnum::Symbol(s2), o2)) + | ((o1, NodeEnum::Symbol(s1)), (NodeEnum::Symbol(s2), o2)) + | ((NodeEnum::Symbol(s1), o1), (o2, NodeEnum::Symbol(s2))) + | ((o1, NodeEnum::Symbol(s1)), (o2, NodeEnum::Symbol(s2))) => { + if s1 == s2 { + Divide::new(Rc::new(o1.clone()), Rc::new(o2.clone())).evaluate(env) + } else { + Ok(Divide::new_rc(evaluated_left, evaluated_right)) + } + } + + _ => Ok(Rc::new(Divide::new(evaluated_left, evaluated_right).into())), + } } // Constant / Constant = Constant diff --git a/src/lib/node/multiply.rs b/src/lib/node/multiply.rs index 10cf7ce..b9b42f1 100644 --- a/src/lib/node/multiply.rs +++ b/src/lib/node/multiply.rs @@ -63,6 +63,18 @@ impl Node for Multiply { div.get_right(), )), + // 0.5*n -> n/2 + (NodeEnum::Constant(c), _) if c.get_value() == &0.5 => Divide::new( + evaluated_right, + Rc::new(Constant::new_from_float(2, &env).into()), + ) + .evaluate(env), + (_, NodeEnum::Constant(c)) if c.get_value() == &0.5 => Divide::new( + evaluated_left, + Rc::new(Constant::new_from_float(2, &env).into()), + ) + .evaluate(env), + // Constant * Constant = Constant (NodeEnum::Constant(a), NodeEnum::Constant(b)) => { Ok(Rc::new(NodeEnum::from(Constant::new(Float::with_val_64( @@ -106,10 +118,10 @@ impl Node for Multiply { 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::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()) diff --git a/src/lib/node/subtract.rs b/src/lib/node/subtract.rs index 3eee08b..d6bdbc1 100644 --- a/src/lib/node/subtract.rs +++ b/src/lib/node/subtract.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use rug::Float; -use super::{Environment, Node, NodeEnum, Precedence, constant::Constant}; +use super::{Environment, Node, NodeEnum, Precedence, constant::Constant, multiply::Multiply}; #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Subtract { @@ -35,9 +35,63 @@ impl Node for Subtract { (NodeEnum::Constant(_), NodeEnum::Symbol(_)) => Ok(Rc::new( Subtract::new(evaluated_right, evaluated_left).into(), )), - _ => Ok(Rc::new( - Subtract::new(evaluated_left, evaluated_right).into(), - )), + + (NodeEnum::Multiply(m1), NodeEnum::Multiply(m2)) => { + match ( + (m1.get_left().as_ref(), m1.get_right().as_ref()), + (m2.get_left().as_ref(), m2.get_right().as_ref()), + ) { + ((NodeEnum::Symbol(s1), o1), (NodeEnum::Symbol(s2), o2)) + | ((o1, NodeEnum::Symbol(s1)), (NodeEnum::Symbol(s2), o2)) + | ((NodeEnum::Symbol(s1), o1), (o2, NodeEnum::Symbol(s2))) + | ((o1, NodeEnum::Symbol(s1)), (o2, NodeEnum::Symbol(s2))) => { + if s1 == s2 { + Multiply::new_rc( + Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone())) + .evaluate(env)?, + Rc::new(s1.clone().into()), + ) + .evaluate(env) + } else { + Ok(Rc::new( + Subtract::new(evaluated_left, evaluated_right).into(), + )) + } + } + + ((NodeEnum::Exponent(e1), o1), (NodeEnum::Exponent(e2), o2)) + | ((o1, NodeEnum::Exponent(e1)), (NodeEnum::Exponent(e2), o2)) + | ((NodeEnum::Exponent(e1), o1), (o2, NodeEnum::Exponent(e2))) + | ((o1, NodeEnum::Exponent(e1)), (o2, NodeEnum::Exponent(e2))) => { + if e1 == e2 { + Multiply::new_rc( + Subtract::new(Rc::new(o1.clone()), Rc::new(o2.clone())) + .evaluate(env)?, + Rc::new(e1.clone().into()), + ) + .evaluate(env) + } else { + Ok(Rc::new( + Subtract::new(evaluated_left, evaluated_right).into(), + )) + } + } + + _ => Ok(Rc::new( + Subtract::new(evaluated_left, evaluated_right).into(), + )), + } + } + + _ => { + if evaluated_left == evaluated_right { + Ok(Rc::new(Constant::new_from_float(0.0, &env).into())) + } else { + Ok(Rc::new( + Subtract::new(evaluated_left, evaluated_right).into(), + )) + } + } } } diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 4ea4ab3..b9158e9 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -1,4 +1,9 @@ -use std::{iter::Peekable, rc::Rc, str::Chars, vec::IntoIter}; +use std::{ + iter::Peekable, + rc::Rc, + str::{Chars, SplitTerminator}, + vec::IntoIter, +}; use rug::Float; @@ -63,6 +68,8 @@ pub enum TokenType { True, False, + + Terminator, } impl TokenType { @@ -100,6 +107,8 @@ impl TokenType { TokenType::True => 4, TokenType::False => 5, + + Self::Terminator => 1, } } } @@ -240,6 +249,8 @@ impl<'a> Lexer<'a> { tokens.push(Token(i, TokenType::ColonEquals)); } + ';' => tokens.push(Token(i, TokenType::Terminator)), + '(' => tokens.push(Token(i, TokenType::LParen)), ')' => tokens.push(Token(i, TokenType::RParen)), @@ -293,6 +304,7 @@ impl<'a> Lexer<'a> { } } +#[derive(Debug)] pub enum ParserError { UnexpectedEndOfTokens(String), UnexpectedToken(usize, usize, String), @@ -325,8 +337,18 @@ impl<'a> Parser<'a> { pub fn parse(&mut self) -> Result>, ParserError> { let mut expressions = vec![]; - while self.tokens.peek().is_some() { + if self.tokens.len() == 0 { + return Ok(expressions); + } + + loop { expressions.push(self.expression()?); + + if !self.is_at_end() { + self.match_or_err(TokenType::Terminator)?; + } else { + break; + } } Ok(expressions) @@ -462,16 +484,31 @@ impl<'a> Parser<'a> { } fn factor(&mut self) -> Result, ParserError> { - let expr = self.unary()?; - if let Some(Token(_, TokenType::Star)) = self.tokens.peek() { - self.consume(); - Ok(Rc::new(Multiply::new(expr, self.comparison()?).into())) - } else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() { - self.consume(); - Ok(Rc::new(Divide::new(expr, self.comparison()?).into())) - } else { - Ok(expr) + let mut expr = self.unary()?; + // if let Some(Token(_, TokenType::Star)) = self.tokens.peek() { + // self.consume(); + // Ok(Rc::new(Multiply::new(expr, self.comparison()?).into())) + // } else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() { + // self.consume(); + // Ok(Rc::new(Divide::new(expr, self.comparison()?).into())) + // } else { + // Ok(expr) + // } + + loop { + if self.match_type(TokenType::Star) { + let right = self.unary()?; + expr = Multiply::new_rc(expr, right); + continue; + } else if self.match_type(TokenType::Slash) { + let right = self.unary()?; + expr = Divide::new_rc(expr, right); + continue; + } + break; } + + Ok(expr) } fn unary(&mut self) -> Result, ParserError> { @@ -729,7 +766,7 @@ impl<'a> Parser<'a> { )); }; - match token { + let expr = match token { TokenType::Number(value) => { let value = if let Ok(incomplete) = Float::parse(&value) { Float::with_val_64(self.environment.get_float_precision(), incomplete) @@ -775,6 +812,25 @@ impl<'a> Parser<'a> { token.len(), format!("Unexpected token {token:?}"), )), + }; + + // Implicit multiplication + if !self.is_at_end() { + match self.tokens.peek().unwrap() { + Token(_, TokenType::Identifier(_)) | Token(_, TokenType::Number(_)) => { + return Ok(Multiply::new_rc(expr?, self.primary()?)); + } + Token(_, TokenType::LParen) if expr.is_ok() => { + if let NodeEnum::Symbol(_) = expr.as_ref().unwrap().as_ref() { + return expr; + } + + return Ok(Multiply::new_rc(expr?, self.primary()?)); + } + _ => {} + } } + + expr } }