diff options
Diffstat (limited to 'src/lib/eval')
-rw-r--r-- | src/lib/eval/arith.rs | 83 | ||||
-rw-r--r-- | src/lib/eval/mod.rs | 62 |
2 files changed, 104 insertions, 41 deletions
diff --git a/src/lib/eval/arith.rs b/src/lib/eval/arith.rs index fae69de..fe3a06b 100644 --- a/src/lib/eval/arith.rs +++ b/src/lib/eval/arith.rs @@ -1,34 +1,67 @@ -use std::ops::Add; +use std::ops::{Add, Sub, Mul, Div}; use super::super::types::Type; -use super::super::types::Type::*; use super::super::types::Number; +fn apply_arithmetic( + func_i: fn(isize, isize) -> isize, + func_f: fn(f32, f32) -> f32, + operand_a: &Type, + operand_b: &Type) -> Result<Type, String> { + + match (operand_a, operand_b) { + (Type::Bool(_), _) | (_, Type::Bool(_)) | + (Type::Str(_), _) | (_, Type::Str(_)) | + (Type::Operator(_), _) | (_, Type::Operator(_)) => { + Err("Incompatible types".to_string()) + }, + + (Type::Number(Number::Int(i)), Type::Number(Number::Float(f))) | + (Type::Number(Number::Float(f)), Type::Number(Number::Int(i))) => { + Ok(Type::Number(Number::Float(func_f(*f, *i as f32)))) + }, + + (Type::Number(Number::Int(a)), Type::Number(Number::Int(b))) => { + Ok(Type::Number(Number::Int(func_i(*a, *b)))) + }, + + (Type::Number(Number::Float(a)), Type::Number(Number::Float(b))) => { + Ok(Type::Number(Number::Float(func_f(*a, *b)))) + }, + + (Type::Symbol(_), Type::Number(_)) | + (Type::Number(_), Type::Symbol(_)) | + (Type::Symbol(_), Type::Symbol(_)) => Err("Not yet implemented".to_string()) + } +} + impl Add for Type { type Output = Result<Type, String>; fn add(self, other: Type) -> Result<Type, String> { - match (self, other) { - (Bool(_), _) | (_, Bool(_)) | - (Str(_), _) | (_, Str(_)) | - (Operator(_), _) | (_, Operator(_)) => { - Err("Cannot add these types".to_string()) - }, - (Number(Number::Int(i)), Number(Number::Float(f))) | - (Number(Number::Float(f)), Number(Number::Int(i))) => { - Ok(Number(Number::Float(f + i as f32))) - }, - - (Number(Number::Int(a)), Number(Number::Int(b))) => { - Ok(Number(Number::Int(a + b))) - }, - - (Number(Number::Float(a)), Number(Number::Float(b))) => { - Ok(Number(Number::Float(a + b))) - }, - - (Symbol(_), Number(_)) | - (Number(_), Symbol(_)) | - (Symbol(_), Symbol(_)) => Err("Not yet implemented".to_string()) - } + apply_arithmetic(|a, b| a + b, |a, b| a + b, &self, &other) + } +} + +impl Sub for Type { + type Output = Result<Type, String>; + + fn sub(self, other: Type) -> Result<Type, String> { + apply_arithmetic(|a, b| a - b, |a, b| a - b, &self, &other) + } +} + +impl Mul for Type { + type Output = Result<Type, String>; + + fn mul(self, other: Type) -> Result<Type, String> { + apply_arithmetic(|a, b| a * b, |a, b| a * b, &self, &other) + } +} + +impl Div for Type { + type Output = Result<Type, String>; + + fn div(self, other: Type) -> Result<Type, String> { + apply_arithmetic(|a, b| a / b, |a, b| a / b, &self, &other) } } diff --git a/src/lib/eval/mod.rs b/src/lib/eval/mod.rs index b582397..adee0e5 100644 --- a/src/lib/eval/mod.rs +++ b/src/lib/eval/mod.rs @@ -1,54 +1,84 @@ -use std::collections::HashMap; use super::types::Op; use super::types::Op::*; -use super::types::SEXP; -use super::types::SEXP::*; -use super::types::Type::*; +use super::sexpr::SExpr; +use super::sexpr::SExpr::*; +use super::types::Type; use super::types::Number; +use super::environment::Environment; pub mod arith; -pub type Env = HashMap<String, SEXP>; - -pub fn eval(expr: &SEXP, env: &mut Env) -> Result<SEXP, String> { +pub fn eval(expr: &SExpr, env: &mut Environment) -> Result<SExpr, String> { match expr { Atom(ref x) => Ok(Atom((*x).clone())), Sexpr(ref s) => seval(s, env) } } -fn seval(sexpr: &[SEXP], env: &mut Env) -> Result<SEXP, String> { +fn seval(sexpr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> { if sexpr.is_empty() { return Err("Empty S Expression".to_string()) } let op = match &sexpr[0] { - Atom(Operator(x)) => *x, - Atom(Symbol(_s)) => return Err("Not yet implemented".to_string()), + 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: &[SEXP], env: &mut Env) -> Result<SEXP, String> { +fn op_eval(op: Op, expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> { 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 op_add(expr: &[SEXP], env: &mut Env) -> Result<SEXP, String> { - let mut acc = Number(Number::Int(0)); +fn arith_op( + expr: &[SExpr], + env: &mut Environment, + identity: Number, + f: fn(Type, Type) -> Result<Type, String>) -> Result<SExpr, String>{ + + 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 = (acc + b)?; - i += 1; + acc = (f(acc, b))?; + i += 1 } - Ok(SEXP::Atom(acc)) + Ok(SExpr::Atom(acc)) +} + +fn op_add(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> { + arith_op(expr, env, Number::Int(0), |a, b| a + b) +} + +fn op_sub(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> { + arith_op(expr, env, Number::Int(0), |a, b| a - b) +} + +fn op_mul(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> { + arith_op(expr, env, Number::Int(1), |a, b| a * b) +} + +fn op_div(expr: &[SExpr], env: &mut Environment) -> Result<SExpr, String> { + arith_op(expr, env, Number::Float(1.0), |a, b| a / b) } |