summaryrefslogtreecommitdiff
path: root/src/lib/eval/mod.rs
blob: adee0e51cdbb80418d975d3aab05bd21984902a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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<SExpr, String> {
    match expr {
        Atom(ref x) => Ok(Atom((*x).clone())),
        Sexpr(ref s) => seval(s, env)
    }
}

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(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<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 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 = (f(acc, b))?;
        i += 1
    }
    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)
}