schemers/src/environment.rs

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))
}