use crate::lexer::Lexer; use crate::num; use crate::num::Num; use num_bigint::BigInt; use std::str::FromStr; enum ParseError { Empty, Consumed, } fn seq(r: Result) -> Result { match r { Err(ParseError::Empty) => Err(ParseError::Consumed), x => x, } } fn or(r: Result) -> Result, ParseError> { match r { Ok(x) => Ok(Some(x)), Err(ParseError::Empty) => Ok(None), Err(ParseError::Consumed) => Err(ParseError::Consumed), } } struct Parser<'a> { r: Lexer<'a>, first_token: Option<&'a str>, } impl<'a> Parser<'a> { fn peek(&mut self) -> Result<&'a str, ParseError> { if let Some(t) = self.first_token { return Ok(t); } let Some(t) = self.r.next() else { return Err(ParseError::Empty); }; self.first_token = Some(t); Ok(t) } fn next(&mut self) -> Result<&'a str, ParseError> { if let Some(t) = std::mem::take(&mut self.first_token) { return Ok(t); } let Some(t) = self.r.next() else { return Err(ParseError::Empty); }; Ok(t) } fn symbol(&mut self, s: &str) -> bool { let Ok(t) = self.peek() else { return false; }; if t != s { return false; } let _ = self.next(); true } fn parse_num(&mut self) -> Result { let negative = self.symbol("-"); let t = seq(self.next())?; if t.contains('.') || t.contains('e') || t.contains('E') { let Ok(f) = f64::from_str(t) else { return Err(ParseError::Consumed); }; if negative { return Ok(num::float(-f)); } return Ok(num::float(f)); } let Ok(i) = BigInt::from_str(t) else { return Err(ParseError::Consumed); }; if negative { return Ok(num::int(-i)); } Ok(num::int(i)) } fn paren_expr(&mut self) -> Result { if !self.symbol("(") { return Err(ParseError::Empty); } let n = seq(self.expr())?; if !self.symbol(")") { return Err(ParseError::Consumed); } Ok(n) } fn parse_const(&mut self) -> Result { if self.symbol("e") { return Ok(num::float(std::f64::consts::E)); } if self.symbol("pi") { return Ok(num::float(std::f64::consts::PI)); } Err(ParseError::Empty) } fn atom(&mut self) -> Result { if let Some(n) = or(self.paren_expr())? { return Ok(n); } if let Some(n) = or(self.parse_const())? { return Ok(n); } self.parse_num() } fn parse_fun(&mut self) -> Result { if self.symbol("sin") { return Ok(self.atom()?.sin()); } if self.symbol("cos") { return Ok(self.atom()?.cos()); } if self.symbol("tan") { return Ok(self.atom()?.tan()); } if self.symbol("sqrt") { return Ok(self.atom()?.sqrt()); } if self.symbol("log") || self.symbol("ln") { return Ok(self.atom()?.log()); } if self.symbol("floor") { return Ok(self.atom()?.floor()); } if self.symbol("ceil") || self.symbol("ceiling") { return Ok(self.atom()?.ceil()); } if self.symbol("round") { return Ok(self.atom()?.round()); } Err(ParseError::Empty) } fn app_expr_fold(&mut self, e1: Num) -> Result { if let Some(e2) = or(self.parse_fun())? { return self.app_expr_fold(e1.mul(e2)); } if let Some(e2) = or(self.paren_expr())? { return self.app_expr_fold(e1.mul(e2)); } if let Some(e2) = or(self.parse_const())? { return self.app_expr_fold(e1.mul(e2)); } Ok(e1) } fn app_expr(&mut self) -> Result { if let Some(e1) = or(self.parse_fun())? { return Ok(e1); } let e1 = self.atom()?; self.app_expr_fold(e1) } fn expt_expr_fold(&mut self, e1: Num) -> Result { if !self.symbol("^") { return Ok(e1); } let e2 = seq(self.app_expr())?; let e2 = self.expt_expr_fold(e2)?; Ok(e1.pow(e2)) } fn expt_expr(&mut self) -> Result { let n = self.app_expr()?; self.expt_expr_fold(n) } fn mul_expr_fold(&mut self, e1: Num) -> Result { if self.symbol("*") { let e2 = seq(self.expt_expr())?; let e = e1.mul(e2); return self.mul_expr_fold(e); } if self.symbol("/") { let e2 = seq(self.expt_expr())?; let e = e1.div(e2); return self.mul_expr_fold(e); } if self.symbol("//") { let e2 = seq(self.expt_expr())?; let e = e1.int_div(e2); return self.mul_expr_fold(e); } Ok(e1) } fn mul_expr(&mut self) -> Result { let n = self.expt_expr()?; self.mul_expr_fold(n) } fn add_expr_fold(&mut self, e1: Num) -> Result { if self.symbol("+") { let e2 = seq(self.mul_expr())?; let e = e1.add(e2); return self.add_expr_fold(e); } if self.symbol("-") { let e2 = seq(self.mul_expr())?; let e = e1.sub(e2); return self.add_expr_fold(e); } Ok(e1) } fn expr(&mut self) -> Result { let n = self.mul_expr()?; self.add_expr_fold(n) } } pub fn parse(expr: &str) -> Option { let mut p = Parser { r: Lexer { buf: expr }, first_token: None, }; let n = p.expr().ok()?; if p.r.next().is_some() { // Trailing characters. return None; } Some(n) }