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