reifydb_engine/vm/
stack.rs1use arrow_array::RecordBatch;
5use reifydb_core::internal;
6use reifydb_evaluate::stack::Variable;
7use reifydb_value::{error, reifydb_assertions};
8
9use crate::Result;
10
11#[derive(Debug, Clone)]
12pub struct Stack {
13 variables: Vec<Variable>,
14}
15
16impl Stack {
17 pub fn new() -> Self {
18 Self {
19 variables: Vec::new(),
20 }
21 }
22
23 pub fn push(&mut self, value: Variable) {
24 reifydb_assertions! {
25 match &value {
26 Variable::Columns {
27 batch,
28 }
29 | Variable::ForIterator {
30 batch,
31 ..
32 } => reifydb_value::value::canonical::assert_canonical_floats(batch, "stack push"),
33 Variable::Closure(_) => {}
34 }
35 }
36 self.variables.push(value);
37 }
38
39 pub fn pop(&mut self) -> Result<Variable> {
40 self.variables.pop().ok_or_else(|| error!(internal!("VM data stack underflow")))
41 }
42
43 pub fn peek(&self) -> Option<&Variable> {
44 self.variables.last()
45 }
46
47 pub fn is_empty(&self) -> bool {
48 self.variables.is_empty()
49 }
50
51 pub fn len(&self) -> usize {
52 self.variables.len()
53 }
54}
55
56impl Default for Stack {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62#[derive(Debug, Clone)]
63pub enum ControlFlow {
64 Normal,
65 Break,
66 Continue,
67 Return(Option<RecordBatch>),
68}
69
70impl ControlFlow {
71 pub fn is_normal(&self) -> bool {
72 matches!(self, ControlFlow::Normal)
73 }
74}
75
76#[cfg(all(test, reifydb_assertions))]
77mod tests {
78 use std::sync::Arc;
79
80 use arrow_array::{ArrayRef, Float64Array, RecordBatch};
81 use reifydb_evaluate::stack::Variable;
82
83 use super::Stack;
84
85 fn negative_zero_batch() -> RecordBatch {
86 let column: ArrayRef = Arc::new(Float64Array::from(vec![-0.0f64]));
87 RecordBatch::try_from_iter([("c", column)]).unwrap()
88 }
89
90 #[test]
91 #[cfg(reifydb_assertions)]
92 #[should_panic(expected = "is not canonical")]
93 fn test_push_columns_with_negative_zero_panics() {
94 Stack::new().push(Variable::Columns {
95 batch: negative_zero_batch(),
96 });
97 }
98
99 #[test]
100 #[cfg(reifydb_assertions)]
101 #[should_panic(expected = "is not canonical")]
102 fn test_push_for_iterator_with_negative_zero_panics() {
103 Stack::new().push(Variable::ForIterator {
104 batch: negative_zero_batch(),
105 index: 0,
106 });
107 }
108}