feat: 实现字符串与数字的连接操作,增强加法运算符的功能
This commit is contained in:
@@ -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) {
|
||||
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)),
|
||||
(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::Sub => match (l,r) {
|
||||
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a-b)),
|
||||
_ => Err(RuntimeError::RuntimeError {
|
||||
@@ -468,10 +474,14 @@ impl Interpreter {
|
||||
match op {
|
||||
AssignOp::Equal => Ok(right),
|
||||
AssignOp::PlusEqual => {
|
||||
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)?;
|
||||
let right_num = self.as_number(&right)?;
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user