Skip to main content

seq_runtime/arithmetic/
compare.rs

1//! Integer comparison operators + boolean logic: `eq`, `lt`, `gt`, `lte`,
2//! `gte`, `neq` plus short-circuit-free `and`/`or`/`not`.
3
4use crate::stack::{Stack, pop, pop_two, push};
5use crate::value::Value;
6
7/// # Safety
8/// Stack must have two Int values on top.
9#[unsafe(no_mangle)]
10pub unsafe extern "C" fn patch_seq_eq(stack: Stack) -> Stack {
11    let (rest, a, b) = unsafe { pop_two(stack, "=") };
12    match (a, b) {
13        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
14            push(rest, Value::Bool(a_val == b_val))
15        },
16        _ => panic!("=: expected two integers on stack"),
17    }
18}
19
20/// Less than: <
21///
22/// Returns Bool (true if a < b, false otherwise)
23/// Stack effect: ( a b -- Bool )
24///
25/// # Safety
26/// Stack must have two Int values on top
27#[unsafe(no_mangle)]
28pub unsafe extern "C" fn patch_seq_lt(stack: Stack) -> Stack {
29    let (rest, a, b) = unsafe { pop_two(stack, "<") };
30    match (a, b) {
31        (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val < b_val)) },
32        _ => panic!("<: expected two integers on stack"),
33    }
34}
35
36/// Greater than: >
37///
38/// Returns Bool (true if a > b, false otherwise)
39/// Stack effect: ( a b -- Bool )
40///
41/// # Safety
42/// Stack must have two Int values on top
43#[unsafe(no_mangle)]
44pub unsafe extern "C" fn patch_seq_gt(stack: Stack) -> Stack {
45    let (rest, a, b) = unsafe { pop_two(stack, ">") };
46    match (a, b) {
47        (Value::Int(a_val), Value::Int(b_val)) => unsafe { push(rest, Value::Bool(a_val > b_val)) },
48        _ => panic!(">: expected two integers on stack"),
49    }
50}
51
52/// Less than or equal: <=
53///
54/// Returns Bool (true if a <= b, false otherwise)
55/// Stack effect: ( a b -- Bool )
56///
57/// # Safety
58/// Stack must have two Int values on top
59#[unsafe(no_mangle)]
60pub unsafe extern "C" fn patch_seq_lte(stack: Stack) -> Stack {
61    let (rest, a, b) = unsafe { pop_two(stack, "<=") };
62    match (a, b) {
63        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
64            push(rest, Value::Bool(a_val <= b_val))
65        },
66        _ => panic!("<=: expected two integers on stack"),
67    }
68}
69
70/// Greater than or equal: >=
71///
72/// Returns Bool (true if a >= b, false otherwise)
73/// Stack effect: ( a b -- Bool )
74///
75/// # Safety
76/// Stack must have two Int values on top
77#[unsafe(no_mangle)]
78pub unsafe extern "C" fn patch_seq_gte(stack: Stack) -> Stack {
79    let (rest, a, b) = unsafe { pop_two(stack, ">=") };
80    match (a, b) {
81        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
82            push(rest, Value::Bool(a_val >= b_val))
83        },
84        _ => panic!(">=: expected two integers on stack"),
85    }
86}
87
88/// Not equal: <>
89///
90/// Returns Bool (true if a != b, false otherwise)
91/// Stack effect: ( a b -- Bool )
92///
93/// # Safety
94/// Stack must have two Int values on top
95#[unsafe(no_mangle)]
96pub unsafe extern "C" fn patch_seq_neq(stack: Stack) -> Stack {
97    let (rest, a, b) = unsafe { pop_two(stack, "<>") };
98    match (a, b) {
99        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
100            push(rest, Value::Bool(a_val != b_val))
101        },
102        _ => panic!("<>: expected two integers on stack"),
103    }
104}
105
106/// Logical AND operation (Forth-style: multiply for boolean values)
107///
108/// Stack effect: ( a b -- result )
109/// where 0 is false, non-zero is true
110/// Returns 1 if both are true (non-zero), 0 otherwise
111///
112/// # Safety
113/// Stack must have at least two Int values
114#[unsafe(no_mangle)]
115pub unsafe extern "C" fn patch_seq_and(stack: Stack) -> Stack {
116    let (rest, a, b) = unsafe { pop_two(stack, "and") };
117    match (a, b) {
118        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
119            push(
120                rest,
121                Value::Int(if a_val != 0 && b_val != 0 { 1 } else { 0 }),
122            )
123        },
124        _ => panic!("and: expected two integers on stack"),
125    }
126}
127
128/// Logical OR operation (Forth-style)
129///
130/// Stack effect: ( a b -- result )
131/// where 0 is false, non-zero is true
132/// Returns 1 if either is true (non-zero), 0 otherwise
133///
134/// # Safety
135/// Stack must have at least two Int values
136#[unsafe(no_mangle)]
137pub unsafe extern "C" fn patch_seq_or(stack: Stack) -> Stack {
138    let (rest, a, b) = unsafe { pop_two(stack, "or") };
139    match (a, b) {
140        (Value::Int(a_val), Value::Int(b_val)) => unsafe {
141            push(
142                rest,
143                Value::Int(if a_val != 0 || b_val != 0 { 1 } else { 0 }),
144            )
145        },
146        _ => panic!("or: expected two integers on stack"),
147    }
148}
149
150/// Logical NOT operation
151///
152/// Stack effect: ( a -- result )
153/// where 0 is false, non-zero is true
154/// Returns 1 if false (0), 0 otherwise
155///
156/// # Safety
157/// Stack must have at least one Int value
158#[unsafe(no_mangle)]
159pub unsafe extern "C" fn patch_seq_not(stack: Stack) -> Stack {
160    assert!(!stack.is_null(), "not: stack is empty");
161    let (rest, a) = unsafe { pop(stack) };
162
163    match a {
164        Value::Int(a_val) => unsafe { push(rest, Value::Int(if a_val == 0 { 1 } else { 0 })) },
165        _ => panic!("not: expected integer on stack"),
166    }
167}