use super::Value; use std::collections::HashMap; use std::rc::Rc; use std::cell::RefCell; #[derive(Debug)] pub struct Env { /// (value, is_mutable) — `is_mutable` is true for `let`, false for `const`. pub values: HashMap, pub parent: Option>>, } impl Env { pub fn new(parent: Option>>) -> Self { Self { values: HashMap::new(), parent, } } pub fn define(&mut self, name: String, val: Value, mutable: bool) { self.values.insert(name, (val, mutable)); } /// Assign a new value to an existing binding. Returns `Err(msg)` if the /// binding exists but was declared with `const` (immutable). pub fn assign(&mut self, name: &str, val: Value) -> Result { if let Some((_, false)) = self.values.get(name) { return Err(format!("Cannot reassign constant '{}'", name)); } if self.values.contains_key(name) { self.values.insert(name.to_string(), (val, true)); Ok(true) } else if let Some(parent) = &self.parent { parent.borrow_mut().assign(name, val) } else { Ok(false) } } pub fn get(&self, name: &str) -> Option { if let Some((val, _)) = self.values.get(name) { Some(val.clone()) } else if let Some(parent) = &self.parent { parent.borrow().get(name) } else { None } } }