feat: 实现字符串与数字的连接操作,增强加法运算符的功能
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user