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