use super::types::Op; use super::types::Op::*; use super::sexpr::SExpr; use super::sexpr::SExpr::*; use super::types::Type; use super::types::Number; use super::environment::Environment; pub mod arith; pub fn eval(expr: &SExpr, env: &mut Environment) -> Result { match expr { Atom(ref x) => Ok(Atom((*x).clone())), Sexpr(ref s) => seval(s, env) } } fn seval(sexpr: &[SExpr], env: &mut Environment) -> Result { if sexpr.is_empty() { return Err("Empty S Expression".to_string()) } let op = match &sexpr[0] { Atom(Type::Operator(x)) => *x, Atom(Type::Symbol(_s)) => return Err("Not yet implemented".to_string()), x => return Err(format!("{:?} is not a procedure", x)) }; op_eval(op, &sexpr[1..], env) } fn op_eval(op: Op, expr: &[SExpr], env: &mut Environment) -> Result { match op { Add => op_add(expr, env), Sub => op_sub(expr, env), Mul => op_mul(expr, env), Div => op_div(expr, env), //Define => define(expr, env), _ => Err("Not yet implemented".to_string()) } } fn arith_op( expr: &[SExpr], env: &mut Environment, identity: Number, f: fn(Type, Type) -> Result) -> Result{ let mut acc = Type::Number(identity); let mut i = 0; if expr.len() > 1 { let b = match eval(&expr[i], env)? { Atom(x) => x, Sexpr(_) => panic!("This should have evaluated to an atom") }; acc = b; i = 1; } while i < expr.len() { let b = match eval(&expr[i], env)? { Atom(x) => x, Sexpr(_) => panic!("This should have evaluated to an atom") }; acc = (f(acc, b))?; i += 1 } Ok(SExpr::Atom(acc)) } fn op_add(expr: &[SExpr], env: &mut Environment) -> Result { arith_op(expr, env, Number::Int(0), |a, b| a + b) } fn op_sub(expr: &[SExpr], env: &mut Environment) -> Result { arith_op(expr, env, Number::Int(0), |a, b| a - b) } fn op_mul(expr: &[SExpr], env: &mut Environment) -> Result { arith_op(expr, env, Number::Int(1), |a, b| a * b) } fn op_div(expr: &[SExpr], env: &mut Environment) -> Result { arith_op(expr, env, Number::Float(1.0), |a, b| a / b) }