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 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}