From 56f5426426436101f9d1a1e0e5cd58bd2f179aad Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Fri, 21 May 2021 13:17:50 -0400 Subject: [PATCH] Implement if else support --- src/interpreter.rs | 61 ++++++++++++++++++++++++++++++++++++++++------ src/main.rs | 2 +- src/parser.rs | 4 +-- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 14c12e6..e605d8d 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -3,13 +3,22 @@ use crate::parser::Datum::*; use crate::primitives::*; use std::mem; -fn lookup_variable_value(exp: Datum) -> Datum { +fn is_true(exp: &Datum) -> bool { + match exp { + Boolean(b) => *b, + Number(_) => true, + List(_) => true, + _ => panic!("IS-TRUE -- unknown-truth-value {:?}", exp), + } +} + +fn lookup_variable_value(exp: &Datum) -> Datum { if let Symbol(string) = exp { match string.as_str() { "+" => Procedure(add), "*" => Procedure(mul), "-" => Procedure(sub), - _ => panic!("unbound-variable {:?}", string), + _ => panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable {:?}", string), } } else { panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) @@ -19,7 +28,7 @@ fn lookup_variable_value(exp: Datum) -> Datum { fn application(exp: Datum) -> Datum { if let List(vector) = exp { if vector.len() == 0 { - panic!("Application needs at least a procedure") + panic!("APPLICATION -- no-procedure") } let mut args: Vec = vector.into_iter().map(interpret).collect(); @@ -27,18 +36,56 @@ fn application(exp: Datum) -> Datum { // FIXME: call procedures with args only proc(args) } else { - panic!("The object {:?} is not applicable", args[0]) + panic!("APPLICATION -- not-aplicable {:?}", args[0]) } } else { - panic!("Cannot apply {:?}", exp) + panic!("APPLICATION -- cannot-apply {:?}", exp) + } +} + +fn has_tag(exp: &Datum, tag: &str) -> bool { + if let List(l) = exp { + if l.len() == 0 { + return false; + } + if let Symbol(s) = &l[0] { + if s == tag { + return true; + } + } + } + false +} + +fn interpret_if(mut args: Vec) -> Datum { + let predicate = mem::take(&mut args[1]); + let alternative = mem::take(&mut args[2]); + + if is_true(&predicate) { + interpret(alternative) + } else { + if args.len() == 4 { + let consequent = mem::take(&mut args[3]); + interpret(consequent) + } else { + Unspecified + } } } pub fn interpret(exp: Datum) -> Datum { match exp { - Boolean(_) | Number(_) => exp, - Symbol(_) => lookup_variable_value(exp), + Boolean(_) => exp, + Number(_) => exp, + Symbol(_) => lookup_variable_value(&exp), + List(v) if has_tag(&exp, "if") => interpret_if(v), + List(_) if has_tag(&exp, "set!") => panic!("assignment-not-supported"), + List(_) if has_tag(&exp, "define") => panic!("define-not-supported"), + 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), + // TODO: quoted _ => panic!("unknown-expression {:?}", exp), } } diff --git a/src/main.rs b/src/main.rs index f81a901..b1a32da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ mod primitives; fn main() { // let scm_code = "(+ a (* 32 b) c #t #f)"; - let scm_code = "(* 1 (- 2 2 2) 3)"; + let scm_code = "(if #f (+ 1 1) (* 2 3 4))"; let tokens = lexer::read(scm_code); let datum = parser::parse(tokens); let result = interpreter::interpret(datum); diff --git a/src/parser.rs b/src/parser.rs index dda21ed..6a4c34d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -8,12 +8,12 @@ pub enum Datum { Symbol(String), List(Vec), Procedure(fn(Vec) -> Datum), - None, + Unspecified, } impl Default for Datum { fn default() -> Self { - Datum::None + Datum::Unspecified } }