From 47477732bac8b56ea30e321adc38ba428fd2bc35 Mon Sep 17 00:00:00 2001 From: Book-reader Date: Fri, 5 Sep 2025 23:32:21 +1200 Subject: [PATCH] finish up lexing & do some parsing improvements (functions now require parens for multiple args :(, I'll see if I can change that later) --- asklyphe-frontend/src/math.rs | 109 +++++++++++++++++----------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/asklyphe-frontend/src/math.rs b/asklyphe-frontend/src/math.rs index 014a2af..125061f 100644 --- a/asklyphe-frontend/src/math.rs +++ b/asklyphe-frontend/src/math.rs @@ -20,7 +20,7 @@ pub fn calculate(query: &str) -> Option { } // TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than f64 -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Token { Op(Op), Atom(Atom), @@ -28,7 +28,7 @@ enum Token { Func(Func),*/ } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Op { Add, Subtract, @@ -57,7 +57,7 @@ impl Op { fn bp_prefix(&self) -> Option { match self { - Op::Func(_) => Some(0.1), + Op::Func(_) => Some(6.0), Op::Subtract => Some(5.0), Op::Add => Some(5.0), _ => None, @@ -78,10 +78,12 @@ impl Op { Func::ArcTangent => Some(args[0].eval().atan()), Func::Log2 => Some(args[0].eval().log2()), Func::Log10 => Some(args[0].eval().log10()), + Func::LogN => Some(args[0].eval().ln()), Func::Square => Some(args[0].eval().powf(2.0)), Func::SquareRoot => Some(args[0].eval().sqrt()), - Func::LogN => None, - _ => todo!("{:?}", self) + Func::Abs => Some(args[0].eval().abs()), + Func::Log => None, + // _ => todo!("{:?}", self) } _ => None, } @@ -93,7 +95,7 @@ impl Op { Op::Multiply => Some(args[0].eval() * args[1].eval()), Op::Divide => Some(args[0].eval() / args[1].eval()), Op::Exponent => Some(args[0].eval().powf(args[1].eval())), - Op::Func(Func::LogN) => Some(args[0].eval().log(args[1].eval())), + Op::Func(Func::Log) => Some(args[0].eval().log(args[1].eval())), _ => None, } _ => None, @@ -105,7 +107,7 @@ impl Op { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Atom { Number(f64), // TODO: use the high precision floats library instead Const(Const), @@ -123,7 +125,7 @@ impl Atom { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq)] enum Func { Sine, Cosine, @@ -135,17 +137,39 @@ enum Func { Log2, Log10, LogN, + Log, Square, SquareRoot, + Abs, } -#[derive(Debug, Copy, Clone)] +impl Func { + fn names() -> &'static [(Func, &'static [&'static str])] { + &[ + (Func::Sine, &["sin", "sine"]), + (Func::Cosine, &["cos", "cosine"]), + (Func::Tangent, &["tan", "tangent"]), + (Func::ArcSine, &["asin", "asine", "arcsin", "arcsine"]), + (Func::ArcCosine, &["acos", "acosine", "arccos", "arccosine"]), + (Func::ArcTangent, &["atan", "atangent", "arctan", "arctangent"]), + (Func::Log2, &["log2"]), + (Func::Log10, &["log10"]), + (Func::LogN, &["ln", "logn"]), + (Func::Log, &["log"]), + (Func::Square, &["square", "squared"]), + (Func::SquareRoot, &["sqrt", "squareroot", "√"]), + (Func::Abs, &["abs", "absolute"]), + ] + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] enum Const { Pi, E, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq)] enum ParseErr { Eof, Invalid, @@ -189,7 +213,7 @@ impl Lexer<'_> { _ if val.is_digit(10) => { let mut len: usize = 0; self.data_ptr.chars().take_while(|c| c.is_digit(10) || *c == '.').for_each(|_| len += 1); - self.next_by += len - 1; + self.next_by = len; match self.data_ptr[..len].parse() { Ok(val) => Ok(Token::Atom(Atom::Number(val))), @@ -197,46 +221,15 @@ impl Lexer<'_> { } }, _ => { -/* match (&self.data[self.idx - 1..]) { - s if s.starts_with("" + let len = self.data_ptr.chars().count(); + for (f, names) in Func::names() { + for name in *names { + if self.data_ptr.starts_with(name) { + self.next_by = if self.data_ptr.len() > name.len() { name.chars().count() + 1} else { name.chars().count() }; + return Ok(Token::Op(Op::Func(*f))); + } + } } - let mut l: usize; - l = matches(&self.data[self.idx - 1..], "sin"); - if l != 0 { - self.idx += l; - return Ok(Token::Op(Op::Func(Func::Sine))); - } - l = matches(&self.data[self.idx - 1..], "cos"); - if l != 0 { - self.idx += l; - return Ok(Token::Op(Op::Func(Func::Cosine))); - } - l = matches(&self.data[self.idx - 1..], "tan"); - if l != 0 { - 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) } @@ -304,7 +297,11 @@ impl Parser<'_> { Ok(val) => match val { Token::Atom(val) => Ok(Expr::Atom(val)), Token::Op(op) => match op { - Op::LParen => self.parse_expr(0.0), + Op::LParen => { + let val = self.parse_expr(0.0); + assert_eq!(self.lex.next(), Ok(Token::Op(Op::RParen))); + val + }, // Op::Func(f) => Ok(Expr::Node(Op::Func(f), vec![self.parse_expr(op.get_lbp())?])), _ => match op.bp_prefix() { Some(bp) => Ok(Expr::Node(op, vec![self.parse_expr(bp)?])), @@ -314,19 +311,24 @@ impl Parser<'_> { }, Err(err) => Err(err), }.map_err(|err| { debug!("Unexpected error at start of expr: {:?}", err); err })?; - debug!("lhs of expression is {:?}", lhs); + debug!("lhs of expression is {:?}, min_bp is {}", lhs, min_bp); loop { + debug!("loop start"); let op: Op = match self.lex.peek() { Err(ParseErr::Eof) => break, Err(e) => { debug!("In expr got err {:?}", e); Err(e) }, Ok(tok) => match tok { Token::Op(op) => match op { - Op::RParen => break, + Op::RParen => { + debug!("got RParen"); + break; + }, _ => Ok(op), } v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) }, } }.map_err(|err| { debug!("Unexpected error inside expr at {:?}", err); err })?; + debug!("op is {:?}", op); if let Some((lbp, rbp)) = op.bp_infix() { if (lbp < min_bp) { break; } self.lex.next(); @@ -337,6 +339,7 @@ impl Parser<'_> { return Err(ParseErr::Invalid); } } + debug!("Returning expr {:?}", lhs); Ok(lhs) } }