diff --git a/asklyphe-frontend/src/math.rs b/asklyphe-frontend/src/math.rs index 58a6455..d3ea75f 100644 --- a/asklyphe-frontend/src/math.rs +++ b/asklyphe-frontend/src/math.rs @@ -20,11 +20,11 @@ pub struct Calculation { pub fn calculate(query: &str) -> Option { debug!("Got query {}", query); let mut parser = Parser::new(Lexer::new(query)); - let tree = parser.parse()?; + let mut tree = parser.parse()?; let res = tree.eval(); debug!("Calculation: {}", query); - debug!("Tree: {:?}", tree); + // debug!("Tree: {:?}", tree); debug!("Result: {}", res); Some(Calculation {equation: query.to_string(), result: res.to_string()}) } @@ -38,7 +38,7 @@ enum Token { Func(Func),*/ } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Op { Add, Subtract, @@ -74,7 +74,7 @@ impl Op { } } - fn apply_to(&self, args: &Vec) -> BigFloat { + fn apply_to(&self, args: &mut Vec) -> BigFloat { match args.len() { 1 => match self { Op::Subtract => { @@ -113,12 +113,12 @@ impl Op { 2 => match self { Op::LParen => args[0].eval(), Op::RParen => args[0].eval(), - Op::Add => args[0].eval().add(&args[1].eval(), PRECISION, RoundingMode::None), - Op::Subtract => args[0].eval().sub(&args[1].eval(), PRECISION, RoundingMode::None), - Op::Multiply => args[0].eval().mul(&args[1].eval(), PRECISION, RoundingMode::None), - Op::Divide => args[0].eval().div(&args[1].eval(), PRECISION, RoundingMode::None), - Op::Exponent => args[0].eval().pow(&args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), - Op::Func(Func::Log) => args[0].eval().log(&args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Op::Add => args[0].eval().add(&mut args[1].eval(), PRECISION, RoundingMode::None), + Op::Subtract => args[0].eval().sub(&mut args[1].eval(), PRECISION, RoundingMode::None), + Op::Multiply => args[0].eval().mul(&mut args[1].eval(), PRECISION, RoundingMode::None), + Op::Divide => args[0].eval().div(&mut args[1].eval(), PRECISION, RoundingMode::None), + Op::Exponent => args[0].eval().pow(&mut args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), + Op::Func(Func::Log) => args[0].eval().log(&mut args[1].eval(), PRECISION, RoundingMode::None, &mut CONST_CACHE.lock().unwrap()), _ => { error!("Got 2 params for {:?} which only expects 1 (should not be possible)", self); astro_float::NAN @@ -134,11 +134,11 @@ impl Op { #[derive(Debug, Clone, PartialEq)] enum Atom { - Number(BigFloat), // TODO: use the high precision floats library instead + Number(BigFloat), Const(Const), } -impl Atom { +/*impl Atom { fn get_val(&self) -> BigFloat { match self { Atom::Number(val) => *val, @@ -150,9 +150,20 @@ impl Atom { } } } +}*/ + +impl Const { + fn get_val(&self) -> BigFloat { + match self { + Const::Pi => CONST_CACHE.lock().unwrap().pi(PRECISION, RoundingMode::None), + Const::E => CONST_CACHE.lock().unwrap().e(PRECISION, RoundingMode::None), + Const::Inf => astro_float::INF_POS, + Const::Nan => astro_float::NAN, + } + } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Func { Sine, Cosine, @@ -190,7 +201,7 @@ impl Func { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Const { Pi, E, @@ -211,7 +222,7 @@ impl Const { } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] enum ParseErr { Eof, Invalid, @@ -295,13 +306,14 @@ impl Lexer<'_> { } fn next(&mut self) -> Result { - let val = mem::replace(&mut self.next_tok, self._next()); + let res = self._next(); + let val = mem::replace(&mut self.next_tok, res); // self.next_tok = self._next(); val } - fn peek(&mut self) -> Result { - self.next_tok + fn peek(&mut self) -> &Result { + &self.next_tok } // TODO: replace with iterator so I can do parser.parse(lexer.iter()) and parse does lex_iter.next() & such @@ -373,14 +385,14 @@ impl Parser<'_> { debug!("loop start"); let op: Op = match self.lex.peek() { Err(ParseErr::Eof) => break, - Err(e) => { debug!("In expr got err {:?}", e); Err(e) }, + Err(e) => { debug!("In expr got err {:?}", e); Err(*e) }, Ok(tok) => match tok { Token::Op(op) => match op { Op::RParen => { debug!("got RParen"); break; }, - _ => Ok(op), + _ => Ok(*op), } v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) }, } @@ -403,15 +415,31 @@ impl Parser<'_> { #[derive(Debug)] enum Expr { + Evaluated, Atom(Atom), Node(Op, Vec), } impl Expr { - fn eval(&self) -> BigFloat { - let res = match (self) { - Expr::Atom(at) => at.get_val(), - Expr::Node(op, exprs) => op.apply_to(exprs), + fn eval(&mut self) -> BigFloat { + let res = match self { + Expr::Atom(_) => { + let v = mem::replace(self, Expr::Evaluated); + if let Expr::Atom(at) = v { + match at { + Atom::Number(n) => n, + Atom::Const(c) => c.get_val(), + } + } else { + unreachable!(); + } + // at.get_val() + } + Expr::Node(op, exprs) => { + *self = Expr::Atom(Atom::Number(op.apply_to(exprs))); + self.eval() + } + Expr::Evaluated => unreachable!("Tried to evaluate an already evaluated node"), }; // debug!("{:?} evaluated to {}", self, res); res