From b6343db0d69110c52ea33feca809d7e4520c664f Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 14 Jun 2023 19:54:28 -0700 Subject: [PATCH] Cleaned up evaluator --- src/evaluate/evaluate.rs | 87 +++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/src/evaluate/evaluate.rs b/src/evaluate/evaluate.rs index 2ae133e..85cacc6 100644 --- a/src/evaluate/evaluate.rs +++ b/src/evaluate/evaluate.rs @@ -7,62 +7,57 @@ use super::operator::eval_operator; use super::function::eval_function; use super::EvalError; -pub fn evaluate(t: &Token, context: &Context) -> Result { - let mut g = t.clone(); +pub fn evaluate(t: &Token, context: &mut Context) -> Result { + + // Keeps track of our position in the token tree. + // For example, the coordinates [0, 2, 1] are interpreted as follows: + // Start at the root node, + // then move to that node's 0th child, + // then move to that node's 2nd child, + // then move to that node's 1st child. + // let mut coords: Vec = Vec::with_capacity(16); + let mut root = t.clone(); + + // coords points to the *next* node we will move to. coords.push(0); - 'outer: loop { - let mut h = &mut g; + // Repeats while we have coordinates to parse. + // Exits when we finish parsing the root node. + loop { + // Current position in the tree + let g = root.get_at_coords_mut(&coords[0 .. coords.len() - 1]); - for t in coords.iter() { - let inner = h.get_args_mut(); + // "Move up" step. + // We move up if we're at a leaf or if we're out of children to move down to. + if { + g.is_quantity() || + g.get_args().is_none() || + (coords.len() != 0 && (*coords.last().unwrap() >= g.get_args().unwrap().len())) + } { - if inner.is_none() || *t >= inner.as_ref().unwrap().len() { - coords.pop(); + if !g.is_quantity() { + *g = match g { + Token::Quantity(_) => panic!(), - - let p = Token::get_at_coords(&mut g, &coords); - let mut e = p.clone(); - - // Evaluate until we get a single number. - // This loop is necessary because some eval_* functions - // May return an incomplete result. - // ( For example, csc(x) is treated as 1/sin(x) ) - loop { - e = match e { - Token::Quantity(_) => { break; }, - Token::Constant(c) => { evaluate(&c.value(), context).unwrap() }, - Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? }, - Token::Operator(o, v) => { eval_operator(&o, &v)? }, - Token::Variable(s) => { context.get_variable(&s).unwrap() } - }; + Token::Constant(c) => { evaluate(&c.value(), context).unwrap() }, + Token::Variable(s) => { context.get_variable(&s).unwrap() }, + Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? }, + Token::Operator(o, v) => { eval_operator(&o, &v, context)? }, } - - *p = e; - - if coords.len() == 0 { break 'outer; } - let l = coords.pop().unwrap(); - coords.push(l + 1); - continue 'outer; } - h = &mut inner.unwrap()[*t]; + // Move up the tree + coords.pop(); + if coords.len() != 0 { + *coords.last_mut().unwrap() += 1; + } else { break; } + + } else { + // Move down the tree + coords.push(0); } - - - match h { - Token::Operator(_,_) - | Token::Constant(_) - | Token::Variable(_) - => { coords.push(0); }, - - Token::Quantity(_) => { - let l = coords.pop().unwrap(); - coords.push(l + 1); - } - }; } - return Ok(g); + return Ok(root); } \ No newline at end of file