1use crate::compat::ToString;
2use crate::interpreter::Interpreter;
3use crate::value::{RuntimeError, Value};
4
5pub fn shr_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
6 let shift_amount = interp.pop_number()?;
7 let value = interp.pop_number()?;
8
9 let value_int = value as i64;
11 let shift_int = shift_amount as u32;
12
13 if shift_int > 63 {
15 return Err(RuntimeError::DomainError(
16 "shift amount too large".to_string(),
17 ));
18 }
19
20 let result = value_int >> shift_int;
22 interp.push(Value::Number(result as f64));
23 Ok(())
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29 use crate::value::Value;
30
31 fn setup_interpreter() -> Interpreter {
32 Interpreter::new()
33 }
34
35 #[test]
36 fn test_shr_basic() {
37 let mut interp = setup_interpreter();
38 interp.push(Value::Number(8.0));
39 interp.push(Value::Number(3.0)); shr_builtin(&mut interp).unwrap();
42
43 let result = interp.pop().unwrap();
44 assert!(matches!(result, Value::Number(n) if n == 1.0)); }
46
47 #[test]
48 fn test_shr_zero_shift() {
49 let mut interp = setup_interpreter();
50 interp.push(Value::Number(42.0));
51 interp.push(Value::Number(0.0)); shr_builtin(&mut interp).unwrap();
54
55 let result = interp.pop().unwrap();
56 assert!(matches!(result, Value::Number(n) if n == 42.0)); }
58
59 #[test]
60 fn test_shr_powers_of_two() {
61 let mut interp = setup_interpreter();
62
63 let test_cases = [
64 (16.0, 1.0, 8.0), (32.0, 2.0, 8.0), (64.0, 4.0, 4.0), (256.0, 8.0, 1.0), ];
69
70 for (value, shift, expected) in test_cases {
71 interp.push(Value::Number(value));
72 interp.push(Value::Number(shift));
73 shr_builtin(&mut interp).unwrap();
74 let result = interp.pop().unwrap();
75 assert!(
76 matches!(result, Value::Number(n) if n == expected),
77 "{} >> {} should be {}, got {:?}",
78 value,
79 shift,
80 expected,
81 result
82 );
83 }
84 }
85
86 #[test]
87 fn test_shr_multiple_bits() {
88 let mut interp = setup_interpreter();
89
90 let test_cases = [
91 (12.0, 2.0, 3.0), (10.0, 1.0, 5.0), (56.0, 3.0, 7.0), ];
95
96 for (value, shift, expected) in test_cases {
97 interp.push(Value::Number(value));
98 interp.push(Value::Number(shift));
99 shr_builtin(&mut interp).unwrap();
100 let result = interp.pop().unwrap();
101 assert!(
102 matches!(result, Value::Number(n) if n == expected),
103 "{} >> {} should be {}, got {:?}",
104 value,
105 shift,
106 expected,
107 result
108 );
109 }
110 }
111
112 #[test]
113 fn test_shr_zero_value() {
114 let mut interp = setup_interpreter();
115 interp.push(Value::Number(0.0));
116 interp.push(Value::Number(5.0)); shr_builtin(&mut interp).unwrap();
119
120 let result = interp.pop().unwrap();
121 assert!(matches!(result, Value::Number(n) if n == 0.0)); }
123
124 #[test]
125 fn test_shr_negative_numbers_arithmetic() {
126 let mut interp = setup_interpreter();
127
128 let test_cases = [
130 (-8.0, 1.0, -4.0), (-4.0, 2.0, -1.0), (-1.0, 1.0, -1.0), (-2.0, 1.0, -1.0), ];
135
136 for (value, shift, expected) in test_cases {
137 interp.push(Value::Number(value));
138 interp.push(Value::Number(shift));
139 shr_builtin(&mut interp).unwrap();
140 let result = interp.pop().unwrap();
141 assert!(
142 matches!(result, Value::Number(n) if n == expected),
143 "{} >> {} should be {}, got {:?}",
144 value,
145 shift,
146 expected,
147 result
148 );
149 }
150 }
151
152 #[test]
153 fn test_shr_large_shifts() {
154 let mut interp = setup_interpreter();
155
156 let test_cases = [
157 (1024.0, 10.0, 1.0), (1048576.0, 20.0, 1.0), ];
160
161 for (value, shift, expected) in test_cases {
162 interp.push(Value::Number(value));
163 interp.push(Value::Number(shift));
164 shr_builtin(&mut interp).unwrap();
165 let result = interp.pop().unwrap();
166 assert!(
167 matches!(result, Value::Number(n) if n == expected),
168 "{} >> {} should be {}, got {:?}",
169 value,
170 shift,
171 expected,
172 result
173 );
174 }
175 }
176
177 #[test]
178 fn test_shr_fractional_truncation() {
179 let mut interp = setup_interpreter();
180
181 interp.push(Value::Number(15.7));
183 interp.push(Value::Number(2.9)); shr_builtin(&mut interp).unwrap();
186
187 let result = interp.pop().unwrap();
188 assert!(matches!(result, Value::Number(n) if n == 3.0)); }
190
191 #[test]
192 fn test_shr_division_equivalence_positive() {
193 let mut interp = setup_interpreter();
194
195 let test_cases = [
197 (20.0, 2.0), (48.0, 4.0), ];
200
201 for (value, shift) in test_cases {
202 interp.push(Value::Number(value));
203 interp.push(Value::Number(shift));
204 shr_builtin(&mut interp).unwrap();
205 let shift_result = interp.pop().unwrap();
206
207 let expected = (value / (2.0_f64.powf(shift))).floor();
208
209 assert!(
210 matches!(shift_result, Value::Number(n) if n == expected),
211 "{} >> {} should equal floor({} / 2^{}) = {}, got {:?}",
212 value,
213 shift,
214 value,
215 shift,
216 expected,
217 shift_result
218 );
219 }
220 }
221
222 #[test]
223 fn test_shr_sign_extension() {
224 let mut interp = setup_interpreter();
225
226 interp.push(Value::Number(-100.0));
228 interp.push(Value::Number(50.0)); shr_builtin(&mut interp).unwrap();
231
232 let result = interp.pop().unwrap();
233 assert!(matches!(result, Value::Number(n) if n == -1.0)); }
235
236 #[test]
237 fn test_shr_excessive_shift_error() {
238 let mut interp = setup_interpreter();
239 interp.push(Value::Number(8.0));
240 interp.push(Value::Number(100.0)); let result = shr_builtin(&mut interp);
243 assert!(matches!(result, Err(RuntimeError::DomainError(_))));
244 }
245
246 #[test]
247 fn test_shr_boundary_shift() {
248 let mut interp = setup_interpreter();
249 interp.push(Value::Number(1024.0));
250 interp.push(Value::Number(63.0)); let result = shr_builtin(&mut interp);
253 assert!(result.is_ok());
255 }
256
257 #[test]
258 fn test_shr_bit_pattern() {
259 let mut interp = setup_interpreter();
260
261 interp.push(Value::Number(340.0)); interp.push(Value::Number(2.0)); shr_builtin(&mut interp).unwrap();
266
267 let result = interp.pop().unwrap();
268 assert!(matches!(result, Value::Number(n) if n == 85.0)); }
270
271 #[test]
272 fn test_shr_odd_numbers() {
273 let mut interp = setup_interpreter();
274
275 let test_cases = [
277 (15.0, 1.0, 7.0), (7.0, 1.0, 3.0), (5.0, 2.0, 1.0), ];
281
282 for (value, shift, expected) in test_cases {
283 interp.push(Value::Number(value));
284 interp.push(Value::Number(shift));
285 shr_builtin(&mut interp).unwrap();
286 let result = interp.pop().unwrap();
287 assert!(
288 matches!(result, Value::Number(n) if n == expected),
289 "{} >> {} should be {}, got {:?}",
290 value,
291 shift,
292 expected,
293 result
294 );
295 }
296 }
297
298 #[test]
299 fn test_shr_reversibility_with_shl() {
300 let value = 42.0;
302 let shift = 3.0;
303
304 let value_int = value as i64;
306 let shifted_left = value_int << (shift as u32);
307 let shifted_back = shifted_left >> (shift as u32);
308
309 assert_eq!(
310 shifted_back, value_int,
311 "({} << {}) >> {} should equal {}",
312 value, shift, shift, value
313 );
314 }
315
316 #[test]
317 fn test_shr_stack_underflow() {
318 let mut interp = setup_interpreter();
319
320 let result = shr_builtin(&mut interp);
321 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
322
323 interp.push(Value::Number(8.0));
324 let result = shr_builtin(&mut interp);
325 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
326 }
327
328 #[test]
329 fn test_shr_type_error() {
330 let mut interp = setup_interpreter();
331 interp.push(Value::String("hello".into()));
332 interp.push(Value::Number(2.0));
333
334 let result = shr_builtin(&mut interp);
335 assert!(matches!(result, Err(RuntimeError::TypeError(_))));
336 }
337}