Skip to main content

rl_lang/interpreter/utils/
binary.rs

1//! Binary operator evaluation for all supported operand type combinations.
2//!
3//! All type mismatches emit a labeled error pointing at both operands.
4
5use crate::{
6    interpreter::evaluator::Evaluator,
7    interpreter::values::Value,
8    lexer::tokentypes::TokenType,
9    utils::{errors::Error, span::Span},
10};
11
12impl Evaluator {
13    fn type_mismatch_binary(
14        &self,
15        op: &str,
16        left: &Value,
17        left_span: Span,
18        right: &Value,
19        right_span: Span,
20        span: Span,
21    ) -> Error {
22        self.err(format!("type mismatch on {}", op), span)
23            .with_label(left_span, format!("this is {}", left.type_name()))
24            .with_label(right_span, format!("this is {}", right.type_name()))
25    }
26
27    pub fn match_binary_operator(
28        &mut self,
29        left: Value,
30        left_span: Span,
31        right: Value,
32        right_span: Span,
33        operator: &TokenType,
34        span: Span,
35    ) -> Result<Value, Error> {
36        let v = match operator {
37            TokenType::Plus => match (&left, &right) {
38                (Value::Integer(a), Value::Integer(b)) => Value::Integer(a + b),
39                (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
40                (Value::Byte(a), Value::Byte(b)) => Value::Byte(a + b),
41
42                _ => {
43                    return Err(
44                        self.type_mismatch_binary("+", &left, left_span, &right, right_span, span)
45                    );
46                }
47            },
48            TokenType::Minus => match (&left, &right) {
49                (Value::Integer(a), Value::Integer(b)) => Value::Integer(a - b),
50                (Value::Float(a), Value::Float(b)) => Value::Float(a - b),
51                (Value::Byte(a), Value::Byte(b)) => Value::Byte(a - b),
52
53                _ => {
54                    return Err(
55                        self.type_mismatch_binary("-", &left, left_span, &right, right_span, span)
56                    );
57                }
58            },
59            TokenType::Star => match (&left, &right) {
60                (Value::Integer(a), Value::Integer(b)) => Value::Integer(a * b),
61                (Value::Float(a), Value::Float(b)) => Value::Float(a * b),
62                (Value::Byte(a), Value::Byte(b)) => Value::Byte(a * b),
63
64                _ => {
65                    return Err(
66                        self.type_mismatch_binary("*", &left, left_span, &right, right_span, span)
67                    );
68                }
69            },
70            TokenType::Slash => match (&left, &right) {
71                (Value::Integer(a), Value::Integer(b)) => {
72                    if *b == 0 {
73                        return Err(self.err("division by zero", span));
74                    }
75                    Value::Integer(a / b)
76                }
77                (Value::Float(a), Value::Float(b)) => Value::Float(a / b),
78                (Value::Byte(a), Value::Byte(b)) => {
79                    if *b == 0 {
80                        return Err(self.err("division by zero", span));
81                    }
82                    Value::Byte(a / b)
83                }
84
85                _ => {
86                    return Err(
87                        self.type_mismatch_binary("/", &left, left_span, &right, right_span, span)
88                    );
89                }
90            },
91            TokenType::Less => match (&left, &right) {
92                (Value::Integer(a), Value::Integer(b)) => Value::Bool(a < b),
93                (Value::Float(a), Value::Float(b)) => Value::Bool(a < b),
94                (Value::Byte(a), Value::Byte(b)) => Value::Bool(a < b),
95                _ => {
96                    return Err(
97                        self.type_mismatch_binary("<", &left, left_span, &right, right_span, span)
98                    );
99                }
100            },
101            TokenType::Greater => match (&left, &right) {
102                (Value::Integer(a), Value::Integer(b)) => Value::Bool(a > b),
103                (Value::Float(a), Value::Float(b)) => Value::Bool(a > b),
104                (Value::Byte(a), Value::Byte(b)) => Value::Bool(a > b),
105                _ => {
106                    return Err(
107                        self.type_mismatch_binary(">", &left, left_span, &right, right_span, span)
108                    );
109                }
110            },
111            TokenType::LessEqual => match (&left, &right) {
112                (Value::Integer(a), Value::Integer(b)) => Value::Bool(a <= b),
113                (Value::Float(a), Value::Float(b)) => Value::Bool(a <= b),
114                (Value::Byte(a), Value::Byte(b)) => Value::Bool(a <= b),
115                _ => {
116                    return Err(
117                        self.type_mismatch_binary("<=", &left, left_span, &right, right_span, span)
118                    );
119                }
120            },
121            TokenType::GreaterEqual => match (&left, &right) {
122                (Value::Integer(a), Value::Integer(b)) => Value::Bool(a >= b),
123                (Value::Float(a), Value::Float(b)) => Value::Bool(a >= b),
124                (Value::Byte(a), Value::Byte(b)) => Value::Bool(a >= b),
125                _ => {
126                    return Err(
127                        self.type_mismatch_binary(">=", &left, left_span, &right, right_span, span)
128                    );
129                }
130            },
131            TokenType::BangEqual => match (&left, &right) {
132                (Value::Integer(a), Value::Integer(b)) => Value::Bool(a != b),
133                (Value::Float(a), Value::Float(b)) => Value::Bool(a != b),
134                (Value::String(a), Value::String(b)) => Value::Bool(a != b),
135                (Value::Char(a), Value::Char(b)) => Value::Bool(a != b),
136                (Value::Bool(a), Value::Bool(b)) => Value::Bool(a != b),
137                (Value::Byte(a), Value::Byte(b)) => Value::Bool(a != b),
138                (
139                    Value::Enum {
140                        name: a_name,
141                        variant: a_var,
142                    },
143                    Value::Enum {
144                        name: b_name,
145                        variant: b_var,
146                    },
147                ) => Value::Bool(a_name != b_name || a_var != b_var),
148                _ => {
149                    return Err(
150                        self.type_mismatch_binary("!=", &left, left_span, &right, right_span, span)
151                    );
152                }
153            },
154            TokenType::Compare => match (&left, &right) {
155                (Value::Integer(a), Value::Integer(b)) => Value::Bool(a == b),
156                (Value::Float(a), Value::Float(b)) => Value::Bool(a == b),
157                (Value::String(a), Value::String(b)) => Value::Bool(a == b),
158                (Value::Char(a), Value::Char(b)) => Value::Bool(a == b),
159                (Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b),
160                (Value::Byte(a), Value::Byte(b)) => Value::Bool(a == b),
161                (
162                    Value::Enum {
163                        name: a_name,
164                        variant: a_var,
165                    },
166                    Value::Enum {
167                        name: b_name,
168                        variant: b_var,
169                    },
170                ) => Value::Bool(a_name == b_name && a_var == b_var),
171                _ => {
172                    return Err(
173                        self.type_mismatch_binary("==", &left, left_span, &right, right_span, span)
174                    );
175                }
176            },
177            _ => return Err(self.err("unknown binary operator", span)),
178        };
179        Ok(v)
180    }
181}