basic/mach/
operation.rs

1use super::Val;
2use crate::error;
3use crate::lang::Error;
4use std::convert::TryFrom;
5
6type Result<T> = std::result::Result<T, Error>;
7
8pub struct Operation {}
9
10impl Operation {
11    pub fn negate(val: Val) -> Result<Val> {
12        use Val::*;
13        match val {
14            Integer(n) => Ok(Integer(-n)),
15            Single(n) => Ok(Single(-n)),
16            Double(n) => Ok(Double(-n)),
17            String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
18        }
19    }
20
21    pub fn power(lhs: Val, rhs: Val) -> Result<Val> {
22        use Val::*;
23        match lhs {
24            Integer(l) => match rhs {
25                Integer(r) if r >= 0 => match l.checked_pow(r as u32) {
26                    Some(i) => Ok(Integer(i)),
27                    None => Err(error!(Overflow)),
28                },
29                Integer(r) => Ok(Single((l as f32).powi(r as i32))),
30                Single(r) => Ok(Single((l as f32).powf(r))),
31                Double(r) => Ok(Double((l as f64).powf(r))),
32                _ => Err(error!(TypeMismatch)),
33            },
34            Single(l) => match rhs {
35                Integer(r) => Ok(Single(l.powi(r as i32))),
36                Single(r) => Ok(Single(l.powf(r))),
37                Double(r) => Ok(Double((l as f64).powf(r))),
38                _ => Err(error!(TypeMismatch)),
39            },
40            Double(l) => match rhs {
41                Integer(r) => Ok(Double(l.powi(r as i32))),
42                Single(r) => Ok(Double(l.powf(r as f64))),
43                Double(r) => Ok(Double(l.powf(r))),
44                _ => Err(error!(TypeMismatch)),
45            },
46            String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
47        }
48    }
49
50    pub fn multiply(lhs: Val, rhs: Val) -> Result<Val> {
51        use Val::*;
52        match lhs {
53            Integer(l) => match rhs {
54                Integer(r) => match l.checked_mul(r) {
55                    Some(i) => Ok(Integer(i)),
56                    None => Err(error!(Overflow)),
57                },
58                Single(r) => Ok(Single(l as f32 * r)),
59                Double(r) => Ok(Double(l as f64 * r)),
60                _ => Err(error!(TypeMismatch)),
61            },
62            Single(l) => match rhs {
63                Integer(r) => Ok(Single(l * r as f32)),
64                Single(r) => Ok(Single(l * r)),
65                Double(r) => Ok(Double(l as f64 * r)),
66                _ => Err(error!(TypeMismatch)),
67            },
68            Double(l) => match rhs {
69                Integer(r) => Ok(Double(l * r as f64)),
70                Single(r) => Ok(Double(l * r as f64)),
71                Double(r) => Ok(Double(l * r)),
72                _ => Err(error!(TypeMismatch)),
73            },
74            String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
75        }
76    }
77
78    pub fn divide(lhs: Val, rhs: Val) -> Result<Val> {
79        use Val::*;
80        match lhs {
81            Integer(l) => match rhs {
82                Integer(r) => Ok(Single(l as f32 / r as f32)),
83                Single(r) => Ok(Single(l as f32 / r)),
84                Double(r) => Ok(Double(l as f64 / r)),
85                _ => Err(error!(TypeMismatch)),
86            },
87            Single(l) => match rhs {
88                Integer(r) => Ok(Single(l / r as f32)),
89                Single(r) => Ok(Single(l / r)),
90                Double(r) => Ok(Double(l as f64 / r)),
91                _ => Err(error!(TypeMismatch)),
92            },
93            Double(l) => match rhs {
94                Integer(r) => Ok(Double(l / r as f64)),
95                Single(r) => Ok(Double(l / r as f64)),
96                Double(r) => Ok(Double(l / r)),
97                _ => Err(error!(TypeMismatch)),
98            },
99            String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
100        }
101    }
102
103    pub fn divint(lhs: Val, rhs: Val) -> Result<Val> {
104        let lhs = i16::try_from(lhs)?;
105        let rhs = i16::try_from(rhs)?;
106        match lhs.checked_div(rhs) {
107            Some(n) => Ok(Val::Integer(n)),
108            None => Err(error!(DivisionByZero)),
109        }
110    }
111
112    pub fn remainder(lhs: Val, rhs: Val) -> Result<Val> {
113        let lhs = i16::try_from(lhs)?;
114        let rhs = i16::try_from(rhs)?;
115        match lhs.checked_rem(rhs) {
116            Some(n) => Ok(Val::Integer(n)),
117            None => Err(error!(DivisionByZero)),
118        }
119    }
120
121    pub fn sum(lhs: Val, rhs: Val) -> Result<Val> {
122        use Val::*;
123        match lhs {
124            String(l) => match rhs {
125                String(r) => Ok(String((l.to_string() + &r).into())),
126                _ => Err(error!(TypeMismatch)),
127            },
128            Integer(l) => match rhs {
129                Integer(r) => match l.checked_add(r) {
130                    Some(i) => Ok(Integer(i)),
131                    None => Err(error!(Overflow)),
132                },
133                Single(r) => Ok(Single(l as f32 + r)),
134                Double(r) => Ok(Double(l as f64 + r)),
135                _ => Err(error!(TypeMismatch)),
136            },
137            Single(l) => match rhs {
138                Integer(r) => Ok(Single(l + r as f32)),
139                Single(r) => Ok(Single(l + r)),
140                Double(r) => Ok(Double(l as f64 + r)),
141                _ => Err(error!(TypeMismatch)),
142            },
143            Double(l) => match rhs {
144                Integer(r) => Ok(Double(l + r as f64)),
145                Single(r) => Ok(Double(l + r as f64)),
146                Double(r) => Ok(Double(l + r)),
147                _ => Err(error!(TypeMismatch)),
148            },
149            Return(_) | Next(_) => Err(error!(TypeMismatch)),
150        }
151    }
152
153    pub fn subtract(lhs: Val, rhs: Val) -> Result<Val> {
154        use Val::*;
155        match lhs {
156            Integer(l) => match rhs {
157                Integer(r) => match l.checked_sub(r) {
158                    Some(i) => Ok(Integer(i)),
159                    None => Err(error!(Overflow)),
160                },
161                Single(r) => Ok(Single(l as f32 - r)),
162                Double(r) => Ok(Double(l as f64 - r)),
163                _ => Err(error!(TypeMismatch)),
164            },
165            Single(l) => match rhs {
166                Integer(r) => Ok(Single(l - r as f32)),
167                Single(r) => Ok(Single(l - r)),
168                Double(r) => Ok(Double(l as f64 - r)),
169                _ => Err(error!(TypeMismatch)),
170            },
171            Double(l) => match rhs {
172                Integer(r) => Ok(Double(l - r as f64)),
173                Single(r) => Ok(Double(l - r as f64)),
174                Double(r) => Ok(Double(l - r)),
175                _ => Err(error!(TypeMismatch)),
176            },
177            String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
178        }
179    }
180
181    pub fn equal(lhs: Val, rhs: Val) -> Result<Val> {
182        if Operation::equal_bool(lhs, rhs)? {
183            Ok(Val::Integer(-1))
184        } else {
185            Ok(Val::Integer(0))
186        }
187    }
188
189    pub fn not_equal(lhs: Val, rhs: Val) -> Result<Val> {
190        if Operation::equal_bool(lhs, rhs)? {
191            Ok(Val::Integer(0))
192        } else {
193            Ok(Val::Integer(-1))
194        }
195    }
196
197    fn equal_bool(lhs: Val, rhs: Val) -> Result<bool> {
198        use Val::*;
199        match lhs {
200            Integer(l) => match rhs {
201                Integer(r) => Ok(l == r),
202                Single(r) => Ok((l as f32 - r).abs() <= std::f32::EPSILON),
203                Double(r) => Ok((l as f64 - r).abs() <= std::f64::EPSILON),
204                _ => Err(error!(TypeMismatch)),
205            },
206            Single(l) => match rhs {
207                Integer(r) => Ok((l - r as f32).abs() <= std::f32::EPSILON),
208                Single(r) => Ok((l - r).abs() <= std::f32::EPSILON),
209                Double(r) => Ok((l as f64 - r).abs() <= std::f64::EPSILON),
210                _ => Err(error!(TypeMismatch)),
211            },
212            Double(l) => match rhs {
213                Integer(r) => Ok((l - r as f64).abs() <= std::f64::EPSILON),
214                Single(r) => Ok((l - r as f64).abs() <= std::f64::EPSILON),
215                Double(r) => Ok((l - r).abs() <= std::f64::EPSILON),
216                _ => Err(error!(TypeMismatch)),
217            },
218            String(l) => match rhs {
219                String(r) => Ok(l == r),
220                _ => Err(error!(TypeMismatch)),
221            },
222            Return(_) | Next(_) => Err(error!(TypeMismatch)),
223        }
224    }
225
226    pub fn greater(lhs: Val, rhs: Val) -> Result<Val> {
227        if Operation::less_bool(rhs, lhs)? {
228            Ok(Val::Integer(-1))
229        } else {
230            Ok(Val::Integer(0))
231        }
232    }
233
234    pub fn less(lhs: Val, rhs: Val) -> Result<Val> {
235        if Operation::less_bool(lhs, rhs)? {
236            Ok(Val::Integer(-1))
237        } else {
238            Ok(Val::Integer(0))
239        }
240    }
241
242    pub fn less_bool(lhs: Val, rhs: Val) -> Result<bool> {
243        use Val::*;
244        match lhs {
245            Integer(l) => match rhs {
246                Integer(r) => Ok(l < r),
247                Single(r) => Ok((l as f32) < r),
248                Double(r) => Ok((l as f64) < r),
249                _ => Err(error!(TypeMismatch)),
250            },
251            Single(l) => match rhs {
252                Integer(r) => Ok(l < r as f32),
253                Single(r) => Ok(l < r),
254                Double(r) => Ok((l as f64) < r),
255                _ => Err(error!(TypeMismatch)),
256            },
257            Double(l) => match rhs {
258                Integer(r) => Ok(l < r as f64),
259                Single(r) => Ok(l < r as f64),
260                Double(r) => Ok(l < r),
261                _ => Err(error!(TypeMismatch)),
262            },
263            String(l) => match rhs {
264                String(r) => Ok(l < r),
265                _ => Err(error!(TypeMismatch)),
266            },
267            Return(_) | Next(_) => Err(error!(TypeMismatch)),
268        }
269    }
270
271    pub fn greater_equal(lhs: Val, rhs: Val) -> Result<Val> {
272        if Operation::less_equal_bool(rhs, lhs)? {
273            Ok(Val::Integer(-1))
274        } else {
275            Ok(Val::Integer(0))
276        }
277    }
278
279    pub fn less_equal(lhs: Val, rhs: Val) -> Result<Val> {
280        if Operation::less_equal_bool(lhs, rhs)? {
281            Ok(Val::Integer(-1))
282        } else {
283            Ok(Val::Integer(0))
284        }
285    }
286
287    pub fn less_equal_bool(lhs: Val, rhs: Val) -> Result<bool> {
288        use Val::*;
289        match lhs {
290            Integer(l) => match rhs {
291                Integer(r) => Ok(l <= r),
292                Single(r) => Ok((l as f32) <= r),
293                Double(r) => Ok((l as f64) <= r),
294                _ => Err(error!(TypeMismatch)),
295            },
296            Single(l) => match rhs {
297                Integer(r) => Ok(l <= r as f32),
298                Single(r) => Ok(l <= r),
299                Double(r) => Ok((l as f64) <= r),
300                _ => Err(error!(TypeMismatch)),
301            },
302            Double(l) => match rhs {
303                Integer(r) => Ok(l <= r as f64),
304                Single(r) => Ok(l <= r as f64),
305                Double(r) => Ok(l <= r),
306                _ => Err(error!(TypeMismatch)),
307            },
308            String(l) => match rhs {
309                String(r) => Ok(l <= r),
310                _ => Err(error!(TypeMismatch)),
311            },
312            Return(_) | Next(_) => Err(error!(TypeMismatch)),
313        }
314    }
315
316    pub fn and(lhs: Val, rhs: Val) -> Result<Val> {
317        let lhs = i16::try_from(lhs)?;
318        let rhs = i16::try_from(rhs)?;
319        Ok(Val::Integer(lhs & rhs))
320    }
321
322    pub fn not(val: Val) -> Result<Val> {
323        Ok(Val::Integer(!i16::try_from(val)?))
324    }
325
326    pub fn or(lhs: Val, rhs: Val) -> Result<Val> {
327        let lhs = i16::try_from(lhs)?;
328        let rhs = i16::try_from(rhs)?;
329        Ok(Val::Integer(lhs | rhs))
330    }
331
332    pub fn xor(lhs: Val, rhs: Val) -> Result<Val> {
333        let lhs = i16::try_from(lhs)?;
334        let rhs = i16::try_from(rhs)?;
335        Ok(Val::Integer(lhs ^ rhs))
336    }
337
338    pub fn imp(lhs: Val, rhs: Val) -> Result<Val> {
339        let lhs = i16::try_from(lhs)?;
340        let rhs = i16::try_from(rhs)?;
341        Ok(Val::Integer(!lhs | rhs))
342    }
343
344    pub fn eqv(lhs: Val, rhs: Val) -> Result<Val> {
345        let lhs = i16::try_from(lhs)?;
346        let rhs = i16::try_from(rhs)?;
347        Ok(Val::Integer(!(lhs ^ rhs)))
348    }
349}