use crate::*;
use std::collections::HashMap;
pub struct Expr {
tree: AST,
context: HashMap<String, f64>,
expr_string: String,
}
impl std::fmt::Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.expr_string)
}
}
impl Expr {
pub fn new(expression: &str) -> Self {
Expr {
tree: parse(expression),
context: HashMap::new(),
expr_string: expression.to_string(),
}
}
fn eval_node(&self, node_ref: &Option<Box<AstNode>>) -> f64 {
let node = node_ref.as_ref().unwrap();
match &node.tok {
Token::Num(k) => *k,
Token::Var(id) => match self.context.get(id) {
None => panic!("{} was not found in the Expr context", id),
Some(x) => *x,
},
Token::Una(op) | Token::Bin(op) => match op {
Op::SUM => self.eval_node(&node.lhs) + self.eval_node(&node.rhs),
Op::SUB => self.eval_node(&node.lhs) - self.eval_node(&node.rhs),
Op::MUL => self.eval_node(&node.lhs) * self.eval_node(&node.rhs),
Op::DIV => self.eval_node(&node.lhs) / self.eval_node(&node.rhs),
Op::EXP => self.eval_node(&node.lhs).powf(self.eval_node(&node.rhs)),
Op::NEG => -self.eval_node(&node.lhs),
Op::FAC => fct(self.eval_node(&node.lhs)),
},
_ => panic!("{:?} should not have been encountered", node.tok),
}
}
#[inline]
pub fn eval(&self) -> f64 {
self.eval_node(&self.tree.root)
}
#[inline]
pub fn set_var(&mut self, id: &str, val: f64) {
*self.context.entry(id.to_string()).or_insert(val) = val;
}
}