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)]
143pub unsafe extern "C" fn patch_seq_eq(stack: Stack) -> Stack {
144 let (rest, a, b) = unsafe { pop_two(stack, "=") };
145 match (a, b) {
146 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
147 push(rest, Value::Bool(a_val == b_val))
148 },
149 _ => panic!("=: expected two integers on stack"),
150 }
151}
152
153#[unsafe(no_mangle)]
161pub unsafe extern "C" fn patch_seq_lt(stack: Stack) -> Stack {
162 let (rest, a, b) = unsafe { pop_two(stack, "<") };
163 match (a, b) {
164 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val < b_val)) },
165 _ => panic!("<: expected two integers on stack"),
166 }
167}
168
169#[unsafe(no_mangle)]
177pub unsafe extern "C" fn patch_seq_gt(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 { push(rest, Value::Bool(a_val > b_val)) },
181 _ => panic!(">: expected two integers on stack"),
182 }
183}
184
185#[unsafe(no_mangle)]
193pub unsafe extern "C" fn patch_seq_lte(stack: Stack) -> Stack {
194 let (rest, a, b) = unsafe { pop_two(stack, "<=") };
195 match (a, b) {
196 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
197 push(rest, Value::Bool(a_val <= b_val))
198 },
199 _ => panic!("<=: expected two integers on stack"),
200 }
201}
202
203#[unsafe(no_mangle)]
211pub unsafe extern "C" fn patch_seq_gte(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 {
215 push(rest, Value::Bool(a_val >= b_val))
216 },
217 _ => panic!(">=: expected two integers on stack"),
218 }
219}
220
221#[unsafe(no_mangle)]
229pub unsafe extern "C" fn patch_seq_neq(stack: Stack) -> Stack {
230 let (rest, a, b) = unsafe { pop_two(stack, "<>") };
231 match (a, b) {
232 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
233 push(rest, Value::Bool(a_val != b_val))
234 },
235 _ => panic!("<>: expected two integers on stack"),
236 }
237}
238
239#[unsafe(no_mangle)]
248pub unsafe extern "C" fn patch_seq_and(stack: Stack) -> Stack {
249 let (rest, a, b) = unsafe { pop_two(stack, "and") };
250 match (a, b) {
251 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
252 push(
253 rest,
254 Value::Int(if a_val != 0 && b_val != 0 { 1 } else { 0 }),
255 )
256 },
257 _ => panic!("and: expected two integers on stack"),
258 }
259}
260
261#[unsafe(no_mangle)]
270pub unsafe extern "C" fn patch_seq_or(stack: Stack) -> Stack {
271 let (rest, a, b) = unsafe { pop_two(stack, "or") };
272 match (a, b) {
273 (Value::Int(a_val), Value::Int(b_val)) => unsafe {
274 push(
275 rest,
276 Value::Int(if a_val != 0 || b_val != 0 { 1 } else { 0 }),
277 )
278 },
279 _ => panic!("or: expected two integers on stack"),
280 }
281}
282
283#[unsafe(no_mangle)]
292pub unsafe extern "C" fn patch_seq_not(stack: Stack) -> Stack {
293 assert!(!stack.is_null(), "not: stack is empty");
294 let (rest, a) = unsafe { pop(stack) };
295
296 match a {
297 Value::Int(a_val) => unsafe { push(rest, Value::Int(if a_val == 0 { 1 } else { 0 })) },
298 _ => panic!("not: expected integer on stack"),
299 }
300}
301
302#[unsafe(no_mangle)]
313pub unsafe extern "C" fn patch_seq_band(stack: Stack) -> Stack {
314 let (rest, a, b) = unsafe { pop_two(stack, "band") };
315 match (a, b) {
316 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val & b_val)) },
317 _ => panic!("band: expected two integers on stack"),
318 }
319}
320
321#[unsafe(no_mangle)]
328pub unsafe extern "C" fn patch_seq_bor(stack: Stack) -> Stack {
329 let (rest, a, b) = unsafe { pop_two(stack, "bor") };
330 match (a, b) {
331 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val | b_val)) },
332 _ => panic!("bor: expected two integers on stack"),
333 }
334}
335
336#[unsafe(no_mangle)]
343pub unsafe extern "C" fn patch_seq_bxor(stack: Stack) -> Stack {
344 let (rest, a, b) = unsafe { pop_two(stack, "bxor") };
345 match (a, b) {
346 (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Int(a_val ^ b_val)) },
347 _ => panic!("bxor: expected two integers on stack"),
348 }
349}
350
351#[unsafe(no_mangle)]
358pub unsafe extern "C" fn patch_seq_bnot(stack: Stack) -> Stack {
359 assert!(!stack.is_null(), "bnot: stack is empty");
360 let (rest, a) = unsafe { pop(stack) };
361 match a {
362 Value::Int(a_val) => unsafe { push(rest, Value::Int(!a_val)) },
363 _ => panic!("bnot: expected integer on stack"),
364 }
365}
366
367#[unsafe(no_mangle)]
375pub unsafe extern "C" fn patch_seq_shl(stack: Stack) -> Stack {
376 let (rest, value, count) = unsafe { pop_two(stack, "shl") };
377 match (value, count) {
378 (Value::Int(v), Value::Int(c)) => {
379 let result = if c < 0 {
382 0
383 } else {
384 v.checked_shl(c as u32).unwrap_or(0)
385 };
386 unsafe { push(rest, Value::Int(result)) }
387 }
388 _ => panic!("shl: expected two integers on stack"),
389 }
390}
391
392#[unsafe(no_mangle)]
401pub unsafe extern "C" fn patch_seq_shr(stack: Stack) -> Stack {
402 let (rest, value, count) = unsafe { pop_two(stack, "shr") };
403 match (value, count) {
404 (Value::Int(v), Value::Int(c)) => {
405 let result = if c < 0 {
408 0
409 } else {
410 (v as u64).checked_shr(c as u32).unwrap_or(0) as i64
411 };
412 unsafe { push(rest, Value::Int(result)) }
413 }
414 _ => panic!("shr: expected two integers on stack"),
415 }
416}
417
418#[unsafe(no_mangle)]
425pub unsafe extern "C" fn patch_seq_popcount(stack: Stack) -> Stack {
426 assert!(!stack.is_null(), "popcount: stack is empty");
427 let (rest, a) = unsafe { pop(stack) };
428 match a {
429 Value::Int(v) => unsafe { push(rest, Value::Int(v.count_ones() as i64)) },
430 _ => panic!("popcount: expected integer on stack"),
431 }
432}
433
434#[unsafe(no_mangle)]
441pub unsafe extern "C" fn patch_seq_clz(stack: Stack) -> Stack {
442 assert!(!stack.is_null(), "clz: stack is empty");
443 let (rest, a) = unsafe { pop(stack) };
444 match a {
445 Value::Int(v) => unsafe { push(rest, Value::Int(v.leading_zeros() as i64)) },
446 _ => panic!("clz: expected integer on stack"),
447 }
448}
449
450#[unsafe(no_mangle)]
457pub unsafe extern "C" fn patch_seq_ctz(stack: Stack) -> Stack {
458 assert!(!stack.is_null(), "ctz: stack is empty");
459 let (rest, a) = unsafe { pop(stack) };
460 match a {
461 Value::Int(v) => unsafe { push(rest, Value::Int(v.trailing_zeros() as i64)) },
462 _ => panic!("ctz: expected integer on stack"),
463 }
464}
465
466#[unsafe(no_mangle)]
473pub unsafe extern "C" fn patch_seq_int_bits(stack: Stack) -> Stack {
474 unsafe { push(stack, Value::Int(64)) }
475}
476
477#[unsafe(no_mangle)]
497pub unsafe extern "C" fn patch_seq_peek_int_value(stack: Stack) -> i64 {
498 assert!(!stack.is_null(), "peek_int_value: stack is empty");
499
500 let sv = unsafe { peek_sv(stack) };
502 if sv.slot0 == DISC_INT {
503 sv.slot1 as i64
504 } else {
505 panic!(
506 "peek_int_value: expected Int on stack, got discriminant {}",
507 sv.slot0
508 )
509 }
510}
511
512#[unsafe(no_mangle)]
517pub unsafe extern "C" fn patch_seq_peek_bool_value(stack: Stack) -> bool {
518 use crate::stack::DISC_BOOL;
519 assert!(!stack.is_null(), "peek_bool_value: stack is empty");
520
521 let sv = unsafe { peek_sv(stack) };
523 if sv.slot0 == DISC_BOOL {
524 sv.slot1 != 0
525 } else {
526 panic!(
527 "peek_bool_value: expected Bool on stack, got discriminant {}",
528 sv.slot0
529 )
530 }
531}
532
533#[unsafe(no_mangle)]
543pub unsafe extern "C" fn patch_seq_pop_stack(stack: Stack) -> Stack {
544 assert!(!stack.is_null(), "pop_stack: stack is empty");
545 let (rest, _value) = unsafe { pop(stack) };
546 rest
547}
548
549pub use patch_seq_add as add;
551pub use patch_seq_and as and;
552pub use patch_seq_band as band;
553pub use patch_seq_bnot as bnot;
554pub use patch_seq_bor as bor;
555pub use patch_seq_bxor as bxor;
556pub use patch_seq_clz as clz;
557pub use patch_seq_ctz as ctz;
558pub use patch_seq_divide as divide;
559pub use patch_seq_eq as eq;
560pub use patch_seq_gt as gt;
561pub use patch_seq_gte as gte;
562pub use patch_seq_int_bits as int_bits;
563pub use patch_seq_lt as lt;
564pub use patch_seq_lte as lte;
565pub use patch_seq_multiply as multiply;
566pub use patch_seq_neq as neq;
567pub use patch_seq_not as not;
568pub use patch_seq_or as or;
569pub use patch_seq_popcount as popcount;
570pub use patch_seq_push_bool as push_bool;
571pub use patch_seq_push_int as push_int;
572pub use patch_seq_shl as shl;
573pub use patch_seq_shr as shr;
574pub use patch_seq_subtract as subtract;
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 #[test]
581 fn test_add() {
582 unsafe {
583 let stack = crate::stack::alloc_test_stack();
584 let stack = push_int(stack, 5);
585 let stack = push_int(stack, 3);
586 let stack = add(stack);
587
588 let (_stack, result) = pop(stack);
589 assert_eq!(result, Value::Int(8));
590 }
591 }
592
593 #[test]
594 fn test_subtract() {
595 unsafe {
596 let stack = crate::stack::alloc_test_stack();
597 let stack = push_int(stack, 10);
598 let stack = push_int(stack, 3);
599 let stack = subtract(stack);
600
601 let (_stack, result) = pop(stack);
602 assert_eq!(result, Value::Int(7));
603 }
604 }
605
606 #[test]
607 fn test_multiply() {
608 unsafe {
609 let stack = crate::stack::alloc_test_stack();
610 let stack = push_int(stack, 4);
611 let stack = push_int(stack, 5);
612 let stack = multiply(stack);
613
614 let (_stack, result) = pop(stack);
615 assert_eq!(result, Value::Int(20));
616 }
617 }
618
619 #[test]
620 fn test_divide() {
621 unsafe {
622 let stack = crate::stack::alloc_test_stack();
623 let stack = push_int(stack, 20);
624 let stack = push_int(stack, 4);
625 let stack = divide(stack);
626
627 let (_stack, result) = pop(stack);
628 assert_eq!(result, Value::Int(5));
629 }
630 }
631
632 #[test]
633 fn test_comparisons() {
634 unsafe {
635 let stack = crate::stack::alloc_test_stack();
637 let stack = push_int(stack, 5);
638 let stack = push_int(stack, 5);
639 let stack = eq(stack);
640 let (_stack, result) = pop(stack);
641 assert_eq!(result, Value::Bool(true));
642
643 let stack = push_int(stack, 3);
645 let stack = push_int(stack, 5);
646 let stack = lt(stack);
647 let (_stack, result) = pop(stack);
648 assert_eq!(result, Value::Bool(true));
649
650 let stack = push_int(stack, 7);
652 let stack = push_int(stack, 5);
653 let stack = gt(stack);
654 let (_stack, result) = pop(stack);
655 assert_eq!(result, Value::Bool(true));
656 }
657 }
658
659 #[test]
660 fn test_overflow_wrapping() {
661 unsafe {
663 let stack = crate::stack::alloc_test_stack();
665 let stack = push_int(stack, i64::MAX);
666 let stack = push_int(stack, 1);
667 let stack = add(stack);
668 let (_stack, result) = pop(stack);
669 assert_eq!(result, Value::Int(i64::MIN)); let stack = push_int(stack, i64::MAX);
673 let stack = push_int(stack, 2);
674 let stack = multiply(stack);
675 let (_stack, result) = pop(stack);
676 assert!(matches!(result, Value::Int(_)));
678
679 let stack = push_int(stack, i64::MIN);
681 let stack = push_int(stack, 1);
682 let stack = subtract(stack);
683 let (_stack, result) = pop(stack);
684 assert_eq!(result, Value::Int(i64::MAX)); }
686 }
687
688 #[test]
689 fn test_negative_division() {
690 unsafe {
691 let stack = crate::stack::alloc_test_stack();
693 let stack = push_int(stack, -10);
694 let stack = push_int(stack, 3);
695 let stack = divide(stack);
696 let (_stack, result) = pop(stack);
697 assert_eq!(result, Value::Int(-3)); let stack = push_int(stack, 10);
701 let stack = push_int(stack, -3);
702 let stack = divide(stack);
703 let (_stack, result) = pop(stack);
704 assert_eq!(result, Value::Int(-3));
705
706 let stack = push_int(stack, -10);
708 let stack = push_int(stack, -3);
709 let stack = divide(stack);
710 let (_stack, result) = pop(stack);
711 assert_eq!(result, Value::Int(3));
712 }
713 }
714
715 #[test]
716 fn test_division_overflow_edge_case() {
717 unsafe {
720 let stack = crate::stack::alloc_test_stack();
721 let stack = push_int(stack, i64::MIN);
722 let stack = push_int(stack, -1);
723 let stack = divide(stack);
724 let (_stack, result) = pop(stack);
725 assert_eq!(result, Value::Int(i64::MIN));
727 }
728 }
729
730 #[test]
731 fn test_and_true_true() {
732 unsafe {
733 let stack = crate::stack::alloc_test_stack();
734 let stack = push_int(stack, 1);
735 let stack = push_int(stack, 1);
736 let stack = and(stack);
737 let (_stack, result) = pop(stack);
738 assert_eq!(result, Value::Int(1));
739 }
740 }
741
742 #[test]
743 fn test_and_true_false() {
744 unsafe {
745 let stack = crate::stack::alloc_test_stack();
746 let stack = push_int(stack, 1);
747 let stack = push_int(stack, 0);
748 let stack = and(stack);
749 let (_stack, result) = pop(stack);
750 assert_eq!(result, Value::Int(0));
751 }
752 }
753
754 #[test]
755 fn test_and_false_false() {
756 unsafe {
757 let stack = crate::stack::alloc_test_stack();
758 let stack = push_int(stack, 0);
759 let stack = push_int(stack, 0);
760 let stack = and(stack);
761 let (_stack, result) = pop(stack);
762 assert_eq!(result, Value::Int(0));
763 }
764 }
765
766 #[test]
767 fn test_or_true_true() {
768 unsafe {
769 let stack = crate::stack::alloc_test_stack();
770 let stack = push_int(stack, 1);
771 let stack = push_int(stack, 1);
772 let stack = or(stack);
773 let (_stack, result) = pop(stack);
774 assert_eq!(result, Value::Int(1));
775 }
776 }
777
778 #[test]
779 fn test_or_true_false() {
780 unsafe {
781 let stack = crate::stack::alloc_test_stack();
782 let stack = push_int(stack, 1);
783 let stack = push_int(stack, 0);
784 let stack = or(stack);
785 let (_stack, result) = pop(stack);
786 assert_eq!(result, Value::Int(1));
787 }
788 }
789
790 #[test]
791 fn test_or_false_false() {
792 unsafe {
793 let stack = crate::stack::alloc_test_stack();
794 let stack = push_int(stack, 0);
795 let stack = push_int(stack, 0);
796 let stack = or(stack);
797 let (_stack, result) = pop(stack);
798 assert_eq!(result, Value::Int(0));
799 }
800 }
801
802 #[test]
803 fn test_not_true() {
804 unsafe {
805 let stack = crate::stack::alloc_test_stack();
806 let stack = push_int(stack, 1);
807 let stack = not(stack);
808 let (_stack, result) = pop(stack);
809 assert_eq!(result, Value::Int(0));
810 }
811 }
812
813 #[test]
814 fn test_not_false() {
815 unsafe {
816 let stack = crate::stack::alloc_test_stack();
817 let stack = push_int(stack, 0);
818 let stack = not(stack);
819 let (_stack, result) = pop(stack);
820 assert_eq!(result, Value::Int(1));
821 }
822 }
823
824 #[test]
825 fn test_and_nonzero_values() {
826 unsafe {
828 let stack = crate::stack::alloc_test_stack();
829 let stack = push_int(stack, 42);
830 let stack = push_int(stack, -5);
831 let stack = and(stack);
832 let (_stack, result) = pop(stack);
833 assert_eq!(result, Value::Int(1));
834 }
835 }
836
837 #[test]
838 fn test_divide_by_zero_sets_error() {
839 unsafe {
840 crate::error::clear_runtime_error();
841 let stack = crate::stack::alloc_test_stack();
842 let stack = push_int(stack, 42);
843 let stack = push_int(stack, 0);
844 let stack = divide(stack);
845
846 assert!(crate::error::has_runtime_error());
848 let error = crate::error::take_runtime_error().unwrap();
849 assert!(error.contains("division by zero"));
850
851 let (_stack, result) = pop(stack);
853 assert_eq!(result, Value::Int(0));
854 }
855 }
856}