119 lines
3.6 KiB
Rust
119 lines
3.6 KiB
Rust
use crate::parser::make_symbol;
|
|
use crate::parser::Datum;
|
|
use std::cell::RefCell;
|
|
use std::mem;
|
|
use std::rc::Rc;
|
|
|
|
type Mapping = (Datum, Datum);
|
|
|
|
#[derive(Debug)]
|
|
pub struct Frame {
|
|
mappings: Vec<Mapping>,
|
|
outer: Option<Rc<RefCell<Frame>>>,
|
|
}
|
|
|
|
pub type Env = Rc<RefCell<Frame>>;
|
|
|
|
pub fn get_global_environment() -> Env {
|
|
use crate::parser::Datum::Primitive;
|
|
use crate::primitives::*;
|
|
let f = Frame {
|
|
mappings: vec![
|
|
(make_symbol("+"), Primitive(add)),
|
|
(make_symbol("*"), Primitive(mul)),
|
|
(make_symbol("-"), Primitive(sub)),
|
|
(make_symbol("="), Primitive(eq)),
|
|
(make_symbol("<"), Primitive(lt)),
|
|
(make_symbol("or"), Primitive(or)),
|
|
(make_symbol("and"), Primitive(and)),
|
|
(make_symbol("not"), Primitive(not)),
|
|
(make_symbol("list"), Primitive(list)),
|
|
(make_symbol("cons"), Primitive(cons)),
|
|
(make_symbol("car"), Primitive(car)),
|
|
(make_symbol("cdr"), Primitive(cdr)),
|
|
(make_symbol("pair?"), Primitive(pair)),
|
|
(make_symbol("null?"), Primitive(null)),
|
|
(make_symbol("display"), Primitive(display)),
|
|
],
|
|
outer: None,
|
|
};
|
|
Rc::new(RefCell::new(f))
|
|
}
|
|
|
|
pub fn lookup_variable_value(var: &Datum, env: &Env) -> Datum {
|
|
let symbol_name = Datum::as_str(var).expect("LOOKUP-VARIABLE-VALUE -- not a symbol");
|
|
let frame = env.borrow();
|
|
|
|
for mapping in &frame.mappings {
|
|
if let (Datum::Symbol(current_name), datum) = mapping {
|
|
if symbol_name == *current_name {
|
|
return datum.clone();
|
|
}
|
|
}
|
|
}
|
|
|
|
match &frame.outer {
|
|
Some(outer_env) => lookup_variable_value(var, &outer_env),
|
|
_ => panic!("LOOKUP-VARIABLE-VALUE -- does not exist {}", var),
|
|
}
|
|
}
|
|
|
|
pub fn define_variable(var: &Datum, val: Datum, env: &mut Env) -> Datum {
|
|
let symbol_name = Datum::as_str(var).expect("DEFINE-VARIABLE -- not a symbol");
|
|
let mut frame = env.borrow_mut();
|
|
|
|
// Assign to variable if it already exits
|
|
for mapping in &mut frame.mappings {
|
|
if let (Datum::Symbol(current_name), _) = mapping {
|
|
if symbol_name == *current_name {
|
|
mapping.1 = val;
|
|
return var.clone();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create variable because it does not exist yet
|
|
let pair = (var.clone(), val);
|
|
frame.mappings.push(pair);
|
|
var.clone()
|
|
}
|
|
|
|
pub fn set_variable(var: &Datum, val: Datum, env: &Env) -> Datum {
|
|
let symbol_name = Datum::as_str(var).expect("SET-VARIABLE -- not a symbol");
|
|
let mut frame = env.borrow_mut();
|
|
for mapping in &mut frame.mappings {
|
|
if let (Datum::Symbol(current_name), _) = mapping {
|
|
if symbol_name == *current_name {
|
|
mapping.1 = val;
|
|
return var.clone();
|
|
}
|
|
}
|
|
}
|
|
|
|
match &frame.outer {
|
|
Some(outer_env) => set_variable(var, val, &outer_env),
|
|
_ => panic!("LOOKUP-VARIABLE-VALUE -- does not exist {}", var),
|
|
}
|
|
}
|
|
|
|
pub fn extend(vars: Datum, vals: Datum, env: &mut Env) -> Env {
|
|
let mut mappings = vec![];
|
|
if let (Datum::List(mut vars), Datum::List(mut vals)) = (vars, vals) {
|
|
if vars.len() != vals.len() {
|
|
panic!("EXTEND-ENVIRONMENT -- length of vars and vals does not match")
|
|
}
|
|
for i in 0..vars.len() {
|
|
let pair = (mem::take(&mut vars[i]), mem::take(&mut vals[i]));
|
|
mappings.push(pair);
|
|
}
|
|
} else {
|
|
panic!("EXTEND-ENVIRONMENT -- vars or vals not lists")
|
|
}
|
|
|
|
let f = Frame {
|
|
mappings,
|
|
outer: Some(env.clone()),
|
|
};
|
|
Rc::new(RefCell::new(f))
|
|
}
|