1use crate::stack::{DISC_INT, Stack, peek_sv, pop, pop_two, push};
25use crate::value::Value;
26
27#[unsafe(no_mangle)]
34pub unsafe extern "C" fn patch_seq_push_int(stack: Stack, value: i64) -> Stack {
35 unsafe { push(stack, Value::Int(value)) }
36}
37
38#[unsafe(no_mangle)]
45pub unsafe extern "C" fn patch_seq_push_bool(stack: Stack, value: bool) -> Stack {
46 unsafe { push(stack, Value::Bool(value)) }
47}
48
49#[unsafe(no_mangle)]
56pub unsafe extern "C" fn patch_seq_add(stack: Stack) -> Stack {
57 let (rest, a, b) = unsafe { pop_two(stack, "add") };
58 match (a, b) {
59 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
60 push(rest, Value::Int(a_val.wrapping_add(b_val)))
61 },
62 _ => panic!("add: expected two integers on stack"),
63 }
64}
65
66#[unsafe(no_mangle)]
73pub unsafe extern "C" fn patch_seq_subtract(stack: Stack) -> Stack {
74 let (rest, a, b) = unsafe { pop_two(stack, "subtract") };
75 match (a, b) {
76 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
77 push(rest, Value::Int(a_val.wrapping_sub(b_val)))
78 },
79 _ => panic!("subtract: expected two integers on stack"),
80 }
81}
82
83#[unsafe(no_mangle)]
90pub unsafe extern "C" fn patch_seq_multiply(stack: Stack) -> Stack {
91 let (rest, a, b) = unsafe { pop_two(stack, "multiply") };
92 match (a, b) {
93 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
94 push(rest, Value::Int(a_val.wrapping_mul(b_val)))
95 },
96 _ => panic!("multiply: expected two integers on stack"),
97 }
98}
99
100#[unsafe(no_mangle)]
107pub unsafe extern "C" fn patch_seq_divide(stack: Stack) -> Stack {
108 let (rest, a, b) = unsafe { pop_two(stack, "divide") };
109 match (a, b) {
110 (Value::Int(a_val), Value::Int(b_val)) => {
111 assert!(
112 b_val != 0,
113 "divide: division by zero (attempted {} / {})",
114 a_val,
115 b_val
116 );
117 unsafe { push(rest, Value::Int(a_val.wrapping_div(b_val))) }
119 }
120 _ => panic!("divide: expected two integers on stack"),
121 }
122}
123
124#[unsafe(no_mangle)]
132pub unsafe extern "C" fn patch_seq_eq(stack: Stack) -> Stack {
133 let (rest, a, b) = unsafe { pop_two(stack, "=") };
134 match (a, b) {
135 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
136 push(rest, Value::Int(if a_val == b_val { 1 } else { 0 }))
137 },
138 _ => panic!("=: expected two integers on stack"),
139 }
140}
141
142#[unsafe(no_mangle)]
150pub unsafe extern "C" fn patch_seq_lt(stack: Stack) -> Stack {
151 let (rest, a, b) = unsafe { pop_two(stack, "<") };
152 match (a, b) {
153 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
154 push(rest, Value::Int(if a_val < b_val { 1 } else { 0 }))
155 },
156 _ => panic!("<: expected two integers on stack"),
157 }
158}
159
160#[unsafe(no_mangle)]
168pub unsafe extern "C" fn patch_seq_gt(stack: Stack) -> Stack {
169 let (rest, a, b) = unsafe { pop_two(stack, ">") };
170 match (a, b) {
171 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
172 push(rest, Value::Int(if a_val > b_val { 1 } else { 0 }))
173 },
174 _ => panic!(">: expected two integers on stack"),
175 }
176}
177
178#[unsafe(no_mangle)]
186pub unsafe extern "C" fn patch_seq_lte(stack: Stack) -> Stack {
187 let (rest, a, b) = unsafe { pop_two(stack, "<=") };
188 match (a, b) {
189 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
190 push(rest, Value::Int(if a_val <= b_val { 1 } else { 0 }))
191 },
192 _ => panic!("<=: expected two integers on stack"),
193 }
194}
195
196#[unsafe(no_mangle)]
204pub unsafe extern "C" fn patch_seq_gte(stack: Stack) -> Stack {
205 let (rest, a, b) = unsafe { pop_two(stack, ">=") };
206 match (a, b) {
207 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
208 push(rest, Value::Int(if a_val >= b_val { 1 } else { 0 }))
209 },
210 _ => panic!(">=: expected two integers on stack"),
211 }
212}
213
214#[unsafe(no_mangle)]
222pub unsafe extern "C" fn patch_seq_neq(stack: Stack) -> Stack {
223 let (rest, a, b) = unsafe { pop_two(stack, "<>") };
224 match (a, b) {
225 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
226 push(rest, Value::Int(if a_val != b_val { 1 } else { 0 }))
227 },
228 _ => panic!("<>: expected two integers on stack"),
229 }
230}
231
232#[unsafe(no_mangle)]
241pub unsafe extern "C" fn patch_seq_and(stack: Stack) -> Stack {
242 let (rest, a, b) = unsafe { pop_two(stack, "and") };
243 match (a, b) {
244 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
245 push(
246 rest,
247 Value::Int(if a_val != 0 && b_val != 0 { 1 } else { 0 }),
248 )
249 },
250 _ => panic!("and: expected two integers on stack"),
251 }
252}
253
254#[unsafe(no_mangle)]
263pub unsafe extern "C" fn patch_seq_or(stack: Stack) -> Stack {
264 let (rest, a, b) = unsafe { pop_two(stack, "or") };
265 match (a, b) {
266 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
267 push(
268 rest,
269 Value::Int(if a_val != 0 || b_val != 0 { 1 } else { 0 }),
270 )
271 },
272 _ => panic!("or: expected two integers on stack"),
273 }
274}
275
276#[unsafe(no_mangle)]
285pub unsafe extern "C" fn patch_seq_not(stack: Stack) -> Stack {
286 assert!(!stack.is_null(), "not: stack is empty");
287 let (rest, a) = unsafe { pop(stack) };
288
289 match a {
290 Value::Int(a_val) => unsafe { push(rest, Value::Int(if a_val == 0 { 1 } else { 0 })) },
291 _ => panic!("not: expected integer on stack"),
292 }
293}
294
295#[unsafe(no_mangle)]
306pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
307 let (rest, a, b) = unsafe { pop_two(stack, "band") };
308 match (a, b) {
309 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
310 _ => panic!("band: expected two integers on stack"),
311 }
312}
313
314#[unsafe(no_mangle)]
321pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
322 let (rest, a, b) = unsafe { pop_two(stack, "bor") };
323 match (a, b) {
324 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
325 _ => panic!("bor: expected two integers on stack"),
326 }
327}
328
329#[unsafe(no_mangle)]
336pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
337 let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
338 match (a, b) {
339 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
340 _ => panic!("bxor: expected two integers on stack"),
341 }
342}
343
344#[unsafe(no_mangle)]
351pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
352 assert!(!stack.is_null(), "bnot: stack is empty");
353 let (rest, a) = unsafe { pop(stack) };
354 match a {
355 Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
356 _ => panic!("bnot: expected integer on stack"),
357 }
358}
359
360#[unsafe(no_mangle)]
368pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
369 let (rest, value, count) = unsafe { pop_two(stack, "shl") };
370 match (value, count) {
371 (Value::Int(v), Value::Int(c)) => {
372 let result = if c < 0 {
375 0
376 } else {
377 v.checked_shl(c as u32).unwrap_or(0)
378 };
379 unsafe { push(rest, Value::Int(result)) }
380 }
381 _ => panic!("shl: expected two integers on stack"),
382 }
383}
384
385#[unsafe(no_mangle)]
394pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
395 let (rest, value, count) = unsafe { pop_two(stack, "shr") };
396 match (value, count) {
397 (Value::Int(v), Value::Int(c)) => {
398 let result = if c < 0 {
401 0
402 } else {
403 (v as u64).checked_shr(c as u32).unwrap_or(0) as i64
404 };
405 unsafe { push(rest, Value::Int(result)) }
406 }
407 _ => panic!("shr: expected two integers on stack"),
408 }
409}
410
411#[unsafe(no_mangle)]
418pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
419 assert!(!stack.is_null(), "popcount: stack is empty");
420 let (rest, a) = unsafe { pop(stack) };
421 match a {
422 Value::Int(v) => unsafe { push(rest, Value::Int(v.count_ones() as i64)) },
423 _ => panic!("popcount: expected integer on stack"),
424 }
425}
426
427#[unsafe(no_mangle)]
434pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
435 assert!(!stack.is_null(), "clz: stack is empty");
436 let (rest, a) = unsafe { pop(stack) };
437 match a {
438 Value::Int(v) => unsafe { push(rest, Value::Int(v.leading_zeros() as i64)) },
439 _ => panic!("clz: expected integer on stack"),
440 }
441}
442
443#[unsafe(no_mangle)]
450pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
451 assert!(!stack.is_null(), "ctz: stack is empty");
452 let (rest, a) = unsafe { pop(stack) };
453 match a {
454 Value::Int(v) => unsafe { push(rest, Value::Int(v.trailing_zeros() as i64)) },
455 _ => panic!("ctz: expected integer on stack"),
456 }
457}
458
459#[unsafe(no_mangle)]
466pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
467 unsafe { push(stack, Value::Int(64)) }
468}
469
470#[unsafe(no_mangle)]
490pub unsafe extern "C" fn patch_seq_peek_int_value(stack: Stack) -> i64 {
491 assert!(!stack.is_null(), "peek_int_value: stack is empty");
492
493 let sv = unsafe { peek_sv(stack) };
495 if sv.slot0 == DISC_INT {
496 sv.slot1 as i64
497 } else {
498 panic!(
499 "peek_int_value: expected Int on stack, got discriminant {}",
500 sv.slot0
501 )
502 }
503}
504
505#[unsafe(no_mangle)]
515pub unsafe extern "C" fn patch_seq_pop_stack(stack: Stack) -> Stack {
516 assert!(!stack.is_null(), "pop_stack: stack is empty");
517 let (rest, _value) = unsafe { pop(stack) };
518 rest
519}
520
521pub use patch_seq_add as add;
523pub use patch_seq_and as and;
524pub use patch_seq_band as band;
525pub use patch_seq_bnot as bnot;
526pub use patch_seq_bor as bor;
527pub use patch_seq_bxor as bxor;
528pub use patch_seq_clz as clz;
529pub use patch_seq_ctz as ctz;
530pub use patch_seq_divide as divide;
531pub use patch_seq_eq as eq;
532pub use patch_seq_gt as gt;
533pub use patch_seq_gte as gte;
534pub use patch_seq_int_bits as int_bits;
535pub use patch_seq_lt as lt;
536pub use patch_seq_lte as lte;
537pub use patch_seq_multiply as multiply;
538pub use patch_seq_neq as neq;
539pub use patch_seq_not as not;
540pub use patch_seq_or as or;
541pub use patch_seq_popcount as popcount;
542pub use patch_seq_push_bool as push_bool;
543pub use patch_seq_push_int as push_int;
544pub use patch_seq_shl as shl;
545pub use patch_seq_shr as shr;
546pub use patch_seq_subtract as subtract;
547
548#[cfg(test)]
549mod tests {
550 use super::*;
551
552 #[test]
553 fn test_add() {
554 unsafe {
555 let stack = crate::stack::alloc_test_stack();
556 let stack = push_int(stack, 5);
557 let stack = push_int(stack, 3);
558 let stack = add(stack);
559
560 let (_stack, result) = pop(stack);
561 assert_eq!(result, Value::Int(8));
562 }
563 }
564
565 #[test]
566 fn test_subtract() {
567 unsafe {
568 let stack = crate::stack::alloc_test_stack();
569 let stack = push_int(stack, 10);
570 let stack = push_int(stack, 3);
571 let stack = subtract(stack);
572
573 let (_stack, result) = pop(stack);
574 assert_eq!(result, Value::Int(7));
575 }
576 }
577
578 #[test]
579 fn test_multiply() {
580 unsafe {
581 let stack = crate::stack::alloc_test_stack();
582 let stack = push_int(stack, 4);
583 let stack = push_int(stack, 5);
584 let stack = multiply(stack);
585
586 let (_stack, result) = pop(stack);
587 assert_eq!(result, Value::Int(20));
588 }
589 }
590
591 #[test]
592 fn test_divide() {
593 unsafe {
594 let stack = crate::stack::alloc_test_stack();
595 let stack = push_int(stack, 20);
596 let stack = push_int(stack, 4);
597 let stack = divide(stack);
598
599 let (_stack, result) = pop(stack);
600 assert_eq!(result, Value::Int(5));
601 }
602 }
603
604 #[test]
605 fn test_comparisons() {
606 unsafe {
607 let stack = crate::stack::alloc_test_stack();
609 let stack = push_int(stack, 5);
610 let stack = push_int(stack, 5);
611 let stack = eq(stack);
612 let (_stack, result) = pop(stack);
613 assert_eq!(result, Value::Int(1)); let stack = push_int(stack, 3);
617 let stack = push_int(stack, 5);
618 let stack = lt(stack);
619 let (_stack, result) = pop(stack);
620 assert_eq!(result, Value::Int(1)); let stack = push_int(stack, 7);
624 let stack = push_int(stack, 5);
625 let stack = gt(stack);
626 let (_stack, result) = pop(stack);
627 assert_eq!(result, Value::Int(1)); }
629 }
630
631 #[test]
632 fn test_overflow_wrapping() {
633 unsafe {
635 let stack = crate::stack::alloc_test_stack();
637 let stack = push_int(stack, i64::MAX);
638 let stack = push_int(stack, 1);
639 let stack = add(stack);
640 let (_stack, result) = pop(stack);
641 assert_eq!(result, Value::Int(i64::MIN)); let stack = push_int(stack, i64::MAX);
645 let stack = push_int(stack, 2);
646 let stack = multiply(stack);
647 let (_stack, result) = pop(stack);
648 assert!(matches!(result, Value::Int(_)));
650
651 let stack = push_int(stack, i64::MIN);
653 let stack = push_int(stack, 1);
654 let stack = subtract(stack);
655 let (_stack, result) = pop(stack);
656 assert_eq!(result, Value::Int(i64::MAX)); }
658 }
659
660 #[test]
661 fn test_negative_division() {
662 unsafe {
663 let stack = crate::stack::alloc_test_stack();
665 let stack = push_int(stack, -10);
666 let stack = push_int(stack, 3);
667 let stack = divide(stack);
668 let (_stack, result) = pop(stack);
669 assert_eq!(result, Value::Int(-3)); let stack = push_int(stack, 10);
673 let stack = push_int(stack, -3);
674 let stack = divide(stack);
675 let (_stack, result) = pop(stack);
676 assert_eq!(result, Value::Int(-3));
677
678 let stack = push_int(stack, -10);
680 let stack = push_int(stack, -3);
681 let stack = divide(stack);
682 let (_stack, result) = pop(stack);
683 assert_eq!(result, Value::Int(3));
684 }
685 }
686
687 #[test]
688 fn test_division_overflow_edge_case() {
689 unsafe {
692 let stack = crate::stack::alloc_test_stack();
693 let stack = push_int(stack, i64::MIN);
694 let stack = push_int(stack, -1);
695 let stack = divide(stack);
696 let (_stack, result) = pop(stack);
697 assert_eq!(result, Value::Int(i64::MIN));
699 }
700 }
701
702 #[test]
703 fn test_and_true_true() {
704 unsafe {
705 let stack = crate::stack::alloc_test_stack();
706 let stack = push_int(stack, 1);
707 let stack = push_int(stack, 1);
708 let stack = and(stack);
709 let (_stack, result) = pop(stack);
710 assert_eq!(result, Value::Int(1));
711 }
712 }
713
714 #[test]
715 fn test_and_true_false() {
716 unsafe {
717 let stack = crate::stack::alloc_test_stack();
718 let stack = push_int(stack, 1);
719 let stack = push_int(stack, 0);
720 let stack = and(stack);
721 let (_stack, result) = pop(stack);
722 assert_eq!(result, Value::Int(0));
723 }
724 }
725
726 #[test]
727 fn test_and_false_false() {
728 unsafe {
729 let stack = crate::stack::alloc_test_stack();
730 let stack = push_int(stack, 0);
731 let stack = push_int(stack, 0);
732 let stack = and(stack);
733 let (_stack, result) = pop(stack);
734 assert_eq!(result, Value::Int(0));
735 }
736 }
737
738 #[test]
739 fn test_or_true_true() {
740 unsafe {
741 let stack = crate::stack::alloc_test_stack();
742 let stack = push_int(stack, 1);
743 let stack = push_int(stack, 1);
744 let stack = or(stack);
745 let (_stack, result) = pop(stack);
746 assert_eq!(result, Value::Int(1));
747 }
748 }
749
750 #[test]
751 fn test_or_true_false() {
752 unsafe {
753 let stack = crate::stack::alloc_test_stack();
754 let stack = push_int(stack, 1);
755 let stack = push_int(stack, 0);
756 let stack = or(stack);
757 let (_stack, result) = pop(stack);
758 assert_eq!(result, Value::Int(1));
759 }
760 }
761
762 #[test]
763 fn test_or_false_false() {
764 unsafe {
765 let stack = crate::stack::alloc_test_stack();
766 let stack = push_int(stack, 0);
767 let stack = push_int(stack, 0);
768 let stack = or(stack);
769 let (_stack, result) = pop(stack);
770 assert_eq!(result, Value::Int(0));
771 }
772 }
773
774 #[test]
775 fn test_not_true() {
776 unsafe {
777 let stack = crate::stack::alloc_test_stack();
778 let stack = push_int(stack, 1);
779 let stack = not(stack);
780 let (_stack, result) = pop(stack);
781 assert_eq!(result, Value::Int(0));
782 }
783 }
784
785 #[test]
786 fn test_not_false() {
787 unsafe {
788 let stack = crate::stack::alloc_test_stack();
789 let stack = push_int(stack, 0);
790 let stack = not(stack);
791 let (_stack, result) = pop(stack);
792 assert_eq!(result, Value::Int(1));
793 }
794 }
795
796 #[test]
797 fn test_and_nonzero_values() {
798 unsafe {
800 let stack = crate::stack::alloc_test_stack();
801 let stack = push_int(stack, 42);
802 let stack = push_int(stack, -5);
803 let stack = and(stack);
804 let (_stack, result) = pop(stack);
805 assert_eq!(result, Value::Int(1));
806 }
807 }
808
809 }