uni_core/primitives/
bit_not.rs

1use crate::interpreter::Interpreter;
2use crate::value::{RuntimeError, Value};
3
4pub fn bit_not_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
5    let n = interp.pop_number()?;
6
7    // Convert to integer for bitwise operation
8    let n_int = n as i64;
9
10    let result = !n_int;
11    interp.push(Value::Number(result as f64));
12    Ok(())
13}
14
15#[cfg(test)]
16mod tests {
17    use super::*;
18    use crate::value::Value;
19
20    fn setup_interpreter() -> Interpreter {
21        Interpreter::new()
22    }
23
24    #[test]
25    fn test_bit_not_zero() {
26        let mut interp = setup_interpreter();
27        interp.push(Value::Number(0.0));
28
29        bit_not_builtin(&mut interp).unwrap();
30
31        let result = interp.pop().unwrap();
32        assert!(matches!(result, Value::Number(n) if n == -1.0)); // ~0 = -1 in two's complement
33    }
34
35    #[test]
36    fn test_bit_not_negative_one() {
37        let mut interp = setup_interpreter();
38        interp.push(Value::Number(-1.0));
39
40        bit_not_builtin(&mut interp).unwrap();
41
42        let result = interp.pop().unwrap();
43        assert!(matches!(result, Value::Number(n) if n == 0.0)); // ~(-1) = 0
44    }
45
46    #[test]
47    fn test_bit_not_small_positive() {
48        let mut interp = setup_interpreter();
49
50        let test_cases = [
51            (1.0, -2.0), // ~1 = -2
52            (2.0, -3.0), // ~2 = -3
53            (3.0, -4.0), // ~3 = -4
54            (4.0, -5.0), // ~4 = -5
55            (5.0, -6.0), // ~5 = -6
56        ];
57
58        for (input, expected) in test_cases {
59            interp.push(Value::Number(input));
60            bit_not_builtin(&mut interp).unwrap();
61            let result = interp.pop().unwrap();
62            assert!(
63                matches!(result, Value::Number(n) if n == expected),
64                "~{} should be {}, got {:?}",
65                input,
66                expected,
67                result
68            );
69        }
70    }
71
72    #[test]
73    fn test_bit_not_powers_of_two() {
74        let mut interp = setup_interpreter();
75
76        let test_cases = [
77            (8.0, -9.0),   // ~1000 = ...11110111 = -9
78            (16.0, -17.0), // ~10000 = ...11101111 = -17
79            (32.0, -33.0), // ~100000 = ...11011111 = -33
80            (64.0, -65.0), // ~1000000 = ...10111111 = -65
81        ];
82
83        for (input, expected) in test_cases {
84            interp.push(Value::Number(input));
85            bit_not_builtin(&mut interp).unwrap();
86            let result = interp.pop().unwrap();
87            assert!(
88                matches!(result, Value::Number(n) if n == expected),
89                "~{} should be {}, got {:?}",
90                input,
91                expected,
92                result
93            );
94        }
95    }
96
97    #[test]
98    fn test_bit_not_byte_values() {
99        let mut interp = setup_interpreter();
100
101        // Test some common byte patterns
102        let test_cases = [
103            (255.0, -256.0), // ~11111111 = -256
104            (170.0, -171.0), // ~10101010 = -171
105            (85.0, -86.0),   // ~01010101 = -86
106            (15.0, -16.0),   // ~00001111 = -16
107        ];
108
109        for (input, expected) in test_cases {
110            interp.push(Value::Number(input));
111            bit_not_builtin(&mut interp).unwrap();
112            let result = interp.pop().unwrap();
113            assert!(
114                matches!(result, Value::Number(n) if n == expected),
115                "~{} should be {}, got {:?}",
116                input,
117                expected,
118                result
119            );
120        }
121    }
122
123    #[test]
124    fn test_bit_not_negative_numbers() {
125        let mut interp = setup_interpreter();
126
127        let test_cases = [
128            (-2.0, 1.0),  // ~(-2) = 1
129            (-3.0, 2.0),  // ~(-3) = 2
130            (-4.0, 3.0),  // ~(-4) = 3
131            (-10.0, 9.0), // ~(-10) = 9
132        ];
133
134        for (input, expected) in test_cases {
135            interp.push(Value::Number(input));
136            bit_not_builtin(&mut interp).unwrap();
137            let result = interp.pop().unwrap();
138            assert!(
139                matches!(result, Value::Number(n) if n == expected),
140                "~{} should be {}, got {:?}",
141                input,
142                expected,
143                result
144            );
145        }
146    }
147
148    #[test]
149    fn test_bit_not_large_numbers() {
150        let mut interp = setup_interpreter();
151        interp.push(Value::Number(1024.0)); // 2^10
152
153        bit_not_builtin(&mut interp).unwrap();
154
155        let result = interp.pop().unwrap();
156        assert!(matches!(result, Value::Number(n) if n == -1025.0)); // ~1024 = -1025
157    }
158
159    #[test]
160    fn test_bit_not_fractional_truncation() {
161        let mut interp = setup_interpreter();
162
163        // Fractional parts should be truncated
164        interp.push(Value::Number(5.7));
165
166        bit_not_builtin(&mut interp).unwrap();
167
168        let result = interp.pop().unwrap();
169        assert!(matches!(result, Value::Number(n) if n == -6.0)); // ~5 = -6
170    }
171
172    #[test]
173    fn test_bit_not_double_negation() {
174        let mut interp = setup_interpreter();
175
176        // Test that ~~x = x
177        let test_values = [0.0, 1.0, 5.0, 42.0, 255.0];
178
179        for value in test_values {
180            // First NOT
181            interp.push(Value::Number(value));
182            bit_not_builtin(&mut interp).unwrap();
183            let first_not = interp.pop().unwrap();
184
185            // Second NOT
186            interp.push(first_not);
187            bit_not_builtin(&mut interp).unwrap();
188            let double_not = interp.pop().unwrap();
189
190            assert!(
191                matches!(double_not, Value::Number(n) if n == value),
192                "~~{} should equal {}, got {:?}",
193                value,
194                value,
195                double_not
196            );
197        }
198    }
199
200    #[test]
201    fn test_bit_not_complement_property() {
202        // Test that n & ~n = 0 for any n
203        let test_values = [1.0, 7.0, 15.0, 42.0, 255.0];
204
205        for value in test_values {
206            let value_int = value as i64;
207            let not_value_int = !value_int;
208            let and_result = value_int & not_value_int;
209
210            assert_eq!(and_result, 0, "{} & ~{} should be 0", value, value);
211        }
212    }
213
214    #[test]
215    fn test_bit_not_relationship_with_minus_one() {
216        let mut interp = setup_interpreter();
217
218        // Test that ~n = -n - 1
219        let test_values = [0.0, 1.0, 5.0, 10.0, 42.0];
220
221        for value in test_values {
222            interp.push(Value::Number(value));
223            bit_not_builtin(&mut interp).unwrap();
224            let not_result = interp.pop().unwrap();
225
226            if let Value::Number(not_n) = not_result {
227                let expected = -value - 1.0;
228                assert!(
229                    (not_n - expected).abs() < f64::EPSILON,
230                    "~{} should equal {} - 1 = {}, got {}",
231                    value,
232                    -value,
233                    expected,
234                    not_n
235                );
236            }
237        }
238    }
239
240    #[test]
241    fn test_bit_not_alternating_pattern() {
242        let mut interp = setup_interpreter();
243
244        // Test NOT on alternating bit pattern
245        interp.push(Value::Number(170.0)); // 10101010 in binary
246
247        bit_not_builtin(&mut interp).unwrap();
248
249        let result = interp.pop().unwrap();
250        assert!(matches!(result, Value::Number(n) if n == -171.0)); // Should flip all bits
251    }
252
253    #[test]
254    fn test_bit_not_mask_generation() {
255        let mut interp = setup_interpreter();
256
257        // NOT of 0 gives all 1s (mask)
258        interp.push(Value::Number(0.0));
259        bit_not_builtin(&mut interp).unwrap();
260        let all_ones = interp.pop().unwrap();
261
262        // Should be -1 (all bits set in two's complement)
263        assert!(matches!(all_ones, Value::Number(n) if n == -1.0));
264    }
265
266    #[test]
267    fn test_bit_not_stack_underflow() {
268        let mut interp = setup_interpreter();
269
270        let result = bit_not_builtin(&mut interp);
271        assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
272    }
273
274    #[test]
275    fn test_bit_not_type_error() {
276        let mut interp = setup_interpreter();
277        interp.push(Value::String("hello".into()));
278
279        let result = bit_not_builtin(&mut interp);
280        assert!(matches!(result, Err(RuntimeError::TypeError(_))));
281    }
282}