oftlisp_anf/
interpret.rs

1use std::collections::HashMap;
2
3use gc::Gc;
4use oftlisp::{InterpreterContext, Symbol, Value};
5use oftlisp::collections::GcLinkedList;
6
7use errors::RuntimeError;
8use primitives::PRIMITIVES;
9use types::{Context, Expr, Prim};
10
11impl Context {
12    /// Applies a function to the given arguments.
13    pub fn apply(func: Gc<Value<Self>>, args: Vec<Gc<Value<Self>>>) -> Result<Gc<Value<Self>>, RuntimeError> {
14        match *func {
15            Value::BuiltinFunction(_, f, _) => {
16                f(args)
17            },
18            Value::Func(n, ref a, (ref b, ref e), _) => {
19                let mut env = e.clone();
20                if let Some(n) = n {
21                    env.push((n, func.clone()));
22                }
23                env.push_all_gc(a.bind(n, args)?);
24                Self::eval(b.clone(), &mut env)
25            },
26            _ => Err(RuntimeError::NotAFunction(func.clone())),
27        }
28    }
29
30    fn eval_prim(prim: &Prim, env: &GcLinkedList<(Symbol, Gc<Value<Context>>)>) -> Result<Gc<Value<Self>>, RuntimeError> {
31        match *prim {
32            Prim::Fn(name, ref args, ref body) => {
33                let mut closure_env = GcLinkedList::new();
34                for var in prim.freevars() {
35                    if let Some(value) = env.lookup(var) {
36                        closure_env.push((var, value));
37                    } else {
38                        return Err(RuntimeError::NonexistentVar(var));
39                    }
40                }
41                Ok(Gc::new(Value::Func(name, args.clone(), (body.clone(), closure_env), ())))
42            },
43            Prim::Lit(ref val) => Ok(val.clone()),
44            Prim::Var(var) => if let Some(value) = env.lookup(var) {
45                Ok(value)
46            } else {
47                Err(RuntimeError::NonexistentVar(var))
48            },
49            Prim::Vec(ref vec) => {
50                let vec = vec.iter()
51                    .cloned()
52                    .map(|p| Self::eval_prim(&p, &env))
53                    .collect::<Result<_, _>>()?;
54                Ok(Gc::new(Value::Vector(vec, ())))
55            },
56        }
57    }
58}
59
60impl InterpreterContext for Context {
61    type RuntimeError = RuntimeError;
62
63    fn eval(expr: Gc<Expr>, env: &mut GcLinkedList<(Symbol, Gc<Value<Self>>)>) -> Result<Gc<Value<Self>>, RuntimeError> {
64        trace!("Evaling {}", expr);
65        match *expr {
66            Expr::Call(ref func, ref args) => {
67                let func = Self::eval_prim(func, env)?;
68                let args = args.iter()
69                    .map(|v| Self::eval_prim(v, env))
70                    .collect::<Result<Vec<_>, _>>()?;
71                Context::apply(func, args)
72            },
73            Expr::If(ref c, ref t, ref e) => {
74                if let Value::Nil(_) = *Self::eval_prim(c, env)? {
75                    Self::eval(e.clone(), env)
76                } else {
77                    Self::eval(t.clone(), env)
78                }
79            },
80            Expr::Let(var, ref bound, ref next) => {
81                let value = Self::eval(bound.clone(), env)?;
82                let mut env = env.clone();
83                if let Some(var) = var {
84                    env.push((var, value));
85                }
86                Self::eval(next.clone(), &mut env)
87            },
88            Expr::Prim(ref prim) => Self::eval_prim(&prim, env),
89        }
90    }
91
92    fn primitives() -> HashMap<Symbol, Gc<Value<Self>>> {
93        PRIMITIVES.clone().into()
94    }
95}