1use crate::compiler::{FetchFastTarget, Jump, Opcode, TypeCheckKind, TypeConversionKind};
2use crate::lexer::Bracket;
3use crate::variable::Variable;
4use crate::variable::Variable::*;
5use crate::vm::error::VMError::*;
6use crate::vm::error::VMResult;
7use crate::vm::helpers::{date_time, date_time_end_of, date_time_start_of, time};
8use crate::vm::variable::IntervalObject;
9use ahash::{HashMap, HashMapExt};
10use chrono::NaiveDateTime;
11use chrono::{Datelike, Timelike};
12#[cfg(not(feature = "regex-lite"))]
13use regex::Regex;
14#[cfg(feature = "regex-lite")]
15use regex_lite::Regex;
16use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
17use rust_decimal::{Decimal, MathematicalOps};
18use rust_decimal_macros::dec;
19use std::cell::RefCell;
20use std::rc::Rc;
21use std::string::String as StdString;
22
23#[derive(Debug)]
24pub struct Scope {
25 array: Variable,
26 len: usize,
27 iter: usize,
28 count: usize,
29}
30
31#[derive(Debug)]
32pub struct VM {
33 scopes: Vec<Scope>,
34 stack: Vec<Variable>,
35}
36
37impl VM {
38 pub fn new() -> Self {
39 Self {
40 scopes: Default::default(),
41 stack: Default::default(),
42 }
43 }
44
45 pub fn run(&mut self, bytecode: &[Opcode], env: Variable) -> VMResult<Variable> {
46 self.stack.clear();
47 self.scopes.clear();
48
49 let s = VMInner::new(bytecode, &mut self.stack, &mut self.scopes).run(env);
50 Ok(s?)
51 }
52}
53
54struct VMInner<'parent_ref, 'bytecode_ref> {
55 scopes: &'parent_ref mut Vec<Scope>,
56 stack: &'parent_ref mut Vec<Variable>,
57 bytecode: &'bytecode_ref [Opcode],
58 ip: u32,
59}
60
61impl<'arena, 'parent_ref, 'bytecode_ref> VMInner<'parent_ref, 'bytecode_ref> {
62 pub fn new(
63 bytecode: &'bytecode_ref [Opcode],
64 stack: &'parent_ref mut Vec<Variable>,
65 scopes: &'parent_ref mut Vec<Scope>,
66 ) -> Self {
67 Self {
68 ip: 0,
69 scopes,
70 stack,
71 bytecode,
72 }
73 }
74
75 fn push(&mut self, var: Variable) {
76 self.stack.push(var);
77 }
78
79 fn pop(&mut self) -> VMResult<Variable> {
80 self.stack.pop().ok_or_else(|| StackOutOfBounds {
81 stack: format!("{:?}", self.stack),
82 })
83 }
84
85 pub fn run(&mut self, env: Variable) -> VMResult<Variable> {
86 if self.ip != 0 {
87 self.ip = 0;
88 }
89
90 while self.ip < self.bytecode.len() as u32 {
91 let op = self
92 .bytecode
93 .get(self.ip as usize)
94 .ok_or_else(|| OpcodeOutOfBounds {
95 bytecode: format!("{:?}", self.bytecode),
96 index: self.ip as usize,
97 })?;
98
99 self.ip += 1;
100
101 match op {
102 Opcode::PushNull => self.push(Null),
103 Opcode::PushBool(b) => self.push(Bool(*b)),
104 Opcode::PushNumber(n) => self.push(Number(*n)),
105 Opcode::PushString(s) => self.push(String(Rc::from(s.as_ref()))),
106 Opcode::Pop => {
107 self.pop()?;
108 }
109 Opcode::Rot => {
110 let b = self.stack.len() - 1;
111 let a = self.stack.len() - 2;
112 self.stack.swap(a, b);
113 }
114 Opcode::Fetch => {
115 let b = self.pop()?;
116 let a = self.pop()?;
117
118 match (a, b) {
119 (Object(o), String(s)) => {
120 let obj = o.borrow();
121 self.push(obj.get(s.as_ref()).cloned().unwrap_or(Null));
122 }
123 (Array(a), Number(n)) => {
124 let arr = a.borrow();
125 self.push(
126 arr.get(n.to_usize().ok_or_else(|| OpcodeErr {
127 opcode: "Fetch".into(),
128 message: "Failed to convert to usize".into(),
129 })?)
130 .cloned()
131 .unwrap_or(Null),
132 )
133 }
134 (String(str), Number(n)) => {
135 let index = n.to_usize().ok_or_else(|| OpcodeErr {
136 opcode: "Fetch".into(),
137 message: "Failed to convert to usize".into(),
138 })?;
139
140 if let Some(slice) = str.get(index..index + 1) {
141 self.push(String(Rc::from(slice)));
142 } else {
143 self.push(Null)
144 };
145 }
146 _ => self.push(Null),
147 }
148 }
149 Opcode::FetchFast(path) => {
150 let variable = path.iter().fold(Null, |v, p| match p {
151 FetchFastTarget::Root => env.clone(),
152 FetchFastTarget::String(key) => match v {
153 Object(obj) => {
154 let obj_ref = obj.borrow();
155 obj_ref.get(key.as_ref()).cloned().unwrap_or(Null)
156 }
157 _ => Null,
158 },
159 FetchFastTarget::Number(num) => match v {
160 Array(arr) => {
161 let arr_ref = arr.borrow();
162 arr_ref.get(*num as usize).cloned().unwrap_or(Null)
163 }
164 _ => Null,
165 },
166 });
167
168 self.push(variable);
169 }
170 Opcode::FetchEnv(f) => match &env {
171 Object(o) => {
172 let obj = o.borrow();
173 match obj.get(f.as_ref()) {
174 None => self.push(Null),
175 Some(v) => self.push(v.clone()),
176 }
177 }
178 Null => self.push(Null),
179 _ => {
180 return Err(OpcodeErr {
181 opcode: "FetchEnv".into(),
182 message: "Unsupported type".into(),
183 });
184 }
185 },
186 Opcode::FetchRootEnv => {
187 self.push(env.clone());
188 }
189 Opcode::Negate => {
190 let a = self.pop()?;
191 match a {
192 Number(n) => {
193 self.push(Number(-n));
194 }
195 _ => {
196 return Err(OpcodeErr {
197 opcode: "Negate".into(),
198 message: "Unsupported type".into(),
199 });
200 }
201 }
202 }
203 Opcode::Not => {
204 let a = self.pop()?;
205 match a {
206 Bool(b) => self.push(Bool(!b)),
207 _ => {
208 return Err(OpcodeErr {
209 opcode: "Not".into(),
210 message: "Unsupported type".into(),
211 });
212 }
213 }
214 }
215 Opcode::Equal => {
216 let b = self.pop()?;
217 let a = self.pop()?;
218 match (a, b) {
219 (Number(a), Number(b)) => {
220 self.push(Bool(a == b));
221 }
222 (Bool(a), Bool(b)) => {
223 self.push(Bool(a == b));
224 }
225 (String(a), String(b)) => {
226 self.push(Bool(a == b));
227 }
228 (Null, Null) => {
229 self.push(Bool(true));
230 }
231 _ => {
232 self.push(Bool(false));
233 }
234 }
235 }
236 Opcode::Jump(kind, j) => match kind {
237 Jump::Forward => self.ip += j,
238 Jump::Backward => self.ip -= j,
239 Jump::IfTrue => {
240 let a = self.stack.last().ok_or_else(|| OpcodeErr {
241 opcode: "JumpIfTrue".into(),
242 message: "Undefined object key".into(),
243 })?;
244 match a {
245 Bool(a) => {
246 if *a {
247 self.ip += j;
248 }
249 }
250 _ => {
251 return Err(OpcodeErr {
252 opcode: "JumpIfTrue".into(),
253 message: "Unsupported type".into(),
254 });
255 }
256 }
257 }
258 Jump::IfFalse => {
259 let a = self.stack.last().ok_or_else(|| OpcodeErr {
260 opcode: "JumpIfFalse".into(),
261 message: "Empty array".into(),
262 })?;
263
264 match a {
265 Bool(a) => {
266 if !*a {
267 self.ip += j;
268 }
269 }
270 _ => {
271 return Err(OpcodeErr {
272 opcode: "JumpIfFalse".into(),
273 message: "Unsupported type".into(),
274 });
275 }
276 }
277 }
278 Jump::IfNotNull => {
279 let a = self.stack.last().ok_or_else(|| OpcodeErr {
280 opcode: "JumpIfNull".into(),
281 message: "Empty array".into(),
282 })?;
283
284 match a {
285 Null => {}
286 _ => {
287 self.ip += j;
288 }
289 }
290 }
291 Jump::IfEnd => {
292 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
293 opcode: "JumpIfEnd".into(),
294 message: "Empty stack".into(),
295 })?;
296
297 if scope.iter >= scope.len {
298 self.ip += j;
299 }
300 }
301 },
302 Opcode::In => {
303 let b = self.pop()?;
304 let a = self.pop()?;
305
306 match (a, &b) {
307 (Number(a), Array(b)) => {
308 let arr = b.borrow();
309 let is_in = arr.iter().any(|b| match b {
310 Number(b) => a == *b,
311 _ => false,
312 });
313
314 self.push(Bool(is_in));
315 }
316 (Number(v), Object(_)) => {
317 let interval =
318 IntervalObject::try_from_object(b).ok_or_else(|| OpcodeErr {
319 opcode: "In".into(),
320 message: "Failed to deconstruct interval".into(),
321 })?;
322
323 match (interval.left, interval.right) {
324 (Number(l), Number(r)) => {
325 let mut is_open = false;
326
327 let first = match interval.left_bracket {
328 Bracket::LeftParenthesis => l < v,
329 Bracket::LeftSquareBracket => l <= v,
330 Bracket::RightParenthesis => {
331 is_open = true;
332 l > v
333 }
334 Bracket::RightSquareBracket => {
335 is_open = true;
336 l >= v
337 }
338 _ => {
339 return Err(OpcodeErr {
340 opcode: "In".into(),
341 message: "Unsupported bracket".into(),
342 })
343 }
344 };
345
346 let second = match interval.right_bracket {
347 Bracket::RightParenthesis => r > v,
348 Bracket::RightSquareBracket => r >= v,
349 Bracket::LeftParenthesis => r < v,
350 Bracket::LeftSquareBracket => r <= v,
351 _ => {
352 return Err(OpcodeErr {
353 opcode: "In".into(),
354 message: "Unsupported bracket".into(),
355 })
356 }
357 };
358
359 let open_stmt = is_open && (first || second);
360 let closed_stmt = !is_open && first && second;
361
362 self.push(Bool(open_stmt || closed_stmt));
363 }
364 _ => {
365 return Err(OpcodeErr {
366 opcode: "In".into(),
367 message: "Unsupported type".into(),
368 });
369 }
370 }
371 }
372 (String(a), Array(b)) => {
373 let arr = b.borrow();
374 let is_in = arr.iter().any(|b| match b {
375 String(b) => &a == b,
376 _ => false,
377 });
378
379 self.push(Bool(is_in));
380 }
381 (String(a), Object(b)) => {
382 let obj = b.borrow();
383 self.push(Bool(obj.contains_key(a.as_ref())));
384 }
385 (Bool(a), Array(b)) => {
386 let arr = b.borrow();
387 let is_in = arr.iter().any(|b| match b {
388 Bool(b) => a == *b,
389 _ => false,
390 });
391
392 self.push(Bool(is_in));
393 }
394 (Null, Array(b)) => {
395 let arr = b.borrow();
396 let is_in = arr.iter().any(|b| match b {
397 Null => true,
398 _ => false,
399 });
400
401 self.push(Bool(is_in));
402 }
403 _ => {
404 return Err(OpcodeErr {
405 opcode: "In".into(),
406 message: "Unsupported type".into(),
407 });
408 }
409 }
410 }
411 Opcode::Less => {
412 let b = self.pop()?;
413 let a = self.pop()?;
414
415 match (a, b) {
416 (Number(a), Number(b)) => self.push(Bool(a < b)),
417 _ => {
418 return Err(OpcodeErr {
419 opcode: "Less".into(),
420 message: "Unsupported type".into(),
421 });
422 }
423 }
424 }
425 Opcode::More => {
426 let b = self.pop()?;
427 let a = self.pop()?;
428
429 match (a, b) {
430 (Number(a), Number(b)) => self.push(Bool(a > b)),
431 _ => {
432 return Err(OpcodeErr {
433 opcode: "More".into(),
434 message: "Unsupported type".into(),
435 });
436 }
437 }
438 }
439 Opcode::LessOrEqual => {
440 let b = self.pop()?;
441 let a = self.pop()?;
442
443 match (a, b) {
444 (Number(a), Number(b)) => self.push(Bool(a <= b)),
445 _ => {
446 return Err(OpcodeErr {
447 opcode: "LessOrEqual".into(),
448 message: "Unsupported type".into(),
449 });
450 }
451 }
452 }
453 Opcode::MoreOrEqual => {
454 let b = self.pop()?;
455 let a = self.pop()?;
456
457 match (a, b) {
458 (Number(a), Number(b)) => self.push(Bool(a >= b)),
459 _ => {
460 return Err(OpcodeErr {
461 opcode: "MoreOrEqual".into(),
462 message: "Unsupported type".into(),
463 });
464 }
465 }
466 }
467 Opcode::Abs => {
468 let a = self.pop()?;
469
470 match a {
471 Number(a) => self.push(Number(a.abs())),
472 _ => {
473 return Err(OpcodeErr {
474 opcode: "Abs".into(),
475 message: "Unsupported type".into(),
476 });
477 }
478 }
479 }
480 Opcode::Round => {
481 let var = self.pop()?;
482
483 match var {
484 Number(a) => self.push(Number(a.round())),
485 _ => {
486 return Err(OpcodeErr {
487 opcode: "Round".into(),
488 message: "Unsupported type".into(),
489 });
490 }
491 }
492 }
493 Opcode::Ceil => {
494 let var = self.pop()?;
495
496 match var {
497 Number(a) => self.push(Number(a.ceil())),
498 _ => {
499 return Err(OpcodeErr {
500 opcode: "Ceil".into(),
501 message: "Unsupported type".into(),
502 });
503 }
504 }
505 }
506 Opcode::Floor => {
507 let var = self.pop()?;
508
509 match var {
510 Number(a) => self.push(Number(a.floor())),
511 _ => {
512 return Err(OpcodeErr {
513 opcode: "Floor".into(),
514 message: "Unsupported type".into(),
515 });
516 }
517 }
518 }
519 Opcode::Random => {
520 let var = self.pop()?;
521 match var {
522 Number(a) => {
523 let upper_range = a.round().to_i64().ok_or_else(|| OpcodeErr {
524 opcode: "Random".into(),
525 message: "Failed to determine upper range".into(),
526 })?;
527
528 let random_number = fastrand::i64(0..=upper_range);
529 self.push(Number(Decimal::from(random_number)));
530 }
531 _ => {
532 return Err(OpcodeErr {
533 opcode: "Random".into(),
534 message: "Unsupported type".into(),
535 });
536 }
537 }
538 }
539 Opcode::Average => {
540 let var = self.pop()?;
541
542 match var {
543 Array(a) => {
544 let mut sum = Decimal::ZERO;
545 let arr = a.borrow();
546 arr.iter().try_for_each(|a| match a {
547 Number(a) => {
548 sum += a;
549 Ok(())
550 }
551 _ => Err(OpcodeErr {
552 opcode: "Average".into(),
553 message: "Invalid array value".into(),
554 }),
555 })?;
556
557 let avg = sum / Decimal::from(arr.len());
558 self.push(Number(avg));
559 }
560 _ => {
561 return Err(OpcodeErr {
562 opcode: "Average".into(),
563 message: "Unsupported type".into(),
564 });
565 }
566 }
567 }
568 Opcode::Median => {
569 let Array(a) = self.pop()? else {
570 return Err(OpcodeErr {
571 opcode: "Median".into(),
572 message: "Unsupported type".into(),
573 });
574 };
575
576 let arr = a.borrow();
577 let mut num_arr = arr
578 .iter()
579 .map(|n| match n {
580 Number(num) => Ok(*num),
581 _ => Err(OpcodeErr {
582 opcode: "Median".into(),
583 message: "Unsupported type".into(),
584 }),
585 })
586 .collect::<Result<Vec<_>, _>>()?;
587
588 if num_arr.len() == 0 {
589 return Err(OpcodeErr {
590 opcode: "Median".into(),
591 message: "Array is empty".into(),
592 });
593 }
594
595 num_arr.sort();
596
597 let center = num_arr.len() / 2;
598 if num_arr.len() % 2 == 1 {
599 let center_num = num_arr.get(center).ok_or_else(|| OpcodeErr {
600 opcode: "Median".into(),
601 message: "Array out of bounds".into(),
602 })?;
603
604 self.push(Number(*center_num));
605 } else {
606 let center_left = num_arr.get(center - 1).ok_or_else(|| OpcodeErr {
607 opcode: "Median".into(),
608 message: "Array out of bounds".into(),
609 })?;
610
611 let center_right = num_arr.get(center).ok_or_else(|| OpcodeErr {
612 opcode: "Median".into(),
613 message: "Array out of bounds".into(),
614 })?;
615
616 let median = ((*center_left) + (*center_right)) / dec!(2);
617 self.push(Number(median));
618 }
619 }
620 Opcode::Mode => {
621 let Array(a) = self.pop()? else {
622 return Err(OpcodeErr {
623 opcode: "Mode".into(),
624 message: "Unsupported type".into(),
625 });
626 };
627
628 let arr = a.borrow();
629 let num_arr = arr
630 .iter()
631 .map(|n| match n {
632 Number(num) => Ok(*num),
633 _ => Err(OpcodeErr {
634 opcode: "Mode".into(),
635 message: "Unsupported type".into(),
636 }),
637 })
638 .collect::<Result<Vec<_>, _>>()?;
639
640 if num_arr.len() == 0 {
641 return Err(OpcodeErr {
642 opcode: "Mode".into(),
643 message: "Array is empty".into(),
644 });
645 }
646
647 let mut map = HashMap::new();
648 num_arr.iter().for_each(|n| {
649 let count = map.entry(*n).or_insert(0);
650 *count += 1;
651 });
652
653 let maybe_mode = map
654 .iter()
655 .max_by_key(|&(_, count)| *count)
656 .map(|(val, _)| val);
657
658 let mode = maybe_mode.ok_or_else(|| OpcodeErr {
659 opcode: "Mode".into(),
660 message: "Failed to find most common element".into(),
661 })?;
662
663 self.push(Number(*mode));
664 }
665 Opcode::Min => {
666 let var = self.pop()?;
667
668 match var {
669 Array(a) => {
670 let arr = a.borrow();
671 let first_item = arr.get(0).ok_or_else(|| OpcodeErr {
672 opcode: "Min".into(),
673 message: "Empty array".into(),
674 })?;
675
676 let mut min: Decimal = match first_item {
677 Number(a) => *a,
678 _ => {
679 return Err(OpcodeErr {
680 opcode: "Min".into(),
681 message: "Unsupported array value".into(),
682 });
683 }
684 };
685
686 arr.iter().try_for_each(|a| match a {
687 Number(a) => {
688 if *a < min {
689 min = *a;
690 }
691 Ok(())
692 }
693 _ => Err(OpcodeErr {
694 opcode: "Min".into(),
695 message: "Unsupported array value".into(),
696 }),
697 })?;
698
699 self.push(Number(min));
700 }
701 _ => {
702 return Err(OpcodeErr {
703 opcode: "Min".into(),
704 message: "Unsupported type".into(),
705 });
706 }
707 }
708 }
709 Opcode::Max => {
710 let var = self.pop()?;
711
712 match var {
713 Array(a) => {
714 let arr = a.borrow();
715 let first_item = arr.get(0).ok_or_else(|| OpcodeErr {
716 opcode: "Max".into(),
717 message: "Empty array".into(),
718 })?;
719
720 let mut max: Decimal = match first_item {
721 Number(a) => *a,
722 _ => {
723 return Err(OpcodeErr {
724 opcode: "Max".into(),
725 message: "Unsupported array value".into(),
726 });
727 }
728 };
729
730 arr.iter().try_for_each(|a| match a {
731 Number(a) => {
732 if *a > max {
733 max = *a;
734 }
735 Ok(())
736 }
737 _ => Err(OpcodeErr {
738 opcode: "Max".into(),
739 message: "Unsupported array value".into(),
740 }),
741 })?;
742
743 self.push(Number(max));
744 }
745 _ => {
746 return Err(OpcodeErr {
747 opcode: "Max".into(),
748 message: "Unsupported type".into(),
749 });
750 }
751 }
752 }
753 Opcode::Sum => {
754 let var = self.pop()?;
755
756 match var {
757 Array(a) => {
758 let mut sum = Decimal::ZERO;
759 let arr = a.borrow();
760 arr.iter().try_for_each(|a| match a {
761 Number(a) => {
762 sum += a;
763 Ok(())
764 }
765 _ => Err(OpcodeErr {
766 opcode: "Sum".into(),
767 message: "Unsupported array value".into(),
768 }),
769 })?;
770
771 self.push(Number(sum));
772 }
773 _ => {
774 return Err(OpcodeErr {
775 opcode: "Sum".into(),
776 message: "Unsupported type".into(),
777 });
778 }
779 }
780 }
781 Opcode::Add => {
782 let b = self.pop()?;
783 let a = self.pop()?;
784
785 match (a, b) {
786 (Number(a), Number(b)) => self.push(Number(a + b)),
787 (String(a), String(b)) => {
788 let mut c = StdString::with_capacity(a.len() + b.len());
789
790 c.push_str(a.as_ref());
791 c.push_str(b.as_ref());
792
793 self.push(String(Rc::from(c.as_str())));
794 }
795 _ => {
796 return Err(OpcodeErr {
797 opcode: "Add".into(),
798 message: "Unsupported type".into(),
799 });
800 }
801 }
802 }
803 Opcode::Subtract => {
804 let b = self.pop()?;
805 let a = self.pop()?;
806
807 match (a, b) {
808 (Number(a), Number(b)) => self.push(Number(a - b)),
809 _ => {
810 return Err(OpcodeErr {
811 opcode: "Subtract".into(),
812 message: "Unsupported type".into(),
813 });
814 }
815 }
816 }
817 Opcode::Multiply => {
818 let b = self.pop()?;
819 let a = self.pop()?;
820
821 match (a, b) {
822 (Number(a), Number(b)) => self.push(Number(a * b)),
823 _ => {
824 return Err(OpcodeErr {
825 opcode: "Multiply".into(),
826 message: "Unsupported type".into(),
827 });
828 }
829 }
830 }
831 Opcode::Divide => {
832 let b = self.pop()?;
833 let a = self.pop()?;
834
835 match (a, b) {
836 (Number(a), Number(b)) => self.push(Number(a / b)),
837 _ => {
838 return Err(OpcodeErr {
839 opcode: "Divide".into(),
840 message: "Unsupported type".into(),
841 });
842 }
843 }
844 }
845 Opcode::Modulo => {
846 let b = self.pop()?;
847 let a = self.pop()?;
848
849 match (a, b) {
850 (Number(a), Number(b)) => self.push(Number(a % b)),
851 _ => {
852 return Err(OpcodeErr {
853 opcode: "Modulo".into(),
854 message: "Unsupported type".into(),
855 });
856 }
857 }
858 }
859 Opcode::Exponent => {
860 let b = self.pop()?;
861 let a = self.pop()?;
862
863 match (a, b) {
864 (Number(a), Number(b)) => {
865 self.push(Number(a.powd(b)));
866 }
867 _ => {
868 return Err(OpcodeErr {
869 opcode: "Exponent".into(),
870 message: "Unsupported type".into(),
871 });
872 }
873 }
874 }
875 Opcode::Interval {
876 left_bracket,
877 right_bracket,
878 } => {
879 let b = self.pop()?;
880 let a = self.pop()?;
881
882 match (&a, &b) {
883 (Number(_), Number(_)) => {
884 let interval = IntervalObject {
885 left_bracket: *left_bracket,
886 right_bracket: *right_bracket,
887 left: a,
888 right: b,
889 };
890
891 self.push(interval.to_variable());
892 }
893 _ => {
894 return Err(OpcodeErr {
895 opcode: "Interval".into(),
896 message: "Unsupported type".into(),
897 });
898 }
899 }
900 }
901 Opcode::Uppercase => {
902 let a = self.pop()?;
903
904 match a {
905 String(a) => {
906 self.push(String(a.to_uppercase().into()));
907 }
908 _ => {
909 return Err(OpcodeErr {
910 opcode: "Uppercase".into(),
911 message: "Unsupported type".into(),
912 });
913 }
914 }
915 }
916 Opcode::Trim => {
917 let a = self.pop()?;
918
919 match a {
920 String(a) => {
921 self.push(String(a.trim().into()));
922 }
923 _ => {
924 return Err(OpcodeErr {
925 opcode: "Trim".into(),
926 message: "Unsupported type".into(),
927 });
928 }
929 }
930 }
931 Opcode::Lowercase => {
932 let a = self.pop()?;
933
934 match a {
935 String(a) => self.push(String(a.to_lowercase().into())),
936 _ => {
937 return Err(OpcodeErr {
938 opcode: "Lowercase".into(),
939 message: "Unsupported type".into(),
940 });
941 }
942 }
943 }
944 Opcode::Contains => {
945 let b = self.pop()?;
946 let a = self.pop()?;
947
948 match (a, &b) {
949 (String(a), String(b)) => {
950 self.push(Bool(a.contains(b.as_ref())));
951 }
952 (Array(a), _) => {
953 let arr = a.borrow();
954 let is_in = arr.iter().any(|a| match (a, &b) {
955 (Number(a), Number(b)) => a == b,
956 (String(a), String(b)) => a == b,
957 (Bool(a), Bool(b)) => a == b,
958 (Null, Null) => true,
959 _ => false,
960 });
961
962 self.push(Bool(is_in));
963 }
964 _ => {
965 return Err(OpcodeErr {
966 opcode: "Contains".into(),
967 message: "Unsupported type".into(),
968 });
969 }
970 }
971 }
972 Opcode::Keys => {
973 let current = self.pop()?;
974
975 match current {
976 Array(a) => {
977 let arr = a.borrow();
978 let indices = arr
979 .iter()
980 .enumerate()
981 .map(|(index, _)| Number(index.into()))
982 .collect();
983
984 self.push(Array(Rc::new(RefCell::new(indices))));
985 }
986 Object(a) => {
987 let obj = a.borrow();
988 let keys = obj
989 .iter()
990 .map(|(key, _)| String(Rc::from(key.as_str())))
991 .collect();
992
993 self.push(Array(Rc::new(RefCell::new(keys))));
994 }
995 _ => {
996 return Err(OpcodeErr {
997 opcode: "Keys".into(),
998 message: "Unsupported type".into(),
999 })
1000 }
1001 }
1002 }
1003 Opcode::Values => {
1004 let current = self.pop()?;
1005
1006 match current {
1007 Object(a) => {
1008 let obj = a.borrow();
1009 let values: Vec<Variable> = obj.values().cloned().collect();
1010
1011 self.push(Array(Rc::new(RefCell::new(values))));
1012 }
1013 _ => {
1014 return Err(OpcodeErr {
1015 opcode: "Values".into(),
1016 message: "Unsupported type".into(),
1017 })
1018 }
1019 }
1020 }
1021 Opcode::StartsWith => {
1022 let b = self.pop()?;
1023 let a = self.pop()?;
1024
1025 match (a, b) {
1026 (String(a), String(b)) => {
1027 self.push(Bool(a.starts_with(b.as_ref())));
1028 }
1029 _ => {
1030 return Err(OpcodeErr {
1031 opcode: "StartsWith".into(),
1032 message: "Unsupported type".into(),
1033 });
1034 }
1035 }
1036 }
1037 Opcode::EndsWith => {
1038 let b = self.pop()?;
1039 let a = self.pop()?;
1040
1041 match (a, b) {
1042 (String(a), String(b)) => {
1043 self.push(Bool(a.ends_with(b.as_ref())));
1044 }
1045 _ => {
1046 return Err(OpcodeErr {
1047 opcode: "EndsWith".into(),
1048 message: "Unsupported type".into(),
1049 });
1050 }
1051 }
1052 }
1053 Opcode::Matches => {
1054 let b = self.pop()?;
1055 let a = self.pop()?;
1056
1057 let (String(a), String(b)) = (a, b) else {
1058 return Err(OpcodeErr {
1059 opcode: "Matches".into(),
1060 message: "Unsupported type".into(),
1061 });
1062 };
1063
1064 let regex = Regex::new(b.as_ref()).map_err(|_| OpcodeErr {
1065 opcode: "Matches".into(),
1066 message: "Invalid regular expression".into(),
1067 })?;
1068
1069 self.push(Bool(regex.is_match(a.as_ref())));
1070 }
1071 Opcode::FuzzyMatch => {
1072 let b = self.pop()?;
1073 let a = self.pop()?;
1074
1075 let String(b) = b else {
1076 return Err(OpcodeErr {
1077 opcode: "FuzzyMatch".into(),
1078 message: "Unsupported type".into(),
1079 });
1080 };
1081
1082 match a {
1083 String(a) => {
1084 let sim =
1085 strsim::normalized_damerau_levenshtein(a.as_ref(), b.as_ref());
1086 self.push(Number(Decimal::from_f64(sim).unwrap_or(dec!(0))));
1088 }
1089 Array(_a) => {
1090 let a = _a.borrow();
1091 let mut sims = Vec::with_capacity(a.len());
1092 for v in a.iter() {
1093 let String(s) = v else {
1094 return Err(OpcodeErr {
1095 opcode: "FuzzyMatch".into(),
1096 message: "Unsupported type".into(),
1097 });
1098 };
1099
1100 let sim = Decimal::from_f64(
1101 strsim::normalized_damerau_levenshtein(s.as_ref(), b.as_ref()),
1102 )
1103 .unwrap_or(dec!(0));
1104 sims.push(Number(sim));
1105 }
1106
1107 self.push(Variable::from_array(sims))
1108 }
1109 _ => {
1110 return Err(OpcodeErr {
1111 opcode: "FuzzyMatch".into(),
1112 message: "Unsupported type".into(),
1113 })
1114 }
1115 }
1116 }
1117 Opcode::Split => {
1118 let b = self.pop()?;
1119 let a = self.pop()?;
1120
1121 match (a, b) {
1122 (String(a), String(b)) => {
1123 let arr = Vec::from_iter(
1124 a.split(b.as_ref())
1125 .into_iter()
1126 .map(|s| String(s.to_string().into())),
1127 );
1128
1129 self.push(Variable::from_array(arr));
1130 }
1131 _ => {
1132 return Err(OpcodeErr {
1133 opcode: "Split".into(),
1134 message: "Unsupported type".into(),
1135 });
1136 }
1137 }
1138 }
1139 Opcode::Join => {
1140 let b = self.pop()?;
1141 let a = self.pop()?;
1142
1143 let (Array(a), String(separator)) = (a, &b) else {
1144 return Err(OpcodeErr {
1145 opcode: "Join".into(),
1146 message: "Unsupported type".into(),
1147 });
1148 };
1149
1150 let arr = a.borrow();
1151 let parts = arr
1152 .iter()
1153 .enumerate()
1154 .map(|(i, var)| match var {
1155 String(str) => Ok(str.clone()),
1156 _ => Err(OpcodeErr {
1157 opcode: "Join".into(),
1158 message: format!("Unexpected type in array on index {i}"),
1159 }),
1160 })
1161 .collect::<Result<Vec<_>, _>>()?;
1162
1163 let str_capacity = parts
1164 .iter()
1165 .fold(separator.len() * (parts.len() - 1), |acc, s| acc + s.len());
1166
1167 let mut s = StdString::with_capacity(str_capacity);
1168 let mut it = parts.into_iter().peekable();
1169 while let Some(part) = it.next() {
1170 s.push_str(part.as_ref());
1171 if it.peek().is_some() {
1172 s.push_str(separator);
1173 }
1174 }
1175
1176 self.push(String(Rc::from(s)));
1177 }
1178 Opcode::Extract => {
1179 let b = self.pop()?;
1180 let a = self.pop()?;
1181
1182 let (String(a), String(b)) = (a, b) else {
1183 return Err(OpcodeErr {
1184 opcode: "Matches".into(),
1185 message: "Unsupported type".into(),
1186 });
1187 };
1188
1189 let regex = Regex::new(b.as_ref()).map_err(|_| OpcodeErr {
1190 opcode: "Matches".into(),
1191 message: "Invalid regular expression".into(),
1192 })?;
1193
1194 let captures = regex
1195 .captures(a.as_ref())
1196 .map(|capture| {
1197 capture
1198 .iter()
1199 .map(|c| c.map(|c| c.as_str()))
1200 .filter_map(|c| c)
1201 .map(|s| String(Rc::from(s)))
1202 .collect()
1203 })
1204 .unwrap_or_default();
1205
1206 self.push(Variable::from_array(captures));
1207 }
1208 Opcode::DateManipulation(operation) => {
1209 let timestamp = self.pop()?;
1210
1211 let time: NaiveDateTime = (×tamp).try_into()?;
1212 let var = match operation.as_ref() {
1213 "year" => Number(time.year().into()),
1214 "dayOfWeek" => Number(time.weekday().number_from_monday().into()),
1215 "dayOfMonth" => Number(time.day().into()),
1216 "dayOfYear" => Number(time.ordinal().into()),
1217 "weekOfYear" => Number(time.iso_week().week().into()),
1218 "monthOfYear" => Number(time.month().into()),
1219 "monthString" => String(Rc::from(time.format("%b").to_string())),
1220 "weekdayString" => String(Rc::from(time.weekday().to_string())),
1221 "dateString" => String(Rc::from(time.to_string())),
1222 _ => {
1223 return Err(OpcodeErr {
1224 opcode: "DateManipulation".into(),
1225 message: "Unsupported operation".into(),
1226 });
1227 }
1228 };
1229
1230 self.push(var);
1231 }
1232 Opcode::DateFunction(name) => {
1233 let unit_var = self.pop()?;
1234 let timestamp = self.pop()?;
1235
1236 let date_time: NaiveDateTime = (×tamp).try_into()?;
1237 let String(unit_name) = unit_var else {
1238 return Err(OpcodeErr {
1239 opcode: "DateFunction".into(),
1240 message: "Unknown date function".into(),
1241 });
1242 };
1243
1244 let s = match name.as_ref() {
1245 "startOf" => date_time_start_of(date_time, unit_name.as_ref().try_into()?),
1246 "endOf" => date_time_end_of(date_time, unit_name.as_ref().try_into()?),
1247 _ => {
1248 return Err(OpcodeErr {
1249 opcode: "DateManipulation".into(),
1250 message: "Unsupported operation".into(),
1251 });
1252 }
1253 }
1254 .ok_or_else(|| OpcodeErr {
1255 opcode: "DateFunction".into(),
1256 message: "Failed to run DateFunction".into(),
1257 })?;
1258
1259 #[allow(deprecated)]
1260 self.push(Number(s.timestamp().into()));
1261 }
1262 Opcode::Slice => {
1263 let from_var = self.pop()?;
1264 let to_var = self.pop()?;
1265 let current = self.pop()?;
1266
1267 match (from_var, to_var) {
1268 (Number(f), Number(t)) => {
1269 let from = f.to_usize().ok_or_else(|| OpcodeErr {
1270 opcode: "Slice".into(),
1271 message: "Failed to get range from".into(),
1272 })?;
1273 let to = t.to_usize().ok_or_else(|| OpcodeErr {
1274 opcode: "Slice".into(),
1275 message: "Failed to get range to".into(),
1276 })?;
1277
1278 match current {
1279 Array(a) => {
1280 let arr = a.borrow();
1281 let slice = arr.get(from..=to).ok_or_else(|| OpcodeErr {
1282 opcode: "Slice".into(),
1283 message: "Index out of range".into(),
1284 })?;
1285
1286 self.push(Variable::from_array(slice.to_vec()));
1287 }
1288 String(s) => {
1289 let slice = s.get(from..=to).ok_or_else(|| OpcodeErr {
1290 opcode: "Slice".into(),
1291 message: "Index out of range".into(),
1292 })?;
1293
1294 self.push(String(Rc::from(slice)));
1295 }
1296 _ => {
1297 return Err(OpcodeErr {
1298 opcode: "Slice".into(),
1299 message: "Unsupported type".into(),
1300 });
1301 }
1302 }
1303 }
1304 _ => {
1305 return Err(OpcodeErr {
1306 opcode: "Slice".into(),
1307 message: "Unsupported type".into(),
1308 });
1309 }
1310 }
1311 }
1312 Opcode::Array => {
1313 let size = self.pop()?;
1314 let Number(s) = size else {
1315 return Err(OpcodeErr {
1316 opcode: "Array".into(),
1317 message: "Unsupported type".into(),
1318 });
1319 };
1320
1321 let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
1322 opcode: "Array".into(),
1323 message: "Failed to extract argument".into(),
1324 })?;
1325
1326 let mut arr = Vec::with_capacity(to);
1327 for _ in 0..to {
1328 arr.push(self.pop()?);
1329 }
1330 arr.reverse();
1331
1332 self.push(Variable::from_array(arr));
1333 }
1334 Opcode::Object => {
1335 let size = self.pop()?;
1336 let Number(s) = size else {
1337 return Err(OpcodeErr {
1338 opcode: "Array".into(),
1339 message: "Unsupported type".into(),
1340 });
1341 };
1342
1343 let to = s.round().to_usize().ok_or_else(|| OpcodeErr {
1344 opcode: "Array".into(),
1345 message: "Failed to extract argument".into(),
1346 })?;
1347
1348 let mut map = HashMap::with_capacity(to);
1349 for _ in 0..to {
1350 let value = self.pop()?;
1351 let String(key) = self.pop()? else {
1352 return Err(OpcodeErr {
1353 opcode: "Object".into(),
1354 message: "Unexpected key value".to_string(),
1355 });
1356 };
1357
1358 map.insert(key.to_string(), value);
1359 }
1360
1361 self.push(Variable::from_object(map));
1362 }
1363 Opcode::Len => {
1364 let current = self.stack.last().ok_or_else(|| OpcodeErr {
1365 opcode: "Len".into(),
1366 message: "Empty stack".into(),
1367 })?;
1368
1369 let len = match current {
1370 String(s) => s.len(),
1371 Array(s) => {
1372 let arr = s.borrow();
1373 arr.len()
1374 }
1375 _ => {
1376 return Err(OpcodeErr {
1377 opcode: "Len".into(),
1378 message: "Unsupported type".into(),
1379 });
1380 }
1381 };
1382
1383 self.push(Number(len.into()));
1384 }
1385 Opcode::Flatten => {
1386 let current = self.pop()?;
1387 let Array(a) = current else {
1388 return Err(OpcodeErr {
1389 opcode: "Flatten".into(),
1390 message: "Unsupported type".into(),
1391 });
1392 };
1393
1394 let arr = a.borrow();
1395
1396 let mut flat_arr = Vec::with_capacity(arr.len());
1397 arr.iter().for_each(|v| match v {
1398 Array(b) => {
1399 let arr = b.borrow();
1400 arr.iter().for_each(|v| flat_arr.push(v.clone()))
1401 }
1402 _ => flat_arr.push(v.clone()),
1403 });
1404
1405 self.push(Variable::from_array(flat_arr));
1406 }
1407 Opcode::ParseDateTime => {
1408 let a = self.pop()?;
1409 let ts = match a {
1410 #[allow(deprecated)]
1411 String(a) => date_time(a.as_ref())?.timestamp(),
1412 Number(a) => a.to_i64().ok_or_else(|| OpcodeErr {
1413 opcode: "ParseDateTime".into(),
1414 message: "Number overflow".into(),
1415 })?,
1416 _ => {
1417 return Err(OpcodeErr {
1418 opcode: "ParseDateTime".into(),
1419 message: "Unsupported type".into(),
1420 });
1421 }
1422 };
1423
1424 self.push(Number(ts.into()));
1425 }
1426 Opcode::ParseTime => {
1427 let a = self.pop()?;
1428 let ts = match a {
1429 String(a) => time(a.as_ref())?.num_seconds_from_midnight(),
1430 Number(a) => a.to_u32().ok_or_else(|| OpcodeErr {
1431 opcode: "ParseTime".into(),
1432 message: "Number overflow".into(),
1433 })?,
1434 _ => {
1435 return Err(OpcodeErr {
1436 opcode: "ParseTime".into(),
1437 message: "Unsupported type".into(),
1438 });
1439 }
1440 };
1441
1442 self.push(Number(ts.into()));
1443 }
1444 Opcode::ParseDuration => {
1445 let a = self.pop()?;
1446
1447 let dur = match a {
1448 String(a) => humantime::parse_duration(a.as_ref())
1449 .map_err(|_| ParseDateTimeErr {
1450 timestamp: a.to_string(),
1451 })?
1452 .as_secs(),
1453 Number(n) => n.to_u64().ok_or_else(|| OpcodeErr {
1454 opcode: "ParseDuration".into(),
1455 message: "Number overflow".into(),
1456 })?,
1457 _ => {
1458 return Err(OpcodeErr {
1459 opcode: "ParseDuration".into(),
1460 message: "Unsupported type".into(),
1461 });
1462 }
1463 };
1464
1465 self.push(Number(dur.into()));
1466 }
1467 Opcode::TypeCheck(check) => {
1468 let var = self.pop()?;
1469
1470 let is_equal = match (check, var) {
1471 (TypeCheckKind::Numeric, String(str)) => {
1472 Decimal::from_str_exact(str.as_ref()).is_ok()
1473 }
1474 (TypeCheckKind::Numeric, Number(_)) => true,
1475 (TypeCheckKind::Numeric, _) => false,
1476 };
1477
1478 self.push(Bool(is_equal));
1479 }
1480 Opcode::TypeConversion(conversion) => {
1481 let var = self.pop()?;
1482
1483 let converted_var = match (conversion, &var) {
1484 (TypeConversionKind::String, String(_)) => var,
1485 (TypeConversionKind::String, Number(num)) => {
1486 String(Rc::from(num.to_string().as_str()))
1487 }
1488 (TypeConversionKind::String, Bool(v)) => {
1489 String(Rc::from(v.to_string().as_str()))
1490 }
1491 (TypeConversionKind::String, Null) => String(Rc::from("null")),
1492 (TypeConversionKind::String, _) => {
1493 return Err(OpcodeErr {
1494 opcode: "TypeConversion".into(),
1495 message: format!(
1496 "Type {} cannot be converted to string",
1497 var.type_name()
1498 ),
1499 });
1500 }
1501 (TypeConversionKind::Number, String(str)) => {
1502 let parsed_number =
1503 Decimal::from_str_exact(str.trim()).map_err(|_| OpcodeErr {
1504 opcode: "TypeConversion".into(),
1505 message: "Failed to parse string to number".into(),
1506 })?;
1507
1508 Number(parsed_number)
1509 }
1510 (TypeConversionKind::Number, Number(_)) => var,
1511 (TypeConversionKind::Number, Bool(v)) => {
1512 let number = if *v { dec!(1) } else { dec!(0) };
1513 Number(number)
1514 }
1515 (TypeConversionKind::Number, _) => {
1516 return Err(OpcodeErr {
1517 opcode: "TypeConversion".into(),
1518 message: format!(
1519 "Type {} cannot be converted to number",
1520 var.type_name()
1521 ),
1522 });
1523 }
1524 (TypeConversionKind::Bool, Number(n)) => Bool(!n.is_zero()),
1525 (TypeConversionKind::Bool, String(s)) => {
1526 let value = match (*s).trim() {
1527 "true" => true,
1528 "false" => false,
1529 _ => s.is_empty(),
1530 };
1531
1532 Bool(value)
1533 }
1534 (TypeConversionKind::Bool, Bool(_)) => var,
1535 (TypeConversionKind::Bool, Null) => Bool(false),
1536 (TypeConversionKind::Bool, Object(_) | Array(_)) => Bool(true),
1537 };
1538
1539 self.push(converted_var);
1540 }
1541 Opcode::GetType => {
1542 let var = self.pop()?;
1543 self.push(String(Rc::from(var.type_name())));
1544 }
1545 Opcode::IncrementIt => {
1546 let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
1547 opcode: "IncrementIt".into(),
1548 message: "Empty scope".into(),
1549 })?;
1550
1551 scope.iter += 1;
1552 }
1553 Opcode::IncrementCount => {
1554 let scope = self.scopes.last_mut().ok_or_else(|| OpcodeErr {
1555 opcode: "IncrementCount".into(),
1556 message: "Empty scope".into(),
1557 })?;
1558
1559 scope.count += 1;
1560 }
1561 Opcode::GetCount => {
1562 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
1563 opcode: "GetCount".into(),
1564 message: "Empty scope".into(),
1565 })?;
1566
1567 self.push(Number(scope.count.into()));
1568 }
1569 Opcode::GetLen => {
1570 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
1571 opcode: "GetLen".into(),
1572 message: "Empty scope".into(),
1573 })?;
1574
1575 self.push(Number(scope.len.into()));
1576 }
1577 Opcode::Pointer => {
1578 let scope = self.scopes.last().ok_or_else(|| OpcodeErr {
1579 opcode: "Pointer".into(),
1580 message: "Empty scope".into(),
1581 })?;
1582
1583 match &scope.array {
1584 Array(a) => {
1585 let a_cloned = a.clone();
1586 let arr = a_cloned.borrow();
1587 let variable =
1588 arr.get(scope.iter).cloned().ok_or_else(|| OpcodeErr {
1589 opcode: "Pointer".into(),
1590 message: "Scope array out of bounds".into(),
1591 })?;
1592
1593 self.push(variable);
1594 }
1595 _ => {
1596 return Err(OpcodeErr {
1597 opcode: "Pointer".into(),
1598 message: "Unsupported scope type".into(),
1599 });
1600 }
1601 }
1602 }
1603 Opcode::Begin => {
1604 let a = self.pop()?;
1605 let arr_len = match &a {
1606 Array(a) => {
1607 let arr = a.borrow();
1608 Some(arr.len())
1609 }
1610 _ => None,
1611 };
1612
1613 match arr_len {
1614 Some(len) => self.scopes.push(Scope {
1615 array: a,
1616 count: 0,
1617 len,
1618 iter: 0,
1619 }),
1620 None => {
1621 return Err(OpcodeErr {
1622 opcode: "Begin".into(),
1623 message: "Unsupported type".into(),
1624 })
1625 }
1626 }
1627 }
1628 Opcode::End => {
1629 self.scopes.pop();
1630 }
1631 }
1632 }
1633
1634 self.pop()
1635 }
1636}