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