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