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