diff --git a/src/environment.rs b/src/environment.rs index ed219c5..54d0ddc 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -1,6 +1,5 @@ use crate::parser::make_symbol; use crate::parser::Datum; -use crate::primitives; use std::mem; type Mapping = (Datum, Datum); @@ -14,23 +13,22 @@ pub struct Frame<'a> { pub type Env<'a> = Frame<'a>; pub fn get_global_environment<'a>() -> Env<'a> { + use crate::parser::Datum::Primitive; + use crate::primitives::*; Frame { mappings: vec![ - (make_symbol("+"), Datum::Procedure(primitives::add)), - (make_symbol("*"), Datum::Procedure(primitives::mul)), - (make_symbol("-"), Datum::Procedure(primitives::sub)), - (make_symbol("="), Datum::Procedure(primitives::eq)), - (make_symbol("<"), Datum::Procedure(primitives::lt)), - (make_symbol("list"), Datum::Procedure(primitives::list)), - (make_symbol("cons"), Datum::Procedure(primitives::cons)), - (make_symbol("car"), Datum::Procedure(primitives::car)), - (make_symbol("cdr"), Datum::Procedure(primitives::cdr)), - (make_symbol("pair?"), Datum::Procedure(primitives::pair)), - (make_symbol("null?"), Datum::Procedure(primitives::null)), - ( - make_symbol("display"), - Datum::Procedure(primitives::display), - ), + (make_symbol("+"), Primitive(add)), + (make_symbol("*"), Primitive(mul)), + (make_symbol("-"), Primitive(sub)), + (make_symbol("="), Primitive(eq)), + (make_symbol("<"), Primitive(lt)), + (make_symbol("list"), Primitive(list)), + (make_symbol("cons"), Primitive(cons)), + (make_symbol("car"), Primitive(car)), + (make_symbol("cdr"), Primitive(cdr)), + (make_symbol("pair?"), Primitive(pair)), + (make_symbol("null?"), Primitive(null)), + (make_symbol("display"), Primitive(display)), ], outer: None, } diff --git a/src/interpreter.rs b/src/interpreter.rs index b7e8abd..65e1b3a 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -109,16 +109,30 @@ fn interpret_lambda(vec: &Vec, _env: &mut Env) -> Datum { } } } - let body; - if let List(insts) = &vec[2] { - body = insts.to_vec(); - } else { - panic!("INTERPRET-LAMBDA - body not a list {:?}", vec[1]); - } + let body = vec[2..].to_vec(); + Lambda { parameters, body } +} - Lambda { - parameters: parameters, - body: body, +fn transform_let_to_lambda(vec: &Vec) -> Datum { + let mut args = vec![]; + let mut parameters = vec![]; + let body = vec[2..].to_vec(); + + if let List(bindings) = &vec[1] { + for binding in bindings { + if let List(binding) = binding { + parameters.push(binding[0].clone()); + args.push(binding[1].clone()); + } else { + panic!("TRANSFORM-LET-TO-LAMBDA -- invalid binding {:?}", binding); + } + } + let lambda = Lambda { parameters, body }; + let mut result = vec![lambda]; + result.append(&mut args); + List(result) + } else { + panic!("TRANSFORM-LET-TO-LAMBDA -- invalid bindings {:?}", vec[1]); } } @@ -142,7 +156,7 @@ fn interpret_application(vec: &Vec, env: &mut Env) -> Datum { } match &args[0] { - Procedure(proc) => proc(args), + Primitive(proc) => proc(args), Lambda { parameters, body } => { let lambda_args = args[1..].to_vec(); let mut new_env = @@ -167,10 +181,11 @@ pub fn interpret(exp: &Datum, env: &mut Env) -> Datum { List(v) if has_tag(v, "define") => interpret_define(v, env), List(v) if has_tag(v, "cond") => interpret_cond(v, env), List(v) if has_tag(v, "lambda") => interpret_lambda(v, env), - List(v) if has_tag(v, "let") => panic!("let-not-supported"), + List(v) if has_tag(v, "let") => interpret(&transform_let_to_lambda(v), env), 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), + Lambda { .. } => exp.clone(), Unspecified => Unspecified, _ => panic!("unknown-expression {:?}", exp), } diff --git a/src/main.rs b/src/main.rs index 6515dde..8668f1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,7 +52,7 @@ fn interpret_file(filename: &Path) { fn main() { let args: Vec = env::args().collect(); // let scm_code = "(begin (define (f n) (if (= n 1) 1 (* n (f (- n 1))))) (f 10))"; - let scm_code = ""; + let scm_code = "(let ((a 3) (b 4)) (define c (+ a b)) (* c c))"; if args.len() == 2 { let arg_path = Path::new(&args[1]); diff --git a/src/parser.rs b/src/parser.rs index 0f28c36..8fa9908 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -11,7 +11,7 @@ pub enum Datum { Symbol(String), Pair(Box<(Datum, Datum)>), List(Vec), - Procedure(fn(Vec) -> Datum), + Primitive(fn(Vec) -> Datum), Lambda { parameters: Vec, body: Vec,