From b7b466b77462c81d6d8a8bb2c9e01c70f11dbbf1 Mon Sep 17 00:00:00 2001 From: Book-reader Date: Fri, 5 Sep 2025 20:37:13 +1200 Subject: [PATCH] *Mostly* works, apart from `4 sqrt 4` being `1.4142135623730951` for some reason (messed up unary operators or something) --- asklyphe-frontend/src/math.rs | 62 ++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/asklyphe-frontend/src/math.rs b/asklyphe-frontend/src/math.rs index fc7b224..3f100c4 100644 --- a/asklyphe-frontend/src/math.rs +++ b/asklyphe-frontend/src/math.rs @@ -10,9 +10,11 @@ pub struct Calculation { pub fn calculate(query: &str) -> Option { debug!("Got query {}", query); let mut parser = Parser::new(Lexer::new(query)); - debug!("Parse tree: {:?}", parser.parse()); - // debug!("final token was: {:?}", lexer.next()); - // debug!("Tokens: {:?}", lexer.lex_all()); + let res = parser.parse()?; + + debug!("Calculation: {}", query); + debug!("Tree: {:?}", res); + debug!("Result: {}", res.eval()); None } @@ -43,7 +45,7 @@ impl Op { BinOp::Divide => 2.0, BinOp::Exponent => 3.0, }, - Op::Func(_) => 2.9, // TODO: decide if this is a good LBP + Op::Func(_) => 0.9, // TODO: decide if this is a good LBP } } @@ -62,6 +64,26 @@ impl Op { } } + + fn apply_to(&self, args: &Vec) -> f64 { + match (self) { + Op::BinOp(op) => match op { + BinOp::LParen => args[0].eval(), + BinOp::RParen => args[0].eval(), + BinOp::Add => args[0].eval() + args[1].eval(), + BinOp::Subtract => args[0].eval() - args[1].eval(), + BinOp::Multiply => args[0].eval() * args[1].eval(), + BinOp::Divide => args[0].eval() / args[1].eval(), + BinOp::Exponent => args[0].eval().powf(args[1].eval()), + }, + Op::Func(f) => match f { + Func::Sine => args[0].eval().sin(), + Func::ArcSine => args[0].eval().asin(), + Func::SquareRoot => args[0].eval().sqrt(), + _ => todo!("{:?}", f), + }, + } + } } #[derive(Debug, Copy, Clone)] @@ -185,6 +207,27 @@ impl Lexer<'_> { self.idx += l; return Ok(Token::Op(Op::Func(Func::Tangent))); } + l = matches(&self.data[self.idx - 1..], "arcsin"); + if l != 0 { + self.idx += l; + return Ok(Token::Op(Op::Func(Func::ArcSine))); + } + l = matches(&self.data[self.idx - 1..], "arccos"); + if l != 0 { + self.idx += l; + return Ok(Token::Op(Op::Func(Func::ArcCosine))); + } + l = matches(&self.data[self.idx - 1..], "arctan"); + if l != 0 { + self.idx += l; + return Ok(Token::Op(Op::Func(Func::ArcTangent))); + } + l = matches(&self.data[self.idx - 1..], "sqrt"); + if l != 0 { + self.idx += l; + return Ok(Token::Op(Op::Func(Func::SquareRoot))); + } + debug!("got invalid char '{}'", val); Err(ParseErr::Invalid) } @@ -289,3 +332,14 @@ enum Expr { Atom(Atom), Node(Op, Vec), } + +impl Expr { + fn eval(&self) -> f64 { + let res = match (self) { + Expr::Atom(at) => at.get_val(), + Expr::Node(op, exprs) => op.apply_to(exprs), + }; + // debug!("{:?} evaluated to {}", self, res); + res + } +}