use std::{ cell::RefCell, collections::{hash_map::Entry, HashMap}, rc::Rc, }; use crate::types::Value; #[derive(Debug, Clone, Default)] pub struct Variable(Rc>); impl Variable { pub fn get(&self) -> Value { self.0.borrow().clone() } pub fn set(&self, value: Value) { *self.0.borrow_mut() = value; } } #[derive(Debug, Clone, Default)] struct ScopeInner { parent: Option, locals: HashMap, } #[derive(Debug, Clone, Default)] pub struct Scope(Rc>); impl Scope { pub fn new() -> Self { Self::default() } pub fn nested(&self) -> Self { Self(Rc::new(RefCell::new(ScopeInner { parent: Some(self.clone()), ..Default::default() }))) } pub fn add(&self, name: String) { self.0.borrow_mut().locals.insert(name, Variable::default()); } pub fn get(&self, name: String) -> Variable { let mut this = self.0.borrow_mut(); let parent = this.parent.clone(); match this.locals.entry(name) { Entry::Occupied(var) => var.get().clone(), Entry::Vacant(var) => { if let Some(parent) = parent { let name = var.into_key(); drop(this); parent.get(name) } else { var.insert(Variable::default()).clone() } } } } }