1use super::*;
2
3impl Interpreter {
4 #[allow(dead_code)]
5 pub(super) fn eval_binop(
6 &self,
7 op: &BinOp,
8 left: Value,
9 right: Value,
10 ) -> Result<Value, RuntimeError> {
11 match op {
12 BinOp::Add => self.op_add(left, right),
13 BinOp::Sub => self.op_sub(left, right),
14 BinOp::Mul => self.op_mul(left, right),
15 BinOp::Div => self.op_div(left, right),
16 BinOp::Eq => Ok(Value::Bool(self.aver_eq(&left, &right))),
17 BinOp::Neq => Ok(Value::Bool(!self.aver_eq(&left, &right))),
18 BinOp::Lt => self.op_compare(&left, &right, "<"),
19 BinOp::Gt => self.op_compare(&left, &right, ">"),
20 BinOp::Lte => self.op_compare(&left, &right, "<="),
21 BinOp::Gte => self.op_compare(&left, &right, ">="),
22 }
23 }
24
25 pub(super) fn eval_binop_nv(
27 &mut self,
28 op: &BinOp,
29 left: NanValue,
30 right: NanValue,
31 ) -> Result<NanValue, RuntimeError> {
32 match op {
33 BinOp::Add => self.op_add_nv(left, right),
34 BinOp::Sub => self.op_sub_nv(left, right),
35 BinOp::Mul => self.op_mul_nv(left, right),
36 BinOp::Div => self.op_div_nv(left, right),
37 BinOp::Eq => Ok(NanValue::new_bool(left.eq_in(right, &self.arena))),
38 BinOp::Neq => Ok(NanValue::new_bool(!left.eq_in(right, &self.arena))),
39 BinOp::Lt => self.op_compare_nv(left, right, "<"),
40 BinOp::Gt => self.op_compare_nv(left, right, ">"),
41 BinOp::Lte => self.op_compare_nv(left, right, "<="),
42 BinOp::Gte => self.op_compare_nv(left, right, ">="),
43 }
44 }
45
46 pub fn aver_eq(&self, a: &Value, b: &Value) -> bool {
47 if let (Some(xs), Some(ys)) = (list_view(a), list_view(b)) {
48 return xs.len() == ys.len()
49 && xs.iter().zip(ys.iter()).all(|(x, y)| self.aver_eq(x, y));
50 }
51
52 match (a, b) {
53 (Value::Int(x), Value::Int(y)) => x == y,
54 (Value::Float(x), Value::Float(y)) => x == y,
55 (Value::Str(x), Value::Str(y)) => x == y,
56 (Value::Bool(x), Value::Bool(y)) => x == y,
57 (Value::Unit, Value::Unit) => true,
58 (Value::None, Value::None) => true,
59 (Value::Ok(x), Value::Ok(y)) => self.aver_eq(x, y),
60 (Value::Err(x), Value::Err(y)) => self.aver_eq(x, y),
61 (Value::Some(x), Value::Some(y)) => self.aver_eq(x, y),
62 (Value::Tuple(xs), Value::Tuple(ys)) => {
63 xs.len() == ys.len() && xs.iter().zip(ys.iter()).all(|(x, y)| self.aver_eq(x, y))
64 }
65 (Value::Map(m1), Value::Map(m2)) => {
66 m1.len() == m2.len()
67 && m1
68 .iter()
69 .all(|(k, v1)| m2.get(k).map(|v2| self.aver_eq(v1, v2)).unwrap_or(false))
70 }
71 (
72 Value::Variant {
73 type_name: t1,
74 variant: v1,
75 fields: f1,
76 },
77 Value::Variant {
78 type_name: t2,
79 variant: v2,
80 fields: f2,
81 },
82 ) => {
83 t1 == t2
84 && v1 == v2
85 && f1.len() == f2.len()
86 && f1.iter().zip(f2.iter()).all(|(x, y)| self.aver_eq(x, y))
87 }
88 (
89 Value::Record {
90 type_name: t1,
91 fields: f1,
92 },
93 Value::Record {
94 type_name: t2,
95 fields: f2,
96 },
97 ) => {
98 t1 == t2
99 && f1.len() == f2.len()
100 && f1
101 .iter()
102 .zip(f2.iter())
103 .all(|((k1, v1), (k2, v2))| k1 == k2 && self.aver_eq(v1, v2))
104 }
105 _ => false,
106 }
107 }
108
109 pub(super) fn op_add(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
110 match (&a, &b) {
111 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
112 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
113 (Value::Str(x), Value::Str(y)) => Ok(Value::Str(format!("{}{}", x, y))),
114 _ => Err(RuntimeError::Error(
115 "Operator '+' does not support these types".to_string(),
116 )),
117 }
118 }
119
120 pub(super) fn op_sub(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
121 match (&a, &b) {
122 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
123 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
124 (Value::Int(0), Value::Float(y)) => Ok(Value::Float(-y)),
126 _ => Err(RuntimeError::Error(
127 "Operator '-' does not support these types".to_string(),
128 )),
129 }
130 }
131
132 pub(super) fn op_mul(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
133 match (&a, &b) {
134 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
135 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
136 _ => Err(RuntimeError::Error(
137 "Operator '*' does not support these types".to_string(),
138 )),
139 }
140 }
141
142 pub(super) fn op_div(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
143 match (&a, &b) {
144 (Value::Int(x), Value::Int(y)) => {
145 if *y == 0 {
146 Err(RuntimeError::Error("Division by zero".to_string()))
147 } else {
148 Ok(Value::Int(x / y))
149 }
150 }
151 (Value::Float(x), Value::Float(y)) => {
152 if *y == 0.0 {
153 Err(RuntimeError::Error("Division by zero".to_string()))
154 } else {
155 Ok(Value::Float(x / y))
156 }
157 }
158 _ => Err(RuntimeError::Error(
159 "Operator '/' does not support these types".to_string(),
160 )),
161 }
162 }
163
164 pub(super) fn op_compare(&self, a: &Value, b: &Value, op: &str) -> Result<Value, RuntimeError> {
165 let result = match (a, b) {
166 (Value::Int(x), Value::Int(y)) => match op {
167 "<" => x < y,
168 ">" => x > y,
169 "<=" => x <= y,
170 ">=" => x >= y,
171 _ => unreachable!(),
172 },
173 (Value::Float(x), Value::Float(y)) => match op {
174 "<" => x < y,
175 ">" => x > y,
176 "<=" => x <= y,
177 ">=" => x >= y,
178 _ => unreachable!(),
179 },
180 (Value::Str(x), Value::Str(y)) => match op {
181 "<" => x < y,
182 ">" => x > y,
183 "<=" => x <= y,
184 ">=" => x >= y,
185 _ => unreachable!(),
186 },
187 _ => {
188 return Err(RuntimeError::Error(format!(
189 "Operator '{}' does not support these types",
190 op
191 )));
192 }
193 };
194 Ok(Value::Bool(result))
195 }
196
197 fn op_add_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
200 if a.is_int() && b.is_int() {
201 let result = a.as_int(&self.arena) + b.as_int(&self.arena);
202 return Ok(NanValue::new_int(result, &mut self.arena));
203 }
204 if a.is_float() && b.is_float() {
205 return Ok(NanValue::new_float(a.as_float() + b.as_float()));
206 }
207 if a.is_string() && b.is_string() {
208 let combined = format!(
209 "{}{}",
210 self.arena.get_string_value(a),
211 self.arena.get_string_value(b)
212 );
213 return Ok(NanValue::new_string_value(&combined, &mut self.arena));
214 }
215 Err(RuntimeError::Error(
216 "Operator '+' does not support these types".to_string(),
217 ))
218 }
219
220 fn op_sub_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
221 if a.is_int() && b.is_int() {
222 let result = a.as_int(&self.arena) - b.as_int(&self.arena);
223 return Ok(NanValue::new_int(result, &mut self.arena));
224 }
225 if a.is_float() && b.is_float() {
226 return Ok(NanValue::new_float(a.as_float() - b.as_float()));
227 }
228 if a.is_int() && a.as_int(&self.arena) == 0 && b.is_float() {
230 return Ok(NanValue::new_float(-b.as_float()));
231 }
232 Err(RuntimeError::Error(
233 "Operator '-' does not support these types".to_string(),
234 ))
235 }
236
237 fn op_mul_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
238 if a.is_int() && b.is_int() {
239 let result = a.as_int(&self.arena) * b.as_int(&self.arena);
240 return Ok(NanValue::new_int(result, &mut self.arena));
241 }
242 if a.is_float() && b.is_float() {
243 return Ok(NanValue::new_float(a.as_float() * b.as_float()));
244 }
245 Err(RuntimeError::Error(
246 "Operator '*' does not support these types".to_string(),
247 ))
248 }
249
250 fn op_div_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
251 if a.is_int() && b.is_int() {
252 let bv = b.as_int(&self.arena);
253 if bv == 0 {
254 return Err(RuntimeError::Error("Division by zero".to_string()));
255 }
256 let result = a.as_int(&self.arena) / bv;
257 return Ok(NanValue::new_int(result, &mut self.arena));
258 }
259 if a.is_float() && b.is_float() {
260 let bv = b.as_float();
261 if bv == 0.0 {
262 return Err(RuntimeError::Error("Division by zero".to_string()));
263 }
264 return Ok(NanValue::new_float(a.as_float() / bv));
265 }
266 Err(RuntimeError::Error(
267 "Operator '/' does not support these types".to_string(),
268 ))
269 }
270
271 fn op_compare_nv(&self, a: NanValue, b: NanValue, op: &str) -> Result<NanValue, RuntimeError> {
272 if a.is_int() && b.is_int() {
273 let x = a.as_int(&self.arena);
274 let y = b.as_int(&self.arena);
275 let result = match op {
276 "<" => x < y,
277 ">" => x > y,
278 "<=" => x <= y,
279 ">=" => x >= y,
280 _ => unreachable!(),
281 };
282 return Ok(NanValue::new_bool(result));
283 }
284 if a.is_float() && b.is_float() {
285 let x = a.as_float();
286 let y = b.as_float();
287 let result = match op {
288 "<" => x < y,
289 ">" => x > y,
290 "<=" => x <= y,
291 ">=" => x >= y,
292 _ => unreachable!(),
293 };
294 return Ok(NanValue::new_bool(result));
295 }
296 if a.is_string() && b.is_string() {
297 let x = self.arena.get_string_value(a);
298 let y = self.arena.get_string_value(b);
299 let result = match op {
300 "<" => x < y,
301 ">" => x > y,
302 "<=" => x <= y,
303 ">=" => x >= y,
304 _ => unreachable!(),
305 };
306 return Ok(NanValue::new_bool(result));
307 }
308 Err(RuntimeError::Error(format!(
309 "Operator '{}' does not support these types",
310 op
311 )))
312 }
313}