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, outer: Option>>, } pub type Env = Rc>; 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)) }