slang_backend/value/operations/
arithmetic.rs

1use super::super::Value;
2
3/// Arithmetic operations on values
4pub trait ArithmeticOps {
5    /// Adds two values and returns the result.
6    ///
7    /// ### Arguments
8    /// * `other` - The other value to add
9    ///
10    /// ### Returns
11    /// * The result of the addition
12    /// * An error message if the types are incompatible
13    fn add(&self, other: &Self) -> Result<Self, String>
14    where
15        Self: Sized;
16
17    /// Subtracts one value from another and returns the result.
18    ///
19    /// ### Arguments
20    /// * `other` - The value to subtract
21    ///
22    /// ### Returns
23    /// * The result of the subtraction
24    /// * An error message if the types are incompatible or if an underflow occurs
25    fn subtract(&self, other: &Self) -> Result<Self, String>
26    where
27        Self: Sized;
28
29    /// Multiplies two values and returns the result.
30    ///
31    /// ### Arguments
32    /// * `other` - The other value to multiply
33    ///
34    /// ### Returns
35    /// * The result of the multiplication
36    /// * An error message if the types are incompatible or if an overflow occurs
37    fn multiply(&self, other: &Self) -> Result<Self, String>
38    where
39        Self: Sized;
40
41    /// Divides one value by another and returns the result.
42    ///
43    /// ### Arguments
44    /// * `other` - The value to divide by
45    ///
46    /// ### Returns
47    /// * The result of the division
48    /// * An error message if the types are incompatible or if division by zero occurs
49    fn divide(&self, other: &Self) -> Result<Self, String>
50    where
51        Self: Sized;
52
53    /// Negates a value and returns the result.
54    ///
55    /// ### Returns
56    /// * The negated value
57    /// * An error message if the type is incompatible, or an overflow occurs
58    fn negate(&self) -> Result<Self, String>
59    where
60        Self: Sized;
61}
62
63impl ArithmeticOps for Value {
64    fn add(&self, other: &Self) -> Result<Value, String> {
65        match (self, other) {
66            // Integer addition with overflow checking
67            (Value::I32(a), Value::I32(b)) => match a.checked_add(*b) {
68                Some(result) => Ok(Value::I32(result)),
69                None => Err("Integer overflow in I32 addition".to_string()),
70            },
71            (Value::I64(a), Value::I64(b)) => match a.checked_add(*b) {
72                Some(result) => Ok(Value::I64(result)),
73                None => Err("Integer overflow in I64 addition".to_string()),
74            },
75            (Value::U32(a), Value::U32(b)) => match a.checked_add(*b) {
76                Some(result) => Ok(Value::U32(result)),
77                None => Err("Integer overflow in U32 addition".to_string()),
78            },
79            (Value::U64(a), Value::U64(b)) => match a.checked_add(*b) {
80                Some(result) => Ok(Value::U64(result)),
81                None => Err("Integer overflow in U64 addition".to_string()),
82            },
83            // Float addition with overflow checking
84            (Value::F32(a), Value::F32(b)) => {
85                let result = *a + *b;
86                if result.is_infinite() && !a.is_infinite() && !b.is_infinite() {
87                    Err("Floating point overflow in F32 addition".to_string())
88                } else {
89                    Ok(Value::F32(result))
90                }
91            }
92            (Value::F64(a), Value::F64(b)) => {
93                let result = *a + *b;
94                if result.is_infinite() && !a.is_infinite() && !b.is_infinite() {
95                    Err("Floating point overflow in F64 addition".to_string())
96                } else {
97                    Ok(Value::F64(result))
98                }
99            }
100            // String concatenation
101            (Value::String(a), Value::String(b)) => {
102                Ok(Value::String(Box::new(format!("{}{}", a, b))))
103            }
104            _ => Err("Cannot add these types".to_string()),
105        }
106    }
107
108    fn subtract(&self, other: &Self) -> Result<Value, String> {
109        match (self, other) {
110            (Value::I32(a), Value::I32(b)) => match a.checked_sub(*b) {
111                Some(result) => Ok(Value::I32(result)),
112                None => Err("Integer underflow in I32 subtraction".to_string()),
113            },
114            (Value::I64(a), Value::I64(b)) => match a.checked_sub(*b) {
115                Some(result) => Ok(Value::I64(result)),
116                None => Err("Integer underflow in I64 subtraction".to_string()),
117            },
118            (Value::U32(a), Value::U32(b)) => match a.checked_sub(*b) {
119                Some(result) => Ok(Value::U32(result)),
120                None => Err("Integer underflow in U32 subtraction".to_string()),
121            },
122            (Value::U64(a), Value::U64(b)) => match a.checked_sub(*b) {
123                Some(result) => Ok(Value::U64(result)),
124                None => Err("Integer underflow in U64 subtraction".to_string()),
125            },
126            (Value::F32(a), Value::F32(b)) => {
127                let result = *a - *b;
128                if result.is_infinite() && !a.is_infinite() && !b.is_infinite() {
129                    Err("Floating point overflow/underflow in F32 subtraction".to_string())
130                } else {
131                    Ok(Value::F32(result))
132                }
133            }
134            (Value::F64(a), Value::F64(b)) => {
135                let result = *a - *b;
136                if result.is_infinite() && !a.is_infinite() && !b.is_infinite() {
137                    Err("Floating point overflow/underflow in F64 subtraction".to_string())
138                } else {
139                    Ok(Value::F64(result))
140                }
141            }
142            _ => Err("Cannot subtract these types".to_string()),
143        }
144    }
145
146    fn multiply(&self, other: &Self) -> Result<Value, String> {
147        match (self, other) {
148            (Value::I32(a), Value::I32(b)) => match a.checked_mul(*b) {
149                Some(result) => Ok(Value::I32(result)),
150                None => Err("Integer overflow in I32 multiplication".to_string()),
151            },
152            (Value::I64(a), Value::I64(b)) => match a.checked_mul(*b) {
153                Some(result) => Ok(Value::I64(result)),
154                None => Err("Integer overflow in I64 multiplication".to_string()),
155            },
156            (Value::U32(a), Value::U32(b)) => match a.checked_mul(*b) {
157                Some(result) => Ok(Value::U32(result)),
158                None => Err("Integer overflow in U32 multiplication".to_string()),
159            },
160            (Value::U64(a), Value::U64(b)) => match a.checked_mul(*b) {
161                Some(result) => Ok(Value::U64(result)),
162                None => Err("Integer overflow in U64 multiplication".to_string()),
163            },
164            (Value::F32(a), Value::F32(b)) => {
165                let result = *a * *b;
166                if result.is_infinite() && !a.is_infinite() && !b.is_infinite() {
167                    Err("Floating point overflow in F32 multiplication".to_string())
168                } else {
169                    Ok(Value::F32(result))
170                }
171            }
172            (Value::F64(a), Value::F64(b)) => {
173                let result = *a * *b;
174                if result.is_infinite() && !a.is_infinite() && !b.is_infinite() {
175                    Err("Floating point overflow in F64 multiplication".to_string())
176                } else {
177                    Ok(Value::F64(result))
178                }
179            }
180            _ => Err("Cannot multiply these types".to_string()),
181        }
182    }
183
184    fn divide(&self, other: &Self) -> Result<Value, String> {
185        match (self, other) {
186            (Value::I32(a), Value::I32(b)) => {
187                if *b == 0 {
188                    return Err("Division by zero".to_string());
189                }
190                if *a == i32::MIN && *b == -1 {
191                    return Err("Integer overflow in I32 division".to_string());
192                }
193                match a.checked_div(*b) {
194                    Some(result) => Ok(Value::I32(result)),
195                    None => Err("Integer division error".to_string()),
196                }
197            }
198            (Value::I64(a), Value::I64(b)) => {
199                if *b == 0 {
200                    return Err("Division by zero".to_string());
201                }
202                if *a == i64::MIN && *b == -1 {
203                    return Err("Integer overflow in I64 division".to_string());
204                }
205                match a.checked_div(*b) {
206                    Some(result) => Ok(Value::I64(result)),
207                    None => Err("Integer division error".to_string()),
208                }
209            }
210            (Value::U32(a), Value::U32(b)) => {
211                if *b == 0 {
212                    return Err("Division by zero".to_string());
213                }
214                match a.checked_div(*b) {
215                    Some(result) => Ok(Value::U32(result)),
216                    None => Err("Integer division error".to_string()),
217                }
218            }
219            (Value::U64(a), Value::U64(b)) => {
220                if *b == 0 {
221                    return Err("Division by zero".to_string());
222                }
223                match a.checked_div(*b) {
224                    Some(result) => Ok(Value::U64(result)),
225                    None => Err("Integer division error".to_string()),
226                }
227            }
228            (Value::F32(a), Value::F32(b)) => {
229                if *b == 0.0 {
230                    return Err("Division by zero".to_string());
231                }
232                let result = *a / *b;
233                if result.is_infinite() && !a.is_infinite() {
234                    Err("Floating point overflow in F32 division".to_string())
235                } else {
236                    Ok(Value::F32(result))
237                }
238            }
239            (Value::F64(a), Value::F64(b)) => {
240                if *b == 0.0 {
241                    return Err("Division by zero".to_string());
242                }
243                let result = *a / *b;
244                if result.is_infinite() && !a.is_infinite() {
245                    Err("Floating point overflow in F64 division".to_string())
246                } else {
247                    Ok(Value::F64(result))
248                }
249            }
250            _ => Err("Cannot divide these types".to_string()),
251        }
252    }
253
254    fn negate(&self) -> Result<Value, String> {
255        match self {
256            Value::I32(i) => {
257                if *i == i32::MIN {
258                    return Err("Integer overflow in I32 negation".to_string());
259                }
260                Ok(Value::I32(-i))
261            }
262            Value::I64(i) => {
263                if *i == i64::MIN {
264                    return Err("Integer overflow in I64 negation".to_string());
265                }
266                Ok(Value::I64(-i))
267            }
268            Value::U32(_) => Err("Cannot negate unsigned integer U32".to_string()),
269            Value::U64(_) => Err("Cannot negate unsigned integer U64".to_string()),
270            Value::F32(f) => Ok(Value::F32(-f)),
271            Value::F64(f) => Ok(Value::F64(-f)),
272            _ => Err("Can only negate numbers".to_string()),
273        }
274    }
275}