Implement lambda application (boom!)

This commit is contained in:
2021-05-29 13:50:26 -04:00
parent b0968ba498
commit 390c5d1b48
4 changed files with 111 additions and 39 deletions

View File

@@ -1,27 +1,25 @@
use crate::parser::Datum;
use crate::parser::Datum::*;
use crate::parser::make_symbol;
use crate::environment;
use crate::environment::Env;
use std::mem;
fn is_true(exp: &Datum) -> bool {
match exp {
Boolean(b) => *b,
Number(_) => true,
List(_) => true,
List(v) if has_tag(v, "list") => true,
_ => panic!("IS-TRUE -- unknown-truth-value {:?}", 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;
}
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
@@ -31,7 +29,8 @@ fn interpret_if(args: &Vec<Datum>, env: &mut Env) -> Datum {
let predicate = &args[1];
let alternative = &args[2];
if is_true(predicate) {
let predicate_interpreted = interpret(predicate, env);
if is_true(&predicate_interpreted) {
interpret(alternative, env)
} else {
if args.len() == 4 {
@@ -44,16 +43,29 @@ fn interpret_if(args: &Vec<Datum>, env: &mut Env) -> Datum {
}
fn interpret_define(args: &Vec<Datum>, env: &mut Env) -> Datum {
match args[1] {
match &args[1] {
Symbol(_) => {
// regular definition
let var = &args[1];
let val = interpret(&args[2], env);
environment::define_variable(var, val, env)
},
List(_) => {
println!("procedure definition");
Number(42)
}
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);
}
}
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)
}
}
@@ -68,7 +80,7 @@ fn interpret_begin(vec: &Vec<Datum>, env: &mut Env) -> Datum {
fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
if vec.len() == 0 {
panic!("APPLICATION -- no-procedure")
panic!("INTERPRET-APPLICATION -- no-procedure")
}
let mut args = vec![];
@@ -77,10 +89,25 @@ fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
args.push(a)
}
if let Procedure(proc) = mem::take(&mut args[0]) {
proc(args)
} else {
panic!("APPLICATION -- not-aplicable {:?}", args[0])
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();
// FIXME: this does not optimize tail-calls
environment::extend_environment(lambda_parameters, List(lambda_args), env);
let mut r = Datum::Unspecified;
if let List(seq) = lambda_body {
for i in 0..seq.len() {
r = interpret(&seq[i], env);
}
}
environment::shrink_environment(env);
r
},
_ => panic!("INTERPRET-APPLICATION -- not-aplicable {:?}", args[0])
}
}
@@ -90,12 +117,12 @@ pub fn interpret(exp: &Datum, env: &mut Env) -> Datum {
Number(_) => exp.clone(),
Unspecified => Unspecified,
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(v) if has_tag(&exp, "define") => interpret_define(v, env),
List(_) if has_tag(&exp, "cond") => panic!("cond-not-supported"),
List(_) if has_tag(&exp, "let") => panic!("let-not-supported"),
List(v) if has_tag(&exp, "begin") => interpret_begin(v, env),
List(v) if has_tag(v, "if") => interpret_if(v, env),
List(v) if has_tag(v, "set!") => panic!("assignment-not-supported"),
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) => interpret_application(v, env),
// TODO: quoted
_ => panic!("unknown-expression {:?}", exp),