use super::value::{LispError, Value};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub type Env = Rc<RefCell<EnvFrame>>;
pub struct EnvFrame {
bindings: HashMap<String, Value>,
parent: Option<Env>,
}
impl EnvFrame {
pub fn new() -> Env {
Rc::new(RefCell::new(EnvFrame {
bindings: HashMap::new(),
parent: None,
}))
}
pub fn child(parent: &Env) -> Env {
Rc::new(RefCell::new(EnvFrame {
bindings: HashMap::new(),
parent: Some(Rc::clone(parent)),
}))
}
pub fn lookup(&self, name: &str) -> Result<Value, LispError> {
if let Some(v) = self.bindings.get(name) {
Ok(v.clone())
} else if let Some(ref parent) = self.parent {
parent.borrow().lookup(name)
} else {
Err(LispError::new(format!("unbound variable: {}", name)))
}
}
pub fn define(&mut self, name: &str, val: Value) {
self.bindings.insert(name.to_string(), val);
}
pub fn set(&mut self, name: &str, val: Value) -> Result<(), LispError> {
if self.bindings.contains_key(name) {
self.bindings.insert(name.to_string(), val);
Ok(())
} else if let Some(ref parent) = self.parent {
parent.borrow_mut().set(name, val)
} else {
Err(LispError::new(format!("set!: unbound variable: {}", name)))
}
}
}