From 794cad2219ef9b21c93c2677fb97edccc7060ebe Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Thu, 27 May 2021 21:02:18 -0400 Subject: [PATCH] Initial version of environment model --- src/environment.rs | 31 ++++++++++++++++++++++++ src/interpreter.rs | 60 ++++++++++++++++++++++------------------------ src/main.rs | 7 ++++-- src/parser.rs | 12 +++++++--- 4 files changed, 74 insertions(+), 36 deletions(-) create mode 100644 src/environment.rs diff --git a/src/environment.rs b/src/environment.rs new file mode 100644 index 0000000..ec05913 --- /dev/null +++ b/src/environment.rs @@ -0,0 +1,31 @@ +use crate::parser::Datum; +use crate::parser::Datum::{Procedure, Symbol}; +use crate::parser::make_symbol; +use crate::primitives; + +type Mapping = (Datum, Datum); +type Frame = Vec; +pub type Env = Vec; + +pub fn get_global_environment() -> Env { + vec![vec![(make_symbol("+"), Procedure(primitives::add)), + (make_symbol("*"), Procedure(primitives::mul)), + (make_symbol("-"), Procedure(primitives::sub))]] +} + +pub fn lookup_variable_value(exp: &Datum, env: &Env) -> Datum { + if let Symbol(symbol_name) = exp { + for frame in env { + for mapping in frame { + if let (Symbol(current_name), datum) = mapping { + if symbol_name == current_name { + return datum.clone(); + } + } + } + } + } else { + panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) + } + panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable-error {:?}", exp) +} \ No newline at end of file diff --git a/src/interpreter.rs b/src/interpreter.rs index e605d8d..3a96a2d 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,8 +1,9 @@ use crate::parser::Datum; use crate::parser::Datum::*; -use crate::primitives::*; +use crate::environment; +use crate::environment::Env; use std::mem; - + fn is_true(exp: &Datum) -> bool { match exp { Boolean(b) => *b, @@ -12,28 +13,20 @@ fn is_true(exp: &Datum) -> bool { } } -fn lookup_variable_value(exp: &Datum) -> Datum { - if let Symbol(string) = exp { - match string.as_str() { - "+" => Procedure(add), - "*" => Procedure(mul), - "-" => Procedure(sub), - _ => panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable {:?}", string), - } - } else { - panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) - } -} - -fn application(exp: Datum) -> Datum { +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(); + // let mut args: Vec = vector.into_iter().map(interpret).collect(); if let Procedure(proc) = mem::take(&mut args[0]) { - // FIXME: call procedures with args only proc(args) } else { panic!("APPLICATION -- not-aplicable {:?}", args[0]) @@ -57,34 +50,39 @@ fn has_tag(exp: &Datum, tag: &str) -> bool { false } -fn interpret_if(mut args: Vec) -> Datum { - let predicate = mem::take(&mut args[1]); - let alternative = mem::take(&mut args[2]); +fn interpret_if(args: &Vec, env: &Env) -> Datum { + let predicate = &args[1]; + let alternative = &args[2]; if is_true(&predicate) { - interpret(alternative) + interpret(&alternative, env) } else { if args.len() == 4 { - let consequent = mem::take(&mut args[3]); - interpret(consequent) + let consequent = &args[3]; + interpret(&consequent, env) } else { Unspecified } } } -pub fn interpret(exp: Datum) -> Datum { +fn interpret_define(_args: &Vec) -> Datum { + + Number(42) +} + +pub fn interpret(exp: &Datum, env: &Env) -> Datum { match exp { - Boolean(_) => exp, - Number(_) => exp, - Symbol(_) => lookup_variable_value(&exp), - List(v) if has_tag(&exp, "if") => interpret_if(v), + 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), List(_) if has_tag(&exp, "set!") => panic!("assignment-not-supported"), - List(_) if has_tag(&exp, "define") => panic!("define-not-supported"), + List(v) if has_tag(&exp, "define") => interpret_define(v), 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), + List(_) => application(exp, env), // TODO: quoted _ => panic!("unknown-expression {:?}", exp), } diff --git a/src/main.rs b/src/main.rs index b1a32da..930041e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,12 +2,15 @@ mod interpreter; mod lexer; mod parser; mod primitives; +mod environment; fn main() { - // let scm_code = "(+ a (* 32 b) c #t #f)"; 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 tokens = lexer::read(scm_code); let datum = parser::parse(tokens); - let result = interpreter::interpret(datum); + let result = interpreter::interpret(&datum, &env); println!("{:?}", result); } diff --git a/src/parser.rs b/src/parser.rs index 6a4c34d..a0bb0bc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use crate::lexer::Token; use crate::lexer::Tokens; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Datum { Boolean(bool), Number(i64), @@ -11,6 +11,10 @@ pub enum Datum { Unspecified, } +pub fn make_symbol(s: &str) -> Datum { + Datum::Symbol(s.to_string()) +} + impl Default for Datum { fn default() -> Self { Datum::Unspecified @@ -35,12 +39,14 @@ fn parse_datum(tokens: &Tokens, ix: usize) -> (Datum, usize) { pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) { let mut datums = vec![]; - // FIXME: will crash when RightRoundBracket is missing - while tokens[ix] != Token::RightRoundBracket { + while ix < tokens.len() && tokens[ix] != Token::RightRoundBracket { let (datum, new_ix) = parse_datum(tokens, ix); datums.push(datum); ix = new_ix; } + if ix == tokens.len() { + panic!("PARSE_LIST -- missing closing bracket {:?}", tokens) + } (Datum::List(datums), ix + 1) }