mirror of https://github.com/rm-dr/daisy
Cleaned up evaluator
parent
4dfaf2b863
commit
b6343db0d6
|
@ -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;
|
||||
|
||||
for t in coords.iter() {
|
||||
let inner = h.get_args_mut();
|
||||
|
||||
if inner.is_none() || *t >= inner.as_ref().unwrap().len() {
|
||||
coords.pop();
|
||||
|
||||
|
||||
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) )
|
||||
// Repeats while we have coordinates to parse.
|
||||
// Exits when we finish parsing the root node.
|
||||
loop {
|
||||
e = match e {
|
||||
Token::Quantity(_) => { break; },
|
||||
// Current position in the tree
|
||||
let g = root.get_at_coords_mut(&coords[0 .. coords.len() - 1]);
|
||||
|
||||
// "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 !g.is_quantity() {
|
||||
*g = match g {
|
||||
Token::Quantity(_) => panic!(),
|
||||
|
||||
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)? },
|
||||
Token::Variable(s) => { context.get_variable(&s).unwrap() }
|
||||
};
|
||||
Token::Operator(o, v) => { eval_operator(&o, &v, context)? },
|
||||
}
|
||||
}
|
||||
|
||||
*p = e;
|
||||
// Move up the tree
|
||||
coords.pop();
|
||||
if coords.len() != 0 {
|
||||
*coords.last_mut().unwrap() += 1;
|
||||
} else { break; }
|
||||
|
||||
if coords.len() == 0 { break 'outer; }
|
||||
let l = coords.pop().unwrap();
|
||||
coords.push(l + 1);
|
||||
continue 'outer;
|
||||
} else {
|
||||
// Move down the tree
|
||||
coords.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
h = &mut inner.unwrap()[*t];
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
Loading…
Reference in New Issue