64 lines
1.2 KiB
Rust
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()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|