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)]
511pub unsafe extern "C" fn patch_seq_pop_stack(stack: Stack) -> Stack {
512 assert!(!stack.is_null(), "pop_stack: stack is empty");
513 let (rest, _value) = unsafe { pop(stack) };
514 rest
515}
516
517pub use patch_seq_add as add;
519pub use patch_seq_and as and;
520pub use patch_seq_band as band;
521pub use patch_seq_bnot as bnot;
522pub use patch_seq_bor as bor;
523pub use patch_seq_bxor as bxor;
524pub use patch_seq_clz as clz;
525pub use patch_seq_ctz as ctz;
526pub use patch_seq_divide as divide;
527pub use patch_seq_eq as eq;
528pub use patch_seq_gt as gt;
529pub use patch_seq_gte as gte;
530pub use patch_seq_int_bits as int_bits;
531pub use patch_seq_lt as lt;
532pub use patch_seq_lte as lte;
533pub use patch_seq_multiply as multiply;
534pub use patch_seq_neq as neq;
535pub use patch_seq_not as not;
536pub use patch_seq_or as or;
537pub use patch_seq_popcount as popcount;
538pub use patch_seq_push_bool as push_bool;
539pub use patch_seq_push_int as push_int;
540pub use patch_seq_shl as shl;
541pub use patch_seq_shr as shr;
542pub use patch_seq_subtract as subtract;
543
544#[cfg(test)]
545mod tests {
546 use super::*;
547
548 #[test]
549 fn test_add() {
550 unsafe {
551 let stack = crate::stack::alloc_test_stack();
552 let stack = push_int(stack, 5);
553 let stack = push_int(stack, 3);
554 let stack = add(stack);
555
556 let (_stack, result) = pop(stack);
557 assert_eq!(result, Value::Int(8));
558 }
559 }
560
561 #[test]
562 fn test_subtract() {
563 unsafe {
564 let stack = crate::stack::alloc_test_stack();
565 let stack = push_int(stack, 10);
566 let stack = push_int(stack, 3);
567 let stack = subtract(stack);
568
569 let (_stack, result) = pop(stack);
570 assert_eq!(result, Value::Int(7));
571 }
572 }
573
574 #[test]
575 fn test_multiply() {
576 unsafe {
577 let stack = crate::stack::alloc_test_stack();
578 let stack = push_int(stack, 4);
579 let stack = push_int(stack, 5);
580 let stack = multiply(stack);
581
582 let (_stack, result) = pop(stack);
583 assert_eq!(result, Value::Int(20));
584 }
585 }
586
587 #[test]
588 fn test_divide() {
589 unsafe {
590 let stack = crate::stack::alloc_test_stack();
591 let stack = push_int(stack, 20);
592 let stack = push_int(stack, 4);
593 let stack = divide(stack);
594
595 let (_stack, result) = pop(stack);
596 assert_eq!(result, Value::Int(5));
597 }
598 }
599
600 #[test]
601 fn test_comparisons() {
602 unsafe {
603 let stack = crate::stack::alloc_test_stack();
605 let stack = push_int(stack, 5);
606 let stack = push_int(stack, 5);
607 let stack = eq(stack);
608 let (_stack, result) = pop(stack);
609 assert_eq!(result, Value::Bool(true));
610
611 let stack = push_int(stack, 3);
613 let stack = push_int(stack, 5);
614 let stack = lt(stack);
615 let (_stack, result) = pop(stack);
616 assert_eq!(result, Value::Bool(true));
617
618 let stack = push_int(stack, 7);
620 let stack = push_int(stack, 5);
621 let stack = gt(stack);
622 let (_stack, result) = pop(stack);
623 assert_eq!(result, Value::Bool(true));
624 }
625 }
626
627 #[test]
628 fn test_overflow_wrapping() {
629 unsafe {
631 let stack = crate::stack::alloc_test_stack();
633 let stack = push_int(stack, i64::MAX);
634 let stack = push_int(stack, 1);
635 let stack = add(stack);
636 let (_stack, result) = pop(stack);
637 assert_eq!(result, Value::Int(i64::MIN)); let stack = push_int(stack, i64::MAX);
641 let stack = push_int(stack, 2);
642 let stack = multiply(stack);
643 let (_stack, result) = pop(stack);
644 assert!(matches!(result, Value::Int(_)));
646
647 let stack = push_int(stack, i64::MIN);
649 let stack = push_int(stack, 1);
650 let stack = subtract(stack);
651 let (_stack, result) = pop(stack);
652 assert_eq!(result, Value::Int(i64::MAX)); }
654 }
655
656 #[test]
657 fn test_negative_division() {
658 unsafe {
659 let stack = crate::stack::alloc_test_stack();
661 let stack = push_int(stack, -10);
662 let stack = push_int(stack, 3);
663 let stack = divide(stack);
664 let (_stack, result) = pop(stack);
665 assert_eq!(result, Value::Int(-3)); let stack = push_int(stack, 10);
669 let stack = push_int(stack, -3);
670 let stack = divide(stack);
671 let (_stack, result) = pop(stack);
672 assert_eq!(result, Value::Int(-3));
673
674 let stack = push_int(stack, -10);
676 let stack = push_int(stack, -3);
677 let stack = divide(stack);
678 let (_stack, result) = pop(stack);
679 assert_eq!(result, Value::Int(3));
680 }
681 }
682
683 #[test]
684 fn test_division_overflow_edge_case() {
685 unsafe {
688 let stack = crate::stack::alloc_test_stack();
689 let stack = push_int(stack, i64::MIN);
690 let stack = push_int(stack, -1);
691 let stack = divide(stack);
692 let (_stack, result) = pop(stack);
693 assert_eq!(result, Value::Int(i64::MIN));
695 }
696 }
697
698 #[test]
699 fn test_and_true_true() {
700 unsafe {
701 let stack = crate::stack::alloc_test_stack();
702 let stack = push_int(stack, 1);
703 let stack = push_int(stack, 1);
704 let stack = and(stack);
705 let (_stack, result) = pop(stack);
706 assert_eq!(result, Value::Int(1));
707 }
708 }
709
710 #[test]
711 fn test_and_true_false() {
712 unsafe {
713 let stack = crate::stack::alloc_test_stack();
714 let stack = push_int(stack, 1);
715 let stack = push_int(stack, 0);
716 let stack = and(stack);
717 let (_stack, result) = pop(stack);
718 assert_eq!(result, Value::Int(0));
719 }
720 }
721
722 #[test]
723 fn test_and_false_false() {
724 unsafe {
725 let stack = crate::stack::alloc_test_stack();
726 let stack = push_int(stack, 0);
727 let stack = push_int(stack, 0);
728 let stack = and(stack);
729 let (_stack, result) = pop(stack);
730 assert_eq!(result, Value::Int(0));
731 }
732 }
733
734 #[test]
735 fn test_or_true_true() {
736 unsafe {
737 let stack = crate::stack::alloc_test_stack();
738 let stack = push_int(stack, 1);
739 let stack = push_int(stack, 1);
740 let stack = or(stack);
741 let (_stack, result) = pop(stack);
742 assert_eq!(result, Value::Int(1));
743 }
744 }
745
746 #[test]
747 fn test_or_true_false() {
748 unsafe {
749 let stack = crate::stack::alloc_test_stack();
750 let stack = push_int(stack, 1);
751 let stack = push_int(stack, 0);
752 let stack = or(stack);
753 let (_stack, result) = pop(stack);
754 assert_eq!(result, Value::Int(1));
755 }
756 }
757
758 #[test]
759 fn test_or_false_false() {
760 unsafe {
761 let stack = crate::stack::alloc_test_stack();
762 let stack = push_int(stack, 0);
763 let stack = push_int(stack, 0);
764 let stack = or(stack);
765 let (_stack, result) = pop(stack);
766 assert_eq!(result, Value::Int(0));
767 }
768 }
769
770 #[test]
771 fn test_not_true() {
772 unsafe {
773 let stack = crate::stack::alloc_test_stack();
774 let stack = push_int(stack, 1);
775 let stack = not(stack);
776 let (_stack, result) = pop(stack);
777 assert_eq!(result, Value::Int(0));
778 }
779 }
780
781 #[test]
782 fn test_not_false() {
783 unsafe {
784 let stack = crate::stack::alloc_test_stack();
785 let stack = push_int(stack, 0);
786 let stack = not(stack);
787 let (_stack, result) = pop(stack);
788 assert_eq!(result, Value::Int(1));
789 }
790 }
791
792 #[test]
793 fn test_and_nonzero_values() {
794 unsafe {
796 let stack = crate::stack::alloc_test_stack();
797 let stack = push_int(stack, 42);
798 let stack = push_int(stack, -5);
799 let stack = and(stack);
800 let (_stack, result) = pop(stack);
801 assert_eq!(result, Value::Int(1));
802 }
803 }
804
805 }