diff --git a/src/evaluator.rs b/src/evaluator.rs index 8c12e93..303e63a 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -4,27 +4,77 @@ struct Evaluator { ast: AST } -impl Evaluator { - pub fn run(&mut self) -> String { - while self.ast.can_reduce() { - self.ast.reduce(); - } +pub type EvaluatorResult = Result; - format!("{}", self.ast) +struct EvaluatorError { + err: String +} + +impl Evaluator { + pub fn run(self) -> String { + match reduce_full(self.ast) { + Err(e) => format!("{}", e.err), + Ok(ast) => format!("{}", ast) + } } } impl AST { fn can_reduce(&self) -> bool { - false + use parser::AST::*; + match self { + &Number(_) => false, + &Name(_) => false, + _ => true + } + } +} + +fn reduce_full(ast: AST) -> EvaluatorResult { + let mut ast = ast; + while ast.can_reduce() { + ast = try!(reduce_step(ast)); } - fn reduce(&mut self) { + Ok(ast) +} + +fn reduce_step(ast: AST) -> EvaluatorResult { + use parser::AST::*; + match ast { + BinOp(left, op, right) => { + let left = try!(reduce_full(*left)); + let op = try!(reduce_full(*op)); + let right = try!(reduce_full(*right)); + match (left, op, right) { + (Number(l), Name(op), Number(r)) => { + match &op[..] { + "+" => Ok(Number(l + r)), + "-" => Ok(Number(l - r)), + "*" => Ok(Number(l * r)), + "/" => { + if r == 0.0 { + Err(EvaluatorError { err: format!("Divide by zero") }) + } else { + Ok(Number(l / r)) + } + }, + _ => Err(EvaluatorError { err: format!("Bad BinOp operator") }) + } + }, + _ => Err(EvaluatorError { + err: format!("Bad arguments for BinOp") + }) + } + }, + Number(_) => Ok(ast), + Name(_) => Ok(ast), } } + pub fn evaluate(ast: AST) -> String { - let mut ev = Evaluator { ast: ast }; + let ev = Evaluator { ast: ast }; ev.run() } diff --git a/src/parser.rs b/src/parser.rs index aaba03e..d0f7ec4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,7 +13,11 @@ pub enum AST { impl fmt::Display for AST { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", "GENERIC DISPLAY") + match self { + &AST::Number(ref n) => write!(f, "{}", n), + &AST::Name(ref s) => write!(f, "{}", s), + astnode => write!(f, "UNEXPANDED AST NODE: {:?}", astnode) + } } }