2025-06-22 12:09:21 +12:00
use tracing ::{ debug , error } ;
use once_cell ::sync ::Lazy ;
2025-09-06 15:08:40 +12:00
use astro_float ::{ BigFloat , Sign , RoundingMode , Consts } ;
use std ::str ::FromStr ;
use std ::sync ::{ Arc , Mutex } ;
use std ::mem ;
pub const PRECISION : usize = 2048 ;
static CONST_CACHE : Lazy < Arc < Mutex < Consts > > > = Lazy ::new ( | | Arc ::new ( Mutex ::new ( Consts ::new ( ) . expect ( " Unable to allocate memory for Conts cache " ) ) ) ) ;
// static PI: Lazy<BigFloat> = Lazy::new(|| BigFloat::from_str("3.141592653589793238462643383279").unwrap());
// static E: Lazy<BigFloat> = Lazy::new(|| BigFloat::from_str("2.718281828459045235360287471352").unwrap());
2025-06-22 12:09:21 +12:00
#[ derive(Debug) ]
pub struct Calculation {
pub equation : String ,
pub result : String ,
}
pub fn calculate ( query : & str ) -> Option < Calculation > {
debug! ( " Got query {} " , query ) ;
let mut parser = Parser ::new ( Lexer ::new ( query ) ) ;
2025-09-06 15:36:22 +12:00
let mut tree = parser . parse ( ) ? ;
2025-09-05 20:58:21 +12:00
let res = tree . eval ( ) ;
2025-09-05 20:37:13 +12:00
debug! ( " Calculation: {} " , query ) ;
2025-09-06 15:36:22 +12:00
// debug!("Tree: {:?}", tree);
2025-09-05 20:58:21 +12:00
debug! ( " Result: {} " , res ) ;
Some ( Calculation { equation : query . to_string ( ) , result : res . to_string ( ) } )
2025-06-22 12:09:21 +12:00
}
2025-09-06 15:08:40 +12:00
// TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than BigFloat
#[ derive(Debug, Clone, PartialEq) ]
2025-06-22 12:09:21 +12:00
enum Token {
2025-09-04 08:54:21 +12:00
Op ( Op ) ,
2025-09-05 16:11:11 +12:00
Atom ( Atom ) ,
2025-09-06 15:08:40 +12:00
/* Number(BigFloat),
2025-09-04 08:54:21 +12:00
Func ( Func ) , * /
}
2025-09-06 15:36:22 +12:00
#[ derive(Debug, Copy, Clone, PartialEq) ]
2025-09-04 08:54:21 +12:00
enum Op {
2025-09-05 21:14:04 +12:00
Add ,
Subtract ,
Multiply ,
Divide ,
Exponent ,
LParen ,
RParen ,
2025-09-05 16:11:11 +12:00
Func ( Func ) , // A function is an Op that takes whatever the next thing is and binds it, either the next number or whatever is in parens
}
2025-09-05 16:45:57 +12:00
impl Op {
2025-09-05 21:50:22 +12:00
fn bp_infix ( & self ) -> Option < ( f64 , f64 ) > {
2025-09-05 19:35:18 +12:00
match self {
2025-09-05 21:50:22 +12:00
// Op::LParen => Some(0.0),
// Op::RParen => Some(0.0),
Op ::Add = > Some ( ( 1.0 , 1.1 ) ) ,
Op ::Subtract = > Some ( ( 1.0 , 1.1 ) ) ,
Op ::Multiply = > Some ( ( 2.0 , 2.1 ) ) ,
Op ::Divide = > Some ( ( 2.0 , 2.1 ) ) ,
Op ::Exponent = > Some ( ( 3.1 , 3.0 ) ) ,
_ = > None ,
// Op::Func(_) => 0.0, // TODO: decide if this is a good LBP
2025-09-05 19:35:18 +12:00
}
2025-09-05 16:45:57 +12:00
}
2025-09-05 21:50:22 +12:00
fn bp_prefix ( & self ) -> Option < f64 > {
2025-09-05 19:35:18 +12:00
match self {
2025-09-05 23:32:21 +12:00
Op ::Func ( _ ) = > Some ( 6.0 ) ,
2025-09-05 21:50:22 +12:00
Op ::Subtract = > Some ( 5.0 ) ,
Op ::Add = > Some ( 5.0 ) ,
_ = > None ,
2025-09-05 19:35:18 +12:00
}
2025-09-05 16:45:57 +12:00
}
2025-09-05 20:37:13 +12:00
2025-09-06 15:36:22 +12:00
fn apply_to ( & self , args : & mut Vec < Expr > ) -> BigFloat {
2025-09-05 21:50:22 +12:00
match args . len ( ) {
1 = > match self {
2025-09-06 15:08:40 +12:00
Op ::Subtract = > {
let mut res = args [ 0 ] . eval ( ) ;
res . set_sign ( Sign ::Neg ) ;
res
} ,
Op ::Add = > {
let mut res = args [ 0 ] . eval ( ) ;
res . set_sign ( Sign ::Pos ) ;
res
2025-09-05 21:50:22 +12:00
}
2025-09-06 15:08:40 +12:00
Op ::Func ( f ) = > match f {
Func ::Sine = > args [ 0 ] . eval ( ) . sin ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::Cosine = > args [ 0 ] . eval ( ) . cos ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::Tangent = > args [ 0 ] . eval ( ) . tan ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::ArcSine = > args [ 0 ] . eval ( ) . asin ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::ArcCosine = > args [ 0 ] . eval ( ) . acos ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::ArcTangent = > args [ 0 ] . eval ( ) . atan ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::Log2 = > args [ 0 ] . eval ( ) . log2 ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::Log10 = > args [ 0 ] . eval ( ) . log10 ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::LogN = > args [ 0 ] . eval ( ) . ln ( PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::Square = > args [ 0 ] . eval ( ) . pow ( & BigFloat ::from_f64 ( 2.0 , PRECISION ) , PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Func ::SquareRoot = > args [ 0 ] . eval ( ) . sqrt ( PRECISION , RoundingMode ::None ) ,
Func ::Abs = > args [ 0 ] . eval ( ) . abs ( ) ,
_ = > {
error! ( " Got 1 params for func {:?} which expects 2 (should not be possible) " , self ) ;
astro_float ::NAN
} ,
} ,
_ = > {
error! ( " Got 1 params for {:?} which expects 2 (should not be possible) " , self ) ;
astro_float ::NAN
} ,
2025-09-05 21:50:22 +12:00
}
2 = > match self {
2025-09-06 15:08:40 +12:00
Op ::LParen = > args [ 0 ] . eval ( ) ,
Op ::RParen = > args [ 0 ] . eval ( ) ,
2025-09-06 15:36:22 +12:00
Op ::Add = > args [ 0 ] . eval ( ) . add ( & mut args [ 1 ] . eval ( ) , PRECISION , RoundingMode ::None ) ,
Op ::Subtract = > args [ 0 ] . eval ( ) . sub ( & mut args [ 1 ] . eval ( ) , PRECISION , RoundingMode ::None ) ,
Op ::Multiply = > args [ 0 ] . eval ( ) . mul ( & mut args [ 1 ] . eval ( ) , PRECISION , RoundingMode ::None ) ,
Op ::Divide = > args [ 0 ] . eval ( ) . div ( & mut args [ 1 ] . eval ( ) , PRECISION , RoundingMode ::None ) ,
Op ::Exponent = > args [ 0 ] . eval ( ) . pow ( & mut args [ 1 ] . eval ( ) , PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
Op ::Func ( Func ::Log ) = > args [ 0 ] . eval ( ) . log ( & mut args [ 1 ] . eval ( ) , PRECISION , RoundingMode ::None , & mut CONST_CACHE . lock ( ) . unwrap ( ) ) ,
2025-09-06 15:08:40 +12:00
_ = > {
error! ( " Got 2 params for {:?} which only expects 1 (should not be possible) " , self ) ;
astro_float ::NAN
} ,
2025-09-05 21:50:22 +12:00
}
2025-09-06 15:08:40 +12:00
_ = > {
error! ( " Unexpected number of params ({}) for {:?} (should not be possible) " , args . len ( ) , self ) ;
astro_float ::NAN
} ,
}
2025-09-05 20:37:13 +12:00
}
2025-09-05 16:45:57 +12:00
}
2025-09-06 15:08:40 +12:00
#[ derive(Debug, Clone, PartialEq) ]
2025-09-04 08:54:21 +12:00
enum Atom {
2025-09-06 15:36:22 +12:00
Number ( BigFloat ) ,
2025-09-05 16:11:11 +12:00
Const ( Const ) ,
2025-06-22 12:09:21 +12:00
}
2025-09-06 15:36:22 +12:00
/* impl Atom {
2025-09-06 15:08:40 +12:00
fn get_val ( & self ) -> BigFloat {
2025-09-05 19:39:48 +12:00
match self {
Atom ::Number ( val ) = > * val ,
Atom ::Const ( c ) = > match c {
2025-09-06 15:08:40 +12:00
Const ::Pi = > CONST_CACHE . lock ( ) . unwrap ( ) . pi ( PRECISION , RoundingMode ::None ) ,
Const ::E = > CONST_CACHE . lock ( ) . unwrap ( ) . e ( PRECISION , RoundingMode ::None ) ,
Const ::Inf = > astro_float ::INF_POS ,
Const ::Nan = > astro_float ::NAN ,
2025-09-05 19:39:48 +12:00
}
}
}
2025-09-06 15:36:22 +12:00
} * /
impl Const {
fn get_val ( & self ) -> BigFloat {
match self {
Const ::Pi = > CONST_CACHE . lock ( ) . unwrap ( ) . pi ( PRECISION , RoundingMode ::None ) ,
Const ::E = > CONST_CACHE . lock ( ) . unwrap ( ) . e ( PRECISION , RoundingMode ::None ) ,
Const ::Inf = > astro_float ::INF_POS ,
Const ::Nan = > astro_float ::NAN ,
}
}
2025-09-05 19:39:48 +12:00
}
2025-09-06 15:36:22 +12:00
#[ derive(Debug, Copy, Clone, PartialEq) ]
2025-06-22 12:09:21 +12:00
enum Func {
Sine ,
Cosine ,
Tangent ,
// sin-1, cos-1, tan-1
ArcSine ,
ArcCosine ,
ArcTangent ,
Log2 ,
Log10 ,
LogN ,
2025-09-05 23:32:21 +12:00
Log ,
2025-06-22 12:09:21 +12:00
Square ,
SquareRoot ,
2025-09-05 23:32:21 +12:00
Abs ,
2025-06-22 12:09:21 +12:00
}
2025-09-05 23:32:21 +12:00
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 " ] ) ,
]
}
}
2025-09-06 15:36:22 +12:00
#[ derive(Debug, Copy, Clone, PartialEq) ]
2025-09-05 16:11:11 +12:00
enum Const {
Pi ,
E ,
2025-09-05 23:58:06 +12:00
Inf ,
Nan ,
2025-09-05 16:11:11 +12:00
}
2025-09-05 23:58:06 +12:00
impl Const {
fn names ( ) -> & 'static [ ( Const , & 'static [ & 'static str ] ) ] {
& [
( Const ::Pi , & [ " pi " , " PI " , " π " ] ) ,
( Const ::E , & [ " e " , " euler " ] ) ,
( Const ::Inf , & [ " inf " , " infinity " , " ∞ " ] ) ,
( Const ::Nan , & [ " nan " , " NaN " ] )
]
}
}
2025-09-06 15:36:22 +12:00
#[ derive(Debug, Copy, Clone, PartialEq) ]
2025-09-05 16:45:57 +12:00
enum ParseErr {
2025-06-22 12:09:21 +12:00
Eof ,
Invalid ,
}
// this can probably be swapped out with a lexer generator like Logos if needed
struct Lexer < ' a > {
data : & ' a str ,
data_ptr : & ' a str ,
2025-09-05 22:26:06 +12:00
// idx: usize,
next_by : usize ,
2025-09-05 19:35:18 +12:00
next_tok : Result < Token , ParseErr > ,
2025-06-22 12:09:21 +12:00
}
// TODO: refactor with iterator that returns Option(Token) where one token option is Eof (or a enum of Token(Token) and Eof, or just Option(Option(Token)))
impl Lexer < '_ > {
2025-09-05 19:35:18 +12:00
fn new ( data : & str ) -> Lexer < '_ > {
2025-09-05 22:26:06 +12:00
let mut n : Lexer = Lexer { data , data_ptr : data , next_by : 0 , next_tok : Err ( ParseErr ::Eof ) } ;
2025-09-05 19:35:18 +12:00
n . next ( ) ;
debug! ( " New finished! " ) ;
n
}
2025-06-22 12:09:21 +12:00
2025-09-05 19:35:18 +12:00
fn _next ( & mut self ) -> Result < Token , ParseErr > {
2025-09-05 22:26:06 +12:00
self . data_ptr = & self . data_ptr [ self . next_by .. ] ;
match self . data_ptr . chars ( ) . nth ( 0 ) {
2025-06-22 12:09:21 +12:00
Some ( val ) = > {
2025-09-05 22:26:06 +12:00
debug! ( " lexing char '{}' at idx {} " , val , self . data . chars ( ) . count ( ) - self . data_ptr . chars ( ) . count ( ) ) ;
self . next_by = 1 ;
2025-06-22 12:09:21 +12:00
match val {
2025-09-05 21:14:04 +12:00
'+' = > Ok ( Token ::Op ( Op ::Add ) ) ,
'-' = > Ok ( Token ::Op ( Op ::Subtract ) ) ,
'× ' | '*' = > Ok ( Token ::Op ( Op ::Multiply ) ) ,
'÷' | '/' = > Ok ( Token ::Op ( Op ::Divide ) ) ,
'^' = > Ok ( Token ::Op ( Op ::Exponent ) ) ,
'(' = > Ok ( Token ::Op ( Op ::LParen ) ) ,
')' = > Ok ( Token ::Op ( Op ::RParen ) ) ,
2025-09-05 19:35:18 +12:00
_ if val . is_whitespace ( ) = > self . _next ( ) ,
2025-06-22 12:09:21 +12:00
_ if val . is_digit ( 10 ) = > {
2025-09-05 22:26:06 +12:00
let mut len : usize = 0 ;
self . data_ptr . chars ( ) . take_while ( | c | c . is_digit ( 10 ) | | * c = = '.' ) . for_each ( | _ | len + = 1 ) ;
2025-09-05 23:32:21 +12:00
self . next_by = len ;
2025-06-22 12:09:21 +12:00
2025-09-05 22:26:06 +12:00
match self . data_ptr [ .. len ] . parse ( ) {
2025-09-05 16:11:11 +12:00
Ok ( val ) = > Ok ( Token ::Atom ( Atom ::Number ( val ) ) ) ,
2025-09-05 16:45:57 +12:00
Err ( e ) = > Err ( ParseErr ::Invalid ) ,
2025-06-22 12:09:21 +12:00
}
} ,
_ = > {
2025-09-05 23:32:21 +12:00
let len = self . data_ptr . chars ( ) . count ( ) ;
for ( f , names ) in Func ::names ( ) {
for name in * names {
2025-09-05 23:58:06 +12:00
let n_len = name . chars ( ) . count ( ) ;
if self . data_ptr . starts_with ( name ) & & ( len = = n_len | | ! self . data_ptr . chars ( ) . nth ( n_len ) . unwrap ( ) . is_alphabetic ( ) ) {
self . next_by = name . chars ( ) . count ( ) ;
2025-09-05 23:32:21 +12:00
return Ok ( Token ::Op ( Op ::Func ( * f ) ) ) ;
}
}
2025-09-05 19:35:18 +12:00
}
2025-09-05 23:58:06 +12:00
for ( f , names ) in Const ::names ( ) {
for name in * names {
let n_len = name . chars ( ) . count ( ) ;
if self . data_ptr . starts_with ( name ) & & ( len = = n_len | | ! self . data_ptr . chars ( ) . nth ( n_len ) . unwrap ( ) . is_alphabetic ( ) ) {
self . next_by = name . chars ( ) . count ( ) ;
return Ok ( Token ::Atom ( Atom ::Const ( * f ) ) ) ;
}
}
}
2025-06-22 12:09:21 +12:00
debug! ( " got invalid char '{}' " , val ) ;
2025-09-05 16:45:57 +12:00
Err ( ParseErr ::Invalid )
2025-06-22 12:09:21 +12:00
}
}
}
2025-09-05 22:26:06 +12:00
None = > {
self . next_by = 0 ;
Err ( ParseErr ::Eof )
} ,
2025-06-22 12:09:21 +12:00
}
}
2025-09-05 19:35:18 +12:00
fn next ( & mut self ) -> Result < Token , ParseErr > {
2025-09-06 15:36:22 +12:00
let res = self . _next ( ) ;
let val = mem ::replace ( & mut self . next_tok , res ) ;
2025-09-06 15:08:40 +12:00
// self.next_tok = self._next();
2025-09-05 19:35:18 +12:00
val
}
2025-09-06 15:36:22 +12:00
fn peek ( & mut self ) -> & Result < Token , ParseErr > {
& self . next_tok
2025-09-05 19:35:18 +12:00
}
2025-06-22 12:09:21 +12:00
// TODO: replace with iterator so I can do parser.parse(lexer.iter()) and parse does lex_iter.next() & such
fn lex_all ( & mut self ) -> Option < Vec < Token > > {
let mut tokens : Vec < Token > = vec! [ ] ;
loop {
match self . next ( ) {
2025-09-05 16:45:57 +12:00
Err ( ParseErr ::Eof ) = > return Some ( tokens ) ,
Err ( ParseErr ::Invalid ) = > return None ,
2025-06-22 12:09:21 +12:00
Ok ( tok ) = > tokens . push ( tok ) ,
}
// debug!("tokens: {:?}", tokens);
}
}
}
2025-09-05 19:35:18 +12:00
fn matches ( s : & str , check : & str ) -> usize {
// debug!("s: \"{}\", check: \"{}\"c_len: {}, s_len: {}, s[c_len]: {:?}, s[c_len + 1]: {:?}", s, check, check.chars().count(), s.chars().count(), s.chars().nth(check.chars().count()), s.chars().nth(check.chars().count() + 1));
match ( s . chars ( ) . count ( ) , check . chars ( ) . count ( ) ) {
( s_len , c_len ) if s_len < c_len = > 0 ,
( s_len , c_len ) if s_len = = c_len & & s = = check = > c_len - 1 ,
( s_len , c_len ) if s_len > c_len & & s . starts_with ( check ) & & s . chars ( ) . nth ( c_len ) . unwrap ( ) . is_whitespace ( ) = > c_len ,
( _ , _ ) = > 0 ,
}
}
2025-06-22 12:09:21 +12:00
struct Parser < ' a > {
lex : Lexer < ' a > ,
}
impl Parser < '_ > {
fn new ( lex : Lexer ) -> Parser { Parser { lex } }
2025-09-04 08:54:21 +12:00
fn parse ( & mut self ) -> Option < Expr > {
self . parse_expr ( 0.0 ) . ok ( )
}
fn parse_expr ( & mut self , min_bp : f64 ) -> Result < Expr , ParseErr > {
2025-09-05 16:45:57 +12:00
/* while let Ok(val) = self.lex.next() {debug!("token: {:?}", val)}
2025-09-05 16:11:11 +12:00
match self . lex . next ( ) . err ( ) {
2025-09-04 08:54:21 +12:00
_ = > return Err ( ParseErr ::Invalid ) ,
2025-09-05 16:45:57 +12:00
} * /
let mut lhs : Expr = match self . lex . next ( ) {
Ok ( val ) = > match val {
Token ::Atom ( val ) = > Ok ( Expr ::Atom ( val ) ) ,
Token ::Op ( op ) = > match op {
2025-09-05 23:32:21 +12:00
Op ::LParen = > {
let val = self . parse_expr ( 0.0 ) ;
2025-09-05 23:58:06 +12:00
if self . lex . next ( ) ! = Ok ( Token ::Op ( Op ::RParen ) ) {
debug! ( " Unclosed parens " ) ;
Err ( ParseErr ::Invalid )
}
else {
val
}
2025-09-05 23:32:21 +12:00
} ,
2025-09-05 21:50:22 +12:00
// 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 ) ? ] ) ) ,
None = > { debug! ( " Got unexpected {:?} as prefix " , op ) ; Err ( ParseErr ::Invalid ) }
}
2025-09-05 16:45:57 +12:00
} ,
} ,
Err ( err ) = > Err ( err ) ,
} . map_err ( | err | { debug! ( " Unexpected error at start of expr: {:?} " , err ) ; err } ) ? ;
2025-09-05 23:32:21 +12:00
debug! ( " lhs of expression is {:?}, min_bp is {} " , lhs , min_bp ) ;
2025-09-05 16:45:57 +12:00
loop {
2025-09-05 23:32:21 +12:00
debug! ( " loop start " ) ;
2025-09-05 19:35:18 +12:00
let op : Op = match self . lex . peek ( ) {
2025-09-05 16:45:57 +12:00
Err ( ParseErr ::Eof ) = > break ,
2025-09-06 15:36:22 +12:00
Err ( e ) = > { debug! ( " In expr got err {:?} " , e ) ; Err ( * e ) } ,
2025-09-05 16:45:57 +12:00
Ok ( tok ) = > match tok {
Token ::Op ( op ) = > match op {
2025-09-05 23:32:21 +12:00
Op ::RParen = > {
debug! ( " got RParen " ) ;
break ;
} ,
2025-09-06 15:36:22 +12:00
_ = > Ok ( * op ) ,
2025-09-05 16:45:57 +12:00
}
2025-09-05 19:35:18 +12:00
v = > { debug! ( " Got unexpected token {:?} " , v ) ; Err ( ParseErr ::Invalid ) } ,
2025-09-05 16:45:57 +12:00
}
2025-09-05 19:35:18 +12:00
} . map_err ( | err | { debug! ( " Unexpected error inside expr at {:?} " , err ) ; err } ) ? ;
2025-09-05 23:32:21 +12:00
debug! ( " op is {:?} " , op ) ;
2025-09-05 21:50:22 +12:00
if let Some ( ( lbp , rbp ) ) = op . bp_infix ( ) {
if ( lbp < min_bp ) { break ; }
self . lex . next ( ) ;
let rhs : Expr = self . parse_expr ( rbp ) ? ;
lhs = Expr ::Node ( op , vec! [ lhs , rhs ] ) ;
} else {
debug! ( " Got unexpected non-infix operator in expression: {:?} " , op ) ;
return Err ( ParseErr ::Invalid ) ;
}
2025-09-04 08:54:21 +12:00
}
2025-09-05 23:32:21 +12:00
debug! ( " Returning expr {:?} " , lhs ) ;
2025-09-05 16:45:57 +12:00
Ok ( lhs )
2025-09-04 08:54:21 +12:00
}
2025-06-22 12:09:21 +12:00
}
2025-09-04 08:54:21 +12:00
#[ derive(Debug) ]
enum Expr {
2025-09-06 15:36:22 +12:00
Evaluated ,
2025-09-05 16:45:57 +12:00
Atom ( Atom ) ,
2025-09-04 08:54:21 +12:00
Node ( Op , Vec < Expr > ) ,
2025-06-22 12:09:21 +12:00
}
2025-09-05 20:37:13 +12:00
impl Expr {
2025-09-06 15:36:22 +12:00
fn eval ( & mut self ) -> BigFloat {
let res = match self {
Expr ::Atom ( _ ) = > {
let v = mem ::replace ( self , Expr ::Evaluated ) ;
if let Expr ::Atom ( at ) = v {
match at {
Atom ::Number ( n ) = > n ,
Atom ::Const ( c ) = > c . get_val ( ) ,
}
} else {
unreachable! ( ) ;
}
// at.get_val()
}
Expr ::Node ( op , exprs ) = > {
* self = Expr ::Atom ( Atom ::Number ( op . apply_to ( exprs ) ) ) ;
self . eval ( )
}
Expr ::Evaluated = > unreachable! ( " Tried to evaluate an already evaluated node " ) ,
2025-09-05 20:37:13 +12:00
} ;
// debug!("{:?} evaluated to {}", self, res);
res
}
}