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 (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}