Skip to main content

aver/interpreter/
ops.rs

1use super::*;
2
3impl Interpreter {
4    pub(super) fn eval_binop(
5        &self,
6        op: &BinOp,
7        left: Value,
8        right: Value,
9    ) -> Result<Value, RuntimeError> {
10        match op {
11            BinOp::Add => self.op_add(left, right),
12            BinOp::Sub => self.op_sub(left, right),
13            BinOp::Mul => self.op_mul(left, right),
14            BinOp::Div => self.op_div(left, right),
15            BinOp::Eq => Ok(Value::Bool(self.aver_eq(&left, &right))),
16            BinOp::Neq => Ok(Value::Bool(!self.aver_eq(&left, &right))),
17            BinOp::Lt => self.op_compare(&left, &right, "<"),
18            BinOp::Gt => self.op_compare(&left, &right, ">"),
19            BinOp::Lte => self.op_compare(&left, &right, "<="),
20            BinOp::Gte => self.op_compare(&left, &right, ">="),
21        }
22    }
23
24    pub fn aver_eq(&self, a: &Value, b: &Value) -> bool {
25        if let (Some(xs), Some(ys)) = (list_slice(a), list_slice(b)) {
26            return xs.len() == ys.len()
27                && xs.iter().zip(ys.iter()).all(|(x, y)| self.aver_eq(x, y));
28        }
29
30        match (a, b) {
31            (Value::Int(x), Value::Int(y)) => x == y,
32            (Value::Float(x), Value::Float(y)) => x == y,
33            (Value::Str(x), Value::Str(y)) => x == y,
34            (Value::Bool(x), Value::Bool(y)) => x == y,
35            (Value::Unit, Value::Unit) => true,
36            (Value::None, Value::None) => true,
37            (Value::Ok(x), Value::Ok(y)) => self.aver_eq(x, y),
38            (Value::Err(x), Value::Err(y)) => self.aver_eq(x, y),
39            (Value::Some(x), Value::Some(y)) => self.aver_eq(x, y),
40            (Value::Tuple(xs), Value::Tuple(ys)) => {
41                xs.len() == ys.len() && xs.iter().zip(ys.iter()).all(|(x, y)| self.aver_eq(x, y))
42            }
43            (Value::Map(m1), Value::Map(m2)) => {
44                m1.len() == m2.len()
45                    && m1
46                        .iter()
47                        .all(|(k, v1)| m2.get(k).map(|v2| self.aver_eq(v1, v2)).unwrap_or(false))
48            }
49            (
50                Value::Variant {
51                    type_name: t1,
52                    variant: v1,
53                    fields: f1,
54                },
55                Value::Variant {
56                    type_name: t2,
57                    variant: v2,
58                    fields: f2,
59                },
60            ) => {
61                t1 == t2
62                    && v1 == v2
63                    && f1.len() == f2.len()
64                    && f1.iter().zip(f2.iter()).all(|(x, y)| self.aver_eq(x, y))
65            }
66            (
67                Value::Record {
68                    type_name: t1,
69                    fields: f1,
70                },
71                Value::Record {
72                    type_name: t2,
73                    fields: f2,
74                },
75            ) => {
76                t1 == t2
77                    && f1.len() == f2.len()
78                    && f1
79                        .iter()
80                        .zip(f2.iter())
81                        .all(|((k1, v1), (k2, v2))| k1 == k2 && self.aver_eq(v1, v2))
82            }
83            _ => false,
84        }
85    }
86
87    pub(super) fn op_add(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
88        match (&a, &b) {
89            (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
90            (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
91            (Value::Str(x), Value::Str(y)) => Ok(Value::Str(format!("{}{}", x, y))),
92            _ => Err(RuntimeError::Error(
93                "Operator '+' does not support these types".to_string(),
94            )),
95        }
96    }
97
98    pub(super) fn op_sub(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
99        match (&a, &b) {
100            (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
101            (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
102            // Unary minus: `- float_expr` is parsed as `0 - expr`
103            (Value::Int(0), Value::Float(y)) => Ok(Value::Float(-y)),
104            _ => Err(RuntimeError::Error(
105                "Operator '-' does not support these types".to_string(),
106            )),
107        }
108    }
109
110    pub(super) fn op_mul(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
111        match (&a, &b) {
112            (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
113            (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
114            _ => Err(RuntimeError::Error(
115                "Operator '*' does not support these types".to_string(),
116            )),
117        }
118    }
119
120    pub(super) fn op_div(&self, a: Value, b: Value) -> Result<Value, RuntimeError> {
121        match (&a, &b) {
122            (Value::Int(x), Value::Int(y)) => {
123                if *y == 0 {
124                    Err(RuntimeError::Error("Division by zero".to_string()))
125                } else {
126                    Ok(Value::Int(x / y))
127                }
128            }
129            (Value::Float(x), Value::Float(y)) => {
130                if *y == 0.0 {
131                    Err(RuntimeError::Error("Division by zero".to_string()))
132                } else {
133                    Ok(Value::Float(x / y))
134                }
135            }
136            _ => Err(RuntimeError::Error(
137                "Operator '/' does not support these types".to_string(),
138            )),
139        }
140    }
141
142    pub(super) fn op_compare(&self, a: &Value, b: &Value, op: &str) -> Result<Value, RuntimeError> {
143        let result = match (a, b) {
144            (Value::Int(x), Value::Int(y)) => match op {
145                "<" => x < y,
146                ">" => x > y,
147                "<=" => x <= y,
148                ">=" => x >= y,
149                _ => unreachable!(),
150            },
151            (Value::Float(x), Value::Float(y)) => match op {
152                "<" => x < y,
153                ">" => x > y,
154                "<=" => x <= y,
155                ">=" => x >= y,
156                _ => unreachable!(),
157            },
158            (Value::Str(x), Value::Str(y)) => match op {
159                "<" => x < y,
160                ">" => x > y,
161                "<=" => x <= y,
162                ">=" => x >= y,
163                _ => unreachable!(),
164            },
165            _ => {
166                return Err(RuntimeError::Error(format!(
167                    "Operator '{}' does not support these types",
168                    op
169                )));
170            }
171        };
172        Ok(Value::Bool(result))
173    }
174}