From b0968ba498fc4981a4c9b7e4ddf282c5801cc231 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sat, 29 May 2021 11:29:27 -0400 Subject: [PATCH] Implement begin and define --- src/environment.rs | 35 +++++++++++++++--- src/interpreter.rs | 90 ++++++++++++++++++++++++++-------------------- src/main.rs | 10 +++--- 3 files changed, 88 insertions(+), 47 deletions(-) diff --git a/src/environment.rs b/src/environment.rs index ec05913..f907190 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -13,8 +13,8 @@ pub fn get_global_environment() -> Env { (make_symbol("-"), Procedure(primitives::sub))]] } -pub fn lookup_variable_value(exp: &Datum, env: &Env) -> Datum { - if let Symbol(symbol_name) = exp { +pub fn lookup_variable_value(var: &Datum, env: &Env) -> Datum { + if let Symbol(symbol_name) = var { for frame in env { for mapping in frame { if let (Symbol(current_name), datum) = mapping { @@ -25,7 +25,34 @@ pub fn lookup_variable_value(exp: &Datum, env: &Env) -> Datum { } } } else { - panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) + panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", var) } - panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable-error {:?}", exp) + panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable-error {:?}", var) +} + +pub fn define_variable(var: &Datum, val: Datum, env: &mut Env) -> Datum { + if let Symbol(symbol_name) = var { + // Assign to variable if it already exits + if let Some(frame) = env.last_mut() { + for mapping in frame { + if let (Symbol(current_name), _) = mapping { + if symbol_name == current_name { + mapping.1 = val; + return Datum::Unspecified; + } + } + } + } else { + panic!("DEFINE-VARIABLE -- no-frames {:?}", env) + } + + // Create variable because it does not exist yet + if let Some(frame) = env.last_mut() { + let pair = (var.clone(), val); + frame.push(pair); + } + } else { + panic!("DEFINE-VARIABLE -- not-a-symbol {:?}", var) + } + Datum::Unspecified } \ No newline at end of file diff --git a/src/interpreter.rs b/src/interpreter.rs index 3a96a2d..a39a2ac 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -13,29 +13,6 @@ fn is_true(exp: &Datum) -> bool { } } -fn application(exp: &Datum, env: &Env) -> Datum { - if let List(vector) = exp { - if vector.len() == 0 { - panic!("APPLICATION -- no-procedure") - } - - let mut args = vec![]; - for v in vector { - let a = interpret(v, env); - args.push(a) - } - - // let mut args: Vec = vector.into_iter().map(interpret).collect(); - if let Procedure(proc) = mem::take(&mut args[0]) { - proc(args) - } else { - panic!("APPLICATION -- not-aplicable {:?}", args[0]) - } - } else { - panic!("APPLICATION -- cannot-apply {:?}", exp) - } -} - fn has_tag(exp: &Datum, tag: &str) -> bool { if let List(l) = exp { if l.len() == 0 { @@ -50,39 +27,76 @@ fn has_tag(exp: &Datum, tag: &str) -> bool { false } -fn interpret_if(args: &Vec, env: &Env) -> Datum { +fn interpret_if(args: &Vec, env: &mut Env) -> Datum { let predicate = &args[1]; let alternative = &args[2]; - if is_true(&predicate) { - interpret(&alternative, env) + if is_true(predicate) { + interpret(alternative, env) } else { if args.len() == 4 { let consequent = &args[3]; - interpret(&consequent, env) + interpret(consequent, env) } else { Unspecified } } } -fn interpret_define(_args: &Vec) -> Datum { - - Number(42) +fn interpret_define(args: &Vec, env: &mut Env) -> Datum { + match args[1] { + Symbol(_) => { + let var = &args[1]; + let val = interpret(&args[2], env); + environment::define_variable(var, val, env) + }, + List(_) => { + println!("procedure definition"); + Number(42) + } + _ => panic!("INTERPRET-DEFINE -- cannot define {:?}", args) + } } -pub fn interpret(exp: &Datum, env: &Env) -> Datum { +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!("APPLICATION -- no-procedure") + } + + let mut args = vec![]; + for v in vec { + let a = interpret(v, env); + args.push(a) + } + + if let Procedure(proc) = mem::take(&mut args[0]) { + proc(args) + } else { + panic!("APPLICATION -- not-aplicable {:?}", args[0]) + } +} + +pub fn interpret(exp: &Datum, env: &mut Env) -> Datum { match exp { - Boolean(b) => Boolean(*b), - Number(n) => Number(*n), - Symbol(_) => environment::lookup_variable_value(&exp, &env), - List(v) if has_tag(&exp, "if") => interpret_if(v, &env), + Boolean(_) => exp.clone(), + Number(_) => exp.clone(), + Unspecified => Unspecified, + Symbol(_) => environment::lookup_variable_value(exp, env), + List(v) if has_tag(&exp, "if") => interpret_if(v, env), List(_) if has_tag(&exp, "set!") => panic!("assignment-not-supported"), - List(v) if has_tag(&exp, "define") => interpret_define(v), + List(v) if has_tag(&exp, "define") => interpret_define(v, env), List(_) if has_tag(&exp, "cond") => panic!("cond-not-supported"), List(_) if has_tag(&exp, "let") => panic!("let-not-supported"), - List(_) if has_tag(&exp, "begin") => panic!("begin-not-supported"), - List(_) => application(exp, env), + List(v) if has_tag(&exp, "begin") => interpret_begin(v, env), + List(v) => interpret_application(v, env), // TODO: quoted _ => panic!("unknown-expression {:?}", exp), } diff --git a/src/main.rs b/src/main.rs index 930041e..2d320a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,12 +5,12 @@ mod primitives; mod environment; fn main() { - let scm_code = "(if #f (+ 1 1) (* 2 3 4))"; - // let scm_code = "(define a (+ 3 3)"; - // let scm_code = "(- (* 3 3) 4)"; - let env = environment::get_global_environment(); + // let scm_code = "(if #t (+ 1 1) (* 2 3 4))"; + // let scm_code = "(begin (define a (+ 2 2)) (* 3 2) (* a a a))"; + let scm_code = "(begin (define (f n) (* n n)) (* 3 2))"; let tokens = lexer::read(scm_code); let datum = parser::parse(tokens); - let result = interpreter::interpret(&datum, &env); + let mut env = environment::get_global_environment(); + let result = interpreter::interpret(&datum, &mut env); println!("{:?}", result); }