zen_expression/vm/
vm.rs

1use crate::compiler::{FetchFastTarget, Jump, Opcode, TypeCheckKind, TypeConversionKind};
2use crate::lexer::Bracket;
3use crate::variable::Variable;
4use crate::variable::Variable::*;
5use crate::vm::error::VMError::*;
6use crate::vm::error::VMResult;
7use crate::vm::helpers::{date_time, date_time_end_of, date_time_start_of, time};
8use crate::vm::variable::IntervalObject;
9use ahash::{HashMap, HashMapExt};
10use chrono::NaiveDateTime;
11use chrono::{Datelike, Timelike};
12#[cfg(not(feature = "regex-lite"))]
13use regex::Regex;
14#[cfg(feature = "regex-lite")]
15use regex_lite::Regex;
16use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
17use rust_decimal::{Decimal, MathematicalOps};
18use rust_decimal_macros::dec;
19use std::cell::RefCell;
20use std::rc::Rc;
21use std::string::String as StdString;
22
23#[derive(Debug)]
24pub struct Scope {
25    array: Variable,
26    len: usize,
27    iter: usize,
28    count: usize,
29}
30
31#[derive(Debug)]
32pub struct VM {
33    scopes: Vec<Scope>,
34    stack: Vec<Variable>,
35}
36
37impl VM {
38    pub fn new() -> Self {
39        Self {
40            scopes: Default::default(),
41            stack: Default::default(),
42        }
43    }
44
45    pub fn run(&mut self, bytecode: &[Opcode], env: Variable) -> VMResult<Variable> {
46        self.stack.clear();
47        self.scopes.clear();
48
49        let s = VMInner::new(bytecode, &mut self.stack, &mut self.scopes).run(env);
50        Ok(s?)
51    }
52}
53
54struct VMInner<'parent_ref, 'bytecode_ref> {
55    scopes: &'parent_ref mut Vec<Scope>,
56    stack: &'parent_ref mut Vec<Variable>,
57    bytecode: &'bytecode_ref [Opcode],
58    ip: u32,
59}
60
61impl<'arena, 'parent_ref, 'bytecode_ref> VMInner<'parent_ref, 'bytecode_ref> {
62    pub fn new(
63        bytecode: &'bytecode_ref [Opcode],
64        stack: &'parent_ref mut Vec<Variable>,
65        scopes: &'parent_ref mut Vec<Scope>,
66    ) -> Self {
67        Self {
68            ip: 0,
69            scopes,
70            stack,
71            bytecode,
72        }
73    }
74
75    fn push(&mut self, var: Variable) {
76        self.stack.push(var);
77    }
78
79    fn pop(&mut self) -> VMResult<Variable> {
80        self.stack.pop().ok_or_else(|| StackOutOfBounds {
81            stack: format!("{:?}", self.stack),
82        })
83    }
84
85    pub fn run(&mut self, env: Variable) -> VMResult<Variable> {
86        if self.ip != 0 {
87            self.ip = 0;
88        }
89
90        while self.ip < self.bytecode.len() as u32 {
91            let op = self
92                .bytecode
93                .get(self.ip as usize)
94                .ok_or_else(|| OpcodeOutOfBounds {
95                    bytecode: format!("{:?}", self.bytecode),
96                    index: self.ip as usize,
97                })?;
98
99            self.ip += 1;
100
101            match op {
102                Opcode::PushNull => self.push(Null),
103                Opcode::PushBool(b) => self.push(Bool(*b)),
104                Opcode::PushNumber(n) => self.push(Number(*n)),
105                Opcode::PushString(s) => self.push(String(Rc::from(s.as_ref()))),
106                Opcode::Pop => {
107                    self.pop()?;
108                }
109                Opcode::Rot => {
110                    let b = self.stack.len() - 1;
111                    let a = self.stack.len() - 2;
112                    self.stack.swap(a, b);
113                }
114                Opcode::Fetch => {
115                    let b = self.pop()?;
116                    let a = self.pop()?;
117
118                    match (a, b) {
119                        (Object(o), String(s)) => {
120                            let obj = o.borrow();
121                            self.push(obj.get(s.as_ref()).cloned().unwrap_or(Null));
122                        }
123                        (Array(a), Number(n)) => {
124                            let arr = a.borrow();
125                            self.push(
126                                arr.get(n.to_usize().ok_or_else(|| OpcodeErr {
127                                    opcode: "Fetch".into(),
128                                    message: "Failed to convert to usize".into(),
129                                })?)
130                                .cloned()
131                                .unwrap_or(Null),
132                            )
133                        }
134                        (String(str), Number(n)) => {
135                            let index = n.to_usize().ok_or_else(|| OpcodeErr {
136                                opcode: "Fetch".into(),
137                                message: "Failed to convert to usize".into(),
138                            })?;
139
140                            if let Some(slice) = str.get(index..index + 1) {
141                                self.push(String(Rc::from(slice)));
142                            } else {
143                                self.push(Null)
144                            };
145                        }
146                        _ => self.push(Null),
147                    }
148                }
149                Opcode::FetchFast(path) => {
150                    let variable = path.iter().fold(Null, |v, p| match p {
151                        FetchFastTarget::Root => env.clone(),
152                        FetchFastTarget::String(key) => match v {
153                            Object(obj) => {
154                                let obj_ref = obj.borrow();
155                                obj_ref.get(key.as_ref()).cloned().unwrap_or(Null)
156                            }
157                            _ => Null,
158                        },
159                        FetchFastTarget::Number(num) => match v {
160                            Array(arr) => {
161                                let arr_ref = arr.borrow();
162                                arr_ref.get(*num as usize).cloned().unwrap_or(Null)
163                            }
164                            _ => Null,
165                        },
166                    });
167
168                    self.push(variable);
169                }
170                Opcode::FetchEnv(f) => match &env {
171                    Object(o) => {
172                        let obj = o.borrow();
173                        match obj.get(f.as_ref()) {
174                            None => self.push(Null),
175                            Some(v) => self.push(v.clone()),
176                        }
177                    }
178                    Null => self.push(Null),
179                    _ => {
180                        return Err(OpcodeErr {
181                            opcode: "FetchEnv".into(),
182                            message: "Unsupported type".into(),
183                        });
184                    }
185                },
186                Opcode::FetchRootEnv => {
187                    self.push(env.clone());
188                }
189                Opcode::Negate => {
190                    let a = self.pop()?;
191                    match a {
192                        Number(n) => {
193                            self.push(Number(-n));
194                        }
195                        _ => {
196                            return Err(OpcodeErr {
197                                opcode: "Negate".into(),
198                                message: "Unsupported type".into(),
199                            });
200                        }
201                    }
202                }
203                Opcode::Not => {
204                    let a = self.pop()?;
205                    match a {
206                        Bool(b) => self.push(Bool(!b)),
207                        _ => {
208                            return Err(OpcodeErr {
209                                opcode: "Not".into(),
210                                message: "Unsupported type".into(),
211                            });
212                        }
213                    }
214                }
215                Opcode::Equal => {
216                    let b = self.pop()?;
217                    let a = self.pop()?;
218                    match (a, b) {
219                        (Number(a), Number(b)) => {
220                            self.push(Bool(a == b));
221                        }
222                        (Bool(a), Bool(b)) => {
223                            self.push(Bool(a == b));
224                        }
225                        (String(a), String(b)) => {
226                            self.push(Bool(a == b));
227                        }
228                        (Null, Null) => {
229                            self.push(Bool(true));
230                        }
231                        _ => {
232                            self.push(Bool(false));
233                        }
234                    }
235                }
236                Opcode::Jump(kind, j) => match kind {
237                    Jump::Forward => self.ip += j,
238                    Jump::Backward => self.ip -= j,
239                    Jump::IfTrue => {
240                        let a = self.stack.last().ok_or_else(|| OpcodeErr {
241                            opcode: "JumpIfTrue".into(),
242                            message: "Undefined object key".into(),
243                        })?;
244                        match a {
245                            Bool(a) => {
246                                if *a {
247                                    self.ip += j;
248                                }
249                            }
250                            _ => {
251                                return Err(OpcodeErr {
252                                    opcode: "JumpIfTrue".into(),
253                                    message: "Unsupported type".into(),
254                                });
255                            }
256                        }
257                    }
258                    Jump::IfFalse => {
259                        let a = self.stack.last().ok_or_else(|| OpcodeErr {
260                            opcode: "JumpIfFalse".into(),
261                            message: "Empty array".into(),
262                        })?;
263
264                        match a {
265                            Bool(a) => {
266                                if !*a {
267                                    self.ip += j;
268                                }
269                            }
270                            _ => {
271                                return Err(OpcodeErr {
272                                    opcode: "JumpIfFalse".into(),
273                                    message: "Unsupported type".into(),
274                                });
275                            }
276                        }
277                    }
278                    Jump::IfNotNull => {
279                        let a = self.stack.last().ok_or_else(|| OpcodeErr {
280                            opcode: "JumpIfNull".into(),
281                            message: "Empty array".into(),
282                        })?;
283
284                        match a {
285                            Null => {}
286                            _ => {
287                                self.ip += j;
288                            }
289                        }
290                    }
291                    Jump::IfEnd => {
292                        let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
293                            opcode: "JumpIfEnd".into(),
294                            message: "Empty stack".into(),
295                        })?;
296
297                        if scope.iter >= scope.len {
298                            self.ip += j;
299                        }
300                    }
301                },
302                Opcode::In => {
303                    let b = self.pop()?;
304                    let a = self.pop()?;
305
306                    match (a, &b) {
307                        (Number(a), Array(b)) => {
308                            let arr = b.borrow();
309                            let is_in = arr.iter().any(|b| match b {
310                                Number(b) => a == *b,
311                                _ => false,
312                            });
313
314                            self.push(Bool(is_in));
315                        }
316                        (Number(v), Object(_)) => {
317                            let interval =
318                                IntervalObject::try_from_object(b).ok_or_else(|| OpcodeErr {
319                                    opcode: "In".into(),
320                                    message: "Failed to deconstruct interval".into(),
321                                })?;
322
323                            match (interval.left, interval.right) {
324                                (Number(l), Number(r)) => {
325                                    let mut is_open = false;
326
327                                    let first = match interval.left_bracket {
328                                        Bracket::LeftParenthesis => l < v,
329                                        Bracket::LeftSquareBracket => l <= v,
330                                        Bracket::RightParenthesis => {
331                                            is_open = true;
332                                            l > v
333                                        }
334                                        Bracket::RightSquareBracket => {
335                                            is_open = true;
336                                            l >= v
337                                        }
338                                        _ => {
339                                            return Err(OpcodeErr {
340                                                opcode: "In".into(),
341                                                message: "Unsupported bracket".into(),
342                                            })
343                                        }
344                                    };
345
346                                    let second = match interval.right_bracket {
347                                        Bracket::RightParenthesis => r > v,
348                                        Bracket::RightSquareBracket => r >= v,
349                                        Bracket::LeftParenthesis => r < v,
350                                        Bracket::LeftSquareBracket => r <= v,
351                                        _ => {
352                                            return Err(OpcodeErr {
353                                                opcode: "In".into(),
354                                                message: "Unsupported bracket".into(),
355                                            })
356                                        }
357                                    };
358
359                                    let open_stmt = is_open && (first || second);
360                                    let closed_stmt = !is_open && first && second;
361
362                                    self.push(Bool(open_stmt || closed_stmt));
363                                }
364                                _ => {
365                                    return Err(OpcodeErr {
366                                        opcode: "In".into(),
367                                        message: "Unsupported type".into(),
368                                    });
369                                }
370                            }
371                        }
372                        (String(a), Array(b)) => {
373                            let arr = b.borrow();
374                            let is_in = arr.iter().any(|b| match b {
375                                String(b) => &a == b,
376                                _ => false,
377                            });
378
379                            self.push(Bool(is_in));
380                        }
381                        (String(a), Object(b)) => {
382                            let obj = b.borrow();
383                            self.push(Bool(obj.contains_key(a.as_ref())));
384                        }
385                        (Bool(a), Array(b)) => {
386                            let arr = b.borrow();
387                            let is_in = arr.iter().any(|b| match b {
388                                Bool(b) => a == *b,
389                                _ => false,
390                            });
391
392                            self.push(Bool(is_in));
393                        }
394                        (Null, Array(b)) => {
395                            let arr = b.borrow();
396                            let is_in = arr.iter().any(|b| match b {
397                                Null => true,
398                                _ => false,
399                            });
400
401                            self.push(Bool(is_in));
402                        }
403                        _ => {
404                            return Err(OpcodeErr {
405                                opcode: "In".into(),
406                                message: "Unsupported type".into(),
407                            });
408                        }
409                    }
410                }
411                Opcode::Less => {
412                    let b = self.pop()?;
413                    let a = self.pop()?;
414
415                    match (a, b) {
416                        (Number(a), Number(b)) => self.push(Bool(a < b)),
417                        _ => {
418                            return Err(OpcodeErr {
419                                opcode: "Less".into(),
420                                message: "Unsupported type".into(),
421                            });
422                        }
423                    }
424                }
425                Opcode::More => {
426                    let b = self.pop()?;
427                    let a = self.pop()?;
428
429                    match (a, b) {
430                        (Number(a), Number(b)) => self.push(Bool(a > b)),
431                        _ => {
432                            return Err(OpcodeErr {
433                                opcode: "More".into(),
434                                message: "Unsupported type".into(),
435                            });
436                        }
437                    }
438                }
439                Opcode::LessOrEqual => {
440                    let b = self.pop()?;
441                    let a = self.pop()?;
442
443                    match (a, b) {
444                        (Number(a), Number(b)) => self.push(Bool(a <= b)),
445                        _ => {
446                            return Err(OpcodeErr {
447                                opcode: "LessOrEqual".into(),
448                                message: "Unsupported type".into(),
449                            });
450                        }
451                    }
452                }
453                Opcode::MoreOrEqual => {
454                    let b = self.pop()?;
455                    let a = self.pop()?;
456
457                    match (a, b) {
458                        (Number(a), Number(b)) => self.push(Bool(a >= b)),
459                        _ => {
460                            return Err(OpcodeErr {
461                                opcode: "MoreOrEqual".into(),
462                                message: "Unsupported type".into(),
463                            });
464                        }
465                    }
466                }
467                Opcode::Abs => {
468                    let a = self.pop()?;
469
470                    match a {
471                        Number(a) => self.push(Number(a.abs())),
472                        _ => {
473                            return Err(OpcodeErr {
474                                opcode: "Abs".into(),
475                                message: "Unsupported type".into(),
476                            });
477                        }
478                    }
479                }
480                Opcode::Round => {
481                    let var = self.pop()?;
482
483                    match var {
484                        Number(a) => self.push(Number(a.round())),
485                        _ => {
486                            return Err(OpcodeErr {
487                                opcode: "Round".into(),
488                                message: "Unsupported type".into(),
489                            });
490                        }
491                    }
492                }
493                Opcode::Ceil => {
494                    let var = self.pop()?;
495
496                    match var {
497                        Number(a) => self.push(Number(a.ceil())),
498                        _ => {
499                            return Err(OpcodeErr {
500                                opcode: "Ceil".into(),
501                                message: "Unsupported type".into(),
502                            });
503                        }
504                    }
505                }
506                Opcode::Floor => {
507                    let var = self.pop()?;
508
509                    match var {
510                        Number(a) => self.push(Number(a.floor())),
511                        _ => {
512                            return Err(OpcodeErr {
513                                opcode: "Floor".into(),
514                                message: "Unsupported type".into(),
515                            });
516                        }
517                    }
518                }
519                Opcode::Random => {
520                    let var = self.pop()?;
521                    match var {
522                        Number(a) => {
523                            let upper_range = a.round().to_i64().ok_or_else(|| OpcodeErr {
524                                opcode: "Random".into(),
525                                message: "Failed to determine upper range".into(),
526                            })?;
527
528                            let random_number = fastrand::i64(0..=upper_range);
529                            self.push(Number(Decimal::from(random_number)));
530                        }
531                        _ => {
532                            return Err(OpcodeErr {
533                                opcode: "Random".into(),
534                                message: "Unsupported type".into(),
535                            });
536                        }
537                    }
538                }
539                Opcode::Average => {
540                    let var = self.pop()?;
541
542                    match var {
543                        Array(a) => {
544                            let mut sum = Decimal::ZERO;
545                            let arr = a.borrow();
546                            arr.iter().try_for_each(|a| match a {
547                                Number(a) => {
548                                    sum += a;
549                                    Ok(())
550                                }
551                                _ => Err(OpcodeErr {
552                                    opcode: "Average".into(),
553                                    message: "Invalid array value".into(),
554                                }),
555                            })?;
556
557                            let avg = sum / Decimal::from(arr.len());
558                            self.push(Number(avg));
559                        }
560                        _ => {
561                            return Err(OpcodeErr {
562                                opcode: "Average".into(),
563                                message: "Unsupported type".into(),
564                            });
565                        }
566                    }
567                }
568                Opcode::Median => {
569                    let Array(a) = self.pop()? else {
570                        return Err(OpcodeErr {
571                            opcode: "Median".into(),
572                            message: "Unsupported type".into(),
573                        });
574                    };
575
576                    let arr = a.borrow();
577                    let mut num_arr = arr
578                        .iter()
579                        .map(|n| match n {
580                            Number(num) => Ok(*num),
581                            _ => Err(OpcodeErr {
582                                opcode: "Median".into(),
583                                message: "Unsupported type".into(),
584                            }),
585                        })
586                        .collect::<Result<Vec<_>, _>>()?;
587
588                    if num_arr.len() == 0 {
589                        return Err(OpcodeErr {
590                            opcode: "Median".into(),
591                            message: "Array is empty".into(),
592                        });
593                    }
594
595                    num_arr.sort();
596
597                    let center = num_arr.len() / 2;
598                    if num_arr.len() % 2 == 1 {
599                        let center_num = num_arr.get(center).ok_or_else(|| OpcodeErr {
600                            opcode: "Median".into(),
601                            message: "Array out of bounds".into(),
602                        })?;
603
604                        self.push(Number(*center_num));
605                    } else {
606                        let center_left = num_arr.get(center - 1).ok_or_else(|| OpcodeErr {
607                            opcode: "Median".into(),
608                            message: "Array out of bounds".into(),
609                        })?;
610
611                        let center_right = num_arr.get(center).ok_or_else(|| OpcodeErr {
612                            opcode: "Median".into(),
613                            message: "Array out of bounds".into(),
614                        })?;
615
616                        let median = ((*center_left) + (*center_right)) / dec!(2);
617                        self.push(Number(median));
618                    }
619                }
620                Opcode::Mode => {
621                    let Array(a) = self.pop()? else {
622                        return Err(OpcodeErr {
623                            opcode: "Mode".into(),
624                            message: "Unsupported type".into(),
625                        });
626                    };
627
628                    let arr = a.borrow();
629                    let num_arr = arr
630                        .iter()
631                        .map(|n| match n {
632                            Number(num) => Ok(*num),
633                            _ => Err(OpcodeErr {
634                                opcode: "Mode".into(),
635                                message: "Unsupported type".into(),
636                            }),
637                        })
638                        .collect::<Result<Vec<_>, _>>()?;
639
640                    if num_arr.len() == 0 {
641                        return Err(OpcodeErr {
642                            opcode: "Mode".into(),
643                            message: "Array is empty".into(),
644                        });
645                    }
646
647                    let mut map = HashMap::new();
648                    num_arr.iter().for_each(|n| {
649                        let count = map.entry(*n).or_insert(0);
650                        *count += 1;
651                    });
652
653                    let maybe_mode = map
654                        .iter()
655                        .max_by_key(|&(_, count)| *count)
656                        .map(|(val, _)| val);
657
658                    let mode = maybe_mode.ok_or_else(|| OpcodeErr {
659                        opcode: "Mode".into(),
660                        message: "Failed to find most common element".into(),
661                    })?;
662
663                    self.push(Number(*mode));
664                }
665                Opcode::Min => {
666                    let var = self.pop()?;
667
668                    match var {
669                        Array(a) => {
670                            let arr = a.borrow();
671                            let first_item = arr.get(0).ok_or_else(|| OpcodeErr {
672                                opcode: "Min".into(),
673                                message: "Empty array".into(),
674                            })?;
675
676                            let mut min: Decimal = match first_item {
677                                Number(a) => *a,
678                                _ => {
679                                    return Err(OpcodeErr {
680                                        opcode: "Min".into(),
681                                        message: "Unsupported array value".into(),
682                                    });
683                                }
684                            };
685
686                            arr.iter().try_for_each(|a| match a {
687                                Number(a) => {
688                                    if *a < min {
689                                        min = *a;
690                                    }
691                                    Ok(())
692                                }
693                                _ => Err(OpcodeErr {
694                                    opcode: "Min".into(),
695                                    message: "Unsupported array value".into(),
696                                }),
697                            })?;
698
699                            self.push(Number(min));
700                        }
701                        _ => {
702                            return Err(OpcodeErr {
703                                opcode: "Min".into(),
704                                message: "Unsupported type".into(),
705                            });
706                        }
707                    }
708                }
709                Opcode::Max => {
710                    let var = self.pop()?;
711
712                    match var {
713                        Array(a) => {
714                            let arr = a.borrow();
715                            let first_item = arr.get(0).ok_or_else(|| OpcodeErr {
716                                opcode: "Max".into(),
717                                message: "Empty array".into(),
718                            })?;
719
720                            let mut max: Decimal = match first_item {
721                                Number(a) => *a,
722                                _ => {
723                                    return Err(OpcodeErr {
724                                        opcode: "Max".into(),
725                                        message: "Unsupported array value".into(),
726                                    });
727                                }
728                            };
729
730                            arr.iter().try_for_each(|a| match a {
731                                Number(a) => {
732                                    if *a > max {
733                                        max = *a;
734                                    }
735                                    Ok(())
736                                }
737                                _ => Err(OpcodeErr {
738                                    opcode: "Max".into(),
739                                    message: "Unsupported array value".into(),
740                                }),
741                            })?;
742
743                            self.push(Number(max));
744                        }
745                        _ => {
746                            return Err(OpcodeErr {
747                                opcode: "Max".into(),
748                                message: "Unsupported type".into(),
749                            });
750                        }
751                    }
752                }
753                Opcode::Sum => {
754                    let var = self.pop()?;
755
756                    match var {
757                        Array(a) => {
758                            let mut sum = Decimal::ZERO;
759                            let arr = a.borrow();
760                            arr.iter().try_for_each(|a| match a {
761                                Number(a) => {
762                                    sum += a;
763                                    Ok(())
764                                }
765                                _ => Err(OpcodeErr {
766                                    opcode: "Sum".into(),
767                                    message: "Unsupported array value".into(),
768                                }),
769                            })?;
770
771                            self.push(Number(sum));
772                        }
773                        _ => {
774                            return Err(OpcodeErr {
775                                opcode: "Sum".into(),
776                                message: "Unsupported type".into(),
777                            });
778                        }
779                    }
780                }
781                Opcode::Add => {
782                    let b = self.pop()?;
783                    let a = self.pop()?;
784
785                    match (a, b) {
786                        (Number(a), Number(b)) => self.push(Number(a + b)),
787                        (String(a), String(b)) => {
788                            let mut c = StdString::with_capacity(a.len() + b.len());
789
790                            c.push_str(a.as_ref());
791                            c.push_str(b.as_ref());
792
793                            self.push(String(Rc::from(c.as_str())));
794                        }
795                        _ => {
796                            return Err(OpcodeErr {
797                                opcode: "Add".into(),
798                                message: "Unsupported type".into(),
799                            });
800                        }
801                    }
802                }
803                Opcode::Subtract => {
804                    let b = self.pop()?;
805                    let a = self.pop()?;
806
807                    match (a, b) {
808                        (Number(a), Number(b)) => self.push(Number(a - b)),
809                        _ => {
810                            return Err(OpcodeErr {
811                                opcode: "Subtract".into(),
812                                message: "Unsupported type".into(),
813                            });
814                        }
815                    }
816                }
817                Opcode::Multiply => {
818                    let b = self.pop()?;
819                    let a = self.pop()?;
820
821                    match (a, b) {
822                        (Number(a), Number(b)) => self.push(Number(a * b)),
823                        _ => {
824                            return Err(OpcodeErr {
825                                opcode: "Multiply".into(),
826                                message: "Unsupported type".into(),
827                            });
828                        }
829                    }
830                }
831                Opcode::Divide => {
832                    let b = self.pop()?;
833                    let a = self.pop()?;
834
835                    match (a, b) {
836                        (Number(a), Number(b)) => self.push(Number(a / b)),
837                        _ => {
838                            return Err(OpcodeErr {
839                                opcode: "Divide".into(),
840                                message: "Unsupported type".into(),
841                            });
842                        }
843                    }
844                }
845                Opcode::Modulo => {
846                    let b = self.pop()?;
847                    let a = self.pop()?;
848
849                    match (a, b) {
850                        (Number(a), Number(b)) => self.push(Number(a % b)),
851                        _ => {
852                            return Err(OpcodeErr {
853                                opcode: "Modulo".into(),
854                                message: "Unsupported type".into(),
855                            });
856                        }
857                    }
858                }
859                Opcode::Exponent => {
860                    let b = self.pop()?;
861                    let a = self.pop()?;
862
863                    match (a, b) {
864                        (Number(a), Number(b)) => {
865                            self.push(Number(a.powd(b)));
866                        }
867                        _ => {
868                            return Err(OpcodeErr {
869                                opcode: "Exponent".into(),
870                                message: "Unsupported type".into(),
871                            });
872                        }
873                    }
874                }
875                Opcode::Interval {
876                    left_bracket,
877                    right_bracket,
878                } => {
879                    let b = self.pop()?;
880                    let a = self.pop()?;
881
882                    match (&a, &b) {
883                        (Number(_), Number(_)) => {
884                            let interval = IntervalObject {
885                                left_bracket: *left_bracket,
886                                right_bracket: *right_bracket,
887                                left: a,
888                                right: b,
889                            };
890
891                            self.push(interval.to_variable());
892                        }
893                        _ => {
894                            return Err(OpcodeErr {
895                                opcode: "Interval".into(),
896                                message: "Unsupported type".into(),
897                            });
898                        }
899                    }
900                }
901                Opcode::Uppercase => {
902                    let a = self.pop()?;
903
904                    match a {
905                        String(a) => {
906                            self.push(String(a.to_uppercase().into()));
907                        }
908                        _ => {
909                            return Err(OpcodeErr {
910                                opcode: "Uppercase".into(),
911                                message: "Unsupported type".into(),
912                            });
913                        }
914                    }
915                }
916                Opcode::Trim => {
917                    let a = self.pop()?;
918
919                    match a {
920                        String(a) => {
921                            self.push(String(a.trim().into()));
922                        }
923                        _ => {
924                            return Err(OpcodeErr {
925                                opcode: "Trim".into(),
926                                message: "Unsupported type".into(),
927                            });
928                        }
929                    }
930                }
931                Opcode::Lowercase => {
932                    let a = self.pop()?;
933
934                    match a {
935                        String(a) => self.push(String(a.to_lowercase().into())),
936                        _ => {
937                            return Err(OpcodeErr {
938                                opcode: "Lowercase".into(),
939                                message: "Unsupported type".into(),
940                            });
941                        }
942                    }
943                }
944                Opcode::Contains => {
945                    let b = self.pop()?;
946                    let a = self.pop()?;
947
948                    match (a, &b) {
949                        (String(a), String(b)) => {
950                            self.push(Bool(a.contains(b.as_ref())));
951                        }
952                        (Array(a), _) => {
953                            let arr = a.borrow();
954                            let is_in = arr.iter().any(|a| match (a, &b) {
955                                (Number(a), Number(b)) => a == b,
956                                (String(a), String(b)) => a == b,
957                                (Bool(a), Bool(b)) => a == b,
958                                (Null, Null) => true,
959                                _ => false,
960                            });
961
962                            self.push(Bool(is_in));
963                        }
964                        _ => {
965                            return Err(OpcodeErr {
966                                opcode: "Contains".into(),
967                                message: "Unsupported type".into(),
968                            });
969                        }
970                    }
971                }
972                Opcode::Keys => {
973                    let current = self.pop()?;
974
975                    match current {
976                        Array(a) => {
977                            let arr = a.borrow();
978                            let indices = arr
979                                .iter()
980                                .enumerate()
981                                .map(|(index, _)| Number(index.into()))
982                                .collect();
983
984                            self.push(Array(Rc::new(RefCell::new(indices))));
985                        }
986                        Object(a) => {
987                            let obj = a.borrow();
988                            let keys = obj
989                                .iter()
990                                .map(|(key, _)| String(Rc::from(key.as_str())))
991                                .collect();
992
993                            self.push(Array(Rc::new(RefCell::new(keys))));
994                        }
995                        _ => {
996                            return Err(OpcodeErr {
997                                opcode: "Keys".into(),
998                                message: "Unsupported type".into(),
999                            })
1000                        }
1001                    }
1002                }
1003                Opcode::Values => {
1004                    let current = self.pop()?;
1005
1006                    match current {
1007                        Object(a) => {
1008                            let obj = a.borrow();
1009                            let values: Vec<Variable> = obj.values().cloned().collect();
1010
1011                            self.push(Array(Rc::new(RefCell::new(values))));
1012                        }
1013                        _ => {
1014                            return Err(OpcodeErr {
1015                                opcode: "Values".into(),
1016                                message: "Unsupported type".into(),
1017                            })
1018                        }
1019                    }
1020                }
1021                Opcode::StartsWith => {
1022                    let b = self.pop()?;
1023                    let a = self.pop()?;
1024
1025                    match (a, b) {
1026                        (String(a), String(b)) => {
1027                            self.push(Bool(a.starts_with(b.as_ref())));
1028                        }
1029                        _ => {
1030                            return Err(OpcodeErr {
1031                                opcode: "StartsWith".into(),
1032                                message: "Unsupported type".into(),
1033                            });
1034                        }
1035                    }
1036                }
1037                Opcode::EndsWith => {
1038                    let b = self.pop()?;
1039                    let a = self.pop()?;
1040
1041                    match (a, b) {
1042                        (String(a), String(b)) => {
1043                            self.push(Bool(a.ends_with(b.as_ref())));
1044                        }
1045                        _ => {
1046                            return Err(OpcodeErr {
1047                                opcode: "EndsWith".into(),
1048                                message: "Unsupported type".into(),
1049                            });
1050                        }
1051                    }
1052                }
1053                Opcode::Matches => {
1054                    let b = self.pop()?;
1055                    let a = self.pop()?;
1056
1057                    let (String(a), String(b)) = (a, b) else {
1058                        return Err(OpcodeErr {
1059                            opcode: "Matches".into(),
1060                            message: "Unsupported type".into(),
1061                        });
1062                    };
1063
1064                    let regex = Regex::new(b.as_ref()).map_err(|_| OpcodeErr {
1065                        opcode: "Matches".into(),
1066                        message: "Invalid regular expression".into(),
1067                    })?;
1068
1069                    self.push(Bool(regex.is_match(a.as_ref())));
1070                }
1071                Opcode::FuzzyMatch => {
1072                    let b = self.pop()?;
1073                    let a = self.pop()?;
1074
1075                    let String(b) = b else {
1076                        return Err(OpcodeErr {
1077                            opcode: "FuzzyMatch".into(),
1078                            message: "Unsupported type".into(),
1079                        });
1080                    };
1081
1082                    match a {
1083                        String(a) => {
1084                            let sim =
1085                                strsim::normalized_damerau_levenshtein(a.as_ref(), b.as_ref());
1086                            // This is okay, as NDL will return [0, 1]
1087                            self.push(Number(Decimal::from_f64(sim).unwrap_or(dec!(0))));
1088                        }
1089                        Array(_a) => {
1090                            let a = _a.borrow();
1091                            let mut sims = Vec::with_capacity(a.len());
1092                            for v in a.iter() {
1093                                let String(s) = v else {
1094                                    return Err(OpcodeErr {
1095                                        opcode: "FuzzyMatch".into(),
1096                                        message: "Unsupported type".into(),
1097                                    });
1098                                };
1099
1100                                let sim = Decimal::from_f64(
1101                                    strsim::normalized_damerau_levenshtein(s.as_ref(), b.as_ref()),
1102                                )
1103                                .unwrap_or(dec!(0));
1104                                sims.push(Number(sim));
1105                            }
1106
1107                            self.push(Variable::from_array(sims))
1108                        }
1109                        _ => {
1110                            return Err(OpcodeErr {
1111                                opcode: "FuzzyMatch".into(),
1112                                message: "Unsupported type".into(),
1113                            })
1114                        }
1115                    }
1116                }
1117                Opcode::Split => {
1118                    let b = self.pop()?;
1119                    let a = self.pop()?;
1120
1121                    match (a, b) {
1122                        (String(a), String(b)) => {
1123                            let arr = Vec::from_iter(
1124                                a.split(b.as_ref())
1125                                    .into_iter()
1126                                    .map(|s| String(s.to_string().into())),
1127                            );
1128
1129                            self.push(Variable::from_array(arr));
1130                        }
1131                        _ => {
1132                            return Err(OpcodeErr {
1133                                opcode: "Split".into(),
1134                                message: "Unsupported type".into(),
1135                            });
1136                        }
1137                    }
1138                }
1139                Opcode::Join => {
1140                    let b = self.pop()?;
1141                    let a = self.pop()?;
1142
1143                    let (Array(a), String(separator)) = (a, &b) else {
1144                        return Err(OpcodeErr {
1145                            opcode: "Join".into(),
1146                            message: "Unsupported type".into(),
1147                        });
1148                    };
1149
1150                    let arr = a.borrow();
1151                    let parts = arr
1152                        .iter()
1153                        .enumerate()
1154                        .map(|(i, var)| match var {
1155                            String(str) => Ok(str.clone()),
1156                            _ => Err(OpcodeErr {
1157                                opcode: "Join".into(),
1158                                message: format!("Unexpected type in array on index {i}"),
1159                            }),
1160                        })
1161                        .collect::<Result<Vec<_>, _>>()?;
1162
1163                    let str_capacity = parts
1164                        .iter()
1165                        .fold(separator.len() * (parts.len() - 1), |acc, s| acc + s.len());
1166
1167                    let mut s = StdString::with_capacity(str_capacity);
1168                    let mut it = parts.into_iter().peekable();
1169                    while let Some(part) = it.next() {
1170                        s.push_str(part.as_ref());
1171                        if it.peek().is_some() {
1172                            s.push_str(separator);
1173                        }
1174                    }
1175
1176                    self.push(String(Rc::from(s)));
1177                }
1178                Opcode::Extract => {
1179                    let b = self.pop()?;
1180                    let a = self.pop()?;
1181
1182                    let (String(a), String(b)) = (a, b) else {
1183                        return Err(OpcodeErr {
1184                            opcode: "Matches".into(),
1185                            message: "Unsupported type".into(),
1186                        });
1187                    };
1188
1189                    let regex = Regex::new(b.as_ref()).map_err(|_| OpcodeErr {
1190                        opcode: "Matches".into(),
1191                        message: "Invalid regular expression".into(),
1192                    })?;
1193
1194                    let captures = regex
1195                        .captures(a.as_ref())
1196                        .map(|capture| {
1197                            capture
1198                                .iter()
1199                                .map(|c| c.map(|c| c.as_str()))
1200                                .filter_map(|c| c)
1201                                .map(|s| String(Rc::from(s)))
1202                                .collect()
1203                        })
1204                        .unwrap_or_default();
1205
1206                    self.push(Variable::from_array(captures));
1207                }
1208                Opcode::DateManipulation(operation) => {
1209                    let timestamp = self.pop()?;
1210
1211                    let time: NaiveDateTime = (&timestamp).try_into()?;
1212                    let var = match operation.as_ref() {
1213                        "year" => Number(time.year().into()),
1214                        "dayOfWeek" => Number(time.weekday().number_from_monday().into()),
1215                        "dayOfMonth" => Number(time.day().into()),
1216                        "dayOfYear" => Number(time.ordinal().into()),
1217                        "weekOfYear" => Number(time.iso_week().week().into()),
1218                        "monthOfYear" => Number(time.month().into()),
1219                        "monthString" => String(Rc::from(time.format("%b").to_string())),
1220                        "weekdayString" => String(Rc::from(time.weekday().to_string())),
1221                        "dateString" => String(Rc::from(time.to_string())),
1222                        _ => {
1223                            return Err(OpcodeErr {
1224                                opcode: "DateManipulation".into(),
1225                                message: "Unsupported operation".into(),
1226                            });
1227                        }
1228                    };
1229
1230                    self.push(var);
1231                }
1232                Opcode::DateFunction(name) => {
1233                    let unit_var = self.pop()?;
1234                    let timestamp = self.pop()?;
1235
1236                    let date_time: NaiveDateTime = (&timestamp).try_into()?;
1237                    let String(unit_name) = unit_var else {
1238                        return Err(OpcodeErr {
1239                            opcode: "DateFunction".into(),
1240                            message: "Unknown date function".into(),
1241                        });
1242                    };
1243
1244                    let s = match name.as_ref() {
1245                        "startOf" => date_time_start_of(date_time, unit_name.as_ref().try_into()?),
1246                        "endOf" => date_time_end_of(date_time, unit_name.as_ref().try_into()?),
1247                        _ => {
1248                            return Err(OpcodeErr {
1249                                opcode: "DateManipulation".into(),
1250                                message: "Unsupported operation".into(),
1251                            });
1252                        }
1253                    }
1254                    .ok_or_else(|| OpcodeErr {
1255                        opcode: "DateFunction".into(),
1256                        message: "Failed to run DateFunction".into(),
1257                    })?;
1258
1259                    #[allow(deprecated)]
1260                    self.push(Number(s.timestamp().into()));
1261                }
1262                Opcode::Slice => {
1263                    let from_var = self.pop()?;
1264                    let to_var = self.pop()?;
1265                    let current = self.pop()?;
1266
1267                    match (from_var, to_var) {
1268                        (Number(f), Number(t)) => {
1269                            let from = f.to_usize().ok_or_else(|| OpcodeErr {
1270                                opcode: "Slice".into(),
1271                                message: "Failed to get range from".into(),
1272                            })?;
1273                            let to = t.to_usize().ok_or_else(|| OpcodeErr {
1274                                opcode: "Slice".into(),
1275                                message: "Failed to get range to".into(),
1276                            })?;
1277
1278                            match current {
1279                                Array(a) => {
1280                                    let arr = a.borrow();
1281                                    let slice = arr.get(from..=to).ok_or_else(|| OpcodeErr {
1282                                        opcode: "Slice".into(),
1283                                        message: "Index out of range".into(),
1284                                    })?;
1285
1286                                    self.push(Variable::from_array(slice.to_vec()));
1287                                }
1288                                String(s) => {
1289                                    let slice = s.get(from..=to).ok_or_else(|| OpcodeErr {
1290                                        opcode: "Slice".into(),
1291                                        message: "Index out of range".into(),
1292                                    })?;
1293
1294                                    self.push(String(Rc::from(slice)));
1295                                }
1296                                _ => {
1297                                    return Err(OpcodeErr {
1298                                        opcode: "Slice".into(),
1299                                        message: "Unsupported type".into(),
1300                                    });
1301                                }
1302                            }
1303                        }
1304                        _ => {
1305                            return Err(OpcodeErr {
1306                                opcode: "Slice".into(),
1307                                message: "Unsupported type".into(),
1308                            });
1309                        }
1310                    }
1311                }
1312                Opcode::Array => {
1313                    let size = self.pop()?;
1314                    let Number(s) = size else {
1315                        return Err(OpcodeErr {
1316                            opcode: "Array".into(),
1317                            message: "Unsupported type".into(),
1318                        });
1319                    };
1320
1321                    let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
1322                        opcode: "Array".into(),
1323                        message: "Failed to extract argument".into(),
1324                    })?;
1325
1326                    let mut arr = Vec::with_capacity(to);
1327                    for _ in 0..to {
1328                        arr.push(self.pop()?);
1329                    }
1330                    arr.reverse();
1331
1332                    self.push(Variable::from_array(arr));
1333                }
1334                Opcode::Object => {
1335                    let size = self.pop()?;
1336                    let Number(s) = size else {
1337                        return Err(OpcodeErr {
1338                            opcode: "Array".into(),
1339                            message: "Unsupported type".into(),
1340                        });
1341                    };
1342
1343                    let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
1344                        opcode: "Array".into(),
1345                        message: "Failed to extract argument".into(),
1346                    })?;
1347
1348                    let mut map = HashMap::with_capacity(to);
1349                    for _ in 0..to {
1350                        let value = self.pop()?;
1351                        let String(key) = self.pop()? else {
1352                            return Err(OpcodeErr {
1353                                opcode: "Object".into(),
1354                                message: "Unexpected key value".to_string(),
1355                            });
1356                        };
1357
1358                        map.insert(key.to_string(), value);
1359                    }
1360
1361                    self.push(Variable::from_object(map));
1362                }
1363                Opcode::Len => {
1364                    let current = self.stack.last().ok_or_else(|| OpcodeErr {
1365                        opcode: "Len".into(),
1366                        message: "Empty stack".into(),
1367                    })?;
1368
1369                    let len = match current {
1370                        String(s) => s.len(),
1371                        Array(s) => {
1372                            let arr = s.borrow();
1373                            arr.len()
1374                        }
1375                        _ => {
1376                            return Err(OpcodeErr {
1377                                opcode: "Len".into(),
1378                                message: "Unsupported type".into(),
1379                            });
1380                        }
1381                    };
1382
1383                    self.push(Number(len.into()));
1384                }
1385                Opcode::Flatten => {
1386                    let current = self.pop()?;
1387                    let Array(a) = current else {
1388                        return Err(OpcodeErr {
1389                            opcode: "Flatten".into(),
1390                            message: "Unsupported type".into(),
1391                        });
1392                    };
1393
1394                    let arr = a.borrow();
1395
1396                    let mut flat_arr = Vec::with_capacity(arr.len());
1397                    arr.iter().for_each(|v| match v {
1398                        Array(b) => {
1399                            let arr = b.borrow();
1400                            arr.iter().for_each(|v| flat_arr.push(v.clone()))
1401                        }
1402                        _ => flat_arr.push(v.clone()),
1403                    });
1404
1405                    self.push(Variable::from_array(flat_arr));
1406                }
1407                Opcode::ParseDateTime => {
1408                    let a = self.pop()?;
1409                    let ts = match a {
1410                        #[allow(deprecated)]
1411                        String(a) => date_time(a.as_ref())?.timestamp(),
1412                        Number(a) => a.to_i64().ok_or_else(|| OpcodeErr {
1413                            opcode: "ParseDateTime".into(),
1414                            message: "Number overflow".into(),
1415                        })?,
1416                        _ => {
1417                            return Err(OpcodeErr {
1418                                opcode: "ParseDateTime".into(),
1419                                message: "Unsupported type".into(),
1420                            });
1421                        }
1422                    };
1423
1424                    self.push(Number(ts.into()));
1425                }
1426                Opcode::ParseTime => {
1427                    let a = self.pop()?;
1428                    let ts = match a {
1429                        String(a) => time(a.as_ref())?.num_seconds_from_midnight(),
1430                        Number(a) => a.to_u32().ok_or_else(|| OpcodeErr {
1431                            opcode: "ParseTime".into(),
1432                            message: "Number overflow".into(),
1433                        })?,
1434                        _ => {
1435                            return Err(OpcodeErr {
1436                                opcode: "ParseTime".into(),
1437                                message: "Unsupported type".into(),
1438                            });
1439                        }
1440                    };
1441
1442                    self.push(Number(ts.into()));
1443                }
1444                Opcode::ParseDuration => {
1445                    let a = self.pop()?;
1446
1447                    let dur = match a {
1448                        String(a) => humantime::parse_duration(a.as_ref())
1449                            .map_err(|_| ParseDateTimeErr {
1450                                timestamp: a.to_string(),
1451                            })?
1452                            .as_secs(),
1453                        Number(n) => n.to_u64().ok_or_else(|| OpcodeErr {
1454                            opcode: "ParseDuration".into(),
1455                            message: "Number overflow".into(),
1456                        })?,
1457                        _ => {
1458                            return Err(OpcodeErr {
1459                                opcode: "ParseDuration".into(),
1460                                message: "Unsupported type".into(),
1461                            });
1462                        }
1463                    };
1464
1465                    self.push(Number(dur.into()));
1466                }
1467                Opcode::TypeCheck(check) => {
1468                    let var = self.pop()?;
1469
1470                    let is_equal = match (check, var) {
1471                        (TypeCheckKind::Numeric, String(str)) => {
1472                            Decimal::from_str_exact(str.as_ref()).is_ok()
1473                        }
1474                        (TypeCheckKind::Numeric, Number(_)) => true,
1475                        (TypeCheckKind::Numeric, _) => false,
1476                    };
1477
1478                    self.push(Bool(is_equal));
1479                }
1480                Opcode::TypeConversion(conversion) => {
1481                    let var = self.pop()?;
1482
1483                    let converted_var = match (conversion, &var) {
1484                        (TypeConversionKind::String, String(_)) => var,
1485                        (TypeConversionKind::String, Number(num)) => {
1486                            String(Rc::from(num.to_string().as_str()))
1487                        }
1488                        (TypeConversionKind::String, Bool(v)) => {
1489                            String(Rc::from(v.to_string().as_str()))
1490                        }
1491                        (TypeConversionKind::String, Null) => String(Rc::from("null")),
1492                        (TypeConversionKind::String, _) => {
1493                            return Err(OpcodeErr {
1494                                opcode: "TypeConversion".into(),
1495                                message: format!(
1496                                    "Type {} cannot be converted to string",
1497                                    var.type_name()
1498                                ),
1499                            });
1500                        }
1501                        (TypeConversionKind::Number, String(str)) => {
1502                            let parsed_number =
1503                                Decimal::from_str_exact(str.trim()).map_err(|_| OpcodeErr {
1504                                    opcode: "TypeConversion".into(),
1505                                    message: "Failed to parse string to number".into(),
1506                                })?;
1507
1508                            Number(parsed_number)
1509                        }
1510                        (TypeConversionKind::Number, Number(_)) => var,
1511                        (TypeConversionKind::Number, Bool(v)) => {
1512                            let number = if *v { dec!(1) } else { dec!(0) };
1513                            Number(number)
1514                        }
1515                        (TypeConversionKind::Number, _) => {
1516                            return Err(OpcodeErr {
1517                                opcode: "TypeConversion".into(),
1518                                message: format!(
1519                                    "Type {} cannot be converted to number",
1520                                    var.type_name()
1521                                ),
1522                            });
1523                        }
1524                        (TypeConversionKind::Bool, Number(n)) => Bool(!n.is_zero()),
1525                        (TypeConversionKind::Bool, String(s)) => {
1526                            let value = match (*s).trim() {
1527                                "true" => true,
1528                                "false" => false,
1529                                _ => s.is_empty(),
1530                            };
1531
1532                            Bool(value)
1533                        }
1534                        (TypeConversionKind::Bool, Bool(_)) => var,
1535                        (TypeConversionKind::Bool, Null) => Bool(false),
1536                        (TypeConversionKind::Bool, Object(_) | Array(_)) => Bool(true),
1537                    };
1538
1539                    self.push(converted_var);
1540                }
1541                Opcode::GetType => {
1542                    let var = self.pop()?;
1543                    self.push(String(Rc::from(var.type_name())));
1544                }
1545                Opcode::IncrementIt => {
1546                    let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
1547                        opcode: "IncrementIt".into(),
1548                        message: "Empty scope".into(),
1549                    })?;
1550
1551                    scope.iter += 1;
1552                }
1553                Opcode::IncrementCount => {
1554                    let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
1555                        opcode: "IncrementCount".into(),
1556                        message: "Empty scope".into(),
1557                    })?;
1558
1559                    scope.count += 1;
1560                }
1561                Opcode::GetCount => {
1562                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
1563                        opcode: "GetCount".into(),
1564                        message: "Empty scope".into(),
1565                    })?;
1566
1567                    self.push(Number(scope.count.into()));
1568                }
1569                Opcode::GetLen => {
1570                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
1571                        opcode: "GetLen".into(),
1572                        message: "Empty scope".into(),
1573                    })?;
1574
1575                    self.push(Number(scope.len.into()));
1576                }
1577                Opcode::Pointer => {
1578                    let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
1579                        opcode: "Pointer".into(),
1580                        message: "Empty scope".into(),
1581                    })?;
1582
1583                    match &scope.array {
1584                        Array(a) => {
1585                            let a_cloned = a.clone();
1586                            let arr = a_cloned.borrow();
1587                            let variable =
1588                                arr.get(scope.iter).cloned().ok_or_else(|| OpcodeErr {
1589                                    opcode: "Pointer".into(),
1590                                    message: "Scope array out of bounds".into(),
1591                                })?;
1592
1593                            self.push(variable);
1594                        }
1595                        _ => {
1596                            return Err(OpcodeErr {
1597                                opcode: "Pointer".into(),
1598                                message: "Unsupported scope type".into(),
1599                            });
1600                        }
1601                    }
1602                }
1603                Opcode::Begin => {
1604                    let a = self.pop()?;
1605                    let arr_len = match &a {
1606                        Array(a) => {
1607                            let arr = a.borrow();
1608                            Some(arr.len())
1609                        }
1610                        _ => None,
1611                    };
1612
1613                    match arr_len {
1614                        Some(len) => self.scopes.push(Scope {
1615                            array: a,
1616                            count: 0,
1617                            len,
1618                            iter: 0,
1619                        }),
1620                        None => {
1621                            return Err(OpcodeErr {
1622                                opcode: "Begin".into(),
1623                                message: "Unsupported type".into(),
1624                            })
1625                        }
1626                    }
1627                }
1628                Opcode::End => {
1629                    self.scopes.pop();
1630                }
1631            }
1632        }
1633
1634        self.pop()
1635    }
1636}