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