use crate::environment; use crate::environment::Env; use crate::parser::make_symbol; use crate::parser::Datum; use crate::parser::Datum::*; fn is_true(exp: &Datum) -> bool { match exp { Boolean(b) => *b, Number(_) => true, List(v) if has_tag(v, "list") => true, _ => panic!("IS-TRUE -- unknown-truth-value {:?}", exp), } } fn has_tag(vec: &Vec, tag: &str) -> bool { if vec.len() == 0 { return false; } if let Symbol(s) = &vec[0] { if s == tag { return true; } } false } fn interpret_if(args: &Vec, env: &mut Env) -> Datum { let predicate = &args[1]; let alternative = &args[2]; let predicate_interpreted = interpret(predicate, env); if is_true(&predicate_interpreted) { interpret(alternative, env) } else { if args.len() == 4 { let consequent = &args[3]; interpret(consequent, env) } else { Unspecified } } } fn interpret_set(args: &Vec, env: &mut Env) -> Datum { match &args[1] { Symbol(_) => { let var = &args[1]; let val = interpret(&args[2], env); environment::set_variable(var, val, env) } _ => panic!("INTERPRET-SET -- cannot set {:?}", args), } } fn interpret_define(args: &Vec, env: &mut Env) -> Datum { match &args[1] { Symbol(_) => { // regular definition let var = &args[1]; let val = interpret(&args[2], env); environment::define_variable(var, val, env) } List(v) => { // procedure definition let definition_var = &v[0]; let mut parameters = vec![]; for p in &v[1..] { if let Symbol(_) = &p { parameters.push(p.clone()); } else { panic!("INTERPRET-DEFINE -- parameter not a symbol {:?}", p); } } // FIXME: we need to keep the current environment here otherwise closures will not work // FIXME: also create a dedicated enum-type for procedures instead of putting it into a vector let lambda_parameters = Datum::List(parameters); let lambda_body = Datum::List(args[2..].to_vec()); let lambda = Datum::List(vec![make_symbol("lambda"), lambda_parameters, lambda_body]); environment::define_variable(definition_var, lambda, env) } _ => panic!("INTERPRET-DEFINE -- cannot define {:?}", args), } } fn interpret_begin(vec: &Vec, env: &mut Env) -> Datum { let mut r = Datum::Unspecified; for i in 1..vec.len() { r = interpret(&vec[i], env); } r } fn interpret_application(vec: &Vec, env: &mut Env) -> Datum { if vec.len() == 0 { panic!("INTERPRET-APPLICATION -- no-procedure") } let mut args = vec![]; for v in vec { let a = interpret(v, env); args.push(a) } match &args[0] { Procedure(proc) => proc(args), List(v) if has_tag(v, "lambda") => { let lambda_parameters = v[1].clone(); let lambda_body = &v[2]; let lambda_args = args[1..].to_vec(); let mut new_env = environment::extend(lambda_parameters, List(lambda_args), env); if let List(seq) = lambda_body { for i in 0..(seq.len() - 1) { interpret(&seq[i], &mut new_env); } interpret(&seq[seq.len() - 1], &mut new_env) } else { panic!("INTERPRET-APPLICATION -- no-list {:?}", lambda_body) } } _ => panic!("INTERPRET-APPLICATION -- not-aplicable {:?}", args[0]), } } pub fn interpret(exp: &Datum, env: &mut Env) -> Datum { match exp { Boolean(_) => exp.clone(), Number(_) => exp.clone(), Unspecified => Unspecified, Symbol(_) => environment::lookup_variable_value(exp, env), List(v) if has_tag(v, "if") => interpret_if(v, env), List(v) if has_tag(v, "set!") => interpret_set(v, env), List(v) if has_tag(v, "define") => interpret_define(v, env), List(v) if has_tag(v, "cond") => panic!("cond-not-supported"), List(v) if has_tag(v, "let") => panic!("let-not-supported"), List(v) if has_tag(v, "begin") => interpret_begin(v, env), List(v) if has_tag(v, "quote") => v[1].clone(), List(v) => interpret_application(v, env), _ => panic!("unknown-expression {:?}", exp), } }