summaryrefslogtreecommitdiff
path: root/src/lib/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eval')
-rw-r--r--src/lib/eval/arith.rs83
-rw-r--r--src/lib/eval/mod.rs62
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)
}