Implement if else support
This commit is contained in:
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user