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 sa = self.arena.get_string(a.arena_index()).to_string();
209 let sb = self.arena.get_string(b.arena_index());
210 let combined = format!("{}{}", sa, sb);
211 let idx = self.arena.push_string(&combined);
212 return Ok(NanValue::new_string(idx));
213 }
214 Err(RuntimeError::Error(
215 "Operator '+' does not support these types".to_string(),
216 ))
217 }
218
219 fn op_sub_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
220 if a.is_int() && b.is_int() {
221 let result = a.as_int(&self.arena) - b.as_int(&self.arena);
222 return Ok(NanValue::new_int(result, &mut self.arena));
223 }
224 if a.is_float() && b.is_float() {
225 return Ok(NanValue::new_float(a.as_float() - b.as_float()));
226 }
227 if a.is_int() && a.as_int(&self.arena) == 0 && b.is_float() {
229 return Ok(NanValue::new_float(-b.as_float()));
230 }
231 Err(RuntimeError::Error(
232 "Operator '-' does not support these types".to_string(),
233 ))
234 }
235
236 fn op_mul_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
237 if a.is_int() && b.is_int() {
238 let result = a.as_int(&self.arena) * b.as_int(&self.arena);
239 return Ok(NanValue::new_int(result, &mut self.arena));
240 }
241 if a.is_float() && b.is_float() {
242 return Ok(NanValue::new_float(a.as_float() * b.as_float()));
243 }
244 Err(RuntimeError::Error(
245 "Operator '*' does not support these types".to_string(),
246 ))
247 }
248
249 fn op_div_nv(&mut self, a: NanValue, b: NanValue) -> Result<NanValue, RuntimeError> {
250 if a.is_int() && b.is_int() {
251 let bv = b.as_int(&self.arena);
252 if bv == 0 {
253 return Err(RuntimeError::Error("Division by zero".to_string()));
254 }
255 let result = a.as_int(&self.arena) / bv;
256 return Ok(NanValue::new_int(result, &mut self.arena));
257 }
258 if a.is_float() && b.is_float() {
259 let bv = b.as_float();
260 if bv == 0.0 {
261 return Err(RuntimeError::Error("Division by zero".to_string()));
262 }
263 return Ok(NanValue::new_float(a.as_float() / bv));
264 }
265 Err(RuntimeError::Error(
266 "Operator '/' does not support these types".to_string(),
267 ))
268 }
269
270 fn op_compare_nv(&self, a: NanValue, b: NanValue, op: &str) -> Result<NanValue, RuntimeError> {
271 if a.is_int() && b.is_int() {
272 let x = a.as_int(&self.arena);
273 let y = b.as_int(&self.arena);
274 let result = match op {
275 "<" => x < y,
276 ">" => x > y,
277 "<=" => x <= y,
278 ">=" => x >= y,
279 _ => unreachable!(),
280 };
281 return Ok(NanValue::new_bool(result));
282 }
283 if a.is_float() && b.is_float() {
284 let x = a.as_float();
285 let y = b.as_float();
286 let result = match op {
287 "<" => x < y,
288 ">" => x > y,
289 "<=" => x <= y,
290 ">=" => x >= y,
291 _ => unreachable!(),
292 };
293 return Ok(NanValue::new_bool(result));
294 }
295 if a.is_string() && b.is_string() {
296 let x = self.arena.get_string(a.arena_index());
297 let y = self.arena.get_string(b.arena_index());
298 let result = match op {
299 "<" => x < y,
300 ">" => x > y,
301 "<=" => x <= y,
302 ">=" => x >= y,
303 _ => unreachable!(),
304 };
305 return Ok(NanValue::new_bool(result));
306 }
307 Err(RuntimeError::Error(format!(
308 "Operator '{}' does not support these types",
309 op
310 )))
311 }
312}