1use kittycad_execution_plan_traits::{NumericPrimitive, Primitive};
2use serde::{Deserialize, Serialize};
3
4use self::operator::{BinaryOperation, UnaryOperation};
5use crate::{events::EventWriter, ExecutionError, Memory, Operand};
6
7pub mod operator;
8
9#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
11pub struct BinaryArithmetic {
12 pub operation: BinaryOperation,
14 pub operand0: Operand,
16 pub operand1: Operand,
18}
19
20#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
22pub struct UnaryArithmetic {
23 pub operation: UnaryOperation,
25 pub operand: Operand,
27}
28
29trait Power {
30 fn power(self, other: Self) -> Self;
31}
32
33macro_rules! power_float_impl {
34 ($($t:ty)*) => ($(
35 impl Power for $t {
36 fn power(self, other: $t) -> $t { self.powf(other) }
37 }
38
39 )*)
40}
41power_float_impl! { f32 f64 }
42
43macro_rules! power_int_impl {
44 ($($t:ty)*) => ($(
45 impl Power for $t {
46 fn power(self, other: $t) -> $t { self.overflowing_pow(other as u32).0 }
47 }
48
49 )*)
50}
51power_int_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
52
53macro_rules! execution_error_if_match_otherwise {
54 ([], $b:ident, $err:expr, $otherwise:expr) => { $otherwise };
55 ([u32$(, $as:ident)*], u32, $err:expr, $otherwise:expr) => {
56 $err
57 };
58 ([i64$(, $as:ident)*], i64, $err:expr, $otherwise:expr) => {
59 $err
60 };
61 ([f64$(, $as:ident)*], f64, $err:expr, $otherwise:expr) => {
62 $err
63 };
64 ([$a:ident$(, $as:ident)*], $b:ident, $err:expr, $otherwise:expr) => {
65 execution_error_if_match_otherwise!([$($as)*], $b, $err, $otherwise)
66 };
67}
68
69macro_rules! binary_arithmetic_body {
70 ($arith:ident, $mem:ident, $events:ident, $method:ident, $($types:tt)*) => {{
71 $events.push(crate::events::Event::new(
72 "Evaluating left operand".to_owned(),
73 crate::events::Severity::Debug,
74 ));
75 let l = $arith.operand0.eval($mem)?.clone();
76 $events.push({
77 let mut evt = crate::events::Event::new(format!("Left operand is {l:?}"), crate::events::Severity::Info);
78 if let Operand::Reference(a) = $arith.operand0 {
79 evt.related_addresses = vec![a];
80 }
81 evt
82 });
83 $events.push(crate::events::Event::new(
84 "Evaluating right operand".to_owned(),
85 crate::events::Severity::Debug,
86 ));
87 let r = $arith.operand1.eval($mem)?.clone();
88 $events.push({
89 let mut evt = crate::events::Event::new(format!("Right operand is {r:?}"), crate::events::Severity::Info);
90 if let Operand::Reference(a) = $arith.operand1 {
91 evt.related_addresses = vec![a];
92 }
93 evt
94 });
95 match (l, r) {
96 (Primitive::NumericValue(x), Primitive::NumericValue(y)) => {
98 let num = match (x, y) {
99 (NumericPrimitive::UInteger(_x), NumericPrimitive::UInteger(_y)) => {
100 execution_error_if_match_otherwise!(
101 $($types)*, u32,
102 Err(ExecutionError::CannotApplyOperation {
103 op: $arith.operation.into(),
104 operands: vec![
105 $arith.operand0.eval($mem)?.clone().to_owned(),
106 $arith.operand1.eval($mem)?.clone().to_owned(),
107 ],
108 })?,
109 NumericPrimitive::UInteger(_x.$method(_y))
110 )
111 }
112 (NumericPrimitive::UInteger(x), NumericPrimitive::Float(y)) => {
113 NumericPrimitive::Float((x as f64).$method(y))
114 }
115 (NumericPrimitive::Float(x), NumericPrimitive::UInteger(y)) => {
116 NumericPrimitive::Float(x.$method(y as f64))
117 }
118 (NumericPrimitive::Float(x), NumericPrimitive::Float(y)) => NumericPrimitive::Float(x.$method(y)),
119 (NumericPrimitive::Integer(_x), NumericPrimitive::Integer(_y)) => {
120 execution_error_if_match_otherwise!(
121 $($types)*, i64,
122 Err(ExecutionError::CannotApplyOperation {
123 op: $arith.operation.into(),
124 operands: vec![
125 $arith.operand0.eval($mem)?.clone().to_owned(),
126 $arith.operand1.eval($mem)?.clone().to_owned(),
127 ],
128 })?,
129 NumericPrimitive::Integer(_x.$method(_y))
130 )
131 }
132 (NumericPrimitive::Integer(x), NumericPrimitive::Float(y)) => {
133 NumericPrimitive::Float((x as f64).$method(y))
134 }
135 (NumericPrimitive::Float(x), NumericPrimitive::Integer(y)) => {
136 NumericPrimitive::Float(x.$method(y as f64))
137 }
138 (NumericPrimitive::Integer(_x), NumericPrimitive::UInteger(_y)) => {
139 execution_error_if_match_otherwise!(
140 $($types)*, i64,
141 Err(ExecutionError::CannotApplyOperation {
142 op: $arith.operation.into(),
143 operands: vec![
144 $arith.operand0.eval($mem)?.clone().to_owned(),
145 $arith.operand1.eval($mem)?.clone().to_owned(),
146 ],
147 })?,
148 NumericPrimitive::Integer(_x.$method(_y as i64))
149 )
150 }
151 (NumericPrimitive::UInteger(_x), NumericPrimitive::Integer(_y)) => {
152 execution_error_if_match_otherwise!(
153 $($types)*, u32,
154 Err(ExecutionError::CannotApplyOperation {
155 op: $arith.operation.into(),
156 operands: vec![
157 $arith.operand0.eval($mem)?.clone().to_owned(),
158 $arith.operand1.eval($mem)?.clone().to_owned(),
159 ],
160 })?,
161 NumericPrimitive::Integer((_x as i64).$method(_y))
162 )
163 }
164 };
165 let prim = Primitive::NumericValue(num);
166 $events.push(crate::events::Event::new(
167 format!("Output is {prim:?}"),
168 crate::events::Severity::Info,
169 ));
170 Ok(prim)
171 }
172 _ => Err(ExecutionError::CannotApplyOperation {
174 op: $arith.operation.into(),
175 operands: vec![
176 $arith.operand0.eval($mem)?.clone().to_owned(),
177 $arith.operand1.eval($mem)?.clone().to_owned(),
178 ],
179 }),
180 }
181 }};
182}
183
184macro_rules! unary_arithmetic_body {
185 ($arith:ident, $mem:ident, $events:ident, $op:ident, $($types:tt)*) => {{
186 $events.push(crate::events::Event::new(
187 "Evaluating operand".to_owned(),
188 crate::events::Severity::Debug,
189 ));
190 let operand = $arith.operand.eval($mem)?.clone();
191 $events.push({
192 let mut evt = crate::events::Event::new(format!("Operand is {operand:?}"), crate::events::Severity::Info);
193 if let Operand::Reference(a) = $arith.operand {
194 evt.related_addresses = vec![a];
195 }
196 evt
197 });
198 match operand {
199 Primitive::NumericValue(wrapped_x) => {
201 let num = match wrapped_x {
202 NumericPrimitive::UInteger(_x) => {
204 execution_error_if_match_otherwise!(
205 $($types)*, u32,
206 Err(ExecutionError::CannotApplyOperation {
207 op: $arith.operation.into(),
208 operands: vec![ $arith.operand.eval($mem)?.clone().to_owned(), ]
209 })?,
210 NumericPrimitive::Integer((_x as i64).$op())
211 )
212 }
213 NumericPrimitive::Float(_x) => {
214 execution_error_if_match_otherwise!(
215 $($types)*, f64,
216 Err(ExecutionError::CannotApplyOperation {
217 op: $arith.operation.into(),
218 operands: vec![ $arith.operand.eval($mem)?.clone().to_owned(), ]
219 })?,
220 NumericPrimitive::Float(_x.$op())
221 )
222 }
223 NumericPrimitive::Integer(_x) => {
224 execution_error_if_match_otherwise!(
225 $($types)*, i64,
226 Err(ExecutionError::CannotApplyOperation {
227 op: $arith.operation.into(),
228 operands: vec![ $arith.operand.eval($mem)?.clone().to_owned(), ]
229 })?,
230 NumericPrimitive::Integer(_x.$op())
231 )
232 }
233 };
234 let prim = Primitive::NumericValue(num);
235 $events.push(crate::events::Event::new(
236 format!("Output is {prim:?}"),
237 crate::events::Severity::Info,
238 ));
239 Ok(prim)
240 }
241 _ => Err(ExecutionError::CannotApplyOperation {
243 op: $arith.operation.into(),
244 operands: vec![
245 $arith.operand.eval($mem)?.clone().to_owned(),
246 ],
247 }),
248 }
249 }};
250}
251impl UnaryArithmetic {
252 pub fn calculate(self, mem: &mut Memory, events: &mut EventWriter) -> Result<Primitive, ExecutionError> {
254 use std::ops::{Neg, Not};
255 match self.operation {
256 UnaryOperation::Not => {
257 unary_arithmetic_body!(self, mem, events, not, [f64])
258 }
259 UnaryOperation::Neg => {
260 unary_arithmetic_body!(self, mem, events, neg, [])
261 }
262 UnaryOperation::Abs => {
263 unary_arithmetic_body!(self, mem, events, abs, [])
264 }
265 UnaryOperation::Acos => {
266 unary_arithmetic_body!(self, mem, events, acos, [i64, u32])
267 }
268 UnaryOperation::Asin => {
269 unary_arithmetic_body!(self, mem, events, asin, [i64, u32])
270 }
271 UnaryOperation::Atan => {
272 unary_arithmetic_body!(self, mem, events, atan, [i64, u32])
273 }
274 UnaryOperation::Ceil => {
275 unary_arithmetic_body!(self, mem, events, ceil, [i64, u32])
276 }
277 UnaryOperation::Cos => {
278 unary_arithmetic_body!(self, mem, events, cos, [i64, u32])
279 }
280 UnaryOperation::Floor => {
281 unary_arithmetic_body!(self, mem, events, floor, [i64, u32])
282 }
283 UnaryOperation::Ln => {
284 unary_arithmetic_body!(self, mem, events, ln, [i64, u32])
285 }
286 UnaryOperation::Log10 => {
287 unary_arithmetic_body!(self, mem, events, log10, [i64, u32])
288 }
289 UnaryOperation::Log2 => {
290 unary_arithmetic_body!(self, mem, events, log2, [i64, u32])
291 }
292 UnaryOperation::Sin => {
293 unary_arithmetic_body!(self, mem, events, sin, [i64, u32])
294 }
295 UnaryOperation::Sqrt => {
296 unary_arithmetic_body!(self, mem, events, sqrt, [i64, u32])
297 }
298 UnaryOperation::Tan => {
299 unary_arithmetic_body!(self, mem, events, tan, [i64, u32])
300 }
301 UnaryOperation::ToDegrees => {
302 unary_arithmetic_body!(self, mem, events, to_degrees, [i64, u32])
303 }
304 UnaryOperation::ToRadians => {
305 unary_arithmetic_body!(self, mem, events, to_radians, [i64, u32])
306 }
307 }
308 }
309}
310impl BinaryArithmetic {
311 pub fn calculate(self, mem: &mut Memory, events: &mut EventWriter) -> Result<Primitive, ExecutionError> {
314 use std::ops::{Add, Div, Mul, Rem, Sub};
315 match self.operation {
316 BinaryOperation::Add => {
317 binary_arithmetic_body!(self, mem, events, add, [])
318 }
319 BinaryOperation::Mul => {
320 binary_arithmetic_body!(self, mem, events, mul, [])
321 }
322 BinaryOperation::Sub => {
323 binary_arithmetic_body!(self, mem, events, sub, [])
324 }
325 BinaryOperation::Div => {
326 binary_arithmetic_body!(self, mem, events, div, [])
327 }
328 BinaryOperation::Mod => {
329 binary_arithmetic_body!(self, mem, events, rem, [])
330 }
331 BinaryOperation::Pow => {
332 binary_arithmetic_body!(self, mem, events, power, [])
333 }
334 BinaryOperation::Log => {
335 binary_arithmetic_body!(self, mem, events, log, [u32, i64])
336 }
337 BinaryOperation::Min => {
338 binary_arithmetic_body!(self, mem, events, min, [])
339 }
340 BinaryOperation::Max => {
341 binary_arithmetic_body!(self, mem, events, max, [])
342 }
343 }
344 }
345}