1use crate::error::set_runtime_error;
25#[cfg(not(feature = "nanbox"))]
26use crate::stack::DISC_INT;
27use crate::stack::{Stack, peek_sv, pop, pop_two, push};
28use crate::value::Value;
29
30#[unsafe(no_mangle)]
37pub unsafe extern "C" fn patch_seq_push_int(stack: Stack, value: i64) -> Stack {
38 unsafe { push(stack, Value::Int(value)) }
39}
40
41#[unsafe(no_mangle)]
48pub unsafe extern "C" fn patch_seq_push_bool(stack: Stack, value: bool) -> Stack {
49 unsafe { push(stack, Value::Bool(value)) }
50}
51
52#[unsafe(no_mangle)]
59pub unsafe extern "C" fn patch_seq_add(stack: Stack) -> Stack {
60 let (rest, a, b) = unsafe { pop_two(stack, "add") };
61 match (a, b) {
62 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
63 push(rest, Value::Int(a_val.wrapping_add(b_val)))
64 },
65 _ => panic!("add: expected two integers on stack"),
66 }
67}
68
69#[unsafe(no_mangle)]
76pub unsafe extern "C" fn patch_seq_subtract(stack: Stack) -> Stack {
77 let (rest, a, b) = unsafe { pop_two(stack, "subtract") };
78 match (a, b) {
79 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
80 push(rest, Value::Int(a_val.wrapping_sub(b_val)))
81 },
82 _ => panic!("subtract: expected two integers on stack"),
83 }
84}
85
86#[unsafe(no_mangle)]
93pub unsafe extern "C" fn patch_seq_multiply(stack: Stack) -> Stack {
94 let (rest, a, b) = unsafe { pop_two(stack, "multiply") };
95 match (a, b) {
96 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
97 push(rest, Value::Int(a_val.wrapping_mul(b_val)))
98 },
99 _ => panic!("multiply: expected two integers on stack"),
100 }
101}
102
103#[unsafe(no_mangle)]
114pub unsafe extern "C" fn patch_seq_divide(stack: Stack) -> Stack {
115 let (rest, a, b) = unsafe { pop_two(stack, "divide") };
116 match (a, b) {
117 (Value::Int(a_val), Value::Int(0)) => {
118 set_runtime_error(format!(
120 "divide: division by zero (attempted {} / 0)",
121 a_val
122 ));
123 unsafe { push(rest, Value::Int(0)) }
124 }
125 (Value::Int(a_val), Value::Int(b_val)) => {
126 unsafe { push(rest, Value::Int(a_val.wrapping_div(b_val))) }
128 }
129 _ => {
130 set_runtime_error("divide: expected two integers on stack");
132 unsafe { push(rest, Value::Int(0)) }
133 }
134 }
135}
136
137#[unsafe(no_mangle)]
148pub unsafe extern "C" fn patch_seq_modulo(stack: Stack) -> Stack {
149 let (rest, a, b) = unsafe { pop_two(stack, "modulo") };
150 match (a, b) {
151 (Value::Int(a_val), Value::Int(0)) => {
152 set_runtime_error(format!(
154 "modulo: division by zero (attempted {} % 0)",
155 a_val
156 ));
157 unsafe { push(rest, Value::Int(0)) }
158 }
159 (Value::Int(a_val), Value::Int(b_val)) => {
160 unsafe { push(rest, Value::Int(a_val.wrapping_rem(b_val))) }
162 }
163 _ => {
164 set_runtime_error("modulo: expected two integers on stack");
166 unsafe { push(rest, Value::Int(0)) }
167 }
168 }
169}
170
171#[unsafe(no_mangle)]
179pub unsafe extern "C" fn patch_seq_eq(stack: Stack) -> Stack {
180 let (rest, a, b) = unsafe { pop_two(stack, "=") };
181 match (a, b) {
182 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
183 push(rest, Value::Bool(a_val == b_val))
184 },
185 _ => panic!("=: expected two integers on stack"),
186 }
187}
188
189#[unsafe(no_mangle)]
197pub unsafe extern "C" fn patch_seq_lt(stack: Stack) -> Stack {
198 let (rest, a, b) = unsafe { pop_two(stack, "<") };
199 match (a, b) {
200 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val < b_val)) },
201 _ => panic!("<: expected two integers on stack"),
202 }
203}
204
205#[unsafe(no_mangle)]
213pub unsafe extern "C" fn patch_seq_gt(stack: Stack) -> Stack {
214 let (rest, a, b) = unsafe { pop_two(stack, ">") };
215 match (a, b) {
216 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val > b_val)) },
217 _ => panic!(">: expected two integers on stack"),
218 }
219}
220
221#[unsafe(no_mangle)]
229pub unsafe extern "C" fn patch_seq_lte(stack: Stack) -> Stack {
230 let (rest, a, b) = unsafe { pop_two(stack, "<=") };
231 match (a, b) {
232 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
233 push(rest, Value::Bool(a_val <= b_val))
234 },
235 _ => panic!("<=: expected two integers on stack"),
236 }
237}
238
239#[unsafe(no_mangle)]
247pub unsafe extern "C" fn patch_seq_gte(stack: Stack) -> Stack {
248 let (rest, a, b) = unsafe { pop_two(stack, ">=") };
249 match (a, b) {
250 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
251 push(rest, Value::Bool(a_val >= b_val))
252 },
253 _ => panic!(">=: expected two integers on stack"),
254 }
255}
256
257#[unsafe(no_mangle)]
265pub unsafe extern "C" fn patch_seq_neq(stack: Stack) -> Stack {
266 let (rest, a, b) = unsafe { pop_two(stack, "<>") };
267 match (a, b) {
268 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
269 push(rest, Value::Bool(a_val != b_val))
270 },
271 _ => panic!("<>: expected two integers on stack"),
272 }
273}
274
275#[unsafe(no_mangle)]
284pub unsafe extern "C" fn patch_seq_and(stack: Stack) -> Stack {
285 let (rest, a, b) = unsafe { pop_two(stack, "and") };
286 match (a, b) {
287 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
288 push(
289 rest,
290 Value::Int(if a_val != 0 && b_val != 0 { 1 } else { 0 }),
291 )
292 },
293 _ => panic!("and: expected two integers on stack"),
294 }
295}
296
297#[unsafe(no_mangle)]
306pub unsafe extern "C" fn patch_seq_or(stack: Stack) -> Stack {
307 let (rest, a, b) = unsafe { pop_two(stack, "or") };
308 match (a, b) {
309 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
310 push(
311 rest,
312 Value::Int(if a_val != 0 || b_val != 0 { 1 } else { 0 }),
313 )
314 },
315 _ => panic!("or: expected two integers on stack"),
316 }
317}
318
319#[unsafe(no_mangle)]
328pub unsafe extern "C" fn patch_seq_not(stack: Stack) -> Stack {
329 assert!(!stack.is_null(), "not: stack is empty");
330 let (rest, a) = unsafe { pop(stack) };
331
332 match a {
333 Value::Int(a_val) => unsafe { push(rest, Value::Int(if a_val == 0 { 1 } else { 0 })) },
334 _ => panic!("not: expected integer on stack"),
335 }
336}
337
338#[unsafe(no_mangle)]
349pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
350 let (rest, a, b) = unsafe { pop_two(stack, "band") };
351 match (a, b) {
352 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
353 _ => panic!("band: expected two integers on stack"),
354 }
355}
356
357#[unsafe(no_mangle)]
364pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
365 let (rest, a, b) = unsafe { pop_two(stack, "bor") };
366 match (a, b) {
367 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
368 _ => panic!("bor: expected two integers on stack"),
369 }
370}
371
372#[unsafe(no_mangle)]
379pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
380 let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
381 match (a, b) {
382 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
383 _ => panic!("bxor: expected two integers on stack"),
384 }
385}
386
387#[unsafe(no_mangle)]
394pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
395 assert!(!stack.is_null(), "bnot: stack is empty");
396 let (rest, a) = unsafe { pop(stack) };
397 match a {
398 Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
399 _ => panic!("bnot: expected integer on stack"),
400 }
401}
402
403#[unsafe(no_mangle)]
411pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
412 let (rest, value, count) = unsafe { pop_two(stack, "shl") };
413 match (value, count) {
414 (Value::Int(v), Value::Int(c)) => {
415 let result = if c < 0 {
418 0
419 } else {
420 v.checked_shl(c as u32).unwrap_or(0)
421 };
422 unsafe { push(rest, Value::Int(result)) }
423 }
424 _ => panic!("shl: expected two integers on stack"),
425 }
426}
427
428#[unsafe(no_mangle)]
437pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
438 let (rest, value, count) = unsafe { pop_two(stack, "shr") };
439 match (value, count) {
440 (Value::Int(v), Value::Int(c)) => {
441 let result = if c < 0 {
444 0
445 } else {
446 (v as u64).checked_shr(c as u32).unwrap_or(0) as i64
447 };
448 unsafe { push(rest, Value::Int(result)) }
449 }
450 _ => panic!("shr: expected two integers on stack"),
451 }
452}
453
454#[unsafe(no_mangle)]
461pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
462 assert!(!stack.is_null(), "popcount: stack is empty");
463 let (rest, a) = unsafe { pop(stack) };
464 match a {
465 Value::Int(v) => unsafe { push(rest, Value::Int(v.count_ones() as i64)) },
466 _ => panic!("popcount: expected integer on stack"),
467 }
468}
469
470#[unsafe(no_mangle)]
477pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
478 assert!(!stack.is_null(), "clz: stack is empty");
479 let (rest, a) = unsafe { pop(stack) };
480 match a {
481 Value::Int(v) => unsafe { push(rest, Value::Int(v.leading_zeros() as i64)) },
482 _ => panic!("clz: expected integer on stack"),
483 }
484}
485
486#[unsafe(no_mangle)]
493pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
494 assert!(!stack.is_null(), "ctz: stack is empty");
495 let (rest, a) = unsafe { pop(stack) };
496 match a {
497 Value::Int(v) => unsafe { push(rest, Value::Int(v.trailing_zeros() as i64)) },
498 _ => panic!("ctz: expected integer on stack"),
499 }
500}
501
502#[unsafe(no_mangle)]
509pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
510 unsafe { push(stack, Value::Int(64)) }
511}
512
513#[cfg(not(feature = "nanbox"))]
533#[unsafe(no_mangle)]
534pub unsafe extern "C" fn patch_seq_peek_int_value(stack: Stack) -> i64 {
535 assert!(!stack.is_null(), "peek_int_value: stack is empty");
536
537 let sv = unsafe { peek_sv(stack) };
539 if sv.slot0 == DISC_INT {
540 sv.slot1 as i64
541 } else {
542 panic!(
543 "peek_int_value: expected Int on stack, got discriminant {}",
544 sv.slot0
545 )
546 }
547}
548
549#[cfg(feature = "nanbox")]
554#[unsafe(no_mangle)]
555pub unsafe extern "C" fn patch_seq_peek_int_value(stack: Stack) -> i64 {
556 assert!(!stack.is_null(), "peek_int_value: stack is empty");
557
558 let sv = unsafe { peek_sv(stack) };
559 if sv.0.is_int() {
560 sv.0.as_int()
561 } else {
562 panic!("peek_int_value: expected Int on stack")
563 }
564}
565
566#[cfg(not(feature = "nanbox"))]
571#[unsafe(no_mangle)]
572pub unsafe extern "C" fn patch_seq_peek_bool_value(stack: Stack) -> bool {
573 use crate::stack::DISC_BOOL;
574 assert!(!stack.is_null(), "peek_bool_value: stack is empty");
575
576 let sv = unsafe { peek_sv(stack) };
578 if sv.slot0 == DISC_BOOL {
579 sv.slot1 != 0
580 } else {
581 panic!(
582 "peek_bool_value: expected Bool on stack, got discriminant {}",
583 sv.slot0
584 )
585 }
586}
587
588#[cfg(feature = "nanbox")]
593#[unsafe(no_mangle)]
594pub unsafe extern "C" fn patch_seq_peek_bool_value(stack: Stack) -> bool {
595 assert!(!stack.is_null(), "peek_bool_value: stack is empty");
596
597 let sv = unsafe { peek_sv(stack) };
598 if sv.0.is_bool() {
599 sv.0.as_bool()
600 } else {
601 panic!("peek_bool_value: expected Bool on stack")
602 }
603}
604
605#[unsafe(no_mangle)]
615pub unsafe extern "C" fn patch_seq_pop_stack(stack: Stack) -> Stack {
616 assert!(!stack.is_null(), "pop_stack: stack is empty");
617 let (rest, _value) = unsafe { pop(stack) };
618 rest
619}
620
621pub use patch_seq_add as add;
623pub use patch_seq_and as and;
624pub use patch_seq_band as band;
625pub use patch_seq_bnot as bnot;
626pub use patch_seq_bor as bor;
627pub use patch_seq_bxor as bxor;
628pub use patch_seq_clz as clz;
629pub use patch_seq_ctz as ctz;
630pub use patch_seq_divide as divide;
631pub use patch_seq_eq as eq;
632pub use patch_seq_gt as gt;
633pub use patch_seq_gte as gte;
634pub use patch_seq_int_bits as int_bits;
635pub use patch_seq_lt as lt;
636pub use patch_seq_lte as lte;
637pub use patch_seq_multiply as multiply;
638pub use patch_seq_neq as neq;
639pub use patch_seq_not as not;
640pub use patch_seq_or as or;
641pub use patch_seq_popcount as popcount;
642pub use patch_seq_push_bool as push_bool;
643pub use patch_seq_push_int as push_int;
644pub use patch_seq_shl as shl;
645pub use patch_seq_shr as shr;
646pub use patch_seq_subtract as subtract;
647
648#[cfg(test)]
649mod tests {
650 use super::*;
651
652 #[test]
653 fn test_add() {
654 unsafe {
655 let stack = crate::stack::alloc_test_stack();
656 let stack = push_int(stack, 5);
657 let stack = push_int(stack, 3);
658 let stack = add(stack);
659
660 let (_stack, result) = pop(stack);
661 assert_eq!(result, Value::Int(8));
662 }
663 }
664
665 #[test]
666 fn test_subtract() {
667 unsafe {
668 let stack = crate::stack::alloc_test_stack();
669 let stack = push_int(stack, 10);
670 let stack = push_int(stack, 3);
671 let stack = subtract(stack);
672
673 let (_stack, result) = pop(stack);
674 assert_eq!(result, Value::Int(7));
675 }
676 }
677
678 #[test]
679 fn test_multiply() {
680 unsafe {
681 let stack = crate::stack::alloc_test_stack();
682 let stack = push_int(stack, 4);
683 let stack = push_int(stack, 5);
684 let stack = multiply(stack);
685
686 let (_stack, result) = pop(stack);
687 assert_eq!(result, Value::Int(20));
688 }
689 }
690
691 #[test]
692 fn test_divide() {
693 unsafe {
694 let stack = crate::stack::alloc_test_stack();
695 let stack = push_int(stack, 20);
696 let stack = push_int(stack, 4);
697 let stack = divide(stack);
698
699 let (_stack, result) = pop(stack);
700 assert_eq!(result, Value::Int(5));
701 }
702 }
703
704 #[test]
705 fn test_comparisons() {
706 unsafe {
707 let stack = crate::stack::alloc_test_stack();
709 let stack = push_int(stack, 5);
710 let stack = push_int(stack, 5);
711 let stack = eq(stack);
712 let (_stack, result) = pop(stack);
713 assert_eq!(result, Value::Bool(true));
714
715 let stack = push_int(stack, 3);
717 let stack = push_int(stack, 5);
718 let stack = lt(stack);
719 let (_stack, result) = pop(stack);
720 assert_eq!(result, Value::Bool(true));
721
722 let stack = push_int(stack, 7);
724 let stack = push_int(stack, 5);
725 let stack = gt(stack);
726 let (_stack, result) = pop(stack);
727 assert_eq!(result, Value::Bool(true));
728 }
729 }
730
731 #[test]
733 #[cfg(not(feature = "nanbox"))]
734 fn test_overflow_wrapping() {
735 unsafe {
737 let stack = crate::stack::alloc_test_stack();
739 let stack = push_int(stack, i64::MAX);
740 let stack = push_int(stack, 1);
741 let stack = add(stack);
742 let (_stack, result) = pop(stack);
743 assert_eq!(result, Value::Int(i64::MIN)); let stack = push_int(stack, i64::MAX);
747 let stack = push_int(stack, 2);
748 let stack = multiply(stack);
749 let (_stack, result) = pop(stack);
750 assert!(matches!(result, Value::Int(_)));
752
753 let stack = push_int(stack, i64::MIN);
755 let stack = push_int(stack, 1);
756 let stack = subtract(stack);
757 let (_stack, result) = pop(stack);
758 assert_eq!(result, Value::Int(i64::MAX)); }
760 }
761
762 #[test]
763 fn test_negative_division() {
764 unsafe {
765 let stack = crate::stack::alloc_test_stack();
767 let stack = push_int(stack, -10);
768 let stack = push_int(stack, 3);
769 let stack = divide(stack);
770 let (_stack, result) = pop(stack);
771 assert_eq!(result, Value::Int(-3)); let stack = push_int(stack, 10);
775 let stack = push_int(stack, -3);
776 let stack = divide(stack);
777 let (_stack, result) = pop(stack);
778 assert_eq!(result, Value::Int(-3));
779
780 let stack = push_int(stack, -10);
782 let stack = push_int(stack, -3);
783 let stack = divide(stack);
784 let (_stack, result) = pop(stack);
785 assert_eq!(result, Value::Int(3));
786 }
787 }
788
789 #[test]
791 #[cfg(not(feature = "nanbox"))]
792 fn test_division_overflow_edge_case() {
793 unsafe {
796 let stack = crate::stack::alloc_test_stack();
797 let stack = push_int(stack, i64::MIN);
798 let stack = push_int(stack, -1);
799 let stack = divide(stack);
800 let (_stack, result) = pop(stack);
801 assert_eq!(result, Value::Int(i64::MIN));
803 }
804 }
805
806 #[test]
807 fn test_and_true_true() {
808 unsafe {
809 let stack = crate::stack::alloc_test_stack();
810 let stack = push_int(stack, 1);
811 let stack = push_int(stack, 1);
812 let stack = and(stack);
813 let (_stack, result) = pop(stack);
814 assert_eq!(result, Value::Int(1));
815 }
816 }
817
818 #[test]
819 fn test_and_true_false() {
820 unsafe {
821 let stack = crate::stack::alloc_test_stack();
822 let stack = push_int(stack, 1);
823 let stack = push_int(stack, 0);
824 let stack = and(stack);
825 let (_stack, result) = pop(stack);
826 assert_eq!(result, Value::Int(0));
827 }
828 }
829
830 #[test]
831 fn test_and_false_false() {
832 unsafe {
833 let stack = crate::stack::alloc_test_stack();
834 let stack = push_int(stack, 0);
835 let stack = push_int(stack, 0);
836 let stack = and(stack);
837 let (_stack, result) = pop(stack);
838 assert_eq!(result, Value::Int(0));
839 }
840 }
841
842 #[test]
843 fn test_or_true_true() {
844 unsafe {
845 let stack = crate::stack::alloc_test_stack();
846 let stack = push_int(stack, 1);
847 let stack = push_int(stack, 1);
848 let stack = or(stack);
849 let (_stack, result) = pop(stack);
850 assert_eq!(result, Value::Int(1));
851 }
852 }
853
854 #[test]
855 fn test_or_true_false() {
856 unsafe {
857 let stack = crate::stack::alloc_test_stack();
858 let stack = push_int(stack, 1);
859 let stack = push_int(stack, 0);
860 let stack = or(stack);
861 let (_stack, result) = pop(stack);
862 assert_eq!(result, Value::Int(1));
863 }
864 }
865
866 #[test]
867 fn test_or_false_false() {
868 unsafe {
869 let stack = crate::stack::alloc_test_stack();
870 let stack = push_int(stack, 0);
871 let stack = push_int(stack, 0);
872 let stack = or(stack);
873 let (_stack, result) = pop(stack);
874 assert_eq!(result, Value::Int(0));
875 }
876 }
877
878 #[test]
879 fn test_not_true() {
880 unsafe {
881 let stack = crate::stack::alloc_test_stack();
882 let stack = push_int(stack, 1);
883 let stack = not(stack);
884 let (_stack, result) = pop(stack);
885 assert_eq!(result, Value::Int(0));
886 }
887 }
888
889 #[test]
890 fn test_not_false() {
891 unsafe {
892 let stack = crate::stack::alloc_test_stack();
893 let stack = push_int(stack, 0);
894 let stack = not(stack);
895 let (_stack, result) = pop(stack);
896 assert_eq!(result, Value::Int(1));
897 }
898 }
899
900 #[test]
901 fn test_and_nonzero_values() {
902 unsafe {
904 let stack = crate::stack::alloc_test_stack();
905 let stack = push_int(stack, 42);
906 let stack = push_int(stack, -5);
907 let stack = and(stack);
908 let (_stack, result) = pop(stack);
909 assert_eq!(result, Value::Int(1));
910 }
911 }
912
913 #[test]
914 fn test_divide_by_zero_sets_error() {
915 unsafe {
916 crate::error::clear_runtime_error();
917 let stack = crate::stack::alloc_test_stack();
918 let stack = push_int(stack, 42);
919 let stack = push_int(stack, 0);
920 let stack = divide(stack);
921
922 assert!(crate::error::has_runtime_error());
924 let error = crate::error::take_runtime_error().unwrap();
925 assert!(error.contains("division by zero"));
926
927 let (_stack, result) = pop(stack);
929 assert_eq!(result, Value::Int(0));
930 }
931 }
932}