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