zen_expression/vm/
vm.rs

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