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