Implement if else support

This commit is contained in:
2021-05-21 13:17:50 -04:00
parent b0bf78a3bd
commit 56f5426426
3 changed files with 57 additions and 10 deletions

View File

@@ -3,13 +3,22 @@ use crate::parser::Datum::*;
use crate::primitives::*; use crate::primitives::*;
use std::mem; 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 { if let Symbol(string) = exp {
match string.as_str() { match string.as_str() {
"+" => Procedure(add), "+" => Procedure(add),
"*" => Procedure(mul), "*" => Procedure(mul),
"-" => Procedure(sub), "-" => Procedure(sub),
_ => panic!("unbound-variable {:?}", string), _ => panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable {:?}", string),
} }
} else { } else {
panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp)
@@ -19,7 +28,7 @@ fn lookup_variable_value(exp: Datum) -> Datum {
fn application(exp: Datum) -> Datum { fn application(exp: Datum) -> Datum {
if let List(vector) = exp { if let List(vector) = exp {
if vector.len() == 0 { if vector.len() == 0 {
panic!("Application needs at least a procedure") panic!("APPLICATION -- no-procedure")
} }
let mut args: Vec<Datum> = vector.into_iter().map(interpret).collect(); let mut args: Vec<Datum> = vector.into_iter().map(interpret).collect();
@@ -27,18 +36,56 @@ fn application(exp: Datum) -> Datum {
// FIXME: call procedures with args only // FIXME: call procedures with args only
proc(args) proc(args)
} else { } else {
panic!("The object {:?} is not applicable", args[0]) panic!("APPLICATION -- not-aplicable {:?}", args[0])
} }
} else { } 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>) -> 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 { pub fn interpret(exp: Datum) -> Datum {
match exp { match exp {
Boolean(_) | Number(_) => exp, Boolean(_) => exp,
Symbol(_) => lookup_variable_value(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), List(_) => application(exp),
// TODO: quoted
_ => panic!("unknown-expression {:?}", exp), _ => panic!("unknown-expression {:?}", exp),
} }
} }

View File

@@ -5,7 +5,7 @@ mod primitives;
fn main() { fn main() {
// let scm_code = "(+ a (* 32 b) c #t #f)"; // 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 tokens = lexer::read(scm_code);
let datum = parser::parse(tokens); let datum = parser::parse(tokens);
let result = interpreter::interpret(datum); let result = interpreter::interpret(datum);

View File

@@ -8,12 +8,12 @@ pub enum Datum {
Symbol(String), Symbol(String),
List(Vec<Datum>), List(Vec<Datum>),
Procedure(fn(Vec<Datum>) -> Datum), Procedure(fn(Vec<Datum>) -> Datum),
None, Unspecified,
} }
impl Default for Datum { impl Default for Datum {
fn default() -> Self { fn default() -> Self {
Datum::None Datum::Unspecified
} }
} }