1use crate::compiler::{FetchFastTarget, Jump, Opcode};
2use crate::functions::registry::FunctionRegistry;
3use crate::functions::{internal, Arguments};
4use crate::lexer::Bracket;
5use crate::variable::Variable;
6use crate::variable::Variable::*;
7use crate::vm::error::VMError::*;
8use crate::vm::error::VMResult;
9use crate::vm::variable::IntervalObject;
10use ahash::{HashMap, HashMapExt};
11use rust_decimal::prelude::ToPrimitive;
12use rust_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 _ => {
220 self.push(Bool(false));
221 }
222 }
223 }
224 Opcode::Jump(kind, j) => match kind {
225 Jump::Forward => self.ip += j,
226 Jump::Backward => self.ip -= j,
227 Jump::IfTrue => {
228 let a = self.stack.last().ok_or_else(|| OpcodeErr {
229 opcode: "JumpIfTrue".into(),
230 message: "Undefined object key".into(),
231 })?;
232 match a {
233 Bool(a) => {
234 if *a {
235 self.ip += j;
236 }
237 }
238 _ => {
239 return Err(OpcodeErr {
240 opcode: "JumpIfTrue".into(),
241 message: "Unsupported type".into(),
242 });
243 }
244 }
245 }
246 Jump::IfFalse => {
247 let a = self.stack.last().ok_or_else(|| OpcodeErr {
248 opcode: "JumpIfFalse".into(),
249 message: "Empty array".into(),
250 })?;
251
252 match a {
253 Bool(a) => {
254 if !*a {
255 self.ip += j;
256 }
257 }
258 _ => {
259 return Err(OpcodeErr {
260 opcode: "JumpIfFalse".into(),
261 message: "Unsupported type".into(),
262 });
263 }
264 }
265 }
266 Jump::IfNotNull => {
267 let a = self.stack.last().ok_or_else(|| OpcodeErr {
268 opcode: "JumpIfNull".into(),
269 message: "Empty array".into(),
270 })?;
271
272 match a {
273 Null => {}
274 _ => {
275 self.ip += j;
276 }
277 }
278 }
279 Jump::IfEnd => {
280 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
281 opcode: "JumpIfEnd".into(),
282 message: "Empty stack".into(),
283 })?;
284
285 if scope.iter >= scope.len {
286 self.ip += j;
287 }
288 }
289 },
290 Opcode::In => {
291 let b = self.pop()?;
292 let a = self.pop()?;
293
294 match (a, &b) {
295 (Number(a), Array(b)) => {
296 let arr = b.borrow();
297 let is_in = arr.iter().any(|b| match b {
298 Number(b) => a == *b,
299 _ => false,
300 });
301
302 self.push(Bool(is_in));
303 }
304 (Number(v), Object(_)) => {
305 let interval =
306 IntervalObject::try_from_object(b).ok_or_else(|| OpcodeErr {
307 opcode: "In".into(),
308 message: "Failed to deconstruct interval".into(),
309 })?;
310
311 match (interval.left, interval.right) {
312 (Number(l), Number(r)) => {
313 let mut is_open = false;
314
315 let first = match interval.left_bracket {
316 Bracket::LeftParenthesis => l < v,
317 Bracket::LeftSquareBracket => l <= v,
318 Bracket::RightParenthesis => {
319 is_open = true;
320 l > v
321 }
322 Bracket::RightSquareBracket => {
323 is_open = true;
324 l >= v
325 }
326 _ => {
327 return Err(OpcodeErr {
328 opcode: "In".into(),
329 message: "Unsupported bracket".into(),
330 })
331 }
332 };
333
334 let second = match interval.right_bracket {
335 Bracket::RightParenthesis => r > v,
336 Bracket::RightSquareBracket => r >= v,
337 Bracket::LeftParenthesis => r < v,
338 Bracket::LeftSquareBracket => r <= v,
339 _ => {
340 return Err(OpcodeErr {
341 opcode: "In".into(),
342 message: "Unsupported bracket".into(),
343 })
344 }
345 };
346
347 let open_stmt = is_open && (first || second);
348 let closed_stmt = !is_open && first && second;
349
350 self.push(Bool(open_stmt || closed_stmt));
351 }
352 _ => {
353 return Err(OpcodeErr {
354 opcode: "In".into(),
355 message: "Unsupported type".into(),
356 });
357 }
358 }
359 }
360 (String(a), Array(b)) => {
361 let arr = b.borrow();
362 let is_in = arr.iter().any(|b| match b {
363 String(b) => &a == b,
364 _ => false,
365 });
366
367 self.push(Bool(is_in));
368 }
369 (String(a), Object(b)) => {
370 let obj = b.borrow();
371 self.push(Bool(obj.contains_key(a.as_ref())));
372 }
373 (Bool(a), Array(b)) => {
374 let arr = b.borrow();
375 let is_in = arr.iter().any(|b| match b {
376 Bool(b) => a == *b,
377 _ => false,
378 });
379
380 self.push(Bool(is_in));
381 }
382 (Null, Array(b)) => {
383 let arr = b.borrow();
384 let is_in = arr.iter().any(|b| match b {
385 Null => true,
386 _ => false,
387 });
388
389 self.push(Bool(is_in));
390 }
391 _ => {
392 return Err(OpcodeErr {
393 opcode: "In".into(),
394 message: "Unsupported type".into(),
395 });
396 }
397 }
398 }
399 Opcode::Less => {
400 let b = self.pop()?;
401 let a = self.pop()?;
402
403 match (a, b) {
404 (Number(a), Number(b)) => self.push(Bool(a < b)),
405 _ => {
406 return Err(OpcodeErr {
407 opcode: "Less".into(),
408 message: "Unsupported type".into(),
409 });
410 }
411 }
412 }
413 Opcode::More => {
414 let b = self.pop()?;
415 let a = self.pop()?;
416
417 match (a, b) {
418 (Number(a), Number(b)) => self.push(Bool(a > b)),
419 _ => {
420 return Err(OpcodeErr {
421 opcode: "More".into(),
422 message: "Unsupported type".into(),
423 });
424 }
425 }
426 }
427 Opcode::LessOrEqual => {
428 let b = self.pop()?;
429 let a = self.pop()?;
430
431 match (a, b) {
432 (Number(a), Number(b)) => self.push(Bool(a <= b)),
433 _ => {
434 return Err(OpcodeErr {
435 opcode: "LessOrEqual".into(),
436 message: "Unsupported type".into(),
437 });
438 }
439 }
440 }
441 Opcode::MoreOrEqual => {
442 let b = self.pop()?;
443 let a = self.pop()?;
444
445 match (a, b) {
446 (Number(a), Number(b)) => self.push(Bool(a >= b)),
447 _ => {
448 return Err(OpcodeErr {
449 opcode: "MoreOrEqual".into(),
450 message: "Unsupported type".into(),
451 });
452 }
453 }
454 }
455 Opcode::Add => {
456 let b = self.pop()?;
457 let a = self.pop()?;
458
459 match (a, b) {
460 (Number(a), Number(b)) => self.push(Number(a + b)),
461 (String(a), String(b)) => {
462 let mut c = StdString::with_capacity(a.len() + b.len());
463
464 c.push_str(a.as_ref());
465 c.push_str(b.as_ref());
466
467 self.push(String(Rc::from(c.as_str())));
468 }
469 _ => {
470 return Err(OpcodeErr {
471 opcode: "Add".into(),
472 message: "Unsupported type".into(),
473 });
474 }
475 }
476 }
477 Opcode::Subtract => {
478 let b = self.pop()?;
479 let a = self.pop()?;
480
481 match (a, b) {
482 (Number(a), Number(b)) => self.push(Number(a - b)),
483 _ => {
484 return Err(OpcodeErr {
485 opcode: "Subtract".into(),
486 message: "Unsupported type".into(),
487 });
488 }
489 }
490 }
491 Opcode::Multiply => {
492 let b = self.pop()?;
493 let a = self.pop()?;
494
495 match (a, b) {
496 (Number(a), Number(b)) => self.push(Number(a * b)),
497 _ => {
498 return Err(OpcodeErr {
499 opcode: "Multiply".into(),
500 message: "Unsupported type".into(),
501 });
502 }
503 }
504 }
505 Opcode::Divide => {
506 let b = self.pop()?;
507 let a = self.pop()?;
508
509 match (a, b) {
510 (Number(a), Number(b)) => self.push(Number(a / b)),
511 _ => {
512 return Err(OpcodeErr {
513 opcode: "Divide".into(),
514 message: "Unsupported type".into(),
515 });
516 }
517 }
518 }
519 Opcode::Modulo => {
520 let b = self.pop()?;
521 let a = self.pop()?;
522
523 match (a, b) {
524 (Number(a), Number(b)) => self.push(Number(a % b)),
525 _ => {
526 return Err(OpcodeErr {
527 opcode: "Modulo".into(),
528 message: "Unsupported type".into(),
529 });
530 }
531 }
532 }
533 Opcode::Exponent => {
534 let b = self.pop()?;
535 let a = self.pop()?;
536
537 match (a, b) {
538 (Number(a), Number(b)) => {
539 self.push(Number(a.powd(b)));
540 }
541 _ => {
542 return Err(OpcodeErr {
543 opcode: "Exponent".into(),
544 message: "Unsupported type".into(),
545 });
546 }
547 }
548 }
549 Opcode::Interval {
550 left_bracket,
551 right_bracket,
552 } => {
553 let b = self.pop()?;
554 let a = self.pop()?;
555
556 match (&a, &b) {
557 (Number(_), Number(_)) => {
558 let interval = IntervalObject {
559 left_bracket: *left_bracket,
560 right_bracket: *right_bracket,
561 left: a,
562 right: b,
563 };
564
565 self.push(interval.to_variable());
566 }
567 _ => {
568 return Err(OpcodeErr {
569 opcode: "Interval".into(),
570 message: "Unsupported type".into(),
571 });
572 }
573 }
574 }
575 Opcode::Join => {
576 let b = self.pop()?;
577 let a = self.pop()?;
578
579 let (Array(a), String(separator)) = (a, &b) else {
580 return Err(OpcodeErr {
581 opcode: "Join".into(),
582 message: "Unsupported type".into(),
583 });
584 };
585
586 let arr = a.borrow();
587 let parts = arr
588 .iter()
589 .enumerate()
590 .map(|(i, var)| match var {
591 String(str) => Ok(str.clone()),
592 _ => Err(OpcodeErr {
593 opcode: "Join".into(),
594 message: format!("Unexpected type in array on index {i}"),
595 }),
596 })
597 .collect::<Result<Vec<_>, _>>()?;
598
599 let str_capacity = parts
600 .iter()
601 .fold(separator.len() * (parts.len() - 1), |acc, s| acc + s.len());
602
603 let mut s = StdString::with_capacity(str_capacity);
604 let mut it = parts.into_iter().peekable();
605 while let Some(part) = it.next() {
606 s.push_str(part.as_ref());
607 if it.peek().is_some() {
608 s.push_str(separator);
609 }
610 }
611
612 self.push(String(Rc::from(s)));
613 }
614 Opcode::Slice => {
615 let from_var = self.pop()?;
616 let to_var = self.pop()?;
617 let current = self.pop()?;
618
619 match (from_var, to_var) {
620 (Number(f), Number(t)) => {
621 let from = f.to_usize().ok_or_else(|| OpcodeErr {
622 opcode: "Slice".into(),
623 message: "Failed to get range from".into(),
624 })?;
625 let to = t.to_usize().ok_or_else(|| OpcodeErr {
626 opcode: "Slice".into(),
627 message: "Failed to get range to".into(),
628 })?;
629
630 match current {
631 Array(a) => {
632 let arr = a.borrow();
633 let slice = arr.get(from..=to).ok_or_else(|| OpcodeErr {
634 opcode: "Slice".into(),
635 message: "Index out of range".into(),
636 })?;
637
638 self.push(Variable::from_array(slice.to_vec()));
639 }
640 String(s) => {
641 let slice = s.get(from..=to).ok_or_else(|| OpcodeErr {
642 opcode: "Slice".into(),
643 message: "Index out of range".into(),
644 })?;
645
646 self.push(String(Rc::from(slice)));
647 }
648 _ => {
649 return Err(OpcodeErr {
650 opcode: "Slice".into(),
651 message: "Unsupported type".into(),
652 });
653 }
654 }
655 }
656 _ => {
657 return Err(OpcodeErr {
658 opcode: "Slice".into(),
659 message: "Unsupported type".into(),
660 });
661 }
662 }
663 }
664 Opcode::Array => {
665 let size = self.pop()?;
666 let Number(s) = size else {
667 return Err(OpcodeErr {
668 opcode: "Array".into(),
669 message: "Unsupported type".into(),
670 });
671 };
672
673 let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
674 opcode: "Array".into(),
675 message: "Failed to extract argument".into(),
676 })?;
677
678 let mut arr = Vec::with_capacity(to);
679 for _ in 0..to {
680 arr.push(self.pop()?);
681 }
682 arr.reverse();
683
684 self.push(Variable::from_array(arr));
685 }
686 Opcode::Object => {
687 let size = self.pop()?;
688 let Number(s) = size else {
689 return Err(OpcodeErr {
690 opcode: "Array".into(),
691 message: "Unsupported type".into(),
692 });
693 };
694
695 let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
696 opcode: "Array".into(),
697 message: "Failed to extract argument".into(),
698 })?;
699
700 let mut map = HashMap::with_capacity(to);
701 for _ in 0..to {
702 let value = self.pop()?;
703 let String(key) = self.pop()? else {
704 return Err(OpcodeErr {
705 opcode: "Object".into(),
706 message: "Unexpected key value".to_string(),
707 });
708 };
709
710 map.insert(key.to_string(), value);
711 }
712
713 self.push(Variable::from_object(map));
714 }
715 Opcode::Len => {
716 let current = self.stack.last().ok_or_else(|| OpcodeErr {
717 opcode: "Len".into(),
718 message: "Empty stack".into(),
719 })?;
720
721 let len_var =
722 internal::imp::len(Arguments(&[current.clone()])).map_err(|err| {
723 OpcodeErr {
724 opcode: "Len".into(),
725 message: err.to_string(),
726 }
727 })?;
728
729 self.push(len_var);
730 }
731 Opcode::Flatten => {
732 let current = self.pop()?;
733 let Array(a) = current else {
734 return Err(OpcodeErr {
735 opcode: "Flatten".into(),
736 message: "Unsupported type".into(),
737 });
738 };
739
740 let arr = a.borrow();
741
742 let mut flat_arr = Vec::with_capacity(arr.len());
743 arr.iter().for_each(|v| match v {
744 Array(b) => {
745 let arr = b.borrow();
746 arr.iter().for_each(|v| flat_arr.push(v.clone()))
747 }
748 _ => flat_arr.push(v.clone()),
749 });
750
751 self.push(Variable::from_array(flat_arr));
752 }
753 Opcode::IncrementIt => {
754 let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
755 opcode: "IncrementIt".into(),
756 message: "Empty scope".into(),
757 })?;
758
759 scope.iter += 1;
760 }
761 Opcode::IncrementCount => {
762 let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
763 opcode: "IncrementCount".into(),
764 message: "Empty scope".into(),
765 })?;
766
767 scope.count += 1;
768 }
769 Opcode::GetCount => {
770 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
771 opcode: "GetCount".into(),
772 message: "Empty scope".into(),
773 })?;
774
775 self.push(Number(scope.count.into()));
776 }
777 Opcode::GetLen => {
778 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
779 opcode: "GetLen".into(),
780 message: "Empty scope".into(),
781 })?;
782
783 self.push(Number(scope.len.into()));
784 }
785 Opcode::Pointer => {
786 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
787 opcode: "Pointer".into(),
788 message: "Empty scope".into(),
789 })?;
790
791 match &scope.array {
792 Array(a) => {
793 let a_cloned = a.clone();
794 let arr = a_cloned.borrow();
795 let variable =
796 arr.get(scope.iter).cloned().ok_or_else(|| OpcodeErr {
797 opcode: "Pointer".into(),
798 message: "Scope array out of bounds".into(),
799 })?;
800
801 self.push(variable);
802 }
803 _ => {
804 return Err(OpcodeErr {
805 opcode: "Pointer".into(),
806 message: "Unsupported scope type".into(),
807 });
808 }
809 }
810 }
811 Opcode::Begin => {
812 let var = self.pop()?;
813 let maybe_scope = match &var {
814 Array(a) => {
815 let arr = a.borrow();
816 Some(Scope {
817 len: arr.len(),
818 array: var.clone(),
819 count: 0,
820 iter: 0,
821 })
822 }
823 _ => match IntervalObject::try_from_object(var)
824 .map(|s| s.to_array())
825 .flatten()
826 {
827 None => None,
828 Some(arr) => Some(Scope {
829 len: arr.len(),
830 array: Variable::from_array(arr),
831 count: 0,
832 iter: 0,
833 }),
834 },
835 };
836
837 let Some(scope) = maybe_scope else {
838 return Err(OpcodeErr {
839 opcode: "Begin".into(),
840 message: "Unsupported type".into(),
841 });
842 };
843
844 self.scopes.push(scope);
845 }
846 Opcode::End => {
847 self.scopes.pop();
848 }
849 Opcode::CallFunction { kind, arg_count } => {
850 let function =
851 FunctionRegistry::get_definition(kind).ok_or_else(|| OpcodeErr {
852 opcode: "CallFunction".into(),
853 message: format!("Function `{kind}` not found"),
854 })?;
855
856 let params_start = self.stack.len().saturating_sub(*arg_count as usize);
857 let result = function
858 .call(Arguments(&self.stack[params_start..]))
859 .map_err(|err| OpcodeErr {
860 opcode: "CallFunction".into(),
861 message: format!("Function `{kind}` failed: {err}"),
862 })?;
863
864 self.stack.drain(params_start..);
865 self.push(result);
866 }
867 }
868 }
869
870 self.pop()
871 }
872}