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 r = self.evaluate(*right)?;
match op {
crate::ast::expr::BinaryOp::Add => match (l, r) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a+b)),
(Value::String(a), Value::String(b)) => Ok(Value::String(a+&b)),
_ => Err(RuntimeError::RuntimeError {
message: "Invalid '+' operands".to_string(),
token: None,
}),
},
crate::ast::expr::BinaryOp::Add => {
// If either operand is a string, coerce both to string and concatenate.
if matches!(l, Value::String(_)) || matches!(r, Value::String(_)) {
Ok(Value::String(format!("{}{}", l, r)))
} else {
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) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a-b)),
_ => Err(RuntimeError::RuntimeError {
@@ -468,9 +474,13 @@ impl Interpreter {
match op {
AssignOp::Equal => Ok(right),
AssignOp::PlusEqual => {
let left_num = self.as_number(&left)?;
let right_num = self.as_number(&right)?;
Ok(Value::Number(left_num + right_num))
if let Value::String(s) = &left {
Ok(Value::String(format!("{}{}", s, right)))
} else {
let left_num = self.as_number(&left)?;
let right_num = self.as_number(&right)?;
Ok(Value::Number(left_num + right_num))
}
}
AssignOp::MinusEqual => {
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
// =========================================================================
@@ -1324,11 +1383,11 @@ mod tests {
}
#[test]
fn error_type_mismatch_add_number_and_string() {
let result = std::panic::catch_unwind(|| {
eval_expr("1 + \"hello\"");
});
assert!(result.is_err(), "Expected error for adding number + string");
fn eval_number_plus_string_concatenates() {
match eval_expr("1 + \"hello\"") {
Value::String(s) => assert_eq!(s, "1hello"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]