make ++ append lists (#6766)

* make `++` append lists

* fmt

* fix for database
This commit is contained in:
pwygab 2022-10-20 18:28:18 +08:00 committed by GitHub
parent 50e53e788a
commit 5e748ae8fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 104 additions and 2 deletions

View File

@ -124,7 +124,8 @@ impl CustomValue for ExprDb {
| Operator::ShiftLeft
| Operator::ShiftRight
| Operator::StartsWith
| Operator::EndsWith => Err(ShellError::UnsupportedOperator(operator, op)),
| Operator::EndsWith
| Operator::Append => Err(ShellError::UnsupportedOperator(operator, op)),
}?;
let expr = Expr::BinaryOp {

View File

@ -473,3 +473,39 @@ fn compound_where_paren() {
assert_eq!(actual.out, r#"[{"a": 2,"b": 1},{"a": 2,"b": 2}]"#);
}
#[test]
fn adding_lists() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
[1 3] ++ [5 6] | to nuon
"#
));
assert_eq!(actual.out, "[1, 3, 5, 6]");
}
#[test]
fn adding_list_and_value() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
[1 3] ++ 5 | to nuon
"#
));
assert_eq!(actual.out, "[1, 3, 5]");
}
#[test]
fn adding_value_and_list() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
1 ++ [3 5] | to nuon
"#
));
assert_eq!(actual.out, "[1, 3, 5]");
}

View File

@ -385,6 +385,10 @@ pub fn eval_expression(
let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.add(op_span, &rhs, expr.span)
}
Operator::Append => {
let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.append(op_span, &rhs, expr.span)
}
Operator::Minus => {
let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.sub(op_span, &rhs, expr.span)

View File

@ -4273,6 +4273,7 @@ pub fn parse_operator(
b"=~" => Operator::RegexMatch,
b"!~" => Operator::NotRegexMatch,
b"+" => Operator::Plus,
b"++" => Operator::Append,
b"-" => Operator::Minus,
b"*" => Operator::Multiply,
b"/" => Operator::Divide,

View File

@ -68,6 +68,35 @@ pub fn math_result_type(
)
}
},
Operator::Append => match (&lhs.ty, &rhs.ty) {
(Type::List(a), Type::List(b)) => {
if a == b {
(Type::List(a.clone()), None)
} else {
(Type::List(Box::new(Type::Any)), None)
}
}
(Type::List(a), b) | (b, Type::List(a)) => {
if a == &Box::new(b.clone()) {
(Type::List(a.clone()), None)
} else {
(Type::List(Box::new(Type::Any)), None)
}
}
_ => {
*op = Expression::garbage(op.span);
(
Type::Any,
Some(ParseError::UnsupportedOperation(
op.span,
lhs.span,
lhs.ty.clone(),
rhs.span,
rhs.ty.clone(),
)),
)
}
},
Operator::Minus => match (&lhs.ty, &rhs.ty) {
(Type::Int, Type::Int) => (Type::Int, None),
(Type::Float, Type::Int) => (Type::Float, None),

View File

@ -47,7 +47,8 @@ impl Expression {
| Operator::Equal
| Operator::NotEqual
| Operator::In
| Operator::NotIn => 80,
| Operator::NotIn
| Operator::Append => 80,
Operator::BitAnd => 75,
Operator::BitXor => 70,
Operator::BitOr => 60,

View File

@ -14,6 +14,7 @@ pub enum Operator {
RegexMatch,
NotRegexMatch,
Plus,
Append,
Minus,
Multiply,
Divide,
@ -43,6 +44,7 @@ impl Display for Operator {
Operator::RegexMatch => write!(f, "=~"),
Operator::NotRegexMatch => write!(f, "!~"),
Operator::Plus => write!(f, "+"),
Operator::Append => write!(f, "++"),
Operator::Minus => write!(f, "-"),
Operator::Multiply => write!(f, "*"),
Operator::Divide => write!(f, "/"),

View File

@ -1681,6 +1681,34 @@ impl Value {
}
}
pub fn append(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
match (self, rhs) {
(Value::List { vals: lhs, .. }, Value::List { vals: rhs, .. }) => {
let mut lhs = lhs.clone();
let mut rhs = rhs.clone();
lhs.append(&mut rhs);
Ok(Value::List { vals: lhs, span })
}
(Value::List { vals: lhs, .. }, val) => {
let mut lhs = lhs.clone();
lhs.push(val.clone());
Ok(Value::List { vals: lhs, span })
}
(val, Value::List { vals: rhs, .. }) => {
let mut rhs = rhs.clone();
rhs.insert(0, val.clone());
Ok(Value::List { vals: rhs, span })
}
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span()?,
rhs_ty: rhs.get_type(),
rhs_span: rhs.span()?,
}),
}
}
pub fn sub(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {