feat: 实现字符串与数字的连接操作,增强加法运算符的功能

This commit is contained in:
0264408
2026-06-16 18:55:05 +08:00
parent db541c315b
commit 18fa53cf4a
+75 -16
View File
@@ -294,14 +294,20 @@ impl Interpreter {
let l = self.evaluate(*left)?; let l = self.evaluate(*left)?;
let r = self.evaluate(*right)?; let r = self.evaluate(*right)?;
match op { match op {
crate::ast::expr::BinaryOp::Add => match (l, r) { crate::ast::expr::BinaryOp::Add => {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a+b)), // If either operand is a string, coerce both to string and concatenate.
(Value::String(a), Value::String(b)) => Ok(Value::String(a+&b)), if matches!(l, Value::String(_)) || matches!(r, Value::String(_)) {
_ => Err(RuntimeError::RuntimeError { Ok(Value::String(format!("{}{}", l, r)))
message: "Invalid '+' operands".to_string(), } else {
token: None, match (l, r) {
}), (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a+b)),
}, _ => Err(RuntimeError::RuntimeError {
message: "Invalid '+' operands".to_string(),
token: None,
}),
}
}
}
crate::ast::expr::BinaryOp::Sub => match (l,r) { crate::ast::expr::BinaryOp::Sub => match (l,r) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a-b)), (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a-b)),
_ => Err(RuntimeError::RuntimeError { _ => Err(RuntimeError::RuntimeError {
@@ -468,9 +474,13 @@ impl Interpreter {
match op { match op {
AssignOp::Equal => Ok(right), AssignOp::Equal => Ok(right),
AssignOp::PlusEqual => { AssignOp::PlusEqual => {
let left_num = self.as_number(&left)?; if let Value::String(s) = &left {
let right_num = self.as_number(&right)?; Ok(Value::String(format!("{}{}", s, right)))
Ok(Value::Number(left_num + right_num)) } else {
let left_num = self.as_number(&left)?;
let right_num = self.as_number(&right)?;
Ok(Value::Number(left_num + right_num))
}
} }
AssignOp::MinusEqual => { AssignOp::MinusEqual => {
let left_num = self.as_number(&left)?; let left_num = self.as_number(&left)?;
@@ -667,6 +677,55 @@ mod tests {
} }
} }
#[test]
fn eval_string_plus_number() {
match eval_expr("\"a\" + 42") {
Value::String(s) => assert_eq!(s, "a42"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_number_plus_string() {
match eval_expr("42 + \"a\"") {
Value::String(s) => assert_eq!(s, "42a"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_string_plus_bool() {
match eval_expr("\"t\" + true") {
Value::String(s) => assert_eq!(s, "ttrue"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_bool_plus_string() {
match eval_expr("false + \"x\"") {
Value::String(s) => assert_eq!(s, "falsex"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_string_plus_nil() {
match eval_expr("\"x\" + nil") {
Value::String(s) => assert_eq!(s, "xnil"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_plusequal_string_concat() {
let interp = run("let s = \"hello\"; s += \" world\"; s += 42;");
match get_var(&interp, "s") {
Value::String(s) => assert_eq!(s, "hello world42"),
v => panic!("Expected String, got {:?}", v),
}
}
// ========================================================================= // =========================================================================
// Comparison // Comparison
// ========================================================================= // =========================================================================
@@ -1324,11 +1383,11 @@ mod tests {
} }
#[test] #[test]
fn error_type_mismatch_add_number_and_string() { fn eval_number_plus_string_concatenates() {
let result = std::panic::catch_unwind(|| { match eval_expr("1 + \"hello\"") {
eval_expr("1 + \"hello\""); Value::String(s) => assert_eq!(s, "1hello"),
}); v => panic!("Expected String, got {:?}", v),
assert!(result.is_err(), "Expected error for adding number + string"); }
} }
#[test] #[test]