1use std::sync::Arc;
2
3use crate::value::Value;
4
5#[derive(Debug, Clone, Default)]
6pub struct Env {
7 inner: Arc<EnvInner>,
8}
9
10#[derive(Debug, Clone, Default)]
11struct EnvInner {
12 bindings: Vec<(String, Value)>,
13 parent: Option<Arc<EnvInner>>,
14}
15
16impl Env {
17 pub fn new() -> Self {
18 Self::default()
19 }
20
21 pub fn bind(&mut self, name: impl Into<String>, value: Value) {
22 let inner = Arc::make_mut(&mut self.inner);
23 inner.bindings.push((name.into(), value));
24 }
25
26 pub fn child(&self) -> Self {
29 Env {
30 inner: Arc::new(EnvInner {
31 bindings: Vec::new(),
32 parent: Some(Arc::clone(&self.inner)),
33 }),
34 }
35 }
36
37 pub fn lookup(&self, name: &str) -> Option<&Value> {
38 let mut inner = &self.inner;
39 loop {
40 if let Some(v) = inner
41 .bindings
42 .iter()
43 .rev()
44 .find(|(k, _)| k == name)
45 .map(|(_, v)| v)
46 {
47 return Some(v);
48 }
49 match &inner.parent {
50 Some(p) => inner = p,
51 None => return None,
52 }
53 }
54 }
55
56 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
57 let mut chain: Vec<&EnvInner> = Vec::new();
58 let mut inner = &*self.inner;
59 loop {
60 chain.push(inner);
61 match &inner.parent {
62 Some(p) => inner = p,
63 None => break,
64 }
65 }
66 chain
67 .into_iter()
68 .flat_map(|inner| inner.bindings.iter().map(|(k, v)| (k.as_str(), v)))
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn empty_env_lookup_returns_none() {
78 assert!(Env::new().lookup("x").is_none());
79 }
80
81 #[test]
82 fn bind_then_lookup_returns_value() {
83 let mut env = Env::new();
84 env.bind("x", Value::Int(1));
85 assert!(matches!(env.lookup("x"), Some(Value::Int(1))));
86 }
87
88 #[test]
89 fn later_binding_shadows_earlier() {
90 let mut env = Env::new();
91 env.bind("x", Value::Int(1));
92 env.bind("x", Value::Int(2));
93 assert!(matches!(env.lookup("x"), Some(Value::Int(2))));
94 }
95
96 #[test]
97 fn unrelated_lookup_after_shadow_still_works() {
98 let mut env = Env::new();
99 env.bind("x", Value::Int(1));
100 env.bind("y", Value::Str("hi".into()));
101 env.bind("x", Value::Int(2));
102 assert!(matches!(env.lookup("y"), Some(Value::Str(s)) if s == "hi"));
103 }
104
105 #[test]
106 fn iter_yields_declaration_order() {
107 let mut env = Env::new();
108 env.bind("a", Value::Int(1));
109 env.bind("b", Value::Int(2));
110 let names: Vec<_> = env.iter().map(|(k, _)| k).collect();
111 assert_eq!(names, vec!["a", "b"]);
112 }
113
114 #[test]
115 fn child_env_inherits_parent() {
116 let mut parent = Env::new();
117 parent.bind("x", Value::Int(42));
118 let child = parent.child();
119 assert!(matches!(child.lookup("x"), Some(Value::Int(42))));
120 }
121
122 #[test]
123 fn child_env_bind_does_not_affect_parent() {
124 let mut parent = Env::new();
125 parent.bind("x", Value::Int(1));
126 let mut child = parent.child();
127 child.bind("x", Value::Int(99));
128 assert!(matches!(parent.lookup("x"), Some(Value::Int(1))));
129 assert!(matches!(child.lookup("x"), Some(Value::Int(99))));
130 }
131
132 #[test]
133 fn clone_is_cheap() {
134 let mut env = Env::new();
135 env.bind("x", Value::Int(1));
136 let cloned = env.clone();
137 assert!(matches!(cloned.lookup("x"), Some(Value::Int(1))));
139 env.bind("y", Value::Int(2));
141 assert!(cloned.lookup("y").is_none());
142 }
143}