From 16b99ed0bae3f81b28a9a3dd7248690126ab8d33 Mon Sep 17 00:00:00 2001 From: Reilly Wood <26268125+rgwood@users.noreply.github.com> Date: Thu, 9 Feb 2023 10:52:10 -0800 Subject: [PATCH] Make ++ operator work with strings and binary values (#8017) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR makes `++` (the append operator) work with strings and binary values. Can now do things like: ```bash 〉"a" ++ "b" ab 〉0x[01 02] ++ 0x[03] Length: 3 (0x3) bytes | printable whitespace ascii_other non_ascii 00000000: 01 02 03 ••• ``` Closes #8015. --- crates/nu-command/tests/commands/math/mod.rs | 24 ++++++++++++++++++++ crates/nu-parser/src/type_check.rs | 2 ++ crates/nu-protocol/src/value/mod.rs | 9 ++++++++ 3 files changed, 35 insertions(+) diff --git a/crates/nu-command/tests/commands/math/mod.rs b/crates/nu-command/tests/commands/math/mod.rs index 9de7102fc5..e8fc3ae106 100644 --- a/crates/nu-command/tests/commands/math/mod.rs +++ b/crates/nu-command/tests/commands/math/mod.rs @@ -473,6 +473,8 @@ fn compound_where_paren() { assert_eq!(actual.out, r#"[{"a": 2,"b": 1},{"a": 2,"b": 2}]"#); } +// TODO: these ++ tests are not really testing *math* functionality, maybe find another place for them + #[test] fn adding_lists() { let actual = nu!( @@ -519,3 +521,25 @@ fn adding_tables() { )); assert_eq!(actual.out, "[{a: 1, b: 2}, {c: 10, d: 11}]"); } + +#[test] +fn append_strings() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + "foo" ++ "bar" + "# + )); + assert_eq!(actual.out, "foobar"); +} + +#[test] +fn append_binary_values() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + 0x[01 02] ++ 0x[03 04] | to nuon + "# + )); + assert_eq!(actual.out, "0x[01020304]"); +} diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index e5fdd5f6c9..93e9dbde71 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -84,6 +84,8 @@ pub fn math_result_type( } } (Type::Table(a), Type::Table(_)) => (Type::Table(a.clone()), None), + (Type::String, Type::String) => (Type::String, None), + (Type::Binary, Type::Binary) => (Type::Binary, None), (Type::Any, _) | (_, Type::Any) => (Type::Any, None), _ => { *op = Expression::garbage(op.span); diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 6f612b603b..300c2c16b2 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -2084,6 +2084,15 @@ impl Value { rhs.insert(0, val.clone()); Ok(Value::List { vals: rhs, span }) } + (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String { + val: lhs.to_string() + rhs, + span, + }), + (Value::Binary { val: lhs, .. }, Value::Binary { val: rhs, .. }) => { + let mut val = lhs.clone(); + val.extend(rhs); + Ok(Value::Binary { val, span }) + } _ => Err(ShellError::OperatorMismatch { op_span: op, lhs_ty: self.get_type(),