143 lines
4.5 KiB
Rust
143 lines
4.5 KiB
Rust
use crate::environment;
|
|
use crate::environment::Env;
|
|
use crate::parser::make_symbol;
|
|
use crate::parser::Datum;
|
|
use crate::parser::Datum::*;
|
|
|
|
fn is_true(exp: &Datum) -> bool {
|
|
match exp {
|
|
Boolean(b) => *b,
|
|
Number(_) => true,
|
|
List(v) if has_tag(v, "list") => true,
|
|
_ => panic!("IS-TRUE -- unknown-truth-value {:?}", exp),
|
|
}
|
|
}
|
|
|
|
fn has_tag(vec: &Vec<Datum>, tag: &str) -> bool {
|
|
if vec.len() == 0 {
|
|
return false;
|
|
}
|
|
if let Symbol(s) = &vec[0] {
|
|
if s == tag {
|
|
return true;
|
|
}
|
|
}
|
|
false
|
|
}
|
|
|
|
fn interpret_if(args: &Vec<Datum>, env: &mut Env) -> Datum {
|
|
let predicate = &args[1];
|
|
let alternative = &args[2];
|
|
|
|
let predicate_interpreted = interpret(predicate, env);
|
|
if is_true(&predicate_interpreted) {
|
|
interpret(alternative, env)
|
|
} else {
|
|
if args.len() == 4 {
|
|
let consequent = &args[3];
|
|
interpret(consequent, env)
|
|
} else {
|
|
Unspecified
|
|
}
|
|
}
|
|
}
|
|
|
|
fn interpret_set(args: &Vec<Datum>, env: &mut Env) -> Datum {
|
|
match &args[1] {
|
|
Symbol(_) => {
|
|
let var = &args[1];
|
|
let val = interpret(&args[2], env);
|
|
environment::set_variable(var, val, env)
|
|
}
|
|
_ => panic!("INTERPRET-SET -- cannot set {:?}", args),
|
|
}
|
|
}
|
|
|
|
fn interpret_define(args: &Vec<Datum>, env: &mut Env) -> Datum {
|
|
match &args[1] {
|
|
Symbol(_) => {
|
|
// regular definition
|
|
let var = &args[1];
|
|
let val = interpret(&args[2], env);
|
|
environment::define_variable(var, val, env)
|
|
}
|
|
List(v) => {
|
|
// procedure definition
|
|
let definition_var = &v[0];
|
|
let mut parameters = vec![];
|
|
for p in &v[1..] {
|
|
if let Symbol(_) = &p {
|
|
parameters.push(p.clone());
|
|
} else {
|
|
panic!("INTERPRET-DEFINE -- parameter not a symbol {:?}", p);
|
|
}
|
|
}
|
|
// FIXME: we need to keep the current environment here otherwise closures will not work
|
|
// FIXME: also create a dedicated enum-type for procedures instead of putting it into a vector
|
|
let lambda_parameters = Datum::List(parameters);
|
|
let lambda_body = Datum::List(args[2..].to_vec());
|
|
let lambda = Datum::List(vec![make_symbol("lambda"), lambda_parameters, lambda_body]);
|
|
environment::define_variable(definition_var, lambda, env)
|
|
}
|
|
_ => panic!("INTERPRET-DEFINE -- cannot define {:?}", args),
|
|
}
|
|
}
|
|
|
|
fn interpret_begin(vec: &Vec<Datum>, 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<Datum>, env: &mut Env) -> Datum {
|
|
if vec.len() == 0 {
|
|
panic!("INTERPRET-APPLICATION -- no-procedure")
|
|
}
|
|
|
|
let mut args = vec![];
|
|
for v in vec {
|
|
let a = interpret(v, env);
|
|
args.push(a)
|
|
}
|
|
|
|
match &args[0] {
|
|
Procedure(proc) => proc(args),
|
|
List(v) if has_tag(v, "lambda") => {
|
|
let lambda_parameters = v[1].clone();
|
|
let lambda_body = &v[2];
|
|
let lambda_args = args[1..].to_vec();
|
|
|
|
let mut new_env = environment::extend(lambda_parameters, List(lambda_args), env);
|
|
if let List(seq) = lambda_body {
|
|
for i in 0..(seq.len() - 1) {
|
|
interpret(&seq[i], &mut new_env);
|
|
}
|
|
interpret(&seq[seq.len() - 1], &mut new_env)
|
|
} else {
|
|
panic!("INTERPRET-APPLICATION -- no-list {:?}", lambda_body)
|
|
}
|
|
}
|
|
_ => panic!("INTERPRET-APPLICATION -- not-aplicable {:?}", args[0]),
|
|
}
|
|
}
|
|
|
|
pub fn interpret(exp: &Datum, env: &mut Env) -> Datum {
|
|
match exp {
|
|
Boolean(_) => exp.clone(),
|
|
Number(_) => exp.clone(),
|
|
Unspecified => Unspecified,
|
|
Symbol(_) => environment::lookup_variable_value(exp, env),
|
|
List(v) if has_tag(v, "if") => interpret_if(v, env),
|
|
List(v) if has_tag(v, "set!") => interpret_set(v, env),
|
|
List(v) if has_tag(v, "define") => interpret_define(v, env),
|
|
List(v) if has_tag(v, "cond") => panic!("cond-not-supported"),
|
|
List(v) if has_tag(v, "let") => panic!("let-not-supported"),
|
|
List(v) if has_tag(v, "begin") => interpret_begin(v, env),
|
|
List(v) if has_tag(v, "quote") => v[1].clone(),
|
|
List(v) => interpret_application(v, env),
|
|
_ => panic!("unknown-expression {:?}", exp),
|
|
}
|
|
}
|