From 8136170431bed4f3da6f1982591a50ae353b7103 Mon Sep 17 00:00:00 2001 From: WindSoilder Date: Tue, 14 Feb 2023 00:35:53 +0800 Subject: [PATCH] support multiplication operation on string and list values (#8061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description As title, I found this feature is useful to me too :) Closes: #8039 # User-Facing Changes ``` ❯ 3 * "ab" ababab ❯ 3 * [1 2 3] ╭───┬───╮ │ 0 │ 1 │ │ 1 │ 2 │ │ 2 │ 3 │ │ 3 │ 1 │ │ 4 │ 2 │ │ 5 │ 3 │ │ 6 │ 1 │ │ 7 │ 2 │ │ 8 │ 3 │ ╰───┴───╯ ``` # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --- crates/nu-command/tests/commands/math/mod.rs | 28 +++++++++++++++++++ crates/nu-parser/src/type_check.rs | 4 +++ crates/nu-protocol/src/value/mod.rs | 29 +++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/crates/nu-command/tests/commands/math/mod.rs b/crates/nu-command/tests/commands/math/mod.rs index e8fc3ae106..fd03b7109d 100644 --- a/crates/nu-command/tests/commands/math/mod.rs +++ b/crates/nu-command/tests/commands/math/mod.rs @@ -543,3 +543,31 @@ fn append_binary_values() { )); assert_eq!(actual.out, "0x[01020304]"); } + +#[test] +fn int_multiple_string() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#"3 * "ab""# + )); + assert_eq!(actual.out, "ababab"); + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#""ab" * 3"# + )); + assert_eq!(actual.out, "ababab"); +} + +#[test] +fn int_multiple_list() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#"3 * [1 2] | to nuon"# + )); + assert_eq!(actual.out, "[1, 2, 1, 2, 1, 2]"); + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#"[1 2] * 3 | to nuon"# + )); + assert_eq!(actual.out, "[1, 2, 1, 2, 1, 2]"); +} diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index 93e9dbde71..2d5ef6fbad 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -142,6 +142,10 @@ pub fn math_result_type( (Type::Int, Type::Duration) => (Type::Duration, None), (Type::Duration, Type::Float) => (Type::Duration, None), (Type::Float, Type::Duration) => (Type::Duration, None), + (Type::Int, Type::String) => (Type::String, None), + (Type::String, Type::Int) => (Type::String, None), + (Type::Int, Type::List(a)) => (Type::List(a.clone()), None), + (Type::List(a), Type::Int) => (Type::List(a.clone()), None), (Type::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.to_string()), None), (Type::Custom(a), _) => (Type::Custom(a.to_string()), None), diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 300c2c16b2..d39be76daf 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -2264,7 +2264,34 @@ impl Value { (Value::CustomValue { val: lhs, span }, rhs) => { lhs.operation(*span, Operator::Math(Math::Multiply), op, rhs) } - + (Value::Int { val: lhs, .. }, Value::String { val: rhs, .. }) => { + let mut res = String::new(); + for _ in 0..*lhs { + res.push_str(rhs) + } + Ok(Value::String { val: res, span }) + } + (Value::String { val: lhs, .. }, Value::Int { val: rhs, .. }) => { + let mut res = String::new(); + for _ in 0..*rhs { + res.push_str(lhs) + } + Ok(Value::String { val: res, span }) + } + (Value::Int { val: lhs, .. }, Value::List { vals: rhs, .. }) => { + let mut res = vec![]; + for _ in 0..*lhs { + res.append(&mut rhs.clone()) + } + Ok(Value::List { vals: res, span }) + } + (Value::List { vals: lhs, .. }, Value::Int { val: rhs, .. }) => { + let mut res = vec![]; + for _ in 0..*rhs { + res.append(&mut lhs.clone()) + } + Ok(Value::List { vals: res, span }) + } _ => Err(ShellError::OperatorMismatch { op_span: op, lhs_ty: self.get_type(),