use crate::lexer::Lexer; use crate::num; use crate::num::Num; use num_bigint::BigInt; use std::str::FromStr; struct Parser<'a> { r: Lexer<'a>, first_token: Option<&'a str>, } impl<'a> Parser<'a> { fn peek(&mut self) -> Option<&'a str> { if let Some(t) = self.first_token { return Some(t); } self.first_token = self.r.next(); self.first_token } 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; } self.next(); true } fn parse_num(&mut self) -> Option { let negative = self.symbol("-"); let t = self.next()?; if t.contains('.') || t.contains('e') || t.contains('E') { let f = f64::from_str(t).ok()?; if negative { return Some(num::float(-f)); } return Some(num::float(f)); } let i = BigInt::from_str(t).ok()?; if negative { return Some(num::int(-i)); } Some(num::int(i)) } fn paren_expr(&mut self) -> Option { if !self.symbol("(") { return None; } let n = self.expr()?; if !self.symbol(")") { return None; } Some(n) } fn parse_const(&mut self) -> Option { if self.symbol("e") { return Some(num::float(std::f64::consts::E)); } if self.symbol("pi") { return Some(num::float(std::f64::consts::PI)); } None } fn atom(&mut self) -> Option { if let Some(n) = self.paren_expr() { return Some(n); } if let Some(n) = self.parse_const() { return Some(n); } self.parse_num() } fn parse_fun(&mut self) -> Option { if self.symbol("sin") { return Some(self.atom()?.sin()); } if self.symbol("cos") { return Some(self.atom()?.cos()); } if self.symbol("tan") { return Some(self.atom()?.tan()); } if self.symbol("sqrt") { return Some(self.atom()?.sqrt()); } if self.symbol("log") || self.symbol("ln") { return Some(self.atom()?.log()); } if self.symbol("floor") { return Some(self.atom()?.floor()); } if self.symbol("ceil") || self.symbol("ceiling") { return Some(self.atom()?.ceil()); } if self.symbol("round") { return Some(self.atom()?.round()); } None } fn app_expr_fold(&mut self, e1: Num) -> Option { if let Some(e2) = self.paren_expr() { return self.app_expr_fold(e1.mul(e2)); } if let Some(e2) = self.parse_const() { return self.app_expr_fold(e1.mul(e2)); } if let Some(e2) = self.parse_fun() { return Some(e1.mul(e2)); } Some(e1) } fn app_expr(&mut self) -> Option { if let Some(e) = self.parse_fun() { return Some(e); } let e1 = self.atom()?; self.app_expr_fold(e1) } fn expt_expr_fold(&mut self, e1: Num) -> Option { if !self.symbol("^") { return Some(e1); } let e2 = self.app_expr()?; if let Some(e2) = self.expt_expr_fold(e2) { return Some(e1.pow(e2)); } None } fn expt_expr(&mut self) -> Option { let n = self.app_expr()?; self.expt_expr_fold(n) } fn mul_expr_fold(&mut self, e1: Num) -> Option { if self.symbol("*") { let e2 = self.expt_expr()?; let e = e1.mul(e2); return self.mul_expr_fold(e); } if self.symbol("/") { let e2 = self.expt_expr()?; let e = e1.div(e2); return self.mul_expr_fold(e); } if self.symbol("//") { let e2 = self.expt_expr()?; let e = e1.int_div(e2); return self.mul_expr_fold(e); } Some(e1) } fn mul_expr(&mut self) -> Option { let n = self.expt_expr()?; self.mul_expr_fold(n) } fn add_expr_fold(&mut self, e1: Num) -> Option { if self.symbol("+") { let e2 = self.mul_expr()?; let e = e1.add(e2); return self.add_expr_fold(e); } if self.symbol("-") { let e2 = self.mul_expr()?; let e = e1.sub(e2); return self.add_expr_fold(e); } Some(e1) } fn expr(&mut self) -> Option { 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, }; p.expr() }