Skip to main content

seq_runtime/arithmetic/
arith.rs

1//! Integer arithmetic: push literals + `add`, `subtract`, `multiply`,
2//! `divide`, `modulo`. All use wrapping semantics.
3
4use crate::stack::{Stack, pop_two, push};
5use crate::value::Value;
6
7/// Push an integer literal onto the stack (for compiler-generated code)
8///
9/// Stack effect: ( -- n )
10///
11/// # Safety
12/// Always safe to call
13#[unsafe(no_mangle)]
14pub unsafe extern "C" fn patch_seq_push_int(stack: Stack, value: i64) -> Stack {
15    unsafe { push(stack, Value::Int(value)) }
16}
17
18/// Push a boolean literal onto the stack (for compiler-generated code)
19///
20/// Stack effect: ( -- bool )
21///
22/// # Safety
23/// Always safe to call
24#[unsafe(no_mangle)]
25pub unsafe extern "C" fn patch_seq_push_bool(stack: Stack, value: bool) -> Stack {
26    unsafe { push(stack, Value::Bool(value)) }
27}
28
29/// Add two integers
30///
31/// Stack effect: ( a b -- a+b )
32///
33/// # Safety
34/// Stack must have two Int values on top
35#[unsafe(no_mangle)]
36pub unsafe extern "C" fn patch_seq_add(stack: Stack) -> Stack {
37    let (rest, a, b) = unsafe { pop_two(stack, "add") };
38    match (a, b) {
39        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
40            push(rest, Value::Int(a_val.wrapping_add(b_val)))
41        },
42        _ => panic!("add: expected two integers on stack"),
43    }
44}
45
46/// Subtract two integers (a - b)
47///
48/// Stack effect: ( a b -- a-b )
49///
50/// # Safety
51/// Stack must have two Int values on top
52#[unsafe(no_mangle)]
53pub unsafe extern "C" fn patch_seq_subtract(stack: Stack) -> Stack {
54    let (rest, a, b) = unsafe { pop_two(stack, "subtract") };
55    match (a, b) {
56        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
57            push(rest, Value::Int(a_val.wrapping_sub(b_val)))
58        },
59        _ => panic!("subtract: expected two integers on stack"),
60    }
61}
62
63/// Multiply two integers
64///
65/// Stack effect: ( a b -- a*b )
66///
67/// # Safety
68/// Stack must have two Int values on top
69#[unsafe(no_mangle)]
70pub unsafe extern "C" fn patch_seq_multiply(stack: Stack) -> Stack {
71    let (rest, a, b) = unsafe { pop_two(stack, "multiply") };
72    match (a, b) {
73        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
74            push(rest, Value::Int(a_val.wrapping_mul(b_val)))
75        },
76        _ => panic!("multiply: expected two integers on stack"),
77    }
78}
79
80/// Divide two integers (a / b)
81///
82/// Stack effect: ( a b -- result success )
83///
84/// Returns the quotient and a Bool success flag.
85/// On division by zero, returns (0, false).
86/// On success, returns (a/b, true).
87///
88/// # Safety
89/// Stack must have at least two values on top
90#[unsafe(no_mangle)]
91pub unsafe extern "C" fn patch_seq_divide(stack: Stack) -> Stack {
92    let (rest, a, b) = unsafe { pop_two(stack, "divide") };
93    match (a, b) {
94        (Value::Int(_a_val), Value::Int(0)) => {
95            // Division by zero - return 0 and false
96            let stack = unsafe { push(rest, Value::Int(0)) };
97            unsafe { push(stack, Value::Bool(false)) }
98        }
99        (Value::Int(a_val), Value::Int(b_val)) => {
100            // Use wrapping_div to handle i64::MIN / -1 overflow edge case
101            let stack = unsafe { push(rest, Value::Int(a_val.wrapping_div(b_val))) };
102            unsafe { push(stack, Value::Bool(true)) }
103        }
104        _ => {
105            // Type error - should not happen with type-checked code
106            panic!("divide: expected two integers on stack");
107        }
108    }
109}
110
111/// Integer power (base^exp)
112///
113/// Stack effect: ( base exp -- result success )
114///
115/// Returns the result and a Bool success flag.
116/// Success returns (base^exp, true) using O(log exp) exponentiation.
117/// Failure returns (0, false) in three cases: exp < 0, exp > u32::MAX,
118/// or the result overflows i64.
119///
120/// By convention, 0^0 = 1 (matching Rust's `i64::pow`, Python, JS).
121///
122/// # Safety
123/// Stack must have two Int values on top
124#[unsafe(no_mangle)]
125pub unsafe extern "C" fn patch_seq_pow(stack: Stack) -> Stack {
126    let (rest, a, b) = unsafe { pop_two(stack, "pow") };
127    match (a, b) {
128        (Value::Int(base), Value::Int(exp)) => {
129            let result = if (0..=i64::from(u32::MAX)).contains(&exp) {
130                base.checked_pow(exp as u32)
131            } else {
132                None
133            };
134            match result {
135                Some(v) => {
136                    let stack = unsafe { push(rest, Value::Int(v)) };
137                    unsafe { push(stack, Value::Bool(true)) }
138                }
139                None => {
140                    let stack = unsafe { push(rest, Value::Int(0)) };
141                    unsafe { push(stack, Value::Bool(false)) }
142                }
143            }
144        }
145        _ => panic!("pow: expected two integers on stack"),
146    }
147}
148
149/// Modulo (remainder) of two integers (a % b)
150///
151/// Stack effect: ( a b -- result success )
152///
153/// Returns the remainder and a Bool success flag.
154/// On division by zero, returns (0, false).
155/// On success, returns (a%b, true).
156///
157/// # Safety
158/// Stack must have at least two values on top
159#[unsafe(no_mangle)]
160pub unsafe extern "C" fn patch_seq_modulo(stack: Stack) -> Stack {
161    let (rest, a, b) = unsafe { pop_two(stack, "modulo") };
162    match (a, b) {
163        (Value::Int(_a_val), Value::Int(0)) => {
164            // Division by zero - return 0 and false
165            let stack = unsafe { push(rest, Value::Int(0)) };
166            unsafe { push(stack, Value::Bool(false)) }
167        }
168        (Value::Int(a_val), Value::Int(b_val)) => {
169            // Use wrapping_rem to handle i64::MIN % -1 overflow edge case
170            let stack = unsafe { push(rest, Value::Int(a_val.wrapping_rem(b_val))) };
171            unsafe { push(stack, Value::Bool(true)) }
172        }
173        _ => {
174            // Type error - should not happen with type-checked code
175            panic!("modulo: expected two integers on stack");
176        }
177    }
178}