use std::collections::HashMap;
mod types;
mod pretty;
use types::*;
use pretty::show;
impl Stmt {
fn eval(&self, env: &mut Env) -> Result<Value, String> {
match *self {
Stmt::Expr(ref e) => e.eval(env),
Stmt::Let(ref p, _, _, ref e) => {
p.bind(e.eval(env)?, env);
Ok(Value::Unit)
},
}
}
}
impl Pat {
fn bind(&self, val: Value, env: &mut Env) {
match *self {
Pat::Var(ref n) => {
let _ = env.insert(n.clone(), val);
},
Pat::Tuple(ref ps) => {
match val {
Value::Tuple(es) => {
if es.len() != ps.len() {
panic!("non-matching tuples!");
}
for (p, e) in ps.iter().zip(es.into_iter()) {
p.bind(e, env);
}
}
_ => panic!("not matching a tuple!"),
}
}
}
}
}
impl Expr {
pub fn eval(&self, env: &mut Env) -> Result<Value, String> {
match *self {
Expr::Var(ref n) => Ok(env.get(n).unwrap().clone()),
Expr::Lit(ref l) => Ok(Value::Lit(l.clone())),
Expr::Fn(ref pat, ref e) =>
Ok(Value::Closure(
*pat.clone(),
*e.clone(),
Box::new(env.clone()),
)),
Expr::App(ref e1, ref e2) => {
let v1 = e1.eval(env)?;
let v2 = e2.eval(env)?;
match v1 {
Value::Closure(p, e, mut env2) => {
p.bind(v2, &mut env2);
e.eval(&mut env2)
},
_ => return Err(format!("not a function")),
}
},
Expr::Do(ref stmts) => {
let mut result = Value::Unit;
for stmt in stmts.iter() {
result = stmt.eval(env)?;
}
Ok(result)
},
Expr::Tuple(ref exprs) => {
let res: Result<Vec<Value>, String> =
exprs.iter().map(|e|e.eval(env)).collect();
Ok(Value::Tuple(res?))
},
}
}
}
fn test(e: &Expr) {
let mut env = HashMap::new();
println!("> {}", show(e));
println!(" -> {}", show(&e.eval(&mut env).unwrap()));
}
fn main() {
let sample = Expr::mk_app(
Expr::mk_fn(
Pat::mk_var("x"),
Expr::mk_fn(
Pat::mk_var("y"),
Expr::mk_tuple(vec![
Expr::mk_var("x"),
Expr::mk_var("y"),
]),
),
),
Expr::Lit(Literal::Int(5)),
);
test(&sample);
let rs = Expr::mk_app(sample, Expr::Lit(Literal::Int(6)));
test(&rs);
let sample2 = Expr::mk_fn(
Pat::mk_tuple(vec![
Pat::mk_var("a"),
Pat::mk_var("b"),
]),
Expr::mk_var("a"),
);
test(&Expr::mk_app(sample2, rs));
}