Skip to main content

zen_expression/
scope.rs

1use crate::variable::Variable;
2use smallvec::SmallVec;
3use zen_types::symbol::Symbol;
4
5#[derive(Debug, Clone)]
6pub struct Scope {
7    base: Variable,
8    locals: SmallVec<[(Symbol, Variable); 4]>,
9}
10
11impl Default for Scope {
12    fn default() -> Self {
13        Self::new(Variable::Null)
14    }
15}
16
17impl Scope {
18    pub fn new(base: Variable) -> Self {
19        Self {
20            base,
21            locals: SmallVec::new(),
22        }
23    }
24
25    pub fn base(&self) -> &Variable {
26        &self.base
27    }
28
29    pub fn base_mut(&mut self) -> &mut Variable {
30        &mut self.base
31    }
32
33    pub fn set_base(&mut self, base: Variable) {
34        self.base = base;
35        self.locals.clear();
36    }
37
38    pub fn locals(&self) -> &[(Symbol, Variable)] {
39        &self.locals
40    }
41
42    pub fn clear_locals(&mut self) {
43        self.locals.clear();
44    }
45
46    pub fn set_local(&mut self, name: Symbol, value: Variable) {
47        match self
48            .locals
49            .iter_mut()
50            .find(|(key, _)| key.as_str() == name.as_str())
51        {
52            Some(slot) => slot.1 = value,
53            None => self.locals.push((name, value)),
54        }
55    }
56
57    pub fn local(&self, name: &Symbol) -> Option<&Variable> {
58        self.locals
59            .iter()
60            .find(|(key, _)| key.as_str() == name.as_str())
61            .map(|(_, value)| value)
62    }
63
64    pub fn local_str(&self, name: &str) -> Option<&Variable> {
65        self.locals
66            .iter()
67            .find(|(key, _)| key.as_str() == name)
68            .map(|(_, value)| value)
69    }
70
71    pub fn get_str(&self, name: &str) -> Option<Variable> {
72        if let Some(value) = self.local_str(name) {
73            return Some(value.clone());
74        }
75
76        match &self.base {
77            Variable::Object(object) => object.borrow().get_str(name).cloned(),
78            _ => None,
79        }
80    }
81
82    pub fn get(&self, name: &Symbol) -> Option<Variable> {
83        if let Some(value) = self.local(name) {
84            return Some(value.clone());
85        }
86
87        match &self.base {
88            Variable::Object(object) => object.borrow().get(name).cloned(),
89            _ => None,
90        }
91    }
92
93    pub fn materialize(&self) -> Variable {
94        if self.locals.is_empty() {
95            return self.base.shallow_clone();
96        }
97
98        let Variable::Object(base) = &self.base else {
99            return self.base.shallow_clone();
100        };
101
102        let mut map = base.borrow().clone();
103        for (key, value) in &self.locals {
104            map.insert(key.clone(), value.clone());
105        }
106
107        Variable::from_object(map)
108    }
109}
110
111impl From<Variable> for Scope {
112    fn from(value: Variable) -> Self {
113        Scope::new(value)
114    }
115}