oftlisp-anf 0.1.3

An OftLisp backend using A-normal form.
Documentation
use std::collections::HashMap;

use gc::Gc;
use oftlisp::{InterpreterContext, Symbol, Value};
use oftlisp::collections::GcLinkedList;

use errors::RuntimeError;
use primitives::PRIMITIVES;
use types::{Context, Expr, Prim};

impl Context {
    /// Applies a function to the given arguments.
    pub fn apply(func: Gc<Value<Self>>, args: Vec<Gc<Value<Self>>>) -> Result<Gc<Value<Self>>, RuntimeError> {
        match *func {
            Value::BuiltinFunction(_, f, _) => {
                f(args)
            },
            Value::Func(n, ref a, (ref b, ref e), _) => {
                let mut env = e.clone();
                if let Some(n) = n {
                    env.push((n, func.clone()));
                }
                env.push_all_gc(a.bind(n, args)?);
                Self::eval(b.clone(), &mut env)
            },
            _ => Err(RuntimeError::NotAFunction(func.clone())),
        }
    }

    fn eval_prim(prim: &Prim, env: &GcLinkedList<(Symbol, Gc<Value<Context>>)>) -> Result<Gc<Value<Self>>, RuntimeError> {
        match *prim {
            Prim::Fn(name, ref args, ref body) => {
                let mut closure_env = GcLinkedList::new();
                for var in prim.freevars() {
                    if let Some(value) = env.lookup(var) {
                        closure_env.push((var, value));
                    } else {
                        return Err(RuntimeError::NonexistentVar(var));
                    }
                }
                Ok(Gc::new(Value::Func(name, args.clone(), (body.clone(), closure_env), ())))
            },
            Prim::Lit(ref val) => Ok(val.clone()),
            Prim::Var(var) => if let Some(value) = env.lookup(var) {
                Ok(value)
            } else {
                Err(RuntimeError::NonexistentVar(var))
            },
            Prim::Vec(ref vec) => {
                let vec = vec.iter()
                    .cloned()
                    .map(|p| Self::eval_prim(&p, &env))
                    .collect::<Result<_, _>>()?;
                Ok(Gc::new(Value::Vector(vec, ())))
            },
        }
    }
}

impl InterpreterContext for Context {
    type RuntimeError = RuntimeError;

    fn eval(expr: Gc<Expr>, env: &mut GcLinkedList<(Symbol, Gc<Value<Self>>)>) -> Result<Gc<Value<Self>>, RuntimeError> {
        trace!("Evaling {}", expr);
        match *expr {
            Expr::Call(ref func, ref args) => {
                let func = Self::eval_prim(func, env)?;
                let args = args.iter()
                    .map(|v| Self::eval_prim(v, env))
                    .collect::<Result<Vec<_>, _>>()?;
                Context::apply(func, args)
            },
            Expr::If(ref c, ref t, ref e) => {
                if let Value::Nil(_) = *Self::eval_prim(c, env)? {
                    Self::eval(e.clone(), env)
                } else {
                    Self::eval(t.clone(), env)
                }
            },
            Expr::Let(var, ref bound, ref next) => {
                let value = Self::eval(bound.clone(), env)?;
                let mut env = env.clone();
                if let Some(var) = var {
                    env.push((var, value));
                }
                Self::eval(next.clone(), &mut env)
            },
            Expr::Prim(ref prim) => Self::eval_prim(&prim, env),
        }
    }

    fn primitives() -> HashMap<Symbol, Gc<Value<Self>>> {
        PRIMITIVES.clone().into()
    }
}