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}