Skip to main content

zen_expression/vm/
vm.rs

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