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