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