1use crate::{
12 ast::statements::TypeAnnotation,
13 interpreter::{
14 evaluator::{EnvironmentItem, Evaluator, PItem},
15 values::Value,
16 },
17 utils::{errors::Error, span::Span},
18};
19
20impl Evaluator {
21 pub fn push_scope(&mut self) {
23 let frame = self.scope_pool.pop().unwrap_or_default();
24 self.environment.push(frame);
25 }
26
27 pub fn pop_scope(&mut self) {
29 if let Some(mut frame) = self.environment.pop() {
30 frame.clear();
31 self.scope_pool.push(frame);
32 }
33 }
34
35 fn ensure_slot(frame: &mut Vec<EnvironmentItem>, slot: usize, item: EnvironmentItem) {
36 match slot.cmp(&frame.len()) {
37 std::cmp::Ordering::Less => frame[slot] = item,
38 std::cmp::Ordering::Equal => frame.push(item),
39 std::cmp::Ordering::Greater => {
40 frame.resize_with(slot, || {
41 EnvironmentItem::PItem(PItem {
42 value: Value::Null,
43 type_annotation: TypeAnnotation::Null,
44 is_const: false,
45 })
46 });
47 frame.push(item);
48 }
49 }
50 }
51
52 pub fn get_value(&self, depth: usize, slot: usize, span: Span) -> Result<Value, Error> {
57 if depth >= self.environment.len() {
58 return match self.globals.get(slot) {
59 Some(EnvironmentItem::PItem(p)) => Ok(p.value.clone()),
60 None => Err(self.err(format!("undefined variable at ({}, {})", depth, slot), span)),
61 };
62 }
63 let idx = self.environment.len() - 1 - depth;
64 match self.environment.get(idx).and_then(|f| f.get(slot)) {
65 Some(EnvironmentItem::PItem(p)) => Ok(p.value.clone()),
66 None => Err(self.err(format!("undefined variable at ({}, {})", depth, slot), span)),
67 }
68 }
69
70 pub fn insert_value(
74 &mut self,
75 slot: usize,
76 value: Value,
77 type_annotation: TypeAnnotation,
78 _: Span,
79 ) -> Result<(), Error> {
80 if self.environment.is_empty() {
81 Self::ensure_slot(
82 &mut self.globals,
83 slot,
84 EnvironmentItem::PItem(PItem {
85 value,
86 type_annotation,
87 is_const: false,
88 }),
89 );
90 return Ok(());
91 }
92
93 let frame = self
94 .environment
95 .last_mut()
96 .expect("checked non-empty above");
97
98 Self::ensure_slot(
99 frame,
100 slot,
101 EnvironmentItem::PItem(PItem {
102 value,
103 type_annotation,
104 is_const: false,
105 }),
106 );
107 Ok(())
108 }
109
110 pub fn insert_global(&mut self, slot: usize, value: Value, type_annotation: TypeAnnotation) {
115 Self::ensure_slot(
116 &mut self.globals,
117 slot,
118 EnvironmentItem::PItem(PItem {
119 value,
120 type_annotation,
121 is_const: false,
122 }),
123 );
124 }
125
126 pub fn insert_const(
130 &mut self,
131 slot: usize,
132 value: Value,
133 type_annotation: TypeAnnotation,
134 span: Span,
135 ) -> Result<(), Error> {
136 if self.environment.is_empty() {
137 Self::ensure_slot(
138 &mut self.globals,
139 slot,
140 EnvironmentItem::PItem(PItem {
141 value,
142 type_annotation,
143 is_const: true,
144 }),
145 );
146 return Ok(());
147 }
148
149 if let Some(EnvironmentItem::PItem(p)) = self.environment.last().and_then(|f| f.get(slot))
150 && p.is_const
151 {
152 return Err(self.err(format!("slot {} is already a constant", slot), span));
153 }
154
155 let frame = self
156 .environment
157 .last_mut()
158 .expect("checked non-empty above");
159
160 Self::ensure_slot(
161 frame,
162 slot,
163 EnvironmentItem::PItem(PItem {
164 value,
165 type_annotation,
166 is_const: true,
167 }),
168 );
169 Ok(())
170 }
171
172 pub fn insert_const_global(
177 &mut self,
178 slot: usize,
179 value: Value,
180 type_annotation: TypeAnnotation,
181 span: Span,
182 ) -> Result<(), Error> {
183 if let Some(EnvironmentItem::PItem(p)) = self.globals.get(slot)
184 && p.is_const
185 {
186 return Err(self.err(format!("slot {} is already a constant", slot), span));
187 }
188 Self::ensure_slot(
189 &mut self.globals,
190 slot,
191 EnvironmentItem::PItem(PItem {
192 value,
193 type_annotation,
194 is_const: true,
195 }),
196 );
197 Ok(())
198 }
199
200 pub fn assign_value(
204 &mut self,
205 depth: usize,
206 slot: usize,
207 value: Value,
208 value_type: TypeAnnotation,
209 span: Span,
210 ) -> Result<(), Error> {
211 if depth >= self.environment.len() {
212 if self.globals.get(slot).is_none() {
213 return Err(self.err(format!("undefined slot {} at depth {}", slot, depth), span));
214 }
215 let entry = &mut self.globals[slot];
216 return match entry {
217 EnvironmentItem::PItem(p) => {
218 if p.is_const {
219 return Err(self.err("cannot assign to constant", span));
220 }
221 let declared = p.type_annotation.clone();
222 let types_match = matches!(value, Value::Null)
223 || match (&declared, &value_type) {
224 (TypeAnnotation::Array(_), TypeAnnotation::Array(inner))
225 if **inner == TypeAnnotation::Null =>
226 {
227 true
228 }
229 (TypeAnnotation::Array(a), TypeAnnotation::Array(_))
230 if **a == TypeAnnotation::Null =>
231 {
232 true
233 }
234 _ => Evaluator::types_compatible(&value_type, &declared),
235 };
236 if !types_match {
237 return Err(self.err(
238 format!(
239 "type mismatch: cannot assign {:?} to {:?}",
240 value_type, declared
241 ),
242 span,
243 ));
244 }
245 p.value = value;
246 Ok(())
247 }
248 };
249 }
250
251 let idx = self.environment.len() - 1 - depth;
252 if slot >= self.environment[idx].len() {
253 return Err(self.err(format!("undefined slot {} at depth {}", slot, depth), span));
254 }
255 let entry = &mut self.environment[idx][slot];
256 match entry {
257 EnvironmentItem::PItem(p) => {
258 if p.is_const {
259 return Err(self.err("cannot assign to constant", span));
260 }
261 let declared = p.type_annotation.clone();
262 let types_match = matches!(value, Value::Null)
263 || match (&declared, &value_type) {
264 (TypeAnnotation::Array(_), TypeAnnotation::Array(inner))
265 if **inner == TypeAnnotation::Null =>
266 {
267 true
268 }
269 (TypeAnnotation::Array(a), TypeAnnotation::Array(_))
270 if **a == TypeAnnotation::Null =>
271 {
272 true
273 }
274 _ => Evaluator::types_compatible(&value_type, &declared),
275 };
276 if !types_match {
277 return Err(self.err(
278 format!(
279 "type mismatch: cannot assign {:?} to {:?}",
280 value_type, declared
281 ),
282 span,
283 ));
284 }
285 p.value = value;
286 Ok(())
287 }
288 }
289 }
290
291 pub fn get_value_raw(&self, name: &str) -> Option<Value> {
293 let (depth, slot) = self.resolver.resolve_name(name)?;
294 if depth >= self.environment.len() {
295 return match self.globals.get(slot)? {
296 crate::interpreter::evaluator::EnvironmentItem::PItem(p) => Some(p.value.clone()),
297 };
298 }
299 let idx = self.environment.len() - 1 - depth;
300 match self.environment.get(idx)?.get(slot)? {
301 crate::interpreter::evaluator::EnvironmentItem::PItem(p) => Some(p.value.clone()),
302 }
303 }
304
305 pub fn get_declared_type(&self, depth: usize, slot: usize) -> Option<TypeAnnotation> {
307 if depth >= self.environment.len() {
308 return match self.globals.get(slot)? {
309 EnvironmentItem::PItem(p) => Some(p.type_annotation.clone()),
310 };
311 }
312 let idx = self.environment.len() - 1 - depth;
313 match self.environment.get(idx)?.get(slot)? {
314 EnvironmentItem::PItem(p) => Some(p.type_annotation.clone()),
315 }
316 }
317}