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                    match (a, b) {
493                        (Number(a), Number(b)) => self.push(Number(a / b)),
494                        _ => {
495                            return Err(OpcodeErr {
496                                opcode: "Divide".into(),
497                                message: "Unsupported type".into(),
498                            });
499                        }
500                    }
501                }
502                Opcode::Modulo => {
503                    let b = self.pop()?;
504                    let a = self.pop()?;
505
506                    match (a, b) {
507                        (Number(a), Number(b)) => self.push(Number(a % b)),
508                        _ => {
509                            return Err(OpcodeErr {
510                                opcode: "Modulo".into(),
511                                message: "Unsupported type".into(),
512                            });
513                        }
514                    }
515                }
516                Opcode::Exponent => {
517                    let b = self.pop()?;
518                    let a = self.pop()?;
519
520                    match (a, b) {
521                        (Number(a), Number(b)) => {
522                            let result = a
523                                .checked_powd(b)
524                                .or_else(|| Decimal::from_f64(a.to_f64()?.powf(b.to_f64()?)))
525                                .ok_or_else(|| OpcodeErr {
526                                    opcode: "Exponent".into(),
527                                    message: "Failed to calculate exponent".into(),
528                                })?;
529
530                            self.push(Number(result));
531                        }
532                        _ => {
533                            return Err(OpcodeErr {
534                                opcode: "Exponent".into(),
535                                message: "Unsupported type".into(),
536                            });
537                        }
538                    }
539                }
540                Opcode::Interval {
541                    left_bracket,
542                    right_bracket,
543                } => {
544                    let b = self.pop()?;
545                    let a = self.pop()?;
546
547                    match (&a, &b) {
548                        (Number(a), Number(b)) => {
549                            let interval = VmInterval {
550                                left_bracket: *left_bracket,
551                                right_bracket: *right_bracket,
552                                left: VmIntervalData::Number(*a),
553                                right: VmIntervalData::Number(*b),
554                            };
555
556                            self.push(Dynamic(Rc::new(interval)));
557                        }
558                        (Dynamic(a), Dynamic(b)) => {
559                            let (a, b) = match (a.as_date(), b.as_date()) {
560                                (Some(a), Some(b)) => (a, b),
561                                _ => {
562                                    return Err(OpcodeErr {
563                                        opcode: "Interval".into(),
564                                        message: "Unsupported type".into(),
565                                    })
566                                }
567                            };
568
569                            let interval = VmInterval {
570                                left_bracket: *left_bracket,
571                                right_bracket: *right_bracket,
572                                left: VmIntervalData::Date(a.clone()),
573                                right: VmIntervalData::Date(b.clone()),
574                            };
575
576                            self.push(Dynamic(Rc::new(interval)));
577                        }
578                        _ => {
579                            return Err(OpcodeErr {
580                                opcode: "Interval".into(),
581                                message: "Unsupported type".into(),
582                            });
583                        }
584                    }
585                }
586                Opcode::Join => {
587                    let b = self.pop()?;
588                    let a = self.pop()?;
589
590                    let (Array(a), String(separator)) = (a, &b) else {
591                        return Err(OpcodeErr {
592                            opcode: "Join".into(),
593                            message: "Unsupported type".into(),
594                        });
595                    };
596
597                    let arr = a.borrow();
598                    let parts = arr
599                        .iter()
600                        .enumerate()
601                        .map(|(i, var)| match var {
602                            String(str) => Ok(str.clone()),
603                            _ => Err(OpcodeErr {
604                                opcode: "Join".into(),
605                                message: format!("Unexpected type in array on index {i}"),
606                            }),
607                        })
608                        .collect::<Result<Vec<_>, _>>()?;
609
610                    let str_capacity = parts
611                        .iter()
612                        .fold(separator.len() * (parts.len() - 1), |acc, s| acc + s.len());
613
614                    let mut s = StdString::with_capacity(str_capacity);
615                    let mut it = parts.into_iter().peekable();
616                    while let Some(part) = it.next() {
617                        s.push_str(part.as_ref());
618                        if it.peek().is_some() {
619                            s.push_str(separator);
620                        }
621                    }
622
623                    self.push(String(Rc::from(s)));
624                }
625                Opcode::Slice => {
626                    let from_var = self.pop()?;
627                    let to_var = self.pop()?;
628                    let current = self.pop()?;
629
630                    match (from_var, to_var) {
631                        (Number(f), Number(t)) => {
632                            let from = f.to_usize().ok_or_else(|| OpcodeErr {
633                                opcode: "Slice".into(),
634                                message: "Failed to get range from".into(),
635                            })?;
636                            let to = t.to_usize().ok_or_else(|| OpcodeErr {
637                                opcode: "Slice".into(),
638                                message: "Failed to get range to".into(),
639                            })?;
640
641                            match current {
642                                Array(a) => {
643                                    let arr = a.borrow();
644                                    let slice = arr.get(from..=to).ok_or_else(|| OpcodeErr {
645                                        opcode: "Slice".into(),
646                                        message: "Index out of range".into(),
647                                    })?;
648
649                                    self.push(Variable::from_array(slice.to_vec()));
650                                }
651                                String(s) => {
652                                    let slice = s.get(from..=to).ok_or_else(|| OpcodeErr {
653                                        opcode: "Slice".into(),
654                                        message: "Index out of range".into(),
655                                    })?;
656
657                                    self.push(String(Rc::from(slice)));
658                                }
659                                _ => {
660                                    return Err(OpcodeErr {
661                                        opcode: "Slice".into(),
662                                        message: "Unsupported type".into(),
663                                    });
664                                }
665                            }
666                        }
667                        _ => {
668                            return Err(OpcodeErr {
669                                opcode: "Slice".into(),
670                                message: "Unsupported type".into(),
671                            });
672                        }
673                    }
674                }
675                Opcode::Array => {
676                    let size = self.pop()?;
677                    let Number(s) = size else {
678                        return Err(OpcodeErr {
679                            opcode: "Array".into(),
680                            message: "Unsupported type".into(),
681                        });
682                    };
683
684                    let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
685                        opcode: "Array".into(),
686                        message: "Failed to extract argument".into(),
687                    })?;
688
689                    let mut arr = Vec::with_capacity(to);
690                    for _ in 0..to {
691                        arr.push(self.pop()?);
692                    }
693                    arr.reverse();
694
695                    self.push(Variable::from_array(arr));
696                }
697                Opcode::Object => {
698                    let size = self.pop()?;
699                    let Number(s) = size else {
700                        return Err(OpcodeErr {
701                            opcode: "Array".into(),
702                            message: "Unsupported type".into(),
703                        });
704                    };
705
706                    let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
707                        opcode: "Array".into(),
708                        message: "Failed to extract argument".into(),
709                    })?;
710
711                    let mut map = HashMap::with_capacity(to);
712                    for _ in 0..to {
713                        let value = self.pop()?;
714                        let String(key) = self.pop()? else {
715                            return Err(OpcodeErr {
716                                opcode: "Object".into(),
717                                message: "Unexpected key value".to_string(),
718                            });
719                        };
720
721                        map.insert(key.clone(), value);
722                    }
723
724                    self.push(Variable::from_object(map));
725                }
726                Opcode::Len => {
727                    let current = self.stack.last().ok_or_else(|| OpcodeErr {
728                        opcode: "Len".into(),
729                        message: "Empty stack".into(),
730                    })?;
731
732                    let len_var =
733                        internal::imp::len(Arguments(&[current.clone()])).map_err(|err| {
734                            OpcodeErr {
735                                opcode: "Len".into(),
736                                message: err.to_string(),
737                            }
738                        })?;
739
740                    self.push(len_var);
741                }
742                Opcode::Flatten => {
743                    let current = self.pop()?;
744                    let Array(a) = current else {
745                        return Err(OpcodeErr {
746                            opcode: "Flatten".into(),
747                            message: "Unsupported type".into(),
748                        });
749                    };
750
751                    let arr = a.borrow();
752
753                    let mut flat_arr = Vec::with_capacity(arr.len());
754                    arr.iter().for_each(|v| match v {
755                        Array(b) => {
756                            let arr = b.borrow();
757                            arr.iter().for_each(|v| flat_arr.push(v.clone()))
758                        }
759                        _ => flat_arr.push(v.clone()),
760                    });
761
762                    self.push(Variable::from_array(flat_arr));
763                }
764                Opcode::IncrementIt => {
765                    let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
766                        opcode: "IncrementIt".into(),
767                        message: "Empty scope".into(),
768                    })?;
769
770                    scope.iter += 1;
771                }
772                Opcode::IncrementCount => {
773                    let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
774                        opcode: "IncrementCount".into(),
775                        message: "Empty scope".into(),
776                    })?;
777
778                    scope.count += 1;
779                }
780                Opcode::GetCount => {
781                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
782                        opcode: "GetCount".into(),
783                        message: "Empty scope".into(),
784                    })?;
785
786                    self.push(Number(scope.count.into()));
787                }
788                Opcode::GetLen => {
789                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
790                        opcode: "GetLen".into(),
791                        message: "Empty scope".into(),
792                    })?;
793
794                    self.push(Number(scope.len.into()));
795                }
796                Opcode::Pointer => {
797                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
798                        opcode: "Pointer".into(),
799                        message: "Empty scope".into(),
800                    })?;
801
802                    match &scope.array {
803                        Array(a) => {
804                            let a_cloned = a.clone();
805                            let arr = a_cloned.borrow();
806                            let variable =
807                                arr.get(scope.iter).cloned().ok_or_else(|| OpcodeErr {
808                                    opcode: "Pointer".into(),
809                                    message: "Scope array out of bounds".into(),
810                                })?;
811
812                            self.push(variable);
813                        }
814                        _ => {
815                            return Err(OpcodeErr {
816                                opcode: "Pointer".into(),
817                                message: "Unsupported scope type".into(),
818                            });
819                        }
820                    }
821                }
822                Opcode::Begin => {
823                    let var = self.pop()?;
824                    let maybe_scope = match &var {
825                        Array(a) => {
826                            let arr = a.borrow();
827                            Some(Scope {
828                                len: arr.len(),
829                                array: var.clone(),
830                                count: 0,
831                                iter: 0,
832                            })
833                        }
834                        _ => match var.dynamic::<VmInterval>().map(|s| s.to_array()).flatten() {
835                            None => None,
836                            Some(arr) => Some(Scope {
837                                len: arr.len(),
838                                array: Variable::from_array(arr),
839                                count: 0,
840                                iter: 0,
841                            }),
842                        },
843                    };
844
845                    let Some(scope) = maybe_scope else {
846                        return Err(OpcodeErr {
847                            opcode: "Begin".into(),
848                            message: "Unsupported type".into(),
849                        });
850                    };
851
852                    self.scopes.push(scope);
853                }
854                Opcode::End => {
855                    self.scopes.pop();
856                }
857                Opcode::CallFunction { kind, arg_count } => {
858                    let function =
859                        FunctionRegistry::get_definition(kind).ok_or_else(|| OpcodeErr {
860                            opcode: "CallFunction".into(),
861                            message: format!("Function `{kind}` not found"),
862                        })?;
863
864                    let params_start = self.stack.len().saturating_sub(*arg_count as usize);
865                    let result = function
866                        .call(Arguments(&self.stack[params_start..]))
867                        .map_err(|err| OpcodeErr {
868                            opcode: "CallFunction".into(),
869                            message: format!("Function `{kind}` failed: {err}"),
870                        })?;
871
872                    self.stack.drain(params_start..);
873                    self.push(result);
874                }
875                Opcode::CallMethod { kind, arg_count } => {
876                    let method = MethodRegistry::get_definition(kind).ok_or_else(|| OpcodeErr {
877                        opcode: "CallMethod".into(),
878                        message: format!("Method `{kind}` not found"),
879                    })?;
880
881                    let params_start = self.stack.len().saturating_sub(*arg_count as usize) - 1;
882                    let result = method
883                        .call(Arguments(&self.stack[params_start..]))
884                        .map_err(|err| OpcodeErr {
885                            opcode: "CallMethod".into(),
886                            message: format!("Method `{kind}` failed: {err}"),
887                        })?;
888
889                    self.stack.drain(params_start..);
890                    self.push(result);
891                }
892            }
893        }
894
895        self.pop()
896    }
897}