use crate::eval; use crate::eval::Num; use crate::lexer::Lexer; use std::str::FromStr; enum Op { Paren, Op { prec: i8, eval: Box Num>, }, } struct Parser<'a> { r: Lexer<'a>, first_token: Option<&'a str>, stack: Vec, } impl<'a> Parser<'a> { fn peek(&mut self) -> Option<&'a str> { if let Some(t) = self.first_token { return Some(t); } let t = self.r.next()?; self.first_token = Some(t); Some(t) } fn next(&mut self) -> Option<&'a str> { if let Some(t) = std::mem::take(&mut self.first_token) { return Some(t); } self.r.next() } fn symbol(&mut self, s: &str) -> bool { let Some(t) = self.peek() else { return false; }; if t != s { return false; } let _ = self.next(); true } fn parse_num(&mut self) -> Option { let t = self.next()?; if t.contains('.') || t.contains('e') || t.contains('E') { let Ok(f) = f64::from_str(t) else { return None; }; return Some(eval::float(f)); } let Ok(i) = i64::from_str(t) else { return None; }; Some(eval::int(i)) } fn parse_const(&mut self) -> Option { if self.symbol("e") { return Some(eval::float(std::f64::consts::E)); } if self.symbol("pi") { return Some(eval::float(std::f64::consts::PI)); } self.parse_num() } fn parse_fun(&mut self) -> bool { if self.symbol("-") { self.stack.push(Op::Op { prec: 0, eval: Box::new(|n| eval::int(0).sub(n)), }); return true; } if self.symbol("sin") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::sin), }); return true; } if self.symbol("cos") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::cos), }); return true; } if self.symbol("tan") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::tan), }); return true; } if self.symbol("sqrt") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::sqrt), }); return true; } if self.symbol("log") || self.symbol("ln") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::log), }); return true; } if self.symbol("log10") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::log10), }); return true; } if self.symbol("log2") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::log2), }); return true; } if self.symbol("floor") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::floor), }); return true; } if self.symbol("ceil") || self.symbol("ceiling") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::ceil), }); return true; } if self.symbol("round") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::round), }); return true; } if self.symbol("abs") { self.stack.push(Op::Op { prec: 3, eval: Box::new(eval::Num::abs), }); return true; } false } fn eval(&mut self, n: Num, target_prec: i8) -> Num { let mut n = n; while let Some(Op::Op { prec, .. }) = self.stack.last() { if *prec < target_prec { break; } let Some(Op::Op { eval, .. }) = self.stack.pop() else { unreachable!(); }; n = eval(n); } n } fn parse_op(&mut self, n: Num) { if self.symbol("^") { let n1 = self.eval(n, 3); self.stack.push(Op::Op { prec: 2, eval: Box::new(move |n2| n1.pow(n2)), }); return; } if self.symbol("*") { let n1 = self.eval(n, 1); self.stack.push(Op::Op { prec: 1, eval: Box::new(move |n2| n1.mul(n2)), }); return; } if self.symbol("/") { let n1 = self.eval(n, 1); self.stack.push(Op::Op { prec: 1, eval: Box::new(move |n2| n1.div(n2)), }); return; } if self.symbol("//") { let n1 = self.eval(n, 1); self.stack.push(Op::Op { prec: 1, eval: Box::new(move |n2| n1.int_div(n2)), }); return; } if self.symbol("%") { let n1 = self.eval(n, 1); self.stack.push(Op::Op { prec: 1, eval: Box::new(move |n2| n1.modulo(n2)), }); return; } if self.symbol("+") { let n1 = self.eval(n, 0); self.stack.push(Op::Op { prec: 0, eval: Box::new(move |n2| n1.add(n2)), }); return; } if self.symbol("-") { let n1 = self.eval(n, 0); self.stack.push(Op::Op { prec: 0, eval: Box::new(move |n2| n1.sub(n2)), }); return; } let n1 = self.eval(n, 1); self.stack.push(Op::Op { prec: 1, eval: Box::new(move |n2| n1.mul(n2)), }); } fn parse(&mut self) -> Option { let mut n = loop { if self.symbol("(") { self.stack.push(Op::Paren); continue; } if self.parse_fun() { continue; } let mut n = self.parse_const()?; while self.symbol(")") { loop { let op = self.stack.pop()?; let Op::Op { eval, .. } = op else { break; }; n = eval(n); } } if self.peek().is_none() { break n; } self.parse_op(n); }; while let Some(op) = self.stack.pop() { let Op::Op { eval, .. } = op else { return None; }; n = eval(n); } Some(n) } } pub fn parse(expr: &str) -> Option { let mut p = Parser { r: Lexer { buf: expr }, first_token: None, stack: Vec::new(), }; p.parse() }