1use super::*;
2
3
4#[derive(Clone, Debug)]
39pub struct Scope(pub Rc<RefCell<ScopeData>>);
40
41#[derive(Clone)]
43pub struct ScopeData {
44 pub parent: Option<Scope>,
46 pub bindings: HashMap<String, Value>,
48}
49
50impl Scope {
51 pub fn new() -> Self {
53 Self(Rc::new(RefCell::new(ScopeData {
54 parent: None,
55 bindings: HashMap::new(),
56 })))
57 }
58
59 pub fn with_parent(parent: Scope) -> Self {
61 Self(Rc::new(RefCell::new(ScopeData {
62 parent: Some(parent),
63 bindings: HashMap::new(),
64 })))
65 }
66
67 pub fn new_child(&self) -> Self {
69 Self::with_parent(self.clone())
70 }
71
72 pub fn get(&self, key: &str) -> Value {
80 let (found, parent) = {
82 let inner = self.0.borrow();
83 let found = inner.bindings.get(key).cloned();
84 let parent = inner.parent.clone();
85 (found, parent)
86 };
87
88 found.unwrap_or_else(|| {
89 parent
90 .map(|p| p.get(key))
91 .unwrap_or(Value::Nothing)
92 })
93 }
94
95 pub fn lift(&self, key: &str) -> Value {
101 let mut chain = Vec::new();
103 let mut current = Some(self.clone());
104
105 while let Some(scope) = current {
106 chain.push(scope.clone());
107 let inner = scope.0.borrow();
108 current = inner.parent.clone();
109 }
110
111 for scope in chain.iter().rev() {
113 let inner = scope.0.borrow();
114 if let Some(val) = inner.bindings.get(key) {
115 return val.clone();
116 }
117 }
118
119 Value::Nothing
120 }
121
122 pub fn set(&self, key: impl Into<String>, val: Value) {
124 self.0.borrow_mut().bindings.insert(key.into(), val);
125 }
126}
127
128impl PartialEq for ScopeData {
129
130 fn eq(&self, other: &Self) -> bool {
131
132 if self.bindings != other.bindings {
134 return false;
135 }
136
137 match (&self.parent, &other.parent) {
139 (None, None) => true,
140 (Some(p1), Some(p2)) => Rc::ptr_eq(&p1.0, &p2.0), _ => false,
142 }
143 }
144}
145
146impl fmt::Debug for ScopeData {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 let mut keys: Vec<&String> = self.bindings.keys().collect();
151 keys.sort();
152 f.debug_struct("ScopeData")
153 .field("bindings", &keys)
154 .field("has_parent", &self.parent.is_some())
155 .finish()
156 }
157}
158
159impl PartialEq for Scope {
160 fn eq(&self, other: &Self) -> bool {
161 if Rc::ptr_eq(&self.0, &other.0) {
163 return true;
164 }
165
166 self.0.borrow().eq(&other.0.borrow())
168 }
169}
170
171impl Eq for Scope {}
172
173
174
175
176
177
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_scope_new_and_set_get() {
185 let scope = Scope::new();
186
187 assert_eq!(scope.get("a"), Value::Nothing);
189
190 scope.set("a", Value::Numb(42.0));
192 assert_eq!(scope.get("a"), Value::Numb(42.0));
193 }
194
195 #[test]
196 fn test_scope_with_parent() {
197 let parent = Scope::new();
198 parent.set("x", Value::Numb(10.0));
199
200 let child = Scope::with_parent(parent);
201
202 assert_eq!(child.get("x"), Value::Numb(10.0));
204
205 assert_eq!(child.get("y"), Value::Nothing);
207 }
208
209 #[test]
210 fn test_scope_new_child() {
211 let parent = Scope::new();
212 parent.set("greeting", Value::Text("hello".into()));
213
214 let child = parent.new_child();
215
216 assert_eq!(child.get("greeting"), Value::Text("hello".into()));
218
219 child.set("local_var", Value::Bool(true));
221 assert_eq!(child.get("local_var"), Value::Bool(true));
222 assert_eq!(parent.get("local_var"), Value::Nothing);
223 }
224
225 #[test]
226 fn test_scope_shadowing() {
227 let parent = Scope::new();
228 parent.set("x", Value::Numb(1.0));
229
230 let child = parent.new_child();
231 child.set("x", Value::Numb(2.0));
233
234 assert_eq!(child.get("x"), Value::Numb(2.0));
236 assert_eq!(parent.get("x"), Value::Numb(1.0));
237 }
238
239 #[test]
240 fn test_parent_mutation_visible_to_child() {
241 let scope1 = Scope::new();
242 let scope2 = scope1.new_child();
243
244 scope1.set("x", Value::Numb(10.0));
246
247 assert_eq!(scope2.get("x"), Value::Numb(10.0));
249 }
250
251 #[test]
252 fn test_deep_scope_chain() {
253 let grand_parent = Scope::new();
254 grand_parent.set("a", Value::Numb(1.0));
255
256 let parent = grand_parent.new_child();
257 parent.set("b", Value::Numb(2.0));
258
259 let child = parent.new_child();
260 child.set("c", Value::Numb(3.0));
261
262 assert_eq!(child.get("a"), Value::Numb(1.0));
264 assert_eq!(child.get("b"), Value::Numb(2.0));
265 assert_eq!(child.get("c"), Value::Numb(3.0));
266
267 assert_eq!(parent.get("c"), Value::Nothing);
269 assert_eq!(grand_parent.get("b"), Value::Nothing);
270 }
271
272 #[test]
273 fn test_scope_equality_same_instance() {
274 let scope = Scope::new();
275 scope.set("a", Value::Numb(1.0));
276
277 let clone = scope.clone();
279 assert_eq!(scope, clone);
280 }
281
282 #[test]
283 fn test_scope_equality_top_level() {
284 let scope1 = Scope::new();
285 scope1.set("a", Value::Numb(1.0));
286
287 let scope2 = Scope::new();
288 scope2.set("a", Value::Numb(1.0));
289
290 assert_eq!(scope1, scope2);
292
293 scope2.set("b", Value::Numb(2.0));
295 assert_ne!(scope1, scope2);
296 }
297
298 #[test]
299 fn test_scope_equality_shared_parent_instance() {
300 let parent = Scope::new();
301 parent.set("shared", Value::Bool(true));
302
303 let child1 = parent.new_child();
304 child1.set("x", Value::Numb(10.0));
305
306 let child2 = parent.new_child();
307 child2.set("x", Value::Numb(10.0));
308
309 assert_eq!(child1, child2);
311 }
312
313 #[test]
314 fn test_scope_equality_different_parent_instances() {
315 let parent1 = Scope::new();
317 parent1.set("shared", Value::Bool(true));
318
319 let parent2 = Scope::new();
320 parent2.set("shared", Value::Bool(true));
321
322 let child1 = parent1.new_child();
323 child1.set("x", Value::Numb(10.0));
324
325 let child2 = parent2.new_child();
326 child2.set("x", Value::Numb(10.0));
327
328 assert_ne!(child1, child2);
330 }
331
332 #[test]
333 fn test_scope_lift() {
334 let root = Scope::new();
335 root.set("x", Value::Numb(1.0));
336 root.set("y", Value::Text("root".into()));
337
338 let parent = root.new_child();
339 parent.set("x", Value::Numb(2.0));
340 parent.set("z", Value::Bool(true));
341
342 let child = parent.new_child();
343 child.set("x", Value::Numb(3.0));
344
345 assert_eq!(child.lift("x"), Value::Numb(1.0));
348 assert_eq!(child.get("x"), Value::Numb(3.0));
349
350 assert_eq!(child.lift("y"), Value::Text("root".into()));
352
353 assert_eq!(child.lift("z"), Value::Bool(true));
356
357 assert_eq!(child.lift("unbound"), Value::Nothing);
359 }
360}