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