Rework environment mode fixes #8

This commit is contained in:
2021-05-30 11:57:59 -04:00
parent 3ae5ccb64c
commit e070441c31
3 changed files with 53 additions and 51 deletions

View File

@@ -4,81 +4,84 @@ use crate::primitives;
use std::mem; use std::mem;
type Mapping = (Datum, Datum); type Mapping = (Datum, Datum);
type Frame = Vec<Mapping>;
pub type Env = Vec<Frame>;
pub fn get_global_environment() -> Env { pub struct Frame<'a> {
vec![vec![ mappings: Vec<Mapping>,
(make_symbol("+"), Datum::Procedure(primitives::add)), outer: Option<&'a Frame<'a>>,
(make_symbol("*"), Datum::Procedure(primitives::mul)), }
(make_symbol("-"), Datum::Procedure(primitives::sub)),
(make_symbol("="), Datum::Procedure(primitives::eq)), pub type Env<'a> = Frame<'a>;
]]
pub fn get_global_environment<'a>() -> Env<'a> {
Frame {
mappings: vec![
(make_symbol("+"), Datum::Procedure(primitives::add)),
(make_symbol("*"), Datum::Procedure(primitives::mul)),
(make_symbol("-"), Datum::Procedure(primitives::sub)),
(make_symbol("="), Datum::Procedure(primitives::eq)),
],
outer: None,
}
} }
pub fn lookup_variable_value(var: &Datum, env: &Env) -> Datum { pub fn lookup_variable_value(var: &Datum, env: &Env) -> Datum {
if let Datum::Symbol(symbol_name) = var { if let Datum::Symbol(symbol_name) = var {
for i in (0..env.len()).rev() { for mapping in &env.mappings {
let frame = &env[i]; if let (Datum::Symbol(current_name), datum) = mapping {
for mapping in frame { if symbol_name == current_name {
if let (Datum::Symbol(current_name), datum) = mapping { return datum.clone();
if symbol_name == current_name {
return datum.clone();
}
} }
} }
} }
match env.outer {
Some(outer_env) => lookup_variable_value(var, outer_env),
None => panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable-error {:?}", var),
}
} else { } else {
panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", var) panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", var)
} }
panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable-error {:?}", var)
} }
pub fn define_variable(var: &Datum, val: Datum, env: &mut Env) -> Datum { pub fn define_variable(var: &Datum, val: Datum, env: &mut Env) -> Datum {
if let Datum::Symbol(symbol_name) = var { if let Datum::Symbol(symbol_name) = var {
// Assign to variable if it already exits // Assign to variable if it already exits
if let Some(frame) = env.last_mut() { for mapping in &mut env.mappings {
for mapping in frame { if let (Datum::Symbol(current_name), _) = mapping {
if let (Datum::Symbol(current_name), _) = mapping { if symbol_name == current_name {
if symbol_name == current_name { mapping.1 = val;
mapping.1 = val; return var.clone();
return Datum::Unspecified;
}
} }
} }
} else {
panic!("DEFINE-VARIABLE -- no-frames {:?}", env)
} }
// Create variable because it does not exist yet // Create variable because it does not exist yet
if let Some(frame) = env.last_mut() { let pair = (var.clone(), val);
let pair = (var.clone(), val); env.mappings.push(pair);
frame.push(pair);
}
} else { } else {
panic!("DEFINE-VARIABLE -- not-a-symbol {:?}", var) panic!("DEFINE-VARIABLE -- not-a-symbol {:?}", var)
} }
Datum::Unspecified var.clone()
} }
pub fn extend_environment(vars: Datum, vals: Datum, env: &mut Env) -> Datum { pub fn extend<'a>(vars: Datum, vals: Datum, env: &'a Env) -> Env<'a> {
let mut mappings = vec![];
if let (Datum::List(mut vars), Datum::List(mut vals)) = (vars, vals) { if let (Datum::List(mut vars), Datum::List(mut vals)) = (vars, vals) {
if vars.len() != vals.len() { if vars.len() != vals.len() {
panic!("EXTEND-ENVIRONMENT -- length of vars and vals does not match") panic!("EXTEND-ENVIRONMENT -- length of vars and vals does not match")
} }
let mut frame = vec![];
for i in 0..vars.len() { for i in 0..vars.len() {
let pair = (mem::take(&mut vars[i]), mem::take(&mut vals[i])); let pair = (mem::take(&mut vars[i]), mem::take(&mut vals[i]));
frame.push(pair); mappings.push(pair);
} }
env.push(frame);
} else { } else {
panic!("EXTEND-ENVIRONMENT -- vars or vals not lists") panic!("EXTEND-ENVIRONMENT -- vars or vals not lists")
} }
Datum::Unspecified Frame {
mappings: mappings,
outer: Some(env),
}
} }
pub fn shrink_environment(env: &mut Env) -> Datum { // pub fn shrink_environment(env: &mut Env) -> Datum {
env.pop(); // env.pop();
Datum::Unspecified // Datum::Unspecified
} // }

View File

@@ -96,16 +96,15 @@ fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
let lambda_body = &v[2]; let lambda_body = &v[2];
let lambda_args = args[1..].to_vec(); let lambda_args = args[1..].to_vec();
// FIXME: this does not optimize tail-calls let mut new_env = environment::extend(lambda_parameters, List(lambda_args), env);
environment::extend_environment(lambda_parameters, List(lambda_args), env);
let mut r = Datum::Unspecified;
if let List(seq) = lambda_body { if let List(seq) = lambda_body {
for i in 0..seq.len() { for i in 0..(seq.len() - 1) {
r = interpret(&seq[i], env); interpret(&seq[i], &mut new_env);
} }
interpret(&seq[seq.len() - 1], &mut new_env)
} else {
panic!("INTERPRET-APPLICATION -- no-list {:?}", lambda_body)
} }
environment::shrink_environment(env);
r
} }
_ => panic!("INTERPRET-APPLICATION -- not-aplicable {:?}", args[0]), _ => panic!("INTERPRET-APPLICATION -- not-aplicable {:?}", args[0]),
} }

View File

@@ -4,11 +4,11 @@ mod lexer;
mod parser; mod parser;
mod primitives; mod primitives;
use std::path::Path;
use std::fs;
use std::env; use std::env;
use std::fs;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::path::Path;
fn repl() { fn repl() {
let mut env = environment::get_global_environment(); let mut env = environment::get_global_environment();
@@ -44,7 +44,7 @@ fn interpret_file(filename: &Path) {
let mut env = environment::get_global_environment(); let mut env = environment::get_global_environment();
let result = interpreter::interpret(&datum, &mut env); let result = interpreter::interpret(&datum, &mut env);
println!("{:?}", result); println!("{:?}", result);
}, }
Err(error) => println!("error: {} {:?}", error, filename), Err(error) => println!("error: {} {:?}", error, filename),
} }
} }