mirror of
https://github.com/nushell/nushell.git
synced 2025-05-01 08:34:26 +02:00
Remove python-like string multiplication (#10293)
# Description Currently we support "multiplication" of strings, resulting in a terse way to repeat a particular string. This can have unintended side effects when dealing with mixed data (e.g. after parsing data that is not all numbers). Furthermore as we frequently fall-back to strings while parsing source code, this introduced a runaway edge case in const evaluation (#10212) Work for #10233 ## Details - Remove python-like string multiplication. - Workaround for indentation - This should probably be addressed with a purpose built command - Remove special const-eval error test # User-Facing Changes **Major breaking change!** `"string" * 42` will stop working. (This was used for example in the stdlib) We should bless a good alternative before landing this --------- Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
This commit is contained in:
parent
a14e9e0a2e
commit
7f39609d9a
@ -498,11 +498,3 @@ fn append_binary_values() {
|
|||||||
));
|
));
|
||||||
assert_eq!(actual.out, "0x[01020304]");
|
assert_eq!(actual.out, "0x[01020304]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn int_multiple_string() {
|
|
||||||
let actual = nu!(pipeline(r#"3 * "ab""#));
|
|
||||||
assert_eq!(actual.out, "ababab");
|
|
||||||
let actual = nu!(pipeline(r#""ab" * 3"#));
|
|
||||||
assert_eq!(actual.out, "ababab");
|
|
||||||
}
|
|
||||||
|
@ -214,14 +214,16 @@ mod regex {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_handles_external_stream_chunking() {
|
fn parse_handles_external_stream_chunking() {
|
||||||
Playground::setup("parse_test_streaming_1", |dirs, _sandbox| {
|
Playground::setup("parse_test_streaming_1", |dirs, sandbox| {
|
||||||
|
let data: String = std::iter::repeat("abcdefghijklmnopqrstuvwxyz")
|
||||||
|
.take(1000)
|
||||||
|
.collect();
|
||||||
|
sandbox.with_files(vec![Stub::FileWithContent("data.txt", &data)]);
|
||||||
|
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: dirs.test(), pipeline(
|
cwd: dirs.test(),
|
||||||
r#"
|
r#"open data.txt | parse --regex "(abcdefghijklmnopqrstuvwxyz)" | length"#
|
||||||
"abcdefghijklmnopqrstuvwxyz" * 1000 | save --force data.txt;
|
);
|
||||||
open data.txt | parse --regex "(abcdefghijklmnopqrstuvwxyz)" | length
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "1000");
|
assert_eq!(actual.out, "1000");
|
||||||
})
|
})
|
||||||
|
@ -239,8 +239,6 @@ pub fn math_result_type(
|
|||||||
(Type::Int, Type::Duration) => (Type::Duration, None),
|
(Type::Int, Type::Duration) => (Type::Duration, None),
|
||||||
(Type::Duration, Type::Float) => (Type::Duration, None),
|
(Type::Duration, Type::Float) => (Type::Duration, None),
|
||||||
(Type::Float, Type::Duration) => (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::Custom(a), Type::Custom(b)) if a == b => (Type::Custom(a.to_string()), 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),
|
(Type::Custom(a), _) => (Type::Custom(a.to_string()), None),
|
||||||
|
@ -415,16 +415,6 @@ pub fn eval_constant(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operator::Math(math) => {
|
Operator::Math(math) => {
|
||||||
match (&math, &lhs.expr, &rhs.expr) {
|
|
||||||
// Multiple may generate super long string
|
|
||||||
// and stop the whole shell while highlighting
|
|
||||||
// e.g. '2 ** 60 * a'
|
|
||||||
(Math::Multiply, Expr::String(..), _)
|
|
||||||
| (Math::Multiply, _, Expr::String(..)) => {
|
|
||||||
return Err(ShellError::NotAConstant(expr.span))
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
let lhs = eval_constant(working_set, lhs)?;
|
let lhs = eval_constant(working_set, lhs)?;
|
||||||
let rhs = eval_constant(working_set, rhs)?;
|
let rhs = eval_constant(working_set, rhs)?;
|
||||||
|
|
||||||
|
@ -2649,20 +2649,6 @@ impl Value {
|
|||||||
(Value::CustomValue { val: lhs, .. }, rhs) => {
|
(Value::CustomValue { val: lhs, .. }, rhs) => {
|
||||||
lhs.operation(self.span(), Operator::Math(Math::Multiply), op, rhs)
|
lhs.operation(self.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(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(res, span))
|
|
||||||
}
|
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
op_span: op,
|
op_span: op,
|
||||||
lhs_ty: self.get_type().to_string(),
|
lhs_ty: self.get_type().to_string(),
|
||||||
|
@ -134,7 +134,7 @@ def show-pretty-test [indent: int = 4] {
|
|||||||
let test = $in
|
let test = $in
|
||||||
|
|
||||||
[
|
[
|
||||||
(" " * $indent)
|
(1..$indent | map {" "} | str join)
|
||||||
(match $test.result {
|
(match $test.result {
|
||||||
"pass" => { ansi green },
|
"pass" => { ansi green },
|
||||||
"skip" => { ansi yellow },
|
"skip" => { ansi yellow },
|
||||||
|
@ -142,7 +142,6 @@ fn const_binary_operator(#[case] inp: &[&str], #[case] expect: &str) {
|
|||||||
#[case(&["const x = 10 ** 10000000", "$x"], "pow operation overflowed")]
|
#[case(&["const x = 10 ** 10000000", "$x"], "pow operation overflowed")]
|
||||||
#[case(&["const x = 2 ** 62 * 2", "$x"], "multiply operation overflowed")]
|
#[case(&["const x = 2 ** 62 * 2", "$x"], "multiply operation overflowed")]
|
||||||
#[case(&["const x = 1 ++ 0", "$x"], "doesn't support this value")]
|
#[case(&["const x = 1 ++ 0", "$x"], "doesn't support this value")]
|
||||||
#[case(&["const x = 20 * a", "$x"], "Value is not a parse-time constant")]
|
|
||||||
fn const_operator_error(#[case] inp: &[&str], #[case] expect: &str) {
|
fn const_operator_error(#[case] inp: &[&str], #[case] expect: &str) {
|
||||||
let actual = nu!(&inp.join("; "));
|
let actual = nu!(&inp.join("; "));
|
||||||
assert!(actual.err.contains(expect));
|
assert!(actual.err.contains(expect));
|
||||||
|
Loading…
Reference in New Issue
Block a user