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 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)); }
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)); }
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), (2.0, -3.0), (3.0, -4.0), (4.0, -5.0), (5.0, -6.0), ];
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), (16.0, -17.0), (32.0, -33.0), (64.0, -65.0), ];
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 let test_cases = [
103 (255.0, -256.0), (170.0, -171.0), (85.0, -86.0), (15.0, -16.0), ];
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), (-3.0, 2.0), (-4.0, 3.0), (-10.0, 9.0), ];
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)); bit_not_builtin(&mut interp).unwrap();
154
155 let result = interp.pop().unwrap();
156 assert!(matches!(result, Value::Number(n) if n == -1025.0)); }
158
159 #[test]
160 fn test_bit_not_fractional_truncation() {
161 let mut interp = setup_interpreter();
162
163 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)); }
171
172 #[test]
173 fn test_bit_not_double_negation() {
174 let mut interp = setup_interpreter();
175
176 let test_values = [0.0, 1.0, 5.0, 42.0, 255.0];
178
179 for value in test_values {
180 interp.push(Value::Number(value));
182 bit_not_builtin(&mut interp).unwrap();
183 let first_not = interp.pop().unwrap();
184
185 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 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 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 interp.push(Value::Number(170.0)); bit_not_builtin(&mut interp).unwrap();
248
249 let result = interp.pop().unwrap();
250 assert!(matches!(result, Value::Number(n) if n == -171.0)); }
252
253 #[test]
254 fn test_bit_not_mask_generation() {
255 let mut interp = setup_interpreter();
256
257 interp.push(Value::Number(0.0));
259 bit_not_builtin(&mut interp).unwrap();
260 let all_ones = interp.pop().unwrap();
261
262 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}