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