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::Bool(a_val == b_val))
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 { push(rest, Value::Bool(a_val < b_val)) },
154 _ => panic!("<: expected two integers on stack"),
155 }
156}
157
158#[unsafe(no_mangle)]
166pub unsafe extern "C" fn patch_seq_gt(stack: Stack) -> Stack {
167 let (rest, a, b) = unsafe { pop_two(stack, ">") };
168 match (a, b) {
169 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val > b_val)) },
170 _ => panic!(">: expected two integers on stack"),
171 }
172}
173
174#[unsafe(no_mangle)]
182pub unsafe extern "C" fn patch_seq_lte(stack: Stack) -> Stack {
183 let (rest, a, b) = unsafe { pop_two(stack, "<=") };
184 match (a, b) {
185 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
186 push(rest, Value::Bool(a_val <= b_val))
187 },
188 _ => panic!("<=: expected two integers on stack"),
189 }
190}
191
192#[unsafe(no_mangle)]
200pub unsafe extern "C" fn patch_seq_gte(stack: Stack) -> Stack {
201 let (rest, a, b) = unsafe { pop_two(stack, ">=") };
202 match (a, b) {
203 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
204 push(rest, Value::Bool(a_val >= b_val))
205 },
206 _ => panic!(">=: expected two integers on stack"),
207 }
208}
209
210#[unsafe(no_mangle)]
218pub unsafe extern "C" fn patch_seq_neq(stack: Stack) -> Stack {
219 let (rest, a, b) = unsafe { pop_two(stack, "<>") };
220 match (a, b) {
221 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
222 push(rest, Value::Bool(a_val != b_val))
223 },
224 _ => panic!("<>: expected two integers on stack"),
225 }
226}
227
228#[unsafe(no_mangle)]
237pub unsafe extern "C" fn patch_seq_and(stack: Stack) -> Stack {
238 let (rest, a, b) = unsafe { pop_two(stack, "and") };
239 match (a, b) {
240 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
241 push(
242 rest,
243 Value::Int(if a_val != 0 && b_val != 0 { 1 } else { 0 }),
244 )
245 },
246 _ => panic!("and: expected two integers on stack"),
247 }
248}
249
250#[unsafe(no_mangle)]
259pub unsafe extern "C" fn patch_seq_or(stack: Stack) -> Stack {
260 let (rest, a, b) = unsafe { pop_two(stack, "or") };
261 match (a, b) {
262 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
263 push(
264 rest,
265 Value::Int(if a_val != 0 || b_val != 0 { 1 } else { 0 }),
266 )
267 },
268 _ => panic!("or: expected two integers on stack"),
269 }
270}
271
272#[unsafe(no_mangle)]
281pub unsafe extern "C" fn patch_seq_not(stack: Stack) -> Stack {
282 assert!(!stack.is_null(), "not: stack is empty");
283 let (rest, a) = unsafe { pop(stack) };
284
285 match a {
286 Value::Int(a_val) => unsafe { push(rest, Value::Int(if a_val == 0 { 1 } else { 0 })) },
287 _ => panic!("not: expected integer on stack"),
288 }
289}
290
291#[unsafe(no_mangle)]
302pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
303 let (rest, a, b) = unsafe { pop_two(stack, "band") };
304 match (a, b) {
305 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
306 _ => panic!("band: expected two integers on stack"),
307 }
308}
309
310#[unsafe(no_mangle)]
317pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
318 let (rest, a, b) = unsafe { pop_two(stack, "bor") };
319 match (a, b) {
320 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
321 _ => panic!("bor: expected two integers on stack"),
322 }
323}
324
325#[unsafe(no_mangle)]
332pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
333 let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
334 match (a, b) {
335 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
336 _ => panic!("bxor: expected two integers on stack"),
337 }
338}
339
340#[unsafe(no_mangle)]
347pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
348 assert!(!stack.is_null(), "bnot: stack is empty");
349 let (rest, a) = unsafe { pop(stack) };
350 match a {
351 Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
352 _ => panic!("bnot: expected integer on stack"),
353 }
354}
355
356#[unsafe(no_mangle)]
364pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
365 let (rest, value, count) = unsafe { pop_two(stack, "shl") };
366 match (value, count) {
367 (Value::Int(v), Value::Int(c)) => {
368 let result = if c < 0 {
371 0
372 } else {
373 v.checked_shl(c as u32).unwrap_or(0)
374 };
375 unsafe { push(rest, Value::Int(result)) }
376 }
377 _ => panic!("shl: expected two integers on stack"),
378 }
379}
380
381#[unsafe(no_mangle)]
390pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
391 let (rest, value, count) = unsafe { pop_two(stack, "shr") };
392 match (value, count) {
393 (Value::Int(v), Value::Int(c)) => {
394 let result = if c < 0 {
397 0
398 } else {
399 (v as u64).checked_shr(c as u32).unwrap_or(0) as i64
400 };
401 unsafe { push(rest, Value::Int(result)) }
402 }
403 _ => panic!("shr: expected two integers on stack"),
404 }
405}
406
407#[unsafe(no_mangle)]
414pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
415 assert!(!stack.is_null(), "popcount: stack is empty");
416 let (rest, a) = unsafe { pop(stack) };
417 match a {
418 Value::Int(v) => unsafe { push(rest, Value::Int(v.count_ones() as i64)) },
419 _ => panic!("popcount: expected integer on stack"),
420 }
421}
422
423#[unsafe(no_mangle)]
430pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
431 assert!(!stack.is_null(), "clz: stack is empty");
432 let (rest, a) = unsafe { pop(stack) };
433 match a {
434 Value::Int(v) => unsafe { push(rest, Value::Int(v.leading_zeros() as i64)) },
435 _ => panic!("clz: expected integer on stack"),
436 }
437}
438
439#[unsafe(no_mangle)]
446pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
447 assert!(!stack.is_null(), "ctz: stack is empty");
448 let (rest, a) = unsafe { pop(stack) };
449 match a {
450 Value::Int(v) => unsafe { push(rest, Value::Int(v.trailing_zeros() as i64)) },
451 _ => panic!("ctz: expected integer on stack"),
452 }
453}
454
455#[unsafe(no_mangle)]
462pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
463 unsafe { push(stack, Value::Int(64)) }
464}
465
466#[unsafe(no_mangle)]
486pub unsafe extern "C" fn patch_seq_peek_int_value(stack: Stack) -> i64 {
487 assert!(!stack.is_null(), "peek_int_value: stack is empty");
488
489 let sv = unsafe { peek_sv(stack) };
491 if sv.slot0 == DISC_INT {
492 sv.slot1 as i64
493 } else {
494 panic!(
495 "peek_int_value: expected Int on stack, got discriminant {}",
496 sv.slot0
497 )
498 }
499}
500
501#[unsafe(no_mangle)]
506pub unsafe extern "C" fn patch_seq_peek_bool_value(stack: Stack) -> bool {
507 use crate::stack::DISC_BOOL;
508 assert!(!stack.is_null(), "peek_bool_value: stack is empty");
509
510 let sv = unsafe { peek_sv(stack) };
512 if sv.slot0 == DISC_BOOL {
513 sv.slot1 != 0
514 } else {
515 panic!(
516 "peek_bool_value: expected Bool on stack, got discriminant {}",
517 sv.slot0
518 )
519 }
520}
521
522#[unsafe(no_mangle)]
532pub unsafe extern "C" fn patch_seq_pop_stack(stack: Stack) -> Stack {
533 assert!(!stack.is_null(), "pop_stack: stack is empty");
534 let (rest, _value) = unsafe { pop(stack) };
535 rest
536}
537
538pub use patch_seq_add as add;
540pub use patch_seq_and as and;
541pub use patch_seq_band as band;
542pub use patch_seq_bnot as bnot;
543pub use patch_seq_bor as bor;
544pub use patch_seq_bxor as bxor;
545pub use patch_seq_clz as clz;
546pub use patch_seq_ctz as ctz;
547pub use patch_seq_divide as divide;
548pub use patch_seq_eq as eq;
549pub use patch_seq_gt as gt;
550pub use patch_seq_gte as gte;
551pub use patch_seq_int_bits as int_bits;
552pub use patch_seq_lt as lt;
553pub use patch_seq_lte as lte;
554pub use patch_seq_multiply as multiply;
555pub use patch_seq_neq as neq;
556pub use patch_seq_not as not;
557pub use patch_seq_or as or;
558pub use patch_seq_popcount as popcount;
559pub use patch_seq_push_bool as push_bool;
560pub use patch_seq_push_int as push_int;
561pub use patch_seq_shl as shl;
562pub use patch_seq_shr as shr;
563pub use patch_seq_subtract as subtract;
564
565#[cfg(test)]
566mod tests {
567 use super::*;
568
569 #[test]
570 fn test_add() {
571 unsafe {
572 let stack = crate::stack::alloc_test_stack();
573 let stack = push_int(stack, 5);
574 let stack = push_int(stack, 3);
575 let stack = add(stack);
576
577 let (_stack, result) = pop(stack);
578 assert_eq!(result, Value::Int(8));
579 }
580 }
581
582 #[test]
583 fn test_subtract() {
584 unsafe {
585 let stack = crate::stack::alloc_test_stack();
586 let stack = push_int(stack, 10);
587 let stack = push_int(stack, 3);
588 let stack = subtract(stack);
589
590 let (_stack, result) = pop(stack);
591 assert_eq!(result, Value::Int(7));
592 }
593 }
594
595 #[test]
596 fn test_multiply() {
597 unsafe {
598 let stack = crate::stack::alloc_test_stack();
599 let stack = push_int(stack, 4);
600 let stack = push_int(stack, 5);
601 let stack = multiply(stack);
602
603 let (_stack, result) = pop(stack);
604 assert_eq!(result, Value::Int(20));
605 }
606 }
607
608 #[test]
609 fn test_divide() {
610 unsafe {
611 let stack = crate::stack::alloc_test_stack();
612 let stack = push_int(stack, 20);
613 let stack = push_int(stack, 4);
614 let stack = divide(stack);
615
616 let (_stack, result) = pop(stack);
617 assert_eq!(result, Value::Int(5));
618 }
619 }
620
621 #[test]
622 fn test_comparisons() {
623 unsafe {
624 let stack = crate::stack::alloc_test_stack();
626 let stack = push_int(stack, 5);
627 let stack = push_int(stack, 5);
628 let stack = eq(stack);
629 let (_stack, result) = pop(stack);
630 assert_eq!(result, Value::Bool(true));
631
632 let stack = push_int(stack, 3);
634 let stack = push_int(stack, 5);
635 let stack = lt(stack);
636 let (_stack, result) = pop(stack);
637 assert_eq!(result, Value::Bool(true));
638
639 let stack = push_int(stack, 7);
641 let stack = push_int(stack, 5);
642 let stack = gt(stack);
643 let (_stack, result) = pop(stack);
644 assert_eq!(result, Value::Bool(true));
645 }
646 }
647
648 #[test]
649 fn test_overflow_wrapping() {
650 unsafe {
652 let stack = crate::stack::alloc_test_stack();
654 let stack = push_int(stack, i64::MAX);
655 let stack = push_int(stack, 1);
656 let stack = add(stack);
657 let (_stack, result) = pop(stack);
658 assert_eq!(result, Value::Int(i64::MIN)); let stack = push_int(stack, i64::MAX);
662 let stack = push_int(stack, 2);
663 let stack = multiply(stack);
664 let (_stack, result) = pop(stack);
665 assert!(matches!(result, Value::Int(_)));
667
668 let stack = push_int(stack, i64::MIN);
670 let stack = push_int(stack, 1);
671 let stack = subtract(stack);
672 let (_stack, result) = pop(stack);
673 assert_eq!(result, Value::Int(i64::MAX)); }
675 }
676
677 #[test]
678 fn test_negative_division() {
679 unsafe {
680 let stack = crate::stack::alloc_test_stack();
682 let stack = push_int(stack, -10);
683 let stack = push_int(stack, 3);
684 let stack = divide(stack);
685 let (_stack, result) = pop(stack);
686 assert_eq!(result, Value::Int(-3)); let stack = push_int(stack, 10);
690 let stack = push_int(stack, -3);
691 let stack = divide(stack);
692 let (_stack, result) = pop(stack);
693 assert_eq!(result, Value::Int(-3));
694
695 let stack = push_int(stack, -10);
697 let stack = push_int(stack, -3);
698 let stack = divide(stack);
699 let (_stack, result) = pop(stack);
700 assert_eq!(result, Value::Int(3));
701 }
702 }
703
704 #[test]
705 fn test_division_overflow_edge_case() {
706 unsafe {
709 let stack = crate::stack::alloc_test_stack();
710 let stack = push_int(stack, i64::MIN);
711 let stack = push_int(stack, -1);
712 let stack = divide(stack);
713 let (_stack, result) = pop(stack);
714 assert_eq!(result, Value::Int(i64::MIN));
716 }
717 }
718
719 #[test]
720 fn test_and_true_true() {
721 unsafe {
722 let stack = crate::stack::alloc_test_stack();
723 let stack = push_int(stack, 1);
724 let stack = push_int(stack, 1);
725 let stack = and(stack);
726 let (_stack, result) = pop(stack);
727 assert_eq!(result, Value::Int(1));
728 }
729 }
730
731 #[test]
732 fn test_and_true_false() {
733 unsafe {
734 let stack = crate::stack::alloc_test_stack();
735 let stack = push_int(stack, 1);
736 let stack = push_int(stack, 0);
737 let stack = and(stack);
738 let (_stack, result) = pop(stack);
739 assert_eq!(result, Value::Int(0));
740 }
741 }
742
743 #[test]
744 fn test_and_false_false() {
745 unsafe {
746 let stack = crate::stack::alloc_test_stack();
747 let stack = push_int(stack, 0);
748 let stack = push_int(stack, 0);
749 let stack = and(stack);
750 let (_stack, result) = pop(stack);
751 assert_eq!(result, Value::Int(0));
752 }
753 }
754
755 #[test]
756 fn test_or_true_true() {
757 unsafe {
758 let stack = crate::stack::alloc_test_stack();
759 let stack = push_int(stack, 1);
760 let stack = push_int(stack, 1);
761 let stack = or(stack);
762 let (_stack, result) = pop(stack);
763 assert_eq!(result, Value::Int(1));
764 }
765 }
766
767 #[test]
768 fn test_or_true_false() {
769 unsafe {
770 let stack = crate::stack::alloc_test_stack();
771 let stack = push_int(stack, 1);
772 let stack = push_int(stack, 0);
773 let stack = or(stack);
774 let (_stack, result) = pop(stack);
775 assert_eq!(result, Value::Int(1));
776 }
777 }
778
779 #[test]
780 fn test_or_false_false() {
781 unsafe {
782 let stack = crate::stack::alloc_test_stack();
783 let stack = push_int(stack, 0);
784 let stack = push_int(stack, 0);
785 let stack = or(stack);
786 let (_stack, result) = pop(stack);
787 assert_eq!(result, Value::Int(0));
788 }
789 }
790
791 #[test]
792 fn test_not_true() {
793 unsafe {
794 let stack = crate::stack::alloc_test_stack();
795 let stack = push_int(stack, 1);
796 let stack = not(stack);
797 let (_stack, result) = pop(stack);
798 assert_eq!(result, Value::Int(0));
799 }
800 }
801
802 #[test]
803 fn test_not_false() {
804 unsafe {
805 let stack = crate::stack::alloc_test_stack();
806 let stack = push_int(stack, 0);
807 let stack = not(stack);
808 let (_stack, result) = pop(stack);
809 assert_eq!(result, Value::Int(1));
810 }
811 }
812
813 #[test]
814 fn test_and_nonzero_values() {
815 unsafe {
817 let stack = crate::stack::alloc_test_stack();
818 let stack = push_int(stack, 42);
819 let stack = push_int(stack, -5);
820 let stack = and(stack);
821 let (_stack, result) = pop(stack);
822 assert_eq!(result, Value::Int(1));
823 }
824 }
825
826 }