1#[macro_export]
2macro_rules! inc_ip {
3 ($code_ip:expr) => {{
4 #[allow(clippy::macro_metavars_in_unsafe)]
5 unsafe {
6 let r = *$code_ip;
8 $code_ip = $code_ip.offset(1);
9 r
10 }
11 }};
12}
13
14#[macro_export]
15macro_rules! get_code {
16 ($chunk:expr) => {{ $chunk.code.as_ptr() }};
17}
18
19#[macro_export]
20macro_rules! get_code_at {
21 ($chunk:expr, $idx:expr) => {{
22 let code = $chunk.code.as_ptr();
23 let idx: isize = $idx as isize;
24 unsafe { code.offset(idx) }
25 }};
26}
27
28#[macro_export]
29macro_rules! decode_u8 {
30 ($code:expr) => {{ $crate::inc_ip!($code) }};
31}
32
33#[macro_export]
34macro_rules! decode_u16 {
35 ($code:expr) => {{
36 #[allow(clippy::macro_metavars_in_unsafe)]
37 unsafe {
38 let idx1 = *$code;
40 let idx2 = *$code.offset(1);
41 $code = $code.offset(2);
42 ((idx1 as u16) << 8) | (idx2 as u16)
43 }
44 }};
45}
46
47#[macro_export]
48macro_rules! decode_u32 {
49 ($code:expr) => {{
50 #[allow(clippy::macro_metavars_in_unsafe)]
51 unsafe {
52 let idx1 = *$code;
54 let idx2 = *$code.offset(1);
55 let idx3 = *$code.offset(2);
56 let idx4 = *$code.offset(3);
57 $code = $code.offset(4);
58 ((idx1 as u32) << 24) | ((idx2 as u32) << 16) | ((idx3 as u32) << 8) | (idx4 as u32)
59 }
60 }};
61}
62
63#[macro_export]
64macro_rules! decode1 {
65 ($code:expr, $wide:expr) => {{
66 if $wide {
67 decode_u16!($code)
68 } else {
69 $crate::inc_ip!($code) as u16
70 }
71 }};
72}
73
74#[macro_export]
75macro_rules! decode2 {
76 ($code:expr, $wide:expr) => {{
77 if $wide {
78 (decode_u16!($code), decode_u16!($code))
79 } else {
80 #[allow(clippy::macro_metavars_in_unsafe)]
82 unsafe {
83 let r = (*$code as u16, *$code.offset(1) as u16);
85 $code = $code.offset(2);
86 r
87 }
88 }
89 }};
90}
91
92#[macro_export]
93macro_rules! decode3 {
94 ($code:expr, $wide:expr) => {{
95 if $wide {
96 (decode_u16!($code), decode_u16!($code), decode_u16!($code))
97 } else {
98 #[allow(clippy::macro_metavars_in_unsafe)]
99 unsafe {
100 let r = (
102 *$code as u16,
103 *$code.offset(1) as u16,
104 *$code.offset(2) as u16,
105 );
106 $code = $code.offset(3);
107 r
108 }
109 }
110 }};
111}
112
113macro_rules! compare_numeric_eq {
115 ($vm:expr, $chunk:expr, $code:expr, $wide:expr) => {{
116 let (dest, reg1, reg2) = decode3!($code, $wide);
117 let mut val = false;
118 for reg in reg1..reg2 {
119 let op1 = $vm.register_unref(reg as usize);
120 let op2 = $vm.register_unref(reg as usize + 1);
121 val = if matches!(op1, $crate::Value::Float(_))
122 || matches!(op2, $crate::Value::Float(_))
123 {
124 let f56_1 = match op1 {
127 $crate::Value::Float(f) => f,
128 $crate::Value::Byte(b) => $crate::float::F56::from(b as f64),
129 $crate::Value::Int(i) => $crate::float::F56::from($crate::from_i56(&i) as f64),
130 _ => {
131 return Err((
132 $crate::VMError::new_value(format!(
133 "Not a number: {}",
134 op1.display_value($vm)
135 )),
136 $chunk.clone(),
137 ));
138 }
139 };
140 let f56_2 = match op2 {
141 $crate::Value::Float(f) => f,
142 $crate::Value::Byte(b) => $crate::float::F56::from(b as f64),
143 $crate::Value::Int(i) => $crate::float::F56::from($crate::from_i56(&i) as f64),
144 _ => {
145 return Err((
146 $crate::VMError::new_value(format!(
147 "Not a number: {}",
148 op2.display_value($vm)
149 )),
150 $chunk.clone(),
151 ));
152 }
153 };
154 f56_1.roughly_equal_using_relative_difference(&f56_2)
155 } else {
156 let i1 = get_primitive_int!($vm, op1).map_err(|e| (e, $chunk.clone()))?;
158 let i2 = get_primitive_int!($vm, op2).map_err(|e| (e, $chunk.clone()))?;
159 i1 == i2
160 };
161 if !val {
162 break;
163 }
164 }
165 let val = if val {
166 $crate::Value::True
167 } else {
168 $crate::Value::False
169 };
170 *$vm.register_mut(dest as usize) = val;
171 }};
172}
173
174macro_rules! compare_numeric {
175 ($vm:expr, $chunk:expr, $code:expr, $comp_fn:expr, $wide:expr) => {{
176 let (dest, reg1, reg2) = decode3!($code, $wide);
177 let mut val = false;
178 for reg in reg1..reg2 {
179 let op1 = $vm.register_unref(reg as usize);
180 let op2 = $vm.register_unref(reg as usize + 1);
181 val = if matches!(op1, $crate::Value::Float(_))
182 || matches!(op2, $crate::Value::Float(_))
183 {
184 #[allow(clippy::redundant_closure_call)]
187 $comp_fn(
188 get_primitive_float!($vm, op1).map_err(|e| (e, $chunk.clone()))?,
189 get_primitive_float!($vm, op2).map_err(|e| (e, $chunk.clone()))?,
190 )
191 } else {
192 #[allow(clippy::redundant_closure_call)]
195 $comp_fn(
196 get_primitive_int!($vm, op1).map_err(|e| (e, $chunk.clone()))?,
197 get_primitive_int!($vm, op2).map_err(|e| (e, $chunk.clone()))?,
198 )
199 };
200 if !val {
201 break;
202 }
203 }
204 let val = if val {
205 $crate::Value::True
206 } else {
207 $crate::Value::False
208 };
209 *$vm.register_mut(dest as usize) = val;
210 }};
211}
212
213macro_rules! get_primitive_int {
215 ($vm:expr, $val:expr) => {{
216 match $val {
217 $crate::Value::Byte(b) => Ok(b as i64),
218 $crate::Value::Int(i) => Ok($crate::from_i56(&i)),
219 _ => Err($crate::VMError::new_value(format!(
220 "Not an integer: {}",
221 $val.display_value($vm)
222 ))),
223 }
224 }};
225}
226
227macro_rules! get_primitive_float {
229 ($vm:expr, $val:expr) => {{
230 match $val {
231 $crate::Value::Byte(b) => Ok(b as f64),
232 $crate::Value::Int(i) => Ok(crate::from_i56(&i) as f64),
233 $crate::Value::Float(f) => Ok(f64::from(f)),
234 _ => Err($crate::VMError::new_value(format!(
235 "Not a float: {:?}",
236 $val
237 ))),
238 }
239 }};
240}
241
242macro_rules! binary_math {
243 ($vm:expr, $chunk:expr, $code:expr, $bin_fn:expr, $wide:expr) => {{
244 let (dest, op2) = decode2!($code, $wide);
245 let op1 = $vm.register(dest as usize);
246 let op2 = $vm.register(op2 as usize);
247 match (op1, op2) {
248 ($crate::Value::Float(op1_f), $crate::Value::Float(op2_f)) => {
249 *$vm.register_mut(dest as usize) =
250 $bin_fn(f64::from(op1_f), f64::from(op2_f)).into();
251 }
252 ($crate::Value::Float(op1_f), _) => {
253 *$vm.register_mut(dest as usize) = $bin_fn(
254 f64::from(op1_f),
255 get_primitive_float!($vm, op2).map_err(|e| (e, $chunk.clone()))?,
256 )
257 .into();
258 }
259 (_, $crate::Value::Float(op2_f)) => {
260 *$vm.register_mut(dest as usize) = $bin_fn(
261 get_primitive_float!($vm, op1).map_err(|e| (e, $chunk.clone()))?,
262 f64::from(op2_f),
263 )
264 .into();
265 }
266 (_, _) => {
267 *$vm.register_mut(dest as usize) = $bin_fn(
268 get_primitive_int!($vm, op1).map_err(|e| (e, $chunk.clone()))?,
269 get_primitive_int!($vm, op2).map_err(|e| (e, $chunk.clone()))?,
270 )
271 .into();
272 }
273 }
274 }};
275}
276
277macro_rules! div_math {
278 ($vm:expr, $chunk:expr, $code:expr, $wide:expr) => {{
279 let (dest, op2) = decode2!($code, $wide);
280 let op1 = $vm.register(dest as usize);
281 let op2 = $vm.register(op2 as usize);
282 match (op1, op2) {
283 ($crate::Value::Float(op1_f), $crate::Value::Float(op2_f)) => {
284 let op1 = f64::from(op1_f);
285 let op2 = f64::from(op2_f);
286 if op2 == 0.0 {
287 return Err(($crate::VMError::new_vm("Divide by zero error."), $chunk));
288 }
289 *$vm.register_mut(dest as usize) = (op1 / op2).into();
290 }
291 ($crate::Value::Float(op1_f), _) => {
292 let op1 = f64::from(op1_f);
293 let op2 = get_primitive_float!($vm, op2).map_err(|e| (e, $chunk.clone()))? as f64;
294 if op2 == 0.0 {
295 return Err(($crate::VMError::new_vm("Divide by zero error."), $chunk));
296 }
297 *$vm.register_mut(dest as usize) = (op1 / op2).into();
298 }
299 (_, $crate::Value::Float(op2_f)) => {
300 let op1 = get_primitive_float!($vm, op1).map_err(|e| (e, $chunk.clone()))? as f64;
301 let op2 = f64::from(op2_f);
302 if op2 == 0.0 {
303 return Err(($crate::VMError::new_vm("Divide by zero error."), $chunk));
304 }
305 *$vm.register_mut(dest as usize) = (op1 / op2).into();
306 }
307 (_, _) => {
308 let op1 = get_primitive_int!($vm, op1).map_err(|e| (e, $chunk.clone()))?;
309 let op2 = get_primitive_int!($vm, op2).map_err(|e| (e, $chunk.clone()))?;
310 if op2 == 0 {
311 return Err(($crate::VMError::new_vm("Divide by zero error."), $chunk));
312 }
313 let val = op1 / op2;
314 *$vm.register_mut(dest as usize) = val.into();
315 }
316 }
317 }};
318}
319
320#[macro_export]
321macro_rules! set_register {
322 ($vm:expr, $idx:expr, $val:expr) => {{
323 match (&$vm.register($idx as usize), $val) {
324 ($crate::Value::Value(_), $crate::Value::Value(_)) => {
325 panic!("Do not set recursive Values...")
326 }
327 ($crate::Value::Value(handle), _) => {
328 *($vm.heap_mut().get_value_mut(*handle)) = $val;
329 }
330 _ => *$vm.register_mut($idx) = $val,
331 }
332 }};
333}
334
335#[macro_export]
336macro_rules! mov_register {
337 ($vm:expr, $idx:expr, $val:expr) => {{
338 *$vm.register_mut($idx) = $val;
339 }};
340}