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 (Value::Vector(a), Value::Vector(b)) => {
106 a.len() == b.len()
107 && (0..a.len()).all(|i| match (a.get(i), b.get(i)) {
108 (Some(x), Some(y)) => self.aver_eq(x, y),
109 _ => false,
110 })
111 }
112 _ => false,
113 }
114 }
115
116 pub(super) fn op_add(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
117 match (a, b) {
118 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
119 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
120 (Value::Str(mut x), Value::Str(y)) => {
121 x.push_str(&y);
122 Ok(Value::Str(x))
123 }
124 _ => Err(RuntimeError::Error(
125 "Operator '+' does not support these types".to_string(),
126 )),
127 }
128 }
129
130 pub(super) fn op_sub(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
131 match (&a, &b) {
132 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
133 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
134 (Value::Int(0), Value::Float(y)) => Ok(Value::Float(-y)),
136 _ => Err(RuntimeError::Error(
137 "Operator '-' does not support these types".to_string(),
138 )),
139 }
140 }
141
142 pub(super) fn op_mul(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
143 match (&a, &b) {
144 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
145 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
146 _ => Err(RuntimeError::Error(
147 "Operator '*' does not support these types".to_string(),
148 )),
149 }
150 }
151
152 pub(super) fn op_div(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
153 match (&a, &b) {
154 (Value::Int(x), Value::Int(y)) => {
155 if *y == 0 {
156 Err(RuntimeError::Error("division by zero".to_string()))
157 } else {
158 Ok(Value::Int(x / y))
159 }
160 }
161 (Value::Float(x), Value::Float(y)) => {
162 if *y == 0.0 {
163 Err(RuntimeError::Error("division by zero".to_string()))
164 } else {
165 Ok(Value::Float(x / y))
166 }
167 }
168 _ => Err(RuntimeError::Error(
169 "Operator '/' does not support these types".to_string(),
170 )),
171 }
172 }
173
174 pub(super) fn op_compare(&self, a: &Value, b: &Value, op: &str) -> Result<Value, RuntimeError> {
175 let result = match (a, b) {
176 (Value::Int(x), Value::Int(y)) => match op {
177 "<" => x < y,
178 ">" => x > y,
179 "<=" => x <= y,
180 ">=" => x >= y,
181 _ => unreachable!(),
182 },
183 (Value::Float(x), Value::Float(y)) => match op {
184 "<" => x < y,
185 ">" => x > y,
186 "<=" => x <= y,
187 ">=" => x >= y,
188 _ => unreachable!(),
189 },
190 (Value::Str(x), Value::Str(y)) => match op {
191 "<" => x < y,
192 ">" => x > y,
193 "<=" => x <= y,
194 ">=" => x >= y,
195 _ => unreachable!(),
196 },
197 _ => {
198 return Err(RuntimeError::Error(format!(
199 "Operator '{}' does not support these types",
200 op
201 )));
202 }
203 };
204 Ok(Value::Bool(result))
205 }
206
207 fn op_add_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
210 if a.is_int() && b.is_int() {
211 let result = a.as_int(&self.arena) + b.as_int(&self.arena);
212 return Ok(NanValue::new_int(result, &mut self.arena));
213 }
214 if a.is_float() && b.is_float() {
215 return Ok(NanValue::new_float(a.as_float() + b.as_float()));
216 }
217 if a.is_string() && b.is_string() {
218 let sa = self.arena.get_string_value(a);
219 let sb = self.arena.get_string_value(b);
220 let mut buf = String::with_capacity(sa.len() + sb.len());
221 buf.push_str(sa.as_str());
222 buf.push_str(sb.as_str());
223 return Ok(NanValue::new_string_value(&buf, &mut self.arena));
224 }
225 Err(RuntimeError::Error(
226 "Operator '+' does not support these types".to_string(),
227 ))
228 }
229
230 fn op_sub_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
231 if a.is_int() && b.is_int() {
232 let result = a.as_int(&self.arena) - b.as_int(&self.arena);
233 return Ok(NanValue::new_int(result, &mut self.arena));
234 }
235 if a.is_float() && b.is_float() {
236 return Ok(NanValue::new_float(a.as_float() - b.as_float()));
237 }
238 if a.is_int() && a.as_int(&self.arena) == 0 && b.is_float() {
240 return Ok(NanValue::new_float(-b.as_float()));
241 }
242 Err(RuntimeError::Error(
243 "Operator '-' does not support these types".to_string(),
244 ))
245 }
246
247 fn op_mul_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
248 if a.is_int() && b.is_int() {
249 let result = a.as_int(&self.arena) * b.as_int(&self.arena);
250 return Ok(NanValue::new_int(result, &mut self.arena));
251 }
252 if a.is_float() && b.is_float() {
253 return Ok(NanValue::new_float(a.as_float() * b.as_float()));
254 }
255 Err(RuntimeError::Error(
256 "Operator '*' does not support these types".to_string(),
257 ))
258 }
259
260 fn op_div_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
261 if a.is_int() && b.is_int() {
262 let bv = b.as_int(&self.arena);
263 if bv == 0 {
264 return Err(RuntimeError::Error("division by zero".to_string()));
265 }
266 let result = a.as_int(&self.arena) / bv;
267 return Ok(NanValue::new_int(result, &mut self.arena));
268 }
269 if a.is_float() && b.is_float() {
270 let bv = b.as_float();
271 if bv == 0.0 {
272 return Err(RuntimeError::Error("division by zero".to_string()));
273 }
274 return Ok(NanValue::new_float(a.as_float() / bv));
275 }
276 Err(RuntimeError::Error(
277 "Operator '/' does not support these types".to_string(),
278 ))
279 }
280
281 fn op_compare_nv(&self, a: NanValue, b: NanValue, op: &str) -> Result<NanValue, RuntimeError> {
282 if a.is_int() && b.is_int() {
283 let x = a.as_int(&self.arena);
284 let y = b.as_int(&self.arena);
285 let result = match op {
286 "<" => x < y,
287 ">" => x > y,
288 "<=" => x <= y,
289 ">=" => x >= y,
290 _ => unreachable!(),
291 };
292 return Ok(NanValue::new_bool(result));
293 }
294 if a.is_float() && b.is_float() {
295 let x = a.as_float();
296 let y = b.as_float();
297 let result = match op {
298 "<" => x < y,
299 ">" => x > y,
300 "<=" => x <= y,
301 ">=" => x >= y,
302 _ => unreachable!(),
303 };
304 return Ok(NanValue::new_bool(result));
305 }
306 if a.is_string() && b.is_string() {
307 let x = self.arena.get_string_value(a);
308 let y = self.arena.get_string_value(b);
309 let result = match op {
310 "<" => x < y,
311 ">" => x > y,
312 "<=" => x <= y,
313 ">=" => x >= y,
314 _ => unreachable!(),
315 };
316 return Ok(NanValue::new_bool(result));
317 }
318 Err(RuntimeError::Error(format!(
319 "Operator '{}' does not support these types",
320 op
321 )))
322 }
323}