Rework environment mode fixes #8
This commit is contained in:
@@ -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
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -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]),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user