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::function::eval_function;
|
||||||
use super::EvalError;
|
use super::EvalError;
|
||||||
|
|
||||||
pub fn evaluate(t: &Token, context: &Context) -> Result<Token, EvalError> {
|
pub fn evaluate(t: &Token, context: &mut Context) -> Result<Token, EvalError> {
|
||||||
let mut g = t.clone();
|
|
||||||
|
// 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 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);
|
coords.push(0);
|
||||||
|
|
||||||
'outer: loop {
|
// Repeats while we have coordinates to parse.
|
||||||
let mut h = &mut g;
|
// 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() {
|
// "Move up" step.
|
||||||
let inner = h.get_args_mut();
|
// 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() {
|
if !g.is_quantity() {
|
||||||
coords.pop();
|
*g = match g {
|
||||||
|
Token::Quantity(_) => panic!(),
|
||||||
|
|
||||||
|
Token::Constant(c) => { evaluate(&c.value(), context).unwrap() },
|
||||||
let p = Token::get_at_coords(&mut g, &coords);
|
Token::Variable(s) => { context.get_variable(&s).unwrap() },
|
||||||
let mut e = p.clone();
|
Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? },
|
||||||
|
Token::Operator(o, v) => { eval_operator(&o, &v, context)? },
|
||||||
// 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() }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*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);
|
||||||
}
|
}
|
Loading…
Reference in New Issue