uni_core/primitives/
bit_or.rs

1use crate::interpreter::Interpreter;
2use crate::value::{RuntimeError, Value};
3
4pub fn bit_or_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
5    let b = interp.pop_number()?;
6    let a = interp.pop_number()?;
7
8    // Convert to integers for bitwise operations
9    let a_int = a as i64;
10    let b_int = b as i64;
11
12    let result = a_int | b_int;
13    interp.push(Value::Number(result as f64));
14    Ok(())
15}
16
17#[cfg(test)]
18mod tests {
19    use super::*;
20    use crate::value::Value;
21
22    fn setup_interpreter() -> Interpreter {
23        Interpreter::new()
24    }
25
26    #[test]
27    fn test_bit_or_basic() {
28        let mut interp = setup_interpreter();
29        interp.push(Value::Number(5.0)); // 101 in binary
30        interp.push(Value::Number(3.0)); // 011 in binary
31
32        bit_or_builtin(&mut interp).unwrap();
33
34        let result = interp.pop().unwrap();
35        assert!(matches!(result, Value::Number(n) if n == 7.0)); // 111 in binary
36    }
37
38    #[test]
39    fn test_bit_or_no_overlap() {
40        let mut interp = setup_interpreter();
41        interp.push(Value::Number(8.0)); // 1000 in binary
42        interp.push(Value::Number(4.0)); // 0100 in binary
43
44        bit_or_builtin(&mut interp).unwrap();
45
46        let result = interp.pop().unwrap();
47        assert!(matches!(result, Value::Number(n) if n == 12.0)); // 1100 in binary
48    }
49
50    #[test]
51    fn test_bit_or_with_zero() {
52        let mut interp = setup_interpreter();
53        interp.push(Value::Number(42.0));
54        interp.push(Value::Number(0.0));
55
56        bit_or_builtin(&mut interp).unwrap();
57
58        let result = interp.pop().unwrap();
59        assert!(matches!(result, Value::Number(n) if n == 42.0));
60    }
61
62    #[test]
63    fn test_bit_or_same_values() {
64        let mut interp = setup_interpreter();
65        interp.push(Value::Number(15.0));
66        interp.push(Value::Number(15.0));
67
68        bit_or_builtin(&mut interp).unwrap();
69
70        let result = interp.pop().unwrap();
71        assert!(matches!(result, Value::Number(n) if n == 15.0));
72    }
73
74    #[test]
75    fn test_bit_or_powers_of_two() {
76        let mut interp = setup_interpreter();
77
78        let test_cases = [
79            (1.0, 2.0, 3.0),  // 01 | 10 = 11
80            (4.0, 8.0, 12.0), // 0100 | 1000 = 1100
81            (1.0, 4.0, 5.0),  // 0001 | 0100 = 0101
82            (2.0, 8.0, 10.0), // 0010 | 1000 = 1010
83        ];
84
85        for (a, b, expected) in test_cases {
86            interp.push(Value::Number(a));
87            interp.push(Value::Number(b));
88            bit_or_builtin(&mut interp).unwrap();
89            let result = interp.pop().unwrap();
90            assert!(
91                matches!(result, Value::Number(n) if n == expected),
92                "{} | {} should be {}, got {:?}",
93                a,
94                b,
95                expected,
96                result
97            );
98        }
99    }
100
101    #[test]
102    fn test_bit_or_alternating_patterns() {
103        let mut interp = setup_interpreter();
104        interp.push(Value::Number(170.0)); // 10101010 in binary
105        interp.push(Value::Number(85.0)); // 01010101 in binary
106
107        bit_or_builtin(&mut interp).unwrap();
108
109        let result = interp.pop().unwrap();
110        assert!(matches!(result, Value::Number(n) if n == 255.0)); // 11111111 in binary
111    }
112
113    #[test]
114    fn test_bit_or_large_numbers() {
115        let mut interp = setup_interpreter();
116        interp.push(Value::Number(512.0)); // 1000000000 in binary
117        interp.push(Value::Number(255.0)); // 0011111111 in binary
118
119        bit_or_builtin(&mut interp).unwrap();
120
121        let result = interp.pop().unwrap();
122        assert!(matches!(result, Value::Number(n) if n == 767.0)); // 1011111111 in binary
123    }
124
125    #[test]
126    fn test_bit_or_negative_numbers() {
127        let mut interp = setup_interpreter();
128
129        // Test with negative numbers (two's complement)
130        interp.push(Value::Number(-1.0)); // All bits set
131        interp.push(Value::Number(42.0));
132
133        bit_or_builtin(&mut interp).unwrap();
134
135        let result = interp.pop().unwrap();
136        assert!(matches!(result, Value::Number(n) if n == -1.0)); // -1 | anything = -1
137    }
138
139    #[test]
140    fn test_bit_or_fractional_truncation() {
141        let mut interp = setup_interpreter();
142
143        // Fractional parts should be truncated
144        interp.push(Value::Number(5.7));
145        interp.push(Value::Number(2.9));
146
147        bit_or_builtin(&mut interp).unwrap();
148
149        let result = interp.pop().unwrap();
150        assert!(matches!(result, Value::Number(n) if n == 7.0)); // 5 | 2 = 7
151    }
152
153    #[test]
154    fn test_bit_or_commutative() {
155        let mut interp = setup_interpreter();
156
157        let a = 13.0;
158        let b = 7.0;
159
160        // Test a | b
161        interp.push(Value::Number(a));
162        interp.push(Value::Number(b));
163        bit_or_builtin(&mut interp).unwrap();
164        let result1 = interp.pop().unwrap();
165
166        // Test b | a
167        interp.push(Value::Number(b));
168        interp.push(Value::Number(a));
169        bit_or_builtin(&mut interp).unwrap();
170        let result2 = interp.pop().unwrap();
171
172        assert!(matches!((result1, result2), (Value::Number(n1), Value::Number(n2)) if n1 == n2));
173    }
174
175    #[test]
176    fn test_bit_or_with_all_bits_set() {
177        let mut interp = setup_interpreter();
178
179        // Test OR with a number that has many bits set
180        interp.push(Value::Number(123.0)); // Arbitrary number
181        interp.push(Value::Number(255.0)); // All bits set in byte
182
183        bit_or_builtin(&mut interp).unwrap();
184
185        let result = interp.pop().unwrap();
186        assert!(matches!(result, Value::Number(n) if n == 255.0)); // Should be 255
187    }
188
189    #[test]
190    fn test_bit_or_identity() {
191        let mut interp = setup_interpreter();
192
193        // OR with 0 should be identity
194        let values = [1.0, 7.0, 15.0, 31.0, 63.0];
195
196        for value in values {
197            interp.push(Value::Number(value));
198            interp.push(Value::Number(0.0));
199            bit_or_builtin(&mut interp).unwrap();
200            let result = interp.pop().unwrap();
201            assert!(
202                matches!(result, Value::Number(n) if n == value),
203                "{} | 0 should be {}, got {:?}",
204                value,
205                value,
206                result
207            );
208        }
209    }
210
211    #[test]
212    fn test_bit_or_stack_underflow() {
213        let mut interp = setup_interpreter();
214
215        let result = bit_or_builtin(&mut interp);
216        assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
217
218        interp.push(Value::Number(5.0));
219        let result = bit_or_builtin(&mut interp);
220        assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
221    }
222
223    #[test]
224    fn test_bit_or_type_error() {
225        let mut interp = setup_interpreter();
226        interp.push(Value::String("hello".into()));
227        interp.push(Value::Number(5.0));
228
229        let result = bit_or_builtin(&mut interp);
230        assert!(matches!(result, Err(RuntimeError::TypeError(_))));
231    }
232}