1use std::{collections::HashMap, sync::Arc};
5
6use reifydb_core::{internal, value::column::columns::Columns};
7use reifydb_rql::instruction::{CompiledClosure, CompiledFunction, ScopeType};
8use reifydb_type::{error, value::Value};
9
10use crate::{Result, error::EngineError};
11
12#[derive(Debug, Clone)]
14pub struct Stack {
15 variables: Vec<Variable>,
16}
17
18impl Stack {
19 pub fn new() -> Self {
20 Self {
21 variables: Vec::new(),
22 }
23 }
24
25 pub fn push(&mut self, value: Variable) {
26 self.variables.push(value);
27 }
28
29 pub fn pop(&mut self) -> Result<Variable> {
30 self.variables.pop().ok_or_else(|| error!(internal!("VM data stack underflow")))
31 }
32
33 pub fn peek(&self) -> Option<&Variable> {
34 self.variables.last()
35 }
36
37 pub fn is_empty(&self) -> bool {
38 self.variables.is_empty()
39 }
40
41 pub fn len(&self) -> usize {
42 self.variables.len()
43 }
44}
45
46impl Default for Stack {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52#[derive(Debug, Clone)]
54pub struct ClosureValue {
55 pub def: CompiledClosure,
56 pub captured: HashMap<String, Variable>,
57}
58
59#[derive(Debug, Clone)]
61pub enum Variable {
62 Scalar(Columns),
64 Columns(Columns),
66 ForIterator {
68 columns: Columns,
69 index: usize,
70 },
71 Closure(ClosureValue),
73}
74
75impl Variable {
76 pub fn scalar(value: Value) -> Self {
78 Variable::Scalar(Columns::scalar(value))
79 }
80
81 pub fn columns(columns: Columns) -> Self {
83 Variable::Columns(columns)
84 }
85}
86
87#[derive(Debug, Clone)]
89pub struct SymbolTable {
90 inner: Arc<SymbolTableInner>,
91}
92
93#[derive(Debug, Clone)]
94struct SymbolTableInner {
95 scopes: Vec<Scope>,
96 functions: HashMap<String, CompiledFunction>,
98}
99
100#[derive(Debug, Clone)]
102struct Scope {
103 variables: HashMap<String, VariableBinding>,
104 scope_type: ScopeType,
105}
106
107#[derive(Debug, Clone)]
109pub enum ControlFlow {
110 Normal,
111 Break,
112 Continue,
113 Return(Option<Columns>),
114}
115
116impl ControlFlow {
117 pub fn is_normal(&self) -> bool {
118 matches!(self, ControlFlow::Normal)
119 }
120}
121
122#[derive(Debug, Clone)]
124struct VariableBinding {
125 variable: Variable,
126 mutable: bool,
127}
128
129impl SymbolTable {
130 pub fn new() -> Self {
132 let global_scope = Scope {
133 variables: HashMap::new(),
134 scope_type: ScopeType::Global,
135 };
136
137 Self {
138 inner: Arc::new(SymbolTableInner {
139 scopes: vec![global_scope],
140 functions: HashMap::new(),
141 }),
142 }
143 }
144
145 pub fn enter_scope(&mut self, scope_type: ScopeType) {
147 let new_scope = Scope {
148 variables: HashMap::new(),
149 scope_type,
150 };
151 Arc::make_mut(&mut self.inner).scopes.push(new_scope);
152 }
153
154 pub fn exit_scope(&mut self) -> Result<()> {
157 if self.inner.scopes.len() <= 1 {
158 return Err(error!(internal!("Cannot exit global scope")));
159 }
160 Arc::make_mut(&mut self.inner).scopes.pop();
161 Ok(())
162 }
163
164 pub fn scope_depth(&self) -> usize {
166 self.inner.scopes.len() - 1
167 }
168
169 pub fn current_scope_type(&self) -> &ScopeType {
171 &self.inner.scopes.last().unwrap().scope_type
172 }
173
174 pub fn set(&mut self, name: String, variable: Variable, mutable: bool) -> Result<()> {
176 self.set_in_current_scope(name, variable, mutable)
177 }
178
179 pub fn reassign(&mut self, name: String, variable: Variable) -> Result<()> {
182 let inner = Arc::make_mut(&mut self.inner);
183 for scope in inner.scopes.iter_mut().rev() {
185 if let Some(existing) = scope.variables.get(&name) {
186 if !existing.mutable {
187 return Err(EngineError::VariableIsImmutable {
188 name: name.clone(),
189 }
190 .into());
191 }
192 let mutable = existing.mutable;
193 scope.variables.insert(
194 name,
195 VariableBinding {
196 variable,
197 mutable,
198 },
199 );
200 return Ok(());
201 }
202 }
203
204 Err(EngineError::VariableNotFound {
205 name: name.clone(),
206 }
207 .into())
208 }
209
210 pub fn set_in_current_scope(&mut self, name: String, variable: Variable, mutable: bool) -> Result<()> {
213 let inner = Arc::make_mut(&mut self.inner);
214 let current_scope = inner.scopes.last_mut().unwrap();
215
216 current_scope.variables.insert(
218 name,
219 VariableBinding {
220 variable,
221 mutable,
222 },
223 );
224 Ok(())
225 }
226
227 pub fn get(&self, name: &str) -> Option<&Variable> {
229 for scope in self.inner.scopes.iter().rev() {
231 if let Some(binding) = scope.variables.get(name) {
232 return Some(&binding.variable);
233 }
234 }
235 None
236 }
237
238 pub fn get_with_scope(&self, name: &str) -> Option<(&Variable, usize)> {
240 for (depth_from_end, scope) in self.inner.scopes.iter().rev().enumerate() {
242 if let Some(binding) = scope.variables.get(name) {
243 let scope_depth = self.inner.scopes.len() - 1 - depth_from_end;
244 return Some((&binding.variable, scope_depth));
245 }
246 }
247 None
248 }
249
250 pub fn exists_in_current_scope(&self, name: &str) -> bool {
252 self.inner.scopes.last().unwrap().variables.contains_key(name)
253 }
254
255 pub fn exists_in_any_scope(&self, name: &str) -> bool {
257 self.get(name).is_some()
258 }
259
260 pub fn is_mutable(&self, name: &str) -> bool {
262 for scope in self.inner.scopes.iter().rev() {
263 if let Some(binding) = scope.variables.get(name) {
264 return binding.mutable;
265 }
266 }
267 false
268 }
269
270 pub fn all_variable_names(&self) -> Vec<String> {
272 let mut names = Vec::new();
273 for (scope_idx, scope) in self.inner.scopes.iter().enumerate() {
274 for name in scope.variables.keys() {
275 names.push(format!("{}@scope{}", name, scope_idx));
276 }
277 }
278 names
279 }
280
281 pub fn visible_variable_names(&self) -> Vec<String> {
283 let mut visible = HashMap::new();
284
285 for scope in &self.inner.scopes {
287 for name in scope.variables.keys() {
288 visible.insert(name.clone(), ());
289 }
290 }
291
292 visible.keys().cloned().collect()
293 }
294
295 pub fn clear(&mut self) {
297 let inner = Arc::make_mut(&mut self.inner);
298 inner.scopes.clear();
299 inner.scopes.push(Scope {
300 variables: HashMap::new(),
301 scope_type: ScopeType::Global,
302 });
303 inner.functions.clear();
304 }
305
306 pub fn define_function(&mut self, name: String, func: CompiledFunction) {
308 Arc::make_mut(&mut self.inner).functions.insert(name, func);
309 }
310
311 pub fn get_function(&self, name: &str) -> Option<&CompiledFunction> {
313 self.inner.functions.get(name)
314 }
315
316 pub fn function_exists(&self, name: &str) -> bool {
318 self.inner.functions.contains_key(name)
319 }
320}
321
322impl Default for SymbolTable {
323 fn default() -> Self {
324 Self::new()
325 }
326}
327
328#[cfg(test)]
329pub mod tests {
330 use reifydb_core::value::column::{Column, data::ColumnData};
331 use reifydb_type::value::{Value, r#type::Type};
332
333 use super::*;
334
335 fn create_test_columns(values: Vec<Value>) -> Columns {
337 if values.is_empty() {
338 let column_data = ColumnData::none_typed(Type::Boolean, 0);
339 let column = Column::new("test_col", column_data);
340 return Columns::new(vec![column]);
341 }
342
343 let mut column_data = ColumnData::none_typed(Type::Boolean, 0);
344 for value in values {
345 column_data.push_value(value);
346 }
347
348 let column = Column::new("test_col", column_data);
349 Columns::new(vec![column])
350 }
351
352 #[test]
353 fn test_basic_variable_operations() {
354 let mut ctx = SymbolTable::new();
355 let cols = create_test_columns(vec![Value::utf8("Alice".to_string())]);
356
357 ctx.set("name".to_string(), Variable::columns(cols.clone()), false).unwrap();
359
360 assert!(ctx.get("name").is_some());
362 assert!(!ctx.is_mutable("name"));
363 assert!(ctx.exists_in_any_scope("name"));
364 assert!(ctx.exists_in_current_scope("name"));
365 }
366
367 #[test]
368 fn test_mutable_variable() {
369 let mut ctx = SymbolTable::new();
370 let cols1 = create_test_columns(vec![Value::Int4(42)]);
371 let cols2 = create_test_columns(vec![Value::Int4(84)]);
372
373 ctx.set("counter".to_string(), Variable::columns(cols1.clone()), true).unwrap();
375 assert!(ctx.is_mutable("counter"));
376 assert!(ctx.get("counter").is_some());
377
378 ctx.set("counter".to_string(), Variable::columns(cols2.clone()), true).unwrap();
380 assert!(ctx.get("counter").is_some());
381 }
382
383 #[test]
384 #[ignore]
385 fn test_immutable_variable_reassignment_fails() {
386 let mut ctx = SymbolTable::new();
387 let cols1 = create_test_columns(vec![Value::utf8("Alice".to_string())]);
388 let cols2 = create_test_columns(vec![Value::utf8("Bob".to_string())]);
389
390 ctx.set("name".to_string(), Variable::columns(cols1.clone()), false).unwrap();
392
393 let result = ctx.set("name".to_string(), Variable::columns(cols2), false);
395 assert!(result.is_err());
396
397 assert!(ctx.get("name").is_some());
399 }
400
401 #[test]
402 fn test_scope_management() {
403 let mut ctx = SymbolTable::new();
404
405 assert_eq!(ctx.scope_depth(), 0);
407 assert_eq!(ctx.current_scope_type(), &ScopeType::Global);
408
409 ctx.enter_scope(ScopeType::Function);
411 assert_eq!(ctx.scope_depth(), 1);
412 assert_eq!(ctx.current_scope_type(), &ScopeType::Function);
413
414 ctx.enter_scope(ScopeType::Block);
416 assert_eq!(ctx.scope_depth(), 2);
417 assert_eq!(ctx.current_scope_type(), &ScopeType::Block);
418
419 ctx.exit_scope().unwrap();
421 assert_eq!(ctx.scope_depth(), 1);
422 assert_eq!(ctx.current_scope_type(), &ScopeType::Function);
423
424 ctx.exit_scope().unwrap();
426 assert_eq!(ctx.scope_depth(), 0);
427 assert_eq!(ctx.current_scope_type(), &ScopeType::Global);
428
429 assert!(ctx.exit_scope().is_err());
431 }
432
433 #[test]
434 fn test_variable_shadowing() {
435 let mut ctx = SymbolTable::new();
436 let outer_cols = create_test_columns(vec![Value::utf8("outer".to_string())]);
437 let inner_cols = create_test_columns(vec![Value::utf8("inner".to_string())]);
438
439 ctx.set("var".to_string(), Variable::columns(outer_cols.clone()), false).unwrap();
441 assert!(ctx.get("var").is_some());
442
443 ctx.enter_scope(ScopeType::Block);
445 ctx.set("var".to_string(), Variable::columns(inner_cols.clone()), false).unwrap();
446
447 assert!(ctx.get("var").is_some());
449 assert!(ctx.exists_in_current_scope("var"));
450
451 ctx.exit_scope().unwrap();
453 assert!(ctx.get("var").is_some());
454 }
455
456 #[test]
457 fn test_parent_scope_access() {
458 let mut ctx = SymbolTable::new();
459 let outer_cols = create_test_columns(vec![Value::utf8("outer".to_string())]);
460
461 ctx.set("global_var".to_string(), Variable::columns(outer_cols.clone()), false).unwrap();
463
464 ctx.enter_scope(ScopeType::Function);
466
467 assert!(ctx.get("global_var").is_some());
469 assert!(!ctx.exists_in_current_scope("global_var"));
470 assert!(ctx.exists_in_any_scope("global_var"));
471
472 let (_, scope_depth) = ctx.get_with_scope("global_var").unwrap();
474 assert_eq!(scope_depth, 0); }
476
477 #[test]
478 fn test_scope_specific_mutability() {
479 let mut ctx = SymbolTable::new();
480 let cols1 = create_test_columns(vec![Value::utf8("value1".to_string())]);
481 let cols2 = create_test_columns(vec![Value::utf8("value2".to_string())]);
482
483 ctx.set("var".to_string(), Variable::columns(cols1.clone()), false).unwrap();
485
486 ctx.enter_scope(ScopeType::Block);
488 ctx.set("var".to_string(), Variable::columns(cols2.clone()), true).unwrap(); assert!(ctx.is_mutable("var"));
492
493 ctx.exit_scope().unwrap();
495 assert!(!ctx.is_mutable("var"));
496 }
497
498 #[test]
499 fn test_visible_variable_names() {
500 let mut ctx = SymbolTable::new();
501 let cols = create_test_columns(vec![Value::utf8("test".to_string())]);
502
503 ctx.set("global1".to_string(), Variable::columns(cols.clone()), false).unwrap();
505 ctx.set("global2".to_string(), Variable::columns(cols.clone()), false).unwrap();
506
507 let global_visible = ctx.visible_variable_names();
508 assert_eq!(global_visible.len(), 2);
509 assert!(global_visible.contains(&"global1".to_string()));
510 assert!(global_visible.contains(&"global2".to_string()));
511
512 ctx.enter_scope(ScopeType::Function);
514 ctx.set("local1".to_string(), Variable::columns(cols.clone()), false).unwrap();
515 ctx.set("global1".to_string(), Variable::columns(cols.clone()), false).unwrap(); let function_visible = ctx.visible_variable_names();
518 assert_eq!(function_visible.len(), 3); assert!(function_visible.contains(&"global1".to_string()));
520 assert!(function_visible.contains(&"global2".to_string()));
521 assert!(function_visible.contains(&"local1".to_string()));
522 }
523
524 #[test]
525 fn test_clear_resets_to_global() {
526 let mut ctx = SymbolTable::new();
527 let cols = create_test_columns(vec![Value::utf8("test".to_string())]);
528
529 ctx.set("var1".to_string(), Variable::columns(cols.clone()), false).unwrap();
531 ctx.enter_scope(ScopeType::Function);
532 ctx.set("var2".to_string(), Variable::columns(cols.clone()), false).unwrap();
533 ctx.enter_scope(ScopeType::Block);
534 ctx.set("var3".to_string(), Variable::columns(cols.clone()), false).unwrap();
535
536 assert_eq!(ctx.scope_depth(), 2);
537 assert_eq!(ctx.visible_variable_names().len(), 3);
538
539 ctx.clear();
541 assert_eq!(ctx.scope_depth(), 0);
542 assert_eq!(ctx.current_scope_type(), &ScopeType::Global);
543 assert_eq!(ctx.visible_variable_names().len(), 0);
544 }
545
546 #[test]
547 fn test_nonexistent_variable() {
548 let ctx = SymbolTable::new();
549
550 assert!(ctx.get("nonexistent").is_none());
551 assert!(!ctx.exists_in_any_scope("nonexistent"));
552 assert!(!ctx.exists_in_current_scope("nonexistent"));
553 assert!(!ctx.is_mutable("nonexistent"));
554 assert!(ctx.get_with_scope("nonexistent").is_none());
555 }
556}