minilua/src/scope.rs
2025-04-11 14:51:02 +03:00

64 lines
1.2 KiB
Rust

use std::{
cell::RefCell,
collections::{hash_map::Entry, HashMap},
rc::Rc,
};
use crate::types::Value;
#[derive(Debug, Clone, Default)]
pub struct Variable(Rc<RefCell<Value>>);
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<Scope>,
locals: HashMap<String, Variable>,
}
#[derive(Debug, Clone, Default)]
pub struct Scope(Rc<RefCell<ScopeInner>>);
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()
}
}
}
}
}