1use crate::stack::DISC_INT;
25use crate::stack::{Stack, peek_sv, pop, pop_two, push};
26use crate::value::Value;
27
28#[unsafe(no_mangle)]
35pub unsafe extern "C" fn patch_seq_push_int(stack: Stack, value: i64) -> Stack {
36 unsafe { push(stack, Value::Int(value)) }
37}
38
39#[unsafe(no_mangle)]
46pub unsafe extern "C" fn patch_seq_push_bool(stack: Stack, value: bool) -> Stack {
47 unsafe { push(stack, Value::Bool(value)) }
48}
49
50#[unsafe(no_mangle)]
57pub unsafe extern "C" fn patch_seq_add(stack: Stack) -> Stack {
58 let (rest, a, b) = unsafe { pop_two(stack, "add") };
59 match (a, b) {
60 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
61 push(rest, Value::Int(a_val.wrapping_add(b_val)))
62 },
63 _ => panic!("add: expected two integers on stack"),
64 }
65}
66
67#[unsafe(no_mangle)]
74pub unsafe extern "C" fn patch_seq_subtract(stack: Stack) -> Stack {
75 let (rest, a, b) = unsafe { pop_two(stack, "subtract") };
76 match (a, b) {
77 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
78 push(rest, Value::Int(a_val.wrapping_sub(b_val)))
79 },
80 _ => panic!("subtract: expected two integers on stack"),
81 }
82}
83
84#[unsafe(no_mangle)]
91pub unsafe extern "C" fn patch_seq_multiply(stack: Stack) -> Stack {
92 let (rest, a, b) = unsafe { pop_two(stack, "multiply") };
93 match (a, b) {
94 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
95 push(rest, Value::Int(a_val.wrapping_mul(b_val)))
96 },
97 _ => panic!("multiply: expected two integers on stack"),
98 }
99}
100
101#[unsafe(no_mangle)]
112pub unsafe extern "C" fn patch_seq_divide(stack: Stack) -> Stack {
113 let (rest, a, b) = unsafe { pop_two(stack, "divide") };
114 match (a, b) {
115 (Value::Int(_a_val), Value::Int(0)) => {
116 let stack = unsafe { push(rest, Value::Int(0)) };
118 unsafe { push(stack, Value::Bool(false)) }
119 }
120 (Value::Int(a_val), Value::Int(b_val)) => {
121 let stack = unsafe { push(rest, Value::Int(a_val.wrapping_div(b_val))) };
123 unsafe { push(stack, Value::Bool(true)) }
124 }
125 _ => {
126 panic!("divide: expected two integers on stack");
128 }
129 }
130}
131
132#[unsafe(no_mangle)]
143pub unsafe extern "C" fn patch_seq_modulo(stack: Stack) -> Stack {
144 let (rest, a, b) = unsafe { pop_two(stack, "modulo") };
145 match (a, b) {
146 (Value::Int(_a_val), Value::Int(0)) => {
147 let stack = unsafe { push(rest, Value::Int(0)) };
149 unsafe { push(stack, Value::Bool(false)) }
150 }
151 (Value::Int(a_val), Value::Int(b_val)) => {
152 let stack = unsafe { push(rest, Value::Int(a_val.wrapping_rem(b_val))) };
154 unsafe { push(stack, Value::Bool(true)) }
155 }
156 _ => {
157 panic!("modulo: expected two integers on stack");
159 }
160 }
161}
162
163#[unsafe(no_mangle)]
171pub unsafe extern "C" fn patch_seq_eq(stack: Stack) -> Stack {
172 let (rest, a, b) = unsafe { pop_two(stack, "=") };
173 match (a, b) {
174 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
175 push(rest, Value::Bool(a_val == b_val))
176 },
177 _ => panic!("=: expected two integers on stack"),
178 }
179}
180
181#[unsafe(no_mangle)]
189pub unsafe extern "C" fn patch_seq_lt(stack: Stack) -> Stack {
190 let (rest, a, b) = unsafe { pop_two(stack, "<") };
191 match (a, b) {
192 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val < b_val)) },
193 _ => panic!("<: expected two integers on stack"),
194 }
195}
196
197#[unsafe(no_mangle)]
205pub unsafe extern "C" fn patch_seq_gt(stack: Stack) -> Stack {
206 let (rest, a, b) = unsafe { pop_two(stack, ">") };
207 match (a, b) {
208 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val > b_val)) },
209 _ => panic!(">: expected two integers on stack"),
210 }
211}
212
213#[unsafe(no_mangle)]
221pub unsafe extern "C" fn patch_seq_lte(stack: Stack) -> Stack {
222 let (rest, a, b) = unsafe { pop_two(stack, "<=") };
223 match (a, b) {
224 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
225 push(rest, Value::Bool(a_val <= b_val))
226 },
227 _ => panic!("<=: expected two integers on stack"),
228 }
229}
230
231#[unsafe(no_mangle)]
239pub unsafe extern "C" fn patch_seq_gte(stack: Stack) -> Stack {
240 let (rest, a, b) = unsafe { pop_two(stack, ">=") };
241 match (a, b) {
242 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
243 push(rest, Value::Bool(a_val >= b_val))
244 },
245 _ => panic!(">=: expected two integers on stack"),
246 }
247}
248
249#[unsafe(no_mangle)]
257pub unsafe extern "C" fn patch_seq_neq(stack: Stack) -> Stack {
258 let (rest, a, b) = unsafe { pop_two(stack, "<>") };
259 match (a, b) {
260 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
261 push(rest, Value::Bool(a_val != b_val))
262 },
263 _ => panic!("<>: expected two integers on stack"),
264 }
265}
266
267#[unsafe(no_mangle)]
276pub unsafe extern "C" fn patch_seq_and(stack: Stack) -> Stack {
277 let (rest, a, b) = unsafe { pop_two(stack, "and") };
278 match (a, b) {
279 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
280 push(
281 rest,
282 Value::Int(if a_val != 0 && b_val != 0 { 1 } else { 0 }),
283 )
284 },
285 _ => panic!("and: expected two integers on stack"),
286 }
287}
288
289#[unsafe(no_mangle)]
298pub unsafe extern "C" fn patch_seq_or(stack: Stack) -> Stack {
299 let (rest, a, b) = unsafe { pop_two(stack, "or") };
300 match (a, b) {
301 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
302 push(
303 rest,
304 Value::Int(if a_val != 0 || b_val != 0 { 1 } else { 0 }),
305 )
306 },
307 _ => panic!("or: expected two integers on stack"),
308 }
309}
310
311#[unsafe(no_mangle)]
320pub unsafe extern "C" fn patch_seq_not(stack: Stack) -> Stack {
321 assert!(!stack.is_null(), "not: stack is empty");
322 let (rest, a) = unsafe { pop(stack) };
323
324 match a {
325 Value::Int(a_val) => unsafe { push(rest, Value::Int(if a_val == 0 { 1 } else { 0 })) },
326 _ => panic!("not: expected integer on stack"),
327 }
328}
329
330#[unsafe(no_mangle)]
341pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
342 let (rest, a, b) = unsafe { pop_two(stack, "band") };
343 match (a, b) {
344 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
345 _ => panic!("band: expected two integers on stack"),
346 }
347}
348
349#[unsafe(no_mangle)]
356pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
357 let (rest, a, b) = unsafe { pop_two(stack, "bor") };
358 match (a, b) {
359 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
360 _ => panic!("bor: expected two integers on stack"),
361 }
362}
363
364#[unsafe(no_mangle)]
371pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
372 let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
373 match (a, b) {
374 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
375 _ => panic!("bxor: expected two integers on stack"),
376 }
377}
378
379#[unsafe(no_mangle)]
386pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
387 assert!(!stack.is_null(), "bnot: stack is empty");
388 let (rest, a) = unsafe { pop(stack) };
389 match a {
390 Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
391 _ => panic!("bnot: expected integer on stack"),
392 }
393}
394
395#[unsafe(no_mangle)]
403pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
404 let (rest, value, count) = unsafe { pop_two(stack, "shl") };
405 match (value, count) {
406 (Value::Int(v), Value::Int(c)) => {
407 let result = if c < 0 {
410 0
411 } else {
412 v.checked_shl(c as u32).unwrap_or(0)
413 };
414 unsafe { push(rest, Value::Int(result)) }
415 }
416 _ => panic!("shl: expected two integers on stack"),
417 }
418}
419
420#[unsafe(no_mangle)]
429pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
430 let (rest, value, count) = unsafe { pop_two(stack, "shr") };
431 match (value, count) {
432 (Value::Int(v), Value::Int(c)) => {
433 let result = if c < 0 {
436 0
437 } else {
438 (v as u64).checked_shr(c as u32).unwrap_or(0) as i64
439 };
440 unsafe { push(rest, Value::Int(result)) }
441 }
442 _ => panic!("shr: expected two integers on stack"),
443 }
444}
445
446#[unsafe(no_mangle)]
453pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
454 assert!(!stack.is_null(), "popcount: stack is empty");
455 let (rest, a) = unsafe { pop(stack) };
456 match a {
457 Value::Int(v) => unsafe { push(rest, Value::Int(v.count_ones() as i64)) },
458 _ => panic!("popcount: expected integer on stack"),
459 }
460}
461
462#[unsafe(no_mangle)]
469pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
470 assert!(!stack.is_null(), "clz: stack is empty");
471 let (rest, a) = unsafe { pop(stack) };
472 match a {
473 Value::Int(v) => unsafe { push(rest, Value::Int(v.leading_zeros() as i64)) },
474 _ => panic!("clz: expected integer on stack"),
475 }
476}
477
478#[unsafe(no_mangle)]
485pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
486 assert!(!stack.is_null(), "ctz: stack is empty");
487 let (rest, a) = unsafe { pop(stack) };
488 match a {
489 Value::Int(v) => unsafe { push(rest, Value::Int(v.trailing_zeros() as i64)) },
490 _ => panic!("ctz: expected integer on stack"),
491 }
492}
493
494#[unsafe(no_mangle)]
501pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
502 unsafe { push(stack, Value::Int(64)) }
503}
504
505#[unsafe(no_mangle)]
525pub unsafe extern "C" fn patch_seq_peek_int_value(stack: Stack) -> i64 {
526 assert!(!stack.is_null(), "peek_int_value: stack is empty");
527
528 let sv = unsafe { peek_sv(stack) };
530 if sv.slot0 == DISC_INT {
531 sv.slot1 as i64
532 } else {
533 panic!(
534 "peek_int_value: expected Int on stack, got discriminant {}",
535 sv.slot0
536 )
537 }
538}
539
540#[unsafe(no_mangle)]
545pub unsafe extern "C" fn patch_seq_peek_bool_value(stack: Stack) -> bool {
546 use crate::stack::DISC_BOOL;
547 assert!(!stack.is_null(), "peek_bool_value: stack is empty");
548
549 let sv = unsafe { peek_sv(stack) };
551 if sv.slot0 == DISC_BOOL {
552 sv.slot1 != 0
553 } else {
554 panic!(
555 "peek_bool_value: expected Bool on stack, got discriminant {}",
556 sv.slot0
557 )
558 }
559}
560
561#[unsafe(no_mangle)]
571pub unsafe extern "C" fn patch_seq_pop_stack(stack: Stack) -> Stack {
572 assert!(!stack.is_null(), "pop_stack: stack is empty");
573 let (rest, _value) = unsafe { pop(stack) };
574 rest
575}
576
577pub use patch_seq_add as add;
579pub use patch_seq_and as and;
580pub use patch_seq_band as band;
581pub use patch_seq_bnot as bnot;
582pub use patch_seq_bor as bor;
583pub use patch_seq_bxor as bxor;
584pub use patch_seq_clz as clz;
585pub use patch_seq_ctz as ctz;
586pub use patch_seq_divide as divide;
587pub use patch_seq_eq as eq;
588pub use patch_seq_gt as gt;
589pub use patch_seq_gte as gte;
590pub use patch_seq_int_bits as int_bits;
591pub use patch_seq_lt as lt;
592pub use patch_seq_lte as lte;
593pub use patch_seq_multiply as multiply;
594pub use patch_seq_neq as neq;
595pub use patch_seq_not as not;
596pub use patch_seq_or as or;
597pub use patch_seq_popcount as popcount;
598pub use patch_seq_push_bool as push_bool;
599pub use patch_seq_push_int as push_int;
600pub use patch_seq_shl as shl;
601pub use patch_seq_shr as shr;
602pub use patch_seq_subtract as subtract;
603
604#[cfg(test)]
605mod tests {
606 use super::*;
607
608 #[test]
609 fn test_add() {
610 unsafe {
611 let stack = crate::stack::alloc_test_stack();
612 let stack = push_int(stack, 5);
613 let stack = push_int(stack, 3);
614 let stack = add(stack);
615
616 let (_stack, result) = pop(stack);
617 assert_eq!(result, Value::Int(8));
618 }
619 }
620
621 #[test]
622 fn test_subtract() {
623 unsafe {
624 let stack = crate::stack::alloc_test_stack();
625 let stack = push_int(stack, 10);
626 let stack = push_int(stack, 3);
627 let stack = subtract(stack);
628
629 let (_stack, result) = pop(stack);
630 assert_eq!(result, Value::Int(7));
631 }
632 }
633
634 #[test]
635 fn test_multiply() {
636 unsafe {
637 let stack = crate::stack::alloc_test_stack();
638 let stack = push_int(stack, 4);
639 let stack = push_int(stack, 5);
640 let stack = multiply(stack);
641
642 let (_stack, result) = pop(stack);
643 assert_eq!(result, Value::Int(20));
644 }
645 }
646
647 #[test]
648 fn test_divide() {
649 unsafe {
650 let stack = crate::stack::alloc_test_stack();
651 let stack = push_int(stack, 20);
652 let stack = push_int(stack, 4);
653 let stack = divide(stack);
654
655 let (stack, success) = pop(stack);
657 assert_eq!(success, Value::Bool(true));
658 let (_stack, result) = pop(stack);
659 assert_eq!(result, Value::Int(5));
660 }
661 }
662
663 #[test]
664 fn test_comparisons() {
665 unsafe {
666 let stack = crate::stack::alloc_test_stack();
668 let stack = push_int(stack, 5);
669 let stack = push_int(stack, 5);
670 let stack = eq(stack);
671 let (_stack, result) = pop(stack);
672 assert_eq!(result, Value::Bool(true));
673
674 let stack = push_int(stack, 3);
676 let stack = push_int(stack, 5);
677 let stack = lt(stack);
678 let (_stack, result) = pop(stack);
679 assert_eq!(result, Value::Bool(true));
680
681 let stack = push_int(stack, 7);
683 let stack = push_int(stack, 5);
684 let stack = gt(stack);
685 let (_stack, result) = pop(stack);
686 assert_eq!(result, Value::Bool(true));
687 }
688 }
689
690 #[test]
692 fn test_overflow_wrapping() {
693 unsafe {
695 let stack = crate::stack::alloc_test_stack();
697 let stack = push_int(stack, i64::MAX);
698 let stack = push_int(stack, 1);
699 let stack = add(stack);
700 let (_stack, result) = pop(stack);
701 assert_eq!(result, Value::Int(i64::MIN)); let stack = push_int(stack, i64::MAX);
705 let stack = push_int(stack, 2);
706 let stack = multiply(stack);
707 let (_stack, result) = pop(stack);
708 assert!(matches!(result, Value::Int(_)));
710
711 let stack = push_int(stack, i64::MIN);
713 let stack = push_int(stack, 1);
714 let stack = subtract(stack);
715 let (_stack, result) = pop(stack);
716 assert_eq!(result, Value::Int(i64::MAX)); }
718 }
719
720 #[test]
721 fn test_negative_division() {
722 unsafe {
723 let stack = crate::stack::alloc_test_stack();
725 let stack = push_int(stack, -10);
726 let stack = push_int(stack, 3);
727 let stack = divide(stack);
728 let (stack, success) = pop(stack);
729 assert_eq!(success, Value::Bool(true));
730 let (_stack, result) = pop(stack);
731 assert_eq!(result, Value::Int(-3)); let stack = push_int(stack, 10);
735 let stack = push_int(stack, -3);
736 let stack = divide(stack);
737 let (stack, success) = pop(stack);
738 assert_eq!(success, Value::Bool(true));
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, success) = pop(stack);
747 assert_eq!(success, Value::Bool(true));
748 let (_stack, result) = pop(stack);
749 assert_eq!(result, Value::Int(3));
750 }
751 }
752
753 #[test]
755 fn test_division_overflow_edge_case() {
756 unsafe {
759 let stack = crate::stack::alloc_test_stack();
760 let stack = push_int(stack, i64::MIN);
761 let stack = push_int(stack, -1);
762 let stack = divide(stack);
763 let (stack, success) = pop(stack);
764 assert_eq!(success, Value::Bool(true));
765 let (_stack, result) = pop(stack);
766 assert_eq!(result, Value::Int(i64::MIN));
768 }
769 }
770
771 #[test]
772 fn test_and_true_true() {
773 unsafe {
774 let stack = crate::stack::alloc_test_stack();
775 let stack = push_int(stack, 1);
776 let stack = push_int(stack, 1);
777 let stack = and(stack);
778 let (_stack, result) = pop(stack);
779 assert_eq!(result, Value::Int(1));
780 }
781 }
782
783 #[test]
784 fn test_and_true_false() {
785 unsafe {
786 let stack = crate::stack::alloc_test_stack();
787 let stack = push_int(stack, 1);
788 let stack = push_int(stack, 0);
789 let stack = and(stack);
790 let (_stack, result) = pop(stack);
791 assert_eq!(result, Value::Int(0));
792 }
793 }
794
795 #[test]
796 fn test_and_false_false() {
797 unsafe {
798 let stack = crate::stack::alloc_test_stack();
799 let stack = push_int(stack, 0);
800 let stack = push_int(stack, 0);
801 let stack = and(stack);
802 let (_stack, result) = pop(stack);
803 assert_eq!(result, Value::Int(0));
804 }
805 }
806
807 #[test]
808 fn test_or_true_true() {
809 unsafe {
810 let stack = crate::stack::alloc_test_stack();
811 let stack = push_int(stack, 1);
812 let stack = push_int(stack, 1);
813 let stack = or(stack);
814 let (_stack, result) = pop(stack);
815 assert_eq!(result, Value::Int(1));
816 }
817 }
818
819 #[test]
820 fn test_or_true_false() {
821 unsafe {
822 let stack = crate::stack::alloc_test_stack();
823 let stack = push_int(stack, 1);
824 let stack = push_int(stack, 0);
825 let stack = or(stack);
826 let (_stack, result) = pop(stack);
827 assert_eq!(result, Value::Int(1));
828 }
829 }
830
831 #[test]
832 fn test_or_false_false() {
833 unsafe {
834 let stack = crate::stack::alloc_test_stack();
835 let stack = push_int(stack, 0);
836 let stack = push_int(stack, 0);
837 let stack = or(stack);
838 let (_stack, result) = pop(stack);
839 assert_eq!(result, Value::Int(0));
840 }
841 }
842
843 #[test]
844 fn test_not_true() {
845 unsafe {
846 let stack = crate::stack::alloc_test_stack();
847 let stack = push_int(stack, 1);
848 let stack = not(stack);
849 let (_stack, result) = pop(stack);
850 assert_eq!(result, Value::Int(0));
851 }
852 }
853
854 #[test]
855 fn test_not_false() {
856 unsafe {
857 let stack = crate::stack::alloc_test_stack();
858 let stack = push_int(stack, 0);
859 let stack = not(stack);
860 let (_stack, result) = pop(stack);
861 assert_eq!(result, Value::Int(1));
862 }
863 }
864
865 #[test]
866 fn test_and_nonzero_values() {
867 unsafe {
869 let stack = crate::stack::alloc_test_stack();
870 let stack = push_int(stack, 42);
871 let stack = push_int(stack, -5);
872 let stack = and(stack);
873 let (_stack, result) = pop(stack);
874 assert_eq!(result, Value::Int(1));
875 }
876 }
877
878 #[test]
879 fn test_divide_by_zero_returns_false() {
880 unsafe {
881 let stack = crate::stack::alloc_test_stack();
882 let stack = push_int(stack, 42);
883 let stack = push_int(stack, 0);
884 let stack = divide(stack);
885
886 let (stack, success) = pop(stack);
888 assert_eq!(success, Value::Bool(false));
889
890 let (_stack, result) = pop(stack);
892 assert_eq!(result, Value::Int(0));
893 }
894 }
895}