zen_expression/vm/
vm.rs

1use crate::compiler::{Compare, FetchFastTarget, Jump, Opcode};
2use crate::functions::arguments::Arguments;
3use crate::functions::registry::FunctionRegistry;
4use crate::functions::{internal, MethodRegistry};
5use crate::variable::Variable;
6use crate::variable::Variable::*;
7use crate::vm::date::DynamicVariableExt;
8use crate::vm::error::VMError::*;
9use crate::vm::error::VMResult;
10use crate::vm::interval::{VmInterval, VmIntervalData};
11use ahash::{HashMap, HashMapExt};
12use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
13use rust_decimal::{Decimal, MathematicalOps};
14use std::rc::Rc;
15use std::string::String as StdString;
16
17#[derive(Debug)]
18pub struct Scope {
19    array: Variable,
20    len: usize,
21    iter: usize,
22    count: usize,
23}
24
25#[derive(Debug)]
26pub struct VM {
27    scopes: Vec<Scope>,
28    stack: Vec<Variable>,
29}
30
31impl VM {
32    pub fn new() -> Self {
33        Self {
34            scopes: Default::default(),
35            stack: Default::default(),
36        }
37    }
38
39    pub fn run(&mut self, bytecode: &[Opcode], env: Variable) -> VMResult<Variable> {
40        self.stack.clear();
41        self.scopes.clear();
42
43        let s = VMInner::new(bytecode, &mut self.stack, &mut self.scopes).run(env);
44        Ok(s?)
45    }
46}
47
48struct VMInner<'parent_ref, 'bytecode_ref> {
49    scopes: &'parent_ref mut Vec<Scope>,
50    stack: &'parent_ref mut Vec<Variable>,
51    bytecode: &'bytecode_ref [Opcode],
52    ip: u32,
53}
54
55impl<'arena, 'parent_ref, 'bytecode_ref> VMInner<'parent_ref, 'bytecode_ref> {
56    pub fn new(
57        bytecode: &'bytecode_ref [Opcode],
58        stack: &'parent_ref mut Vec<Variable>,
59        scopes: &'parent_ref mut Vec<Scope>,
60    ) -> Self {
61        Self {
62            ip: 0,
63            scopes,
64            stack,
65            bytecode,
66        }
67    }
68
69    fn push(&mut self, var: Variable) {
70        self.stack.push(var);
71    }
72
73    fn pop(&mut self) -> VMResult<Variable> {
74        self.stack.pop().ok_or_else(|| StackOutOfBounds {
75            stack: format!("{:?}", self.stack),
76        })
77    }
78
79    pub fn run(&mut self, root_env: Variable) -> VMResult<Variable> {
80        let mut env = root_env.clone();
81        let mut assigned_object: Option<Variable> = None;
82        if self.ip != 0 {
83            self.ip = 0;
84        }
85
86        while self.ip < self.bytecode.len() as u32 {
87            let op = self
88                .bytecode
89                .get(self.ip as usize)
90                .ok_or_else(|| OpcodeOutOfBounds {
91                    bytecode: format!("{:?}", self.bytecode),
92                    index: self.ip as usize,
93                })?;
94
95            self.ip += 1;
96
97            match op {
98                Opcode::PushNull => self.push(Null),
99                Opcode::PushBool(b) => self.push(Bool(*b)),
100                Opcode::PushNumber(n) => self.push(Number(*n)),
101                Opcode::PushString(s) => self.push(String(Rc::from(s.as_ref()))),
102                Opcode::Pop => {
103                    self.pop()?;
104                }
105                Opcode::Fetch => {
106                    let b = self.pop()?;
107                    let a = self.pop()?;
108
109                    match (a, b) {
110                        (Object(o), String(s)) => {
111                            let obj = o.borrow();
112                            self.push(obj.get(s.as_ref()).cloned().unwrap_or(Null));
113                        }
114                        (Array(a), Number(n)) => {
115                            let arr = a.borrow();
116                            self.push(
117                                arr.get(n.to_usize().ok_or_else(|| OpcodeErr {
118                                    opcode: "Fetch".into(),
119                                    message: "Failed to convert to usize".into(),
120                                })?)
121                                .cloned()
122                                .unwrap_or(Null),
123                            )
124                        }
125                        (String(str), Number(n)) => {
126                            let index = n.to_usize().ok_or_else(|| OpcodeErr {
127                                opcode: "Fetch".into(),
128                                message: "Failed to convert to usize".into(),
129                            })?;
130
131                            if let Some(slice) = str.get(index..index + 1) {
132                                self.push(String(Rc::from(slice)));
133                            } else {
134                                self.push(Null)
135                            };
136                        }
137                        _ => self.push(Null),
138                    }
139                }
140                Opcode::FetchFast(path) => {
141                    let variable = path.iter().fold(Null, |v, p| match p {
142                        FetchFastTarget::Root => root_env.clone(),
143                        FetchFastTarget::Begin => env.clone(),
144                        FetchFastTarget::String(key) => match v {
145                            Object(obj) => {
146                                let obj_ref = obj.borrow();
147                                obj_ref.get(key.as_ref()).cloned().unwrap_or(Null)
148                            }
149                            _ => Null,
150                        },
151                        FetchFastTarget::Number(num) => match v {
152                            Array(arr) => {
153                                let arr_ref = arr.borrow();
154                                arr_ref.get(*num as usize).cloned().unwrap_or(Null)
155                            }
156                            _ => Null,
157                        },
158                    });
159
160                    self.push(variable);
161                }
162                Opcode::FetchEnv(f) => match &env {
163                    Object(o) => {
164                        let obj = o.borrow();
165                        match obj.get(f.as_ref()) {
166                            None => self.push(Null),
167                            Some(v) => self.push(v.clone()),
168                        }
169                    }
170                    Null => self.push(Null),
171                    _ => {
172                        return Err(OpcodeErr {
173                            opcode: "FetchEnv".into(),
174                            message: "Unsupported type".into(),
175                        });
176                    }
177                },
178                Opcode::FetchRootEnv => {
179                    self.push(env.clone());
180                }
181                Opcode::Negate => {
182                    let a = self.pop()?;
183                    match a {
184                        Number(n) => {
185                            self.push(Number(-n));
186                        }
187                        _ => {
188                            return Err(OpcodeErr {
189                                opcode: "Negate".into(),
190                                message: "Unsupported type".into(),
191                            });
192                        }
193                    }
194                }
195                Opcode::Not => {
196                    let a = self.pop()?;
197                    match a {
198                        Bool(b) => self.push(Bool(!b)),
199                        _ => {
200                            return Err(OpcodeErr {
201                                opcode: "Not".into(),
202                                message: "Unsupported type".into(),
203                            });
204                        }
205                    }
206                }
207                Opcode::Equal => {
208                    let b = self.pop()?;
209                    let a = self.pop()?;
210                    match (a, b) {
211                        (Number(a), Number(b)) => {
212                            self.push(Bool(a == b));
213                        }
214                        (Bool(a), Bool(b)) => {
215                            self.push(Bool(a == b));
216                        }
217                        (String(a), String(b)) => {
218                            self.push(Bool(a == b));
219                        }
220                        (Null, Null) => {
221                            self.push(Bool(true));
222                        }
223                        (Dynamic(a), Dynamic(b)) => {
224                            let a = a.as_date();
225                            let b = b.as_date();
226
227                            self.push(Bool(a.is_some() && b.is_some() && a == b));
228                        }
229                        _ => {
230                            self.push(Bool(false));
231                        }
232                    }
233                }
234                Opcode::Jump(kind, j) => match kind {
235                    Jump::Forward => self.ip += j,
236                    Jump::Backward => self.ip -= j,
237                    Jump::IfTrue => {
238                        let a = self.stack.last().ok_or_else(|| OpcodeErr {
239                            opcode: "JumpIfTrue".into(),
240                            message: "Undefined object key".into(),
241                        })?;
242                        match a {
243                            Bool(a) => {
244                                if *a {
245                                    self.ip += j;
246                                }
247                            }
248                            _ => {
249                                return Err(OpcodeErr {
250                                    opcode: "JumpIfTrue".into(),
251                                    message: "Unsupported type".into(),
252                                });
253                            }
254                        }
255                    }
256                    Jump::IfFalse => {
257                        let a = self.stack.last().ok_or_else(|| OpcodeErr {
258                            opcode: "JumpIfFalse".into(),
259                            message: "Empty array".into(),
260                        })?;
261
262                        match a {
263                            Bool(a) => {
264                                if !*a {
265                                    self.ip += j;
266                                }
267                            }
268                            _ => {
269                                return Err(OpcodeErr {
270                                    opcode: "JumpIfFalse".into(),
271                                    message: "Unsupported type".into(),
272                                });
273                            }
274                        }
275                    }
276                    Jump::IfNotNull => {
277                        let a = self.stack.last().ok_or_else(|| OpcodeErr {
278                            opcode: "JumpIfNull".into(),
279                            message: "Empty array".into(),
280                        })?;
281
282                        match a {
283                            Null => {}
284                            _ => {
285                                self.ip += j;
286                            }
287                        }
288                    }
289                    Jump::IfEnd => {
290                        let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
291                            opcode: "JumpIfEnd".into(),
292                            message: "Empty stack".into(),
293                        })?;
294
295                        if scope.iter >= scope.len {
296                            self.ip += j;
297                        }
298                    }
299                },
300                Opcode::In => {
301                    let b = self.pop()?;
302                    let a = self.pop()?;
303
304                    match (a, &b) {
305                        (Number(a), Array(b)) => {
306                            let arr = b.borrow();
307                            let is_in = arr.iter().any(|b| match b {
308                                Number(b) => a == *b,
309                                _ => false,
310                            });
311
312                            self.push(Bool(is_in));
313                        }
314                        (Number(v), Dynamic(d)) => {
315                            let Some(i) = d.as_any().downcast_ref::<VmInterval>() else {
316                                return Err(OpcodeErr {
317                                    opcode: "In".into(),
318                                    message: "Unsupported type".into(),
319                                });
320                            };
321
322                            self.push(Bool(i.includes(VmIntervalData::Number(v)).map_err(
323                                |err| OpcodeErr {
324                                    opcode: "In".into(),
325                                    message: err.to_string(),
326                                },
327                            )?));
328                        }
329                        (Dynamic(d), Dynamic(i)) => {
330                            let Some(d) = d.as_date() else {
331                                return Err(OpcodeErr {
332                                    opcode: "In".into(),
333                                    message: "Unsupported type".into(),
334                                });
335                            };
336
337                            let Some(i) = i.as_any().downcast_ref::<VmInterval>() else {
338                                return Err(OpcodeErr {
339                                    opcode: "In".into(),
340                                    message: "Unsupported type".into(),
341                                });
342                            };
343
344                            self.push(Bool(i.includes(VmIntervalData::Date(d.clone())).map_err(
345                                |err| OpcodeErr {
346                                    opcode: "In".into(),
347                                    message: err.to_string(),
348                                },
349                            )?));
350                        }
351                        (Dynamic(a), Array(arr)) => {
352                            let Some(a) = a.as_date() else {
353                                return Err(OpcodeErr {
354                                    opcode: "In".into(),
355                                    message: "Unsupported type".into(),
356                                });
357                            };
358
359                            let arr = arr.borrow();
360                            let is_in = arr.iter().any(|b| match b {
361                                Dynamic(b) => Some(a) == b.as_date(),
362                                _ => false,
363                            });
364
365                            self.push(Bool(is_in));
366                        }
367                        (String(a), Array(b)) => {
368                            let arr = b.borrow();
369                            let is_in = arr.iter().any(|b| match b {
370                                String(b) => &a == b,
371                                _ => false,
372                            });
373
374                            self.push(Bool(is_in));
375                        }
376                        (String(a), Object(b)) => {
377                            let obj = b.borrow();
378                            self.push(Bool(obj.contains_key(a.as_ref())));
379                        }
380                        (Bool(a), Array(b)) => {
381                            let arr = b.borrow();
382                            let is_in = arr.iter().any(|b| match b {
383                                Bool(b) => a == *b,
384                                _ => false,
385                            });
386
387                            self.push(Bool(is_in));
388                        }
389                        (Null, Array(b)) => {
390                            let arr = b.borrow();
391                            let is_in = arr.iter().any(|b| match b {
392                                Null => true,
393                                _ => false,
394                            });
395
396                            self.push(Bool(is_in));
397                        }
398                        _ => {
399                            return Err(OpcodeErr {
400                                opcode: "In".into(),
401                                message: "Unsupported type".into(),
402                            });
403                        }
404                    }
405                }
406                Opcode::Compare(comparison) => {
407                    let b = self.pop()?;
408                    let a = self.pop()?;
409
410                    fn compare<T: Ord>(a: &T, b: &T, comparison: &Compare) -> bool {
411                        match comparison {
412                            Compare::More => a > b,
413                            Compare::MoreOrEqual => a >= b,
414                            Compare::Less => a < b,
415                            Compare::LessOrEqual => a <= b,
416                        }
417                    }
418
419                    match (a, b) {
420                        (Number(a), Number(b)) => self.push(Bool(compare(&a, &b, comparison))),
421                        (Dynamic(a), Dynamic(b)) => {
422                            let (a, b) = match (a.as_date(), b.as_date()) {
423                                (Some(a), Some(b)) => (a, b),
424                                _ => {
425                                    return Err(OpcodeErr {
426                                        opcode: "Compare".into(),
427                                        message: "Unsupported type".into(),
428                                    })
429                                }
430                            };
431
432                            self.push(Bool(compare(a, b, comparison)));
433                        }
434                        _ => {
435                            return Err(OpcodeErr {
436                                opcode: "Compare".into(),
437                                message: "Unsupported type".into(),
438                            });
439                        }
440                    }
441                }
442                Opcode::Add => {
443                    let b = self.pop()?;
444                    let a = self.pop()?;
445
446                    match (a, b) {
447                        (Number(a), Number(b)) => self.push(Number(a + b)),
448                        (String(a), String(b)) => {
449                            let mut c = StdString::with_capacity(a.len() + b.len());
450
451                            c.push_str(a.as_ref());
452                            c.push_str(b.as_ref());
453
454                            self.push(String(Rc::from(c.as_str())));
455                        }
456                        _ => {
457                            return Err(OpcodeErr {
458                                opcode: "Add".into(),
459                                message: "Unsupported type".into(),
460                            });
461                        }
462                    }
463                }
464                Opcode::Subtract => {
465                    let b = self.pop()?;
466                    let a = self.pop()?;
467
468                    match (a, b) {
469                        (Number(a), Number(b)) => self.push(Number(a - b)),
470                        _ => {
471                            return Err(OpcodeErr {
472                                opcode: "Subtract".into(),
473                                message: "Unsupported type".into(),
474                            });
475                        }
476                    }
477                }
478                Opcode::Multiply => {
479                    let b = self.pop()?;
480                    let a = self.pop()?;
481
482                    match (a, b) {
483                        (Number(a), Number(b)) => self.push(Number(a * b)),
484                        _ => {
485                            return Err(OpcodeErr {
486                                opcode: "Multiply".into(),
487                                message: "Unsupported type".into(),
488                            });
489                        }
490                    }
491                }
492                Opcode::Divide => {
493                    let b = self.pop()?;
494                    let a = self.pop()?;
495
496                    let (Number(a), Number(b)) = (a, b) else {
497                        return Err(OpcodeErr {
498                            opcode: "Divide".into(),
499                            message: "Unsupported type".into(),
500                        });
501                    };
502
503                    let result = match a.checked_div(b) {
504                        Some(r) => Number(r),
505                        None => Null,
506                    };
507
508                    self.push(result);
509                }
510                Opcode::Modulo => {
511                    let b = self.pop()?;
512                    let a = self.pop()?;
513
514                    match (a, b) {
515                        (Number(a), Number(b)) => self.push(Number(a % b)),
516                        _ => {
517                            return Err(OpcodeErr {
518                                opcode: "Modulo".into(),
519                                message: "Unsupported type".into(),
520                            });
521                        }
522                    }
523                }
524                Opcode::Exponent => {
525                    let b = self.pop()?;
526                    let a = self.pop()?;
527
528                    match (a, b) {
529                        (Number(a), Number(b)) => {
530                            let result = a
531                                .checked_powd(b)
532                                .or_else(|| Decimal::from_f64(a.to_f64()?.powf(b.to_f64()?)))
533                                .ok_or_else(|| OpcodeErr {
534                                    opcode: "Exponent".into(),
535                                    message: "Failed to calculate exponent".into(),
536                                })?;
537
538                            self.push(Number(result));
539                        }
540                        _ => {
541                            return Err(OpcodeErr {
542                                opcode: "Exponent".into(),
543                                message: "Unsupported type".into(),
544                            });
545                        }
546                    }
547                }
548                Opcode::Interval {
549                    left_bracket,
550                    right_bracket,
551                } => {
552                    let b = self.pop()?;
553                    let a = self.pop()?;
554
555                    match (&a, &b) {
556                        (Number(a), Number(b)) => {
557                            let interval = VmInterval {
558                                left_bracket: *left_bracket,
559                                right_bracket: *right_bracket,
560                                left: VmIntervalData::Number(*a),
561                                right: VmIntervalData::Number(*b),
562                            };
563
564                            self.push(Dynamic(Rc::new(interval)));
565                        }
566                        (Dynamic(a), Dynamic(b)) => {
567                            let (a, b) = match (a.as_date(), b.as_date()) {
568                                (Some(a), Some(b)) => (a, b),
569                                _ => {
570                                    return Err(OpcodeErr {
571                                        opcode: "Interval".into(),
572                                        message: "Unsupported type".into(),
573                                    })
574                                }
575                            };
576
577                            let interval = VmInterval {
578                                left_bracket: *left_bracket,
579                                right_bracket: *right_bracket,
580                                left: VmIntervalData::Date(a.clone()),
581                                right: VmIntervalData::Date(b.clone()),
582                            };
583
584                            self.push(Dynamic(Rc::new(interval)));
585                        }
586                        _ => {
587                            return Err(OpcodeErr {
588                                opcode: "Interval".into(),
589                                message: "Unsupported type".into(),
590                            });
591                        }
592                    }
593                }
594                Opcode::Join => {
595                    let b = self.pop()?;
596                    let a = self.pop()?;
597
598                    let (Array(a), String(separator)) = (a, &b) else {
599                        return Err(OpcodeErr {
600                            opcode: "Join".into(),
601                            message: "Unsupported type".into(),
602                        });
603                    };
604
605                    let arr = a.borrow();
606                    let parts = arr
607                        .iter()
608                        .enumerate()
609                        .map(|(i, var)| match var {
610                            String(str) => Ok(str.clone()),
611                            _ => Err(OpcodeErr {
612                                opcode: "Join".into(),
613                                message: format!("Unexpected type in array on index {i}"),
614                            }),
615                        })
616                        .collect::<Result<Vec<_>, _>>()?;
617
618                    let str_capacity = parts
619                        .iter()
620                        .fold(separator.len() * (parts.len() - 1), |acc, s| acc + s.len());
621
622                    let mut s = StdString::with_capacity(str_capacity);
623                    let mut it = parts.into_iter().peekable();
624                    while let Some(part) = it.next() {
625                        s.push_str(part.as_ref());
626                        if it.peek().is_some() {
627                            s.push_str(separator);
628                        }
629                    }
630
631                    self.push(String(Rc::from(s)));
632                }
633                Opcode::Slice => {
634                    let from_var = self.pop()?;
635                    let to_var = self.pop()?;
636                    let current = self.pop()?;
637
638                    match (from_var, to_var) {
639                        (Number(f), Number(t)) => {
640                            let from = f.to_usize().ok_or_else(|| OpcodeErr {
641                                opcode: "Slice".into(),
642                                message: "Failed to get range from".into(),
643                            })?;
644                            let to = t.to_usize().ok_or_else(|| OpcodeErr {
645                                opcode: "Slice".into(),
646                                message: "Failed to get range to".into(),
647                            })?;
648
649                            match current {
650                                Array(a) => {
651                                    let arr = a.borrow();
652                                    let slice = arr.get(from..=to).ok_or_else(|| OpcodeErr {
653                                        opcode: "Slice".into(),
654                                        message: "Index out of range".into(),
655                                    })?;
656
657                                    self.push(Variable::from_array(slice.to_vec()));
658                                }
659                                String(s) => {
660                                    let slice = s.get(from..=to).ok_or_else(|| OpcodeErr {
661                                        opcode: "Slice".into(),
662                                        message: "Index out of range".into(),
663                                    })?;
664
665                                    self.push(String(Rc::from(slice)));
666                                }
667                                _ => {
668                                    return Err(OpcodeErr {
669                                        opcode: "Slice".into(),
670                                        message: "Unsupported type".into(),
671                                    });
672                                }
673                            }
674                        }
675                        _ => {
676                            return Err(OpcodeErr {
677                                opcode: "Slice".into(),
678                                message: "Unsupported type".into(),
679                            });
680                        }
681                    }
682                }
683                Opcode::Array => {
684                    let size = self.pop()?;
685                    let Number(s) = size else {
686                        return Err(OpcodeErr {
687                            opcode: "Array".into(),
688                            message: "Unsupported type".into(),
689                        });
690                    };
691
692                    let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
693                        opcode: "Array".into(),
694                        message: "Failed to extract argument".into(),
695                    })?;
696
697                    let mut arr = Vec::with_capacity(to);
698                    for _ in 0..to {
699                        arr.push(self.pop()?);
700                    }
701                    arr.reverse();
702
703                    self.push(Variable::from_array(arr));
704                }
705                Opcode::Object => {
706                    let size = self.pop()?;
707                    let Number(s) = size else {
708                        return Err(OpcodeErr {
709                            opcode: "Array".into(),
710                            message: "Unsupported type".into(),
711                        });
712                    };
713
714                    let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
715                        opcode: "Array".into(),
716                        message: "Failed to extract argument".into(),
717                    })?;
718
719                    let mut map = HashMap::with_capacity(to);
720                    for _ in 0..to {
721                        let value = self.pop()?;
722                        let String(key) = self.pop()? else {
723                            return Err(OpcodeErr {
724                                opcode: "Object".into(),
725                                message: "Unexpected key value".to_string(),
726                            });
727                        };
728
729                        map.insert(key.clone(), value);
730                    }
731
732                    self.push(Variable::from_object(map));
733                }
734                Opcode::AssignedObjectBegin => {
735                    assigned_object = Some(Variable::empty_object());
736                }
737                Opcode::AssignedObjectStep => {
738                    let value = self.pop()?;
739                    let String(key) = self.pop()? else {
740                        return Err(OpcodeErr {
741                            opcode: "AssignedObjectStep".into(),
742                            message: "Unexpected key value".to_string(),
743                        });
744                    };
745
746                    let Some(assigned_object) = &assigned_object else {
747                        return Err(OpcodeErr {
748                            opcode: "AssignedObjectStep".into(),
749                            message: "Assigned object scope must be set".to_owned(),
750                        });
751                    };
752
753                    let Some(new_env) = env.dot_insert_detached(key.as_ref(), value.clone()) else {
754                        return Err(OpcodeErr {
755                            opcode: "AssignedObjectStep".into(),
756                            message: "Failed to mutate existing env".to_owned(),
757                        });
758                    };
759
760                    env = new_env;
761                    assigned_object.dot_insert(key.as_ref(), value);
762                }
763                Opcode::AssignedObjectEnd { with_return } => {
764                    let Some(assigned_object) = assigned_object.take() else {
765                        return Err(OpcodeErr {
766                            opcode: "AssignedObjectEnd".into(),
767                            message: "Assigned object scope must be set".to_owned(),
768                        });
769                    };
770
771                    if *with_return {
772                        let output = self.pop()?;
773                        self.push(output);
774                    } else {
775                        self.push(assigned_object);
776                    }
777                }
778                Opcode::Len => {
779                    let current = self.stack.last().ok_or_else(|| OpcodeErr {
780                        opcode: "Len".into(),
781                        message: "Empty stack".into(),
782                    })?;
783
784                    let len_var =
785                        internal::imp::len(Arguments(&[current.clone()])).map_err(|err| {
786                            OpcodeErr {
787                                opcode: "Len".into(),
788                                message: err.to_string(),
789                            }
790                        })?;
791
792                    self.push(len_var);
793                }
794                Opcode::Flatten => {
795                    let current = self.pop()?;
796                    let Array(a) = current else {
797                        return Err(OpcodeErr {
798                            opcode: "Flatten".into(),
799                            message: "Unsupported type".into(),
800                        });
801                    };
802
803                    let arr = a.borrow();
804
805                    let mut flat_arr = Vec::with_capacity(arr.len());
806                    arr.iter().for_each(|v| match v {
807                        Array(b) => {
808                            let arr = b.borrow();
809                            arr.iter().for_each(|v| flat_arr.push(v.clone()))
810                        }
811                        _ => flat_arr.push(v.clone()),
812                    });
813
814                    self.push(Variable::from_array(flat_arr));
815                }
816                Opcode::IncrementIt => {
817                    let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
818                        opcode: "IncrementIt".into(),
819                        message: "Empty scope".into(),
820                    })?;
821
822                    scope.iter += 1;
823                }
824                Opcode::IncrementCount => {
825                    let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
826                        opcode: "IncrementCount".into(),
827                        message: "Empty scope".into(),
828                    })?;
829
830                    scope.count += 1;
831                }
832                Opcode::GetCount => {
833                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
834                        opcode: "GetCount".into(),
835                        message: "Empty scope".into(),
836                    })?;
837
838                    self.push(Number(scope.count.into()));
839                }
840                Opcode::GetLen => {
841                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
842                        opcode: "GetLen".into(),
843                        message: "Empty scope".into(),
844                    })?;
845
846                    self.push(Number(scope.len.into()));
847                }
848                Opcode::Pointer => {
849                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
850                        opcode: "Pointer".into(),
851                        message: "Empty scope".into(),
852                    })?;
853
854                    match &scope.array {
855                        Array(a) => {
856                            let a_cloned = a.clone();
857                            let arr = a_cloned.borrow();
858                            let variable =
859                                arr.get(scope.iter).cloned().ok_or_else(|| OpcodeErr {
860                                    opcode: "Pointer".into(),
861                                    message: "Scope array out of bounds".into(),
862                                })?;
863
864                            self.push(variable);
865                        }
866                        _ => {
867                            return Err(OpcodeErr {
868                                opcode: "Pointer".into(),
869                                message: "Unsupported scope type".into(),
870                            });
871                        }
872                    }
873                }
874                Opcode::Begin => {
875                    let var = self.pop()?;
876                    let maybe_scope = match &var {
877                        Array(a) => {
878                            let arr = a.borrow();
879                            Some(Scope {
880                                len: arr.len(),
881                                array: var.clone(),
882                                count: 0,
883                                iter: 0,
884                            })
885                        }
886                        _ => match var.dynamic::<VmInterval>().map(|s| s.to_array()).flatten() {
887                            None => None,
888                            Some(arr) => Some(Scope {
889                                len: arr.len(),
890                                array: Variable::from_array(arr),
891                                count: 0,
892                                iter: 0,
893                            }),
894                        },
895                    };
896
897                    let Some(scope) = maybe_scope else {
898                        return Err(OpcodeErr {
899                            opcode: "Begin".into(),
900                            message: "Unsupported type".into(),
901                        });
902                    };
903
904                    self.scopes.push(scope);
905                }
906                Opcode::End => {
907                    self.scopes.pop();
908                }
909                Opcode::CallFunction { kind, arg_count } => {
910                    let function =
911                        FunctionRegistry::get_definition(kind).ok_or_else(|| OpcodeErr {
912                            opcode: "CallFunction".into(),
913                            message: format!("Function `{kind}` not found"),
914                        })?;
915
916                    let params_start = self.stack.len().saturating_sub(*arg_count as usize);
917                    let result = function
918                        .call(Arguments(&self.stack[params_start..]))
919                        .map_err(|err| OpcodeErr {
920                            opcode: "CallFunction".into(),
921                            message: format!("Function `{kind}` failed: {err}"),
922                        })?;
923
924                    self.stack.drain(params_start..);
925                    self.push(result);
926                }
927                Opcode::CallMethod { kind, arg_count } => {
928                    let method = MethodRegistry::get_definition(kind).ok_or_else(|| OpcodeErr {
929                        opcode: "CallMethod".into(),
930                        message: format!("Method `{kind}` not found"),
931                    })?;
932
933                    let params_start = self.stack.len().saturating_sub(*arg_count as usize) - 1;
934                    let result = method
935                        .call(Arguments(&self.stack[params_start..]))
936                        .map_err(|err| OpcodeErr {
937                            opcode: "CallMethod".into(),
938                            message: format!("Method `{kind}` failed: {err}"),
939                        })?;
940
941                    self.stack.drain(params_start..);
942                    self.push(result);
943                }
944            }
945        }
946
947        self.pop()
948    }
949}