Allow eq eq comparison between strings

master
Nick Krichevsky 2024-05-24 10:42:23 -04:00
parent 465039cf43
commit 32266d07f6
1 changed files with 22 additions and 8 deletions

View File

@ -1,4 +1,7 @@
use std::fmt::{self, Display, Formatter}; use std::{
fmt::{self, Display, Formatter},
rc::Rc,
};
use crate::{ use crate::{
ast::{Expr, ExprVisitor, LiteralValue, Stmt, StmtVisitor}, ast::{Expr, ExprVisitor, LiteralValue, Stmt, StmtVisitor},
@ -120,7 +123,12 @@ impl ExprVisitor<Result<EvaluatedValue, ScriptError>> for InterpreterRunner<'_>
// Finish the short circuit; if we get to this point the result will always be right. // Finish the short circuit; if we get to this point the result will always be right.
TokenKind::Or | TokenKind::And => Ok(right_operand), TokenKind::Or | TokenKind::And => Ok(right_operand),
TokenKind::Plus => evaluate_addition((left_operand, right_operand), operator), TokenKind::Plus => evaluate_arithmetic_or_string_operation(
(left_operand, right_operand),
operator,
|left, right| EvaluatedValue::Number(left + right),
|left, right| EvaluatedValue::String((left.to_string() + right.as_ref()).into()),
),
TokenKind::Minus => evaluate_binary_arithmetic( TokenKind::Minus => evaluate_binary_arithmetic(
(left_operand, right_operand), (left_operand, right_operand),
@ -164,16 +172,18 @@ impl ExprVisitor<Result<EvaluatedValue, ScriptError>> for InterpreterRunner<'_>
|left_value, right_value| EvaluatedValue::Boolean(left_value <= right_value), |left_value, right_value| EvaluatedValue::Boolean(left_value <= right_value),
), ),
TokenKind::EqualEqual => evaluate_binary_arithmetic( TokenKind::EqualEqual => evaluate_arithmetic_or_string_operation(
(left_operand, right_operand), (left_operand, right_operand),
operator, operator,
|left_value, right_value| EvaluatedValue::Boolean(left_value == right_value), |left_value, right_value| EvaluatedValue::Boolean(left_value == right_value),
|left_value, right_value| EvaluatedValue::Boolean(left_value == right_value),
), ),
TokenKind::BangEqual => evaluate_binary_arithmetic( TokenKind::BangEqual => evaluate_arithmetic_or_string_operation(
(left_operand, right_operand), (left_operand, right_operand),
operator, operator,
|left_value, right_value| EvaluatedValue::Boolean(left_value != right_value), |left_value, right_value| EvaluatedValue::Boolean(left_value != right_value),
|left_value, right_value| EvaluatedValue::Boolean(left_value != right_value),
), ),
_ => unreachable!( _ => unreachable!(
@ -287,18 +297,22 @@ fn convert_arithmetic_operands(
} }
} }
fn evaluate_addition( fn evaluate_arithmetic_or_string_operation<
F: FnOnce(f64, f64) -> EvaluatedValue,
G: FnOnce(Rc<str>, Rc<str>) -> EvaluatedValue,
>(
(left, right): (EvaluatedValue, EvaluatedValue), (left, right): (EvaluatedValue, EvaluatedValue),
operator: &Token, operator: &Token,
make_number_output: F,
make_string_output: G,
) -> Result<EvaluatedValue, ScriptError> { ) -> Result<EvaluatedValue, ScriptError> {
match (left, right) { match (left, right) {
(EvaluatedValue::Number(left_value), EvaluatedValue::Number(right_value)) => { (EvaluatedValue::Number(left_value), EvaluatedValue::Number(right_value)) => {
Ok(EvaluatedValue::Number(left_value + right_value)) Ok(make_number_output(left_value, right_value))
} }
(EvaluatedValue::String(left_value), EvaluatedValue::String(right_value)) => { (EvaluatedValue::String(left_value), EvaluatedValue::String(right_value)) => {
let concatted = left_value.to_string() + right_value.as_ref(); Ok(make_string_output(left_value, right_value))
Ok(EvaluatedValue::String(concatted.into()))
} }
// TODO: we could improve this error (and others) to include the types // TODO: we could improve this error (and others) to include the types