slang_backend/value/operations/
arithmetic.rs1use super::super::Value;
2
3pub trait ArithmeticOps {
5 fn add(&self, other: &Self) -> Result<Self, String>
14 where
15 Self: Sized;
16
17 fn subtract(&self, other: &Self) -> Result<Self, String>
26 where
27 Self: Sized;
28
29 fn multiply(&self, other: &Self) -> Result<Self, String>
38 where
39 Self: Sized;
40
41 fn divide(&self, other: &Self) -> Result<Self, String>
50 where
51 Self: Sized;
52
53 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 (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 (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 (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}