Implement lambda support

master
Felix Martin 2021-06-01 19:47:48 -04:00
parent f8b8019682
commit b3181602d6
2 changed files with 43 additions and 19 deletions

View File

@ -1,6 +1,5 @@
use crate::environment;
use crate::environment::Env;
use crate::parser::make_symbol;
use crate::parser::Datum;
use crate::parser::Datum::*;
@ -72,11 +71,14 @@ fn interpret_define(args: &Vec<Datum>, env: &mut Env) -> Datum {
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]);
// XXX: A procedure is clearly not a lambda. We have to keep the
// scope of the definition. Otherwise, closures won't work.
let lambda_body = args[2..].to_vec();
let lambda = Lambda {
parameters: parameters,
body: lambda_body,
};
environment::define_variable(definition_var, lambda, env)
}
_ => panic!("INTERPRET-DEFINE -- cannot define {:?}", args),
@ -96,6 +98,30 @@ fn interpret_cond(vec: &Vec<Datum>, env: &mut Env) -> Datum {
panic!("INTERPRET-COND -- missing else statement? {:?}", vec)
}
fn interpret_lambda(vec: &Vec<Datum>, _env: &mut Env) -> Datum {
let mut parameters = vec![];
if let List(params) = &vec[1] {
for p in params {
if let Symbol(_) = p {
parameters.push(p.clone());
} else {
panic!("INTERPRET-LAMBDA - not a symbol {:?}", p);
}
}
}
let body;
if let List(insts) = &vec[2] {
body = insts.to_vec();
} else {
panic!("INTERPRET-LAMBDA - body not a list {:?}", vec[1]);
}
Lambda {
parameters: parameters,
body: body,
}
}
fn interpret_begin(vec: &Vec<Datum>, env: &mut Env) -> Datum {
let mut r = Datum::Unspecified;
for i in 1..vec.len() {
@ -117,21 +143,14 @@ fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
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];
Lambda { parameters, body } => {
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);
}
// XXX: not tail-call optimized
interpret(&seq[seq.len() - 1], &mut new_env)
} else {
panic!("INTERPRET-APPLICATION -- no-list {:?}", lambda_body)
let mut new_env =
environment::extend(List(parameters.to_vec()), List(lambda_args), env);
for i in 0..(body.len() - 1) {
interpret(&body[i], &mut new_env);
}
interpret(&body[body.len() - 1], &mut new_env)
}
_ => panic!("INTERPRET-APPLICATION -- not-aplicable {:?}", args[0]),
}
@ -147,6 +166,7 @@ pub fn interpret(exp: &Datum, env: &mut Env) -> Datum {
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") => interpret_cond(v, env),
List(v) if has_tag(v, "lambda") => interpret_lambda(v, env),
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(),

View File

@ -12,6 +12,10 @@ pub enum Datum {
Pair(Box<(Datum, Datum)>),
List(Vec<Datum>),
Procedure(fn(Vec<Datum>) -> Datum),
Lambda {
parameters: Vec<Datum>,
body: Vec<Datum>,
},
Unspecified,
}