Cleaned up evaluator

pull/2/head
Mark 2023-06-14 19:54:28 -07:00
parent 4dfaf2b863
commit b6343db0d6
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
1 changed files with 41 additions and 46 deletions

View File

@ -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<Token, EvalError> {
let mut g = t.clone();
pub fn evaluate(t: &Token, context: &mut Context) -> Result<Token, EvalError> {
// 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<usize> = 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);
}