Simplify expressions (#3389)

* WIP: experiment with simpler expressions

* fix simple invoke

* update tests

* fix a few tests

* Make paren parsing more robust

* fix external args

* Remove old invocation

* Update tests

* Update tests
This commit is contained in:
JT 2021-05-12 13:01:48 +12:00 committed by GitHub
parent c80a9585b0
commit 25a8caa9b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 181 additions and 364 deletions

View file

@ -81,11 +81,7 @@ ptree-support = ["nu-cli/ptree", "nu-command/ptree"]
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
term-support = ["nu-cli/term", "nu-command/term"]
uuid-support = ["nu-cli/uuid_crate", "nu-command/uuid_crate"]
which-support = [
"nu-cli/which",
"nu-command/which",
"nu-engine/which",
]
which-support = ["nu-cli/which", "nu-command/which", "nu-engine/which"]
default = [
"nu-cli/shadow-rs",

View file

@ -384,7 +384,7 @@ mod tests {
#[test]
fn completes_incomplete_nested_structure() {
let registry: VecRegistry = vec![Signature::build("sys")].into();
let line = "echo $(sy";
let line = "echo (sy";
assert_eq!(
completion_location(line, &registry, 8),

View file

@ -145,7 +145,7 @@ fn requote(orig_value: String) -> String {
if should_quote {
if quotes.is_empty() {
// TODO we don't really have an escape character, so there isn't a great option right
// now. One possibility is `{{$(char backtick)}}`
// now. One possibility is `{{(char backtick)}}`
value.to_string()
} else {
let quote = quotes[0];

View file

@ -44,7 +44,7 @@ impl WholeStreamCommand for Command {
},
Example {
description: "Check that all values are even",
example: "echo [2 4 6 8] | all? $(= $it mod 2) == 0",
example: "echo [2 4 6 8] | all? ($it mod 2) == 0",
result: Some(vec![Value::from(true)]),
},
]

View file

@ -69,7 +69,7 @@ following values:
https://en.wikipedia.org/wiki/ANSI_escape_code
OSC: '\x1b]' is not required for --osc parameter
Example: echo [$(ansi -o '0') 'some title' $(char bel)] | str collect
Example: echo [(ansi -o '0') 'some title' (char bel)] | str collect
Format: #
0 Set window title and icon name
1 Set icon name
@ -96,7 +96,7 @@ Format: #
Example {
description:
"Use ansi to color text (rb = red bold, gb = green bold, pb = purple bold)",
example: r#"echo [$(ansi rb) Hello " " $(ansi gb) Nu " " $(ansi pb) World] | str collect"#,
example: r#"echo [(ansi rb) Hello " " (ansi gb) Nu " " (ansi pb) World] | str collect"#,
result: Some(vec![Value::from(
"\u{1b}[1;31mHello \u{1b}[1;32mNu \u{1b}[1;35mWorld",
)]),
@ -104,7 +104,7 @@ Format: #
Example {
description:
"Use ansi to color text (rb = red bold, gb = green bold, pb = purple bold)",
example: r#"echo [$(ansi -e '3;93;41m') Hello $(ansi reset) " " $(ansi gb) Nu " " $(ansi pb) World] | str collect"#,
example: r#"echo [(ansi -e '3;93;41m') Hello (ansi reset) " " (ansi gb) Nu " " (ansi pb) World] | str collect"#,
result: Some(vec![Value::from(
"\u{1b}[3;93;41mHello\u{1b}[0m \u{1b}[1;32mNu \u{1b}[1;35mWorld",
)]),
@ -299,7 +299,7 @@ pub fn str_to_ansi(s: &str) -> Option<String> {
// Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
// Another good reference http://ascii-table.com/ansi-escape-sequences.php
// For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect`
// For setting title like `echo [(char title) (pwd) (char bel)] | str collect`
"title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title using OSC syntax escapes
// Ansi Erase Sequences

View file

@ -31,7 +31,7 @@ impl WholeStreamCommand for SubCommand {
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "strip ansi escape sequences from string",
example: "echo [$(ansi gb) 'hello' $(ansi reset)] | str collect | ansi strip",
example: "echo [(ansi gb) 'hello' (ansi reset)] | str collect | ansi strip",
result: None,
}]
}

View file

@ -44,7 +44,7 @@ impl WholeStreamCommand for Command {
},
Example {
description: "Check if any of the values is odd",
example: "echo [2 4 1 6 8] | any? $(= $it mod 2) == 1",
example: "echo [2 4 1 6 8] | any? ($it mod 2) == 1",
result: Some(vec![Value::from(true)]),
},
]

View file

@ -35,7 +35,7 @@ impl WholeStreamCommand for Char {
},
Example {
description: "Output prompt character, newline and a hamburger character",
example: r#"echo $(char prompt) $(char newline) $(char hamburger)"#,
example: r#"echo (char prompt) (char newline) (char hamburger)"#,
result: Some(vec![
UntaggedValue::string("\u{25b6}").into(),
UntaggedValue::string("\n").into(),

View file

@ -42,7 +42,7 @@ impl WholeStreamCommand for Each {
},
Example {
description: "Echo the square of each integer",
example: "echo [1 2 3] | each { echo $(= $it * $it) }",
example: "echo [1 2 3] | each { echo ($it * $it) }",
result: Some(vec![
UntaggedValue::int(1).into(),
UntaggedValue::int(4).into(),

View file

@ -63,7 +63,7 @@ impl WholeStreamCommand for Command {
),
},Example {
description: "use a block if setting the empty cell contents is wanted",
example: "echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { = [33 37] }",
example: "echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { [33 37] }",
result: Some(
vec![
UntaggedValue::row(indexmap! {

View file

@ -39,12 +39,12 @@ impl WholeStreamCommand for Command {
},
Example {
description: "flatten a column having a nested table",
example: "echo [[origin, people]; [Ecuador, $(echo [[name, meal]; ['Andres', 'arepa']])]] | flatten | get meal",
example: "echo [[origin, people]; [Ecuador, (echo [[name, meal]; ['Andres', 'arepa']])]] | flatten | get meal",
result: Some(vec![Value::from("arepa")]),
},
Example {
description: "restrict the flattening by passing column names",
example: "echo [[origin, crate, versions]; [World, $(echo [[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions | last | get versions",
example: "echo [[origin, crate, versions]; [World, (echo [[name]; ['nu-cli']]), ['0.21', '0.22']]] | flatten versions | last | get versions",
result: Some(vec![Value::from("0.22")]),
}
]

View file

@ -100,7 +100,7 @@ impl WholeStreamCommand for Command {
Example {
description:
"use the block form to generate a grouping key when each row gets processed",
example: "echo [1 3 1 3 2 1 1] | group-by { = ($it - 1) mod 3 }",
example: "echo [1 3 1 3 2 1 1] | group-by { ($it - 1) mod 3 }",
result: Some(vec![UntaggedValue::row(indexmap! {
"0".to_string() => UntaggedValue::Table(vec![
UntaggedValue::int(1).into(),

View file

@ -51,7 +51,7 @@ impl WholeStreamCommand for Command {
.into()]),
},Example {
description: "Use in block form for more involved insertion logic",
example: "echo [[author, lucky_number]; ['Yehuda', 4]] | insert success { = $it.lucky_number * 10 }",
example: "echo [[author, lucky_number]; ['Yehuda', 4]] | insert success { $it.lucky_number * 10 }",
result: Some(vec![UntaggedValue::row(indexmap! {
"author".to_string() => Value::from("Yehuda"),
"lucky_number".to_string() => UntaggedValue::int(4).into(),

View file

@ -67,7 +67,7 @@ On Windows, an extra 'prefix' column is added."#
},
Example {
description: "Replace a complex extension",
example: r"echo 'C:\Users\viking\spam.tar.gz' | path parse -e tar.gz | update extension { = txt }",
example: r"echo 'C:\Users\viking\spam.tar.gz' | path parse -e tar.gz | update extension { 'txt' }",
result: None,
},
Example {
@ -93,7 +93,7 @@ On Windows, an extra 'prefix' column is added."#
},
Example {
description: "Replace a complex extension",
example: r"echo '/home/viking/spam.tar.gz' | path parse -e tar.gz | update extension { = txt }",
example: r"echo '/home/viking/spam.tar.gz' | path parse -e tar.gz | update extension { 'txt' }",
result: None,
},
Example {

View file

@ -57,22 +57,22 @@ impl WholeStreamCommand for Reduce {
vec![
Example {
description: "Simple summation (equivalent to math sum)",
example: "echo 1 2 3 4 | reduce { = $acc + $it }",
example: "echo 1 2 3 4 | reduce { $acc + $it }",
result: Some(vec![UntaggedValue::int(10).into()]),
},
Example {
description: "Summation from starting value using fold",
example: "echo 1 2 3 4 | reduce -f $(= -1) { = $acc + $it }",
example: "echo 1 2 3 4 | reduce -f (-1) { $acc + $it }",
result: Some(vec![UntaggedValue::int(9).into()]),
},
Example {
description: "Folding with rows",
example: "<table> | reduce -f 1.6 { = $acc * $(echo $it.a | str to-int) + $(echo $it.b | str to-int) }",
example: "<table> | reduce -f 1.6 { $acc * (echo $it.a | str to-int) + (echo $it.b | str to-int) }",
result: None,
},
Example {
description: "Numbered reduce to find index of longest word",
example: "echo one longest three bar | reduce -n { if $(echo $it.item | str length) > $(echo $acc.item | str length) {echo $it} {echo $acc}} | get index",
example: "echo one longest three bar | reduce -n { if ($it.item | str length) > ($acc.item | str length) {echo $it} {echo $acc}} | get index",
result: None,
},
]

View file

@ -69,7 +69,7 @@ impl WholeStreamCommand for Command {
},
Example {
description: "Treat each row as a markdown element",
example: "echo [[H1]; [\"Welcome to Nushell\"]] | append $(ls | first 2) | to md --per-element --pretty",
example: "echo [[H1]; [\"Welcome to Nushell\"]] | append (ls | first 2) | to md --per-element --pretty",
result: Some(vec![Value::from(one(r#"
# Welcome to Nushell
| name | type | chickens | modified |

View file

@ -10,7 +10,7 @@ fn filesystem_change_from_current_directory_using_relative_path() {
cwd: dirs.root(),
r#"
cd cd_test_1
echo $(pwd)
echo (pwd)
"#
);
@ -25,7 +25,7 @@ fn filesystem_change_from_current_directory_using_absolute_path() {
cwd: dirs.test(),
r#"
cd "{}"
echo $(pwd)
echo (pwd)
"#,
dirs.formats()
);
@ -44,7 +44,7 @@ fn filesystem_switch_back_to_previous_working_directory() {
r#"
cd {}
cd -
echo $(pwd)
echo (pwd)
"#,
dirs.test()
);
@ -62,7 +62,7 @@ fn filesytem_change_from_current_directory_using_relative_path_and_dash() {
cwd: dirs.test(),
r#"
cd odin/-
echo $(pwd)
echo (pwd)
"#
);
@ -80,7 +80,7 @@ fn filesystem_change_current_directory_to_parent_directory() {
cwd: dirs.test(),
r#"
cd ..
echo $(pwd)
echo (pwd)
"#
);
@ -97,7 +97,7 @@ fn filesystem_change_current_directory_to_two_parents_up_using_multiple_dots() {
cwd: dirs.test().join("foo/bar"),
r#"
cd ...
echo $(pwd)
echo (pwd)
"#
);
@ -116,7 +116,7 @@ fn filesystem_change_current_directory_to_parent_directory_after_delete_cwd() {
rm {}/foo/bar
echo ","
cd ..
echo $(pwd)
echo (pwd)
"#,
dirs.test()
);
@ -135,7 +135,7 @@ fn filesystem_change_to_home_directory() {
cwd: dirs.test(),
r#"
cd ~
echo $(pwd)
echo (pwd)
"#
);
@ -152,7 +152,7 @@ fn filesystem_change_to_a_directory_containing_spaces() {
cwd: dirs.test(),
r#"
cd "robalino turner katz"
echo $(pwd)
echo (pwd)
"#
);
@ -219,7 +219,7 @@ fn filesystem_change_directory_to_symlink_relative() {
cwd: dirs.test().join("boo"),
r#"
cd ../foo_link
echo $(pwd)
echo (pwd)
"#
);

View file

@ -17,7 +17,7 @@ fn each_group_works() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo [1 2 3 4 5 6] | each group 3 { echo $it } | to json
echo [1 2 3 4 5 6] | each group 3 { $it } | to json
"#
));
@ -29,7 +29,7 @@ fn each_window() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo [1 2 3 4] | each window 3 { echo $it } | to json
echo [1 2 3 4] | each window 3 { $it } | to json
"#
));

View file

@ -6,9 +6,9 @@ fn reports_emptiness() {
cwd: ".", pipeline(
r#"
echo [[are_empty];
[$(= [[check]; [[]] ])]
[$(= [[check]; [""] ])]
[$(= [[check]; [$(wrap)] ])]
[([[check]; [[]] ])]
[([[check]; [""] ])]
[([[check]; [(wrap)] ])]
]
| get are_empty
| empty? check
@ -32,7 +32,7 @@ fn sets_block_run_value_for_an_empty_column() {
[ Jason, Gedge, 10/11/2013, 1 ]
[ Yehuda, Katz, 10/11/2013, '' ]
]
| empty? likes { = 1 }
| empty? likes { 1 }
| get likes
| math sum
"#
@ -50,9 +50,9 @@ fn sets_block_run_value_for_many_empty_columns() {
[ boost check ];
[ 1, [] ]
[ 1, "" ]
[ 1, $(wrap) ]
[ 1, (wrap) ]
]
| empty? boost check { = 1 }
| empty? boost check { 1 }
| get boost check
| math sum
"#
@ -73,9 +73,9 @@ fn passing_a_block_will_set_contents_on_empty_cells_and_leave_non_empty_ones_unt
[ Arepas, "", "" ]
[ Jorge, 30, 3000 ]
]
| empty? LVL { = 9 }
| empty? LVL { 9 }
| empty? HP {
= $it.LVL * 1000
$it.LVL * 1000
}
| math sum
| get HP

View file

@ -7,8 +7,8 @@ fn flatten_nested_tables_with_columns() {
let actual = nu!(
cwd: ".", pipeline(
r#"
echo [[origin, people]; [Ecuador, $(= 'Andres' | wrap name)]]
[[origin, people]; [Nu, $(= 'nuno' | wrap name)]]
echo [[origin, people]; [Ecuador, ('Andres' | wrap name)]]
[[origin, people]; [Nu, ('nuno' | wrap name)]]
| flatten
| get name
| str collect ','
@ -23,8 +23,8 @@ fn flatten_nested_tables_that_have_many_columns() {
let actual = nu!(
cwd: ".", pipeline(
r#"
echo [[origin, people]; [Ecuador, $(echo [[name, meal]; ['Andres', 'arepa']])]]
[[origin, people]; [USA, $(echo [[name, meal]; ['Katz', 'nurepa']])]]
echo [[origin, people]; [Ecuador, (echo [[name, meal]; ['Andres', 'arepa']])]]
[[origin, people]; [USA, (echo [[name, meal]; ['Katz', 'nurepa']])]]
| flatten
| get meal
| str collect ','

View file

@ -35,7 +35,7 @@ fn sets_the_column_from_an_invocation() {
cwd: "tests/fixtures/formats", pipeline(
r#"
wrap content
| insert content $(open --raw cargo_sample.toml | lines | first 5)
| insert content (open --raw cargo_sample.toml | lines | first 5)
| get content.1
| str contains "nu"
"#

View file

@ -5,7 +5,7 @@ fn into_int_filesize() {
let actual = nu!(
cwd: ".", pipeline(
r#"
echo 1kb | into int | each {= $it / 1000 }
echo 1kb | into int | each { $it / 1000 }
"#
));
@ -17,7 +17,7 @@ fn into_int_filesize2() {
let actual = nu!(
cwd: ".", pipeline(
r#"
echo 1kib | into int | each {= $it / 1024 }
echo 1kib | into int | each { $it / 1024 }
"#
));
@ -29,7 +29,7 @@ fn into_int_int() {
let actual = nu!(
cwd: ".", pipeline(
r#"
echo 1024 | into int | each {= $it / 1024 }
echo 1024 | into int | each { $it / 1024 }
"#
));

View file

@ -12,7 +12,7 @@ fn one_arg() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1
1
"#
));
@ -24,7 +24,7 @@ fn add() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 + 1
1 + 1
"#
));
@ -36,7 +36,7 @@ fn add_compound() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 + 2 + 2
1 + 2 + 2
"#
));
@ -48,7 +48,7 @@ fn precedence_of_operators() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 + 2 * 2
1 + 2 * 2
"#
));
@ -60,7 +60,7 @@ fn precedence_of_operators2() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 + 2 * 2 + 1
1 + 2 * 2 + 1
"#
));
@ -72,7 +72,7 @@ fn division_of_ints() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 4 / 2
4 / 2
"#
));
@ -84,7 +84,7 @@ fn division_of_ints2() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 / 4
1 / 4
"#
));
@ -96,7 +96,7 @@ fn error_zero_division_int_int() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 / 0
1 / 0
"#
));
@ -108,7 +108,7 @@ fn error_zero_division_decimal_int() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1.0 / 0
1.0 / 0
"#
));
@ -120,7 +120,7 @@ fn error_zero_division_int_decimal() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1 / 0.0
1 / 0.0
"#
));
@ -132,7 +132,7 @@ fn error_zero_division_decimal_decimal() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1.0 / 0.0
1.0 / 0.0
"#
));
@ -144,7 +144,7 @@ fn proper_precedence_history() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 2 / 2 / 2 + 1
2 / 2 / 2 + 1
"#
));
@ -156,7 +156,7 @@ fn parens_precedence() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 4 * (6 - 3)
4 * (6 - 3)
"#
));
@ -168,7 +168,7 @@ fn modulo() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 9 mod 2
9 mod 2
"#
));
@ -180,7 +180,7 @@ fn duration_math() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1wk + 1day
1wk + 1day
"#
));
@ -192,7 +192,7 @@ fn duration_decimal_math() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 5.5day + 0.5day
5.5day + 0.5day
"#
));
@ -204,7 +204,7 @@ fn duration_math_with_nanoseconds() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1wk + 10ns
1wk + 10ns
"#
));
@ -216,7 +216,7 @@ fn duration_decimal_math_with_nanoseconds() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1.5wk + 10ns
1.5wk + 10ns
"#
));
@ -228,7 +228,7 @@ fn duration_math_with_negative() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 1day - 1wk
1day - 1wk
"#
));
@ -240,7 +240,7 @@ fn compound_comparison() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 4 > 3 && 2 > 1
4 > 3 && 2 > 1
"#
));
@ -252,7 +252,7 @@ fn compound_comparison2() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
= 4 < 3 || 2 > 1
4 < 3 || 2 > 1
"#
));
@ -276,7 +276,7 @@ fn compound_where_paren() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
echo '[{"a": 1, "b": 1}, {"a": 2, "b": 1}, {"a": 2, "b": 2}]' | from json | where (a == 2 && b == 1) || b == 2 | to json
echo '[{"a": 1, "b": 1}, {"a": 2, "b": 1}, {"a": 2, "b": 2}]' | from json | where ($it.a == 2 && $it.b == 1) || $it.b == 2 | to json
"#
));

View file

@ -8,7 +8,7 @@ fn reduce_table_column() {
echo "[{month:2,total:30}, {month:3,total:10}, {month:4,total:3}, {month:5,total:60}]"
| from json
| get total
| reduce -f 20 { = $it + $( math eval `{{$acc}}^1.05` )}
| reduce -f 20 { $it + ( math eval `{{$acc}}^1.05` )}
| str from -d 1
"#
)
@ -21,7 +21,7 @@ fn reduce_table_column() {
r#"
echo "[{month:2,total:30}, {month:3,total:10}, {month:4,total:3}, {month:5,total:60}]"
| from json
| reduce -f 20 { = $it.total + $( math eval `{{$acc}}^1.05` )}
| reduce -f 20 { $it.total + ( math eval `{{$acc}}^1.05` )}
| str from -d 1
"#
)
@ -38,7 +38,7 @@ fn reduce_rows_example() {
echo a,b 1,2 3,4
| split column ,
| headers
| reduce -f 1.6 { = $acc * $(echo $it.a | str to-int) + $(echo $it.b | str to-int) }
| reduce -f 1.6 { $acc * ($it.a | str to-int) + ($it.b | str to-int) }
"#
)
);
@ -52,7 +52,7 @@ fn reduce_numbered_example() {
cwd: ".", pipeline(
r#"
echo one longest three bar
| reduce -n { if $(echo $it.item | str length) > $(echo $acc.item | str length) {echo $it} {echo $acc}}
| reduce -n { if ($it.item | str length) > ($acc.item | str length) {echo $it} {echo $acc}}
| get index
"#
)
@ -67,7 +67,7 @@ fn reduce_numbered_integer_addition_example() {
cwd: ".", pipeline(
r#"
echo [1 2 3 4]
| reduce -n {= $acc.item + $it.item }
| reduce -n { $acc.item + $it.item }
| get item
"#
)
@ -84,7 +84,7 @@ fn folding_with_tables() {
echo [10 20 30 40]
| reduce -f [] {
with-env [value $it] {
echo $acc | append $(= 10 * $(= $nu.env.value | str to-int))
echo $acc | append (10 * ($nu.env.value | str to-int))
}
}
| math sum
@ -100,7 +100,7 @@ fn error_reduce_fold_type_mismatch() {
let actual = nu!(
cwd: ".", pipeline(
r#"
echo a b c | reduce -f 0 { = $acc + $it }
echo a b c | reduce -f 0 { $acc + $it }
"#
)
);
@ -113,7 +113,7 @@ fn error_reduce_empty() {
let actual = nu!(
cwd: ".", pipeline(
r#"
reduce { = $acc + $it }
reduce { $acc + $it }
"#
)
);

View file

@ -136,7 +136,7 @@ mod columns {
| get bit
| reverse
| each --numbered {
= $it.item * (2 ** $it.index)
$it.item * (2 ** $it.index)
}
| math sum
"#,

View file

@ -50,7 +50,7 @@ fn sets_the_column_from_an_invocation() {
cwd: "tests/fixtures/formats", pipeline(
r#"
wrap content
| update content $(open --raw cargo_sample.toml | lines | first 5)
| update content (open --raw cargo_sample.toml | lines | first 5)
| get content.1
| str contains "nu"
"#

View file

@ -86,7 +86,7 @@ fn md_combined() {
};
title
| append $(meals)
| append (meals)
| to md --per-element --pretty
"#
));

View file

@ -293,6 +293,11 @@ pub fn compute_values(
Ok(UntaggedValue::Primitive(Primitive::Duration(result)))
}
(Primitive::String(x), Primitive::String(y)) => {
let mut new_string = x.clone();
new_string.push_str(y);
Ok(UntaggedValue::Primitive(Primitive::String(new_string)))
}
_ => Err((left.type_name(), right.type_name())),
},
_ => Err((left.type_name(), right.type_name())),

View file

@ -5,6 +5,7 @@ use log::{log_enabled, trace};
use crate::evaluation_context::EvaluationContext;
use nu_errors::ShellError;
use nu_protocol::hir::SpannedExpression;
use nu_protocol::{UntaggedValue, Value};
use nu_stream::{InputStream, ToInputStream};
pub(crate) fn run_expression_block(
@ -18,5 +19,11 @@ pub(crate) fn run_expression_block(
let output = evaluate_baseline_expr(expr, ctx)?;
Ok(std::iter::once(Ok(output)).to_input_stream())
match output {
Value {
value: UntaggedValue::Table(x),
..
} => Ok(InputStream::from_stream(x.into_iter())),
output => Ok(std::iter::once(Ok(output)).to_input_stream()),
}
}

View file

@ -6,7 +6,7 @@ fn test_parse_invocation_with_range() {
cwd: ".",
r#"
let foo = 3
echo $(echo 1..$foo | each { echo $it }) | to json
echo (echo 1..$foo | each { $it }) | to json
"#
);
assert_eq!(actual.out, "[1,2,3]")

View file

@ -1,5 +1,6 @@
use std::{path::Path, sync::Arc};
use bigdecimal::BigDecimal;
use indexmap::IndexMap;
use log::trace;
use nu_errors::{ArgumentError, ParseError};
@ -12,11 +13,12 @@ use nu_protocol::{NamedType, PositionalType, Signature, SyntaxShape, UnspannedPa
use nu_source::{HasSpan, Span, Spanned, SpannedItem};
use num_bigint::BigInt;
use crate::lex::lexer::{lex, parse_block};
use crate::lex::tokens::{LiteBlock, LiteCommand, LitePipeline};
use crate::path::expand_path;
use crate::scope::ParserScope;
use bigdecimal::BigDecimal;
use crate::{
lex::lexer::{lex, parse_block},
ParserScope,
};
use self::{
def::{parse_definition, parse_definition_prototype},
@ -94,8 +96,7 @@ pub fn parse_full_column_path(
lite_arg: &Spanned<String>,
scope: &dyn ParserScope,
) -> (SpannedExpression, Option<ParseError>) {
let mut delimiter = '.';
let mut inside_delimiter = false;
let mut inside_delimiter = vec![];
let mut output = vec![];
let mut current_part = String::new();
let mut start_index = 0;
@ -106,23 +107,21 @@ pub fn parse_full_column_path(
for (idx, c) in lite_arg.item.char_indices() {
last_index = idx;
if inside_delimiter {
if c == delimiter {
inside_delimiter = false;
if c == '(' {
inside_delimiter.push(')');
} else if let Some(delimiter) = inside_delimiter.last() {
if c == *delimiter {
inside_delimiter.pop();
}
} else if c == '(' {
inside_delimiter = true;
delimiter = ')';
} else if c == '\'' || c == '"' {
inside_delimiter = true;
delimiter = c;
inside_delimiter.push(c);
} else if c == '.' {
let part_span = Span::new(
lite_arg.span.start() + start_index,
lite_arg.span.start() + idx,
);
if head.is_none() && current_part.starts_with("$(") && current_part.ends_with(')') {
if head.is_none() && current_part.starts_with('(') && current_part.ends_with(')') {
let (invoc, err) =
parse_invocation(&current_part.clone().spanned(part_span), scope);
if error.is_none() {
@ -158,7 +157,7 @@ pub fn parse_full_column_path(
);
if head.is_none() {
if current_part.starts_with("$(") && current_part.ends_with(')') {
if current_part.starts_with('(') && current_part.ends_with(')') {
let (invoc, err) = parse_invocation(&current_part.spanned(part_span), scope);
if error.is_none() {
error = err;
@ -419,12 +418,12 @@ fn parse_invocation(
let string: String = lite_arg
.item
.chars()
.skip(2)
.take(lite_arg.item.chars().count() - 3)
.skip(1)
.take(lite_arg.item.chars().count() - 2)
.collect();
// We haven't done much with the inner string, so let's go ahead and work with it
let (tokens, err) = lex(&string, lite_arg.span.start() + 2);
let (tokens, err) = lex(&string, lite_arg.span.start() + 1);
if err.is_some() {
return (garbage(lite_arg.span), err);
};
@ -468,21 +467,7 @@ fn parse_dollar_expr(
scope: &dyn ParserScope,
) -> (SpannedExpression, Option<ParseError>) {
trace!("Parsing dollar expression: {:?}", lite_arg.item);
if lite_arg.item == "$true" {
(
SpannedExpression::new(Expression::boolean(true), lite_arg.span),
None,
)
} else if lite_arg.item == "$false" {
(
SpannedExpression::new(Expression::boolean(false), lite_arg.span),
None,
)
} else if lite_arg.item.ends_with(')') {
//Return invocation
trace!("Parsing invocation expression");
parse_invocation(lite_arg, scope)
} else if let (expr, None) = parse_range(lite_arg, scope) {
if let (expr, None) = parse_range(lite_arg, scope) {
(expr, None)
} else if let (expr, None) = parse_full_column_path(lite_arg, scope) {
(expr, None)
@ -661,10 +646,13 @@ fn parse_external_arg(
scope: &dyn ParserScope,
) -> (SpannedExpression, Option<ParseError>) {
if lite_arg.item.starts_with('$') {
return parse_dollar_expr(&lite_arg, scope);
}
if lite_arg.item.starts_with('`') && lite_arg.item.len() > 1 && lite_arg.item.ends_with('`') {
parse_dollar_expr(&lite_arg, scope)
} else if lite_arg.item.starts_with('(') {
parse_invocation(&lite_arg, scope)
} else if lite_arg.item.starts_with('`')
&& lite_arg.item.len() > 1
&& lite_arg.item.ends_with('`')
{
// This is an interpolated string
parse_interpolated_string(&lite_arg, scope)
} else {
@ -772,65 +760,6 @@ fn parse_table(
)
}
/// Tries to parse a number in a paranthesis, e.g., (123) or (-123)
fn try_parse_number_in_paranthesis(
lite_arg: &Spanned<String>,
) -> (SpannedExpression, Option<ParseError>) {
let mut chars = lite_arg.item.chars();
match (chars.next(), chars.next_back()) {
(Some('('), Some(')')) => {
match chars.as_str().trim().parse::<BigInt>() {
Ok(parsed_integer) => (
SpannedExpression::new(Expression::integer(parsed_integer), lite_arg.span),
None,
),
// we don't care if it does not manage to parse it, because then likely it is not a number
Err(_) => {
match chars.as_str().trim().parse::<BigDecimal>() {
Ok(parsed_decimal) => (
SpannedExpression::new(
Expression::decimal(parsed_decimal),
lite_arg.span,
),
None,
),
// we don't care if it does not manage to parse it, because then likely it is not a number
Err(_) => (
garbage(lite_arg.span),
Some(ParseError::mismatch(
"cannot parse number",
lite_arg.clone(),
)),
),
}
}
}
}
(Some('('), _) => (
garbage(lite_arg.span),
Some(ParseError::mismatch(
"missing closing bracket",
lite_arg.clone(),
)),
),
(_, Some(')')) => (
garbage(lite_arg.span),
Some(ParseError::mismatch(
"missing starting bracket",
lite_arg.clone(),
)),
),
(_, _) => (
garbage(lite_arg.span),
Some(ParseError::mismatch(
"number in paranthesis",
lite_arg.clone(),
)),
),
}
}
/// Parses the given argument using the shape as a guide for how to correctly parse the argument
fn parse_arg(
expected_type: SyntaxShape,
@ -843,7 +772,7 @@ fn parse_arg(
// before anything else, try to see if this is a number in paranthesis
if lite_arg.item.starts_with('(') {
let (expr, err) = try_parse_number_in_paranthesis(lite_arg);
let (expr, err) = parse_full_column_path(&lite_arg, scope);
if err.is_none() {
return (expr, None);
}
@ -1117,69 +1046,15 @@ fn shorthand_reparse(
}
}
fn parse_parenthesized_expression(
lite_arg: &Spanned<String>,
scope: &dyn ParserScope,
shorthand_mode: bool,
) -> (SpannedExpression, Option<ParseError>) {
let mut chars = lite_arg.item.chars();
match (chars.next(), chars.next_back()) {
(Some('('), Some(')')) => {
// We have a literal row
let string: String = chars.collect();
// We haven't done much with the inner string, so let's go ahead and work with it
let (tokens, err) = lex(&string, lite_arg.span.start() + 1);
if err.is_some() {
return (garbage(lite_arg.span), err);
}
let (lite_block, err) = parse_block(tokens);
if err.is_some() {
return (garbage(lite_arg.span), err);
}
if lite_block.block.len() != 1 {
return (
garbage(lite_arg.span),
Some(ParseError::mismatch("math expression", lite_arg.clone())),
);
}
let mut lite_pipeline = lite_block.block[0].clone();
let mut collection = vec![];
for lite_pipeline in lite_pipeline.pipelines.iter_mut() {
for lite_cmd in lite_pipeline.commands.iter_mut() {
collection.append(&mut lite_cmd.parts);
}
}
let (_, expr, err) = parse_math_expression(0, &collection[..], scope, shorthand_mode);
(expr, err)
}
_ => (
garbage(lite_arg.span),
Some(ParseError::mismatch("table", lite_arg.clone())),
),
}
}
fn parse_possibly_parenthesized(
lite_arg: &Spanned<String>,
scope: &dyn ParserScope,
shorthand_mode: bool,
) -> (
(Option<Spanned<String>>, SpannedExpression),
Option<ParseError>,
) {
if lite_arg.item.starts_with('(') {
let (lhs, err) = parse_parenthesized_expression(lite_arg, scope, shorthand_mode);
((None, lhs), err)
} else {
let (lhs, err) = parse_arg(SyntaxShape::Any, scope, lite_arg);
((Some(lite_arg.clone()), lhs), err)
}
}
/// Handle parsing math expressions, complete with working with the precedence of the operators
@ -1200,8 +1075,7 @@ pub fn parse_math_expression(
let mut working_exprs = vec![];
let mut prec = vec![];
let (lhs_working_expr, err) =
parse_possibly_parenthesized(&lite_args[idx], scope, shorthand_mode);
let (lhs_working_expr, err) = parse_possibly_parenthesized(&lite_args[idx], scope);
if error.is_none() {
error = err;
@ -1239,8 +1113,7 @@ pub fn parse_math_expression(
prec
);
let (rhs_working_expr, err) =
parse_possibly_parenthesized(&lite_args[idx], scope, shorthand_mode);
let (rhs_working_expr, err) = parse_possibly_parenthesized(&lite_args[idx], scope);
if error.is_none() {
error = err;
@ -1740,22 +1613,32 @@ fn parse_call(
})),
error,
);
} else if lite_cmd.parts[0].item.starts_with('$') || lite_cmd.parts[0].item.starts_with('{') {
// } else if lite_cmd.parts[0].item.starts_with('(') {
// let (expr, err) = parse_simple_invocation(&lite_cmd.parts[0], scope);
// error = error.or(err);
// return (Some(ClassifiedCommand::Expr(Box::new(expr))), error);
} else if lite_cmd.parts[0].item.starts_with('{') {
return parse_value_call(lite_cmd, scope);
} else if lite_cmd.parts[0].item == "=" {
let expr = if lite_cmd.parts.len() > 1 {
let (_, expr, err) = parse_math_expression(0, &lite_cmd.parts[1..], scope, false);
} else if lite_cmd.parts[0].item.starts_with('$')
|| lite_cmd.parts[0].item.starts_with('\"')
|| lite_cmd.parts[0].item.starts_with('\'')
|| lite_cmd.parts[0].item.starts_with('`')
|| lite_cmd.parts[0].item.starts_with('-')
|| lite_cmd.parts[0].item.starts_with('0')
|| lite_cmd.parts[0].item.starts_with('1')
|| lite_cmd.parts[0].item.starts_with('2')
|| lite_cmd.parts[0].item.starts_with('3')
|| lite_cmd.parts[0].item.starts_with('4')
|| lite_cmd.parts[0].item.starts_with('5')
|| lite_cmd.parts[0].item.starts_with('6')
|| lite_cmd.parts[0].item.starts_with('7')
|| lite_cmd.parts[0].item.starts_with('8')
|| lite_cmd.parts[0].item.starts_with('9')
|| lite_cmd.parts[0].item.starts_with('[')
|| lite_cmd.parts[0].item.starts_with('(')
{
let (_, expr, err) = parse_math_expression(0, &lite_cmd.parts[..], scope, false);
error = error.or(err);
expr
} else {
error = error.or_else(|| {
Some(ParseError::argument_error(
lite_cmd.parts[0].clone(),
ArgumentError::MissingMandatoryPositional("an expression".into()),
))
});
garbage(lite_cmd.span())
};
return (Some(ClassifiedCommand::Expr(Box::new(expr))), error);
} else if lite_cmd.parts[0].item == "alias" {
let error = parse_alias(&lite_cmd, scope);
@ -1925,77 +1808,6 @@ fn expand_shorthand_forms(
}
}
// pub fn parse_block(lite_block: &LiteBlock, scope: &dyn ParserScope) -> ClassifiedBlock {
// let mut block = vec![];
// let mut error = None;
// for lite_group in &lite_block.block {
// let mut command_list = vec![];
// for lite_pipeline in &lite_group.pipelines {
// let (lite_pipeline, vars, err) = expand_shorthand_forms(lite_pipeline);
// if error.is_none() {
// error = err;
// }
// let (pipeline, err) = parse_pipeline(&lite_pipeline, scope);
// let pipeline = if let Some(vars) = vars {
// let span = pipeline.commands.span;
// let group = Group::new(vec![pipeline.commands.clone()], span);
// let block = hir::Block::new(vec![], vec![group], span);
// let mut call = hir::Call::new(
// Box::new(SpannedExpression {
// expr: Expression::string("with-env".to_string()),
// span,
// }),
// span,
// );
// call.positional = Some(vec![
// SpannedExpression {
// expr: Expression::List(vec![
// SpannedExpression {
// expr: Expression::string(vars.0.item),
// span: vars.0.span,
// },
// SpannedExpression {
// expr: Expression::string(vars.1.item),
// span: vars.1.span,
// },
// ]),
// span: Span::new(vars.0.span.start(), vars.1.span.end()),
// },
// SpannedExpression {
// expr: Expression::Block(block),
// span,
// },
// ]);
// let classified_with_env = ClassifiedCommand::Internal(InternalCommand {
// name: "with-env".to_string(),
// name_span: Span::unknown(),
// args: call,
// });
// ClassifiedPipeline {
// commands: Pipeline {
// list: vec![classified_with_env],
// span,
// },
// }
// } else {
// pipeline
// };
// command_list.push(pipeline.commands);
// if error.is_none() {
// error = err;
// }
// }
// let group = Group::new(command_list, lite_block.span());
// block.push(group);
// }
// let block = Block::new(vec![], block, lite_block.span());
// ClassifiedBlock::new(block, error)
// }
fn parse_alias(call: &LiteCommand, scope: &dyn ParserScope) -> Option<ParseError> {
if call.parts.len() < 4 {
return Some(ParseError::mismatch("alias", call.parts[0].clone()));

View file

@ -1,8 +1,5 @@
[package]
authors = [
"Andrei Volnin <wolandr@gmail.com>",
"The Nu Project Contributors"
]
authors = ["Andrei Volnin <wolandr@gmail.com>", "The Nu Project Contributors"]
description = "Pretty hex dump of bytes slice in the common style."
edition = "2018"
license = "MIT"

View file

@ -48,7 +48,7 @@ Some text
The style used by `textview` can be configured in `config.toml`.
```shell
> open --raw $(which nu | get path) | autoview
> open --raw (which nu | get path) | autoview
...
126d1c0: 64 31 66 37 62 30 31 63 36 2e 31 31 38 2e 6c 6c d1f7b01c6.118.ll
126d1d0: 76 6d 2e 34 34 38 37 35 37 31 32 34 39 35 33 39 vm.4487571249539

View file

@ -56,7 +56,7 @@ We want to add two totals (numbers `33` and `37`) for the day `2020/04/16`
Set a table with two numbers for the empty column
```shell
> echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { = [33 37] }
> echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { [33 37] }
═══╦════════════════╦════════════════╦════════════════
# ║ 2020/04/16 ║ 2020/07/10 ║ 2020/11/16
═══╬════════════════╬════════════════╬════════════════
@ -66,7 +66,7 @@ Set a table with two numbers for the empty column
Checking all the numbers
```shell
> echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { = [33 37] } | pivot _ totals | get totals
> echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { [33 37] } | pivot _ totals | get totals
═══╦════
0 ║ 33
1 ║ 37

View file

@ -14,7 +14,7 @@ pivot_mode = "auto" # auto, always, never
ctrlc_exit = false
complete_from_path = true
rm_always_trash = true
prompt = "build-string $(ansi gb) $(pwd) $(ansi reset) '(' $(ansi cb) $(do -i { git rev-parse --abbrev-ref HEAD } | str trim ) $(ansi reset) ')' $(ansi yb) $(date format '%m/%d/%Y %I:%M:%S%.3f %p' ) $(ansi reset) '> ' "
prompt = "build-string (ansi gb) (pwd) (ansi reset) '(' (ansi cb) (do -i { git rev-parse --abbrev-ref HEAD } | str trim ) (ansi reset) ')' (ansi yb) (date format '%m/%d/%Y %I:%M:%S%.3f %p' ) (ansi reset) '> ' "
# for each of the options in the color_config section, you are able to set
# the color alone or with one of the following attributes.

View file

@ -47,7 +47,7 @@ fn plugins_are_declared_with_wix() {
| wrap wix
}
| default wix _
| each { if $it.wix != $it.cargo { = 1 } { = 0 } }
| each { if $it.wix != $it.cargo { 1 } { 0 } }
| math sum
"#
));

View file

@ -34,7 +34,7 @@ fn automatically_change_directory() {
cwd: dirs.test(),
r#"
autodir
echo $(pwd)
echo (pwd)
"#
);
@ -300,7 +300,7 @@ mod external_command_arguments {
let actual = nu!(
cwd: dirs.test(), pipeline(
r#"
nu --testbin cococo $(ls | get name)
nu --testbin cococo (ls | get name)
"#
));

View file

@ -50,7 +50,7 @@ fn treats_dot_dot_as_path_not_range() {
r#"
mkdir temp;
cd temp;
echo $(open ../nu_times.csv).name | autoview;
echo (open ../nu_times.csv).name | autoview;
cd ..;
rmdir temp
"#
@ -66,7 +66,7 @@ fn invocation_properly_redirects() {
let actual = nu!(
cwd: ".",
r#"
echo $(nu --testbin cococo "hello") | str collect
echo (nu --testbin cococo "hello") | str collect
"#
);
@ -78,7 +78,7 @@ fn argument_invocation() {
let actual = nu!(
cwd: ".",
r#"
echo "foo" | each { echo $(echo $it) }
echo "foo" | each { echo (echo $it) }
"#
);
@ -102,7 +102,7 @@ fn invocation_handles_dot() {
let actual = nu!(
cwd: dirs.test(), pipeline(
r#"
echo $(open nu_times.csv)
echo (open nu_times.csv)
| get name
| each { nu --testbin chop $it | lines }
| nth 3
@ -202,7 +202,7 @@ fn run_custom_command() {
let actual = nu!(
cwd: ".",
r#"
def add-me [x y] { = $x + $y}; add-me 10 5
def add-me [x y] { $x + $y}; add-me 10 5
"#
);
@ -214,7 +214,7 @@ fn run_custom_command_with_flag() {
let actual = nu!(
cwd: ".",
r#"
def foo [--bar:number] { if $(echo $bar | empty?) { echo "empty" } { echo $bar } }; foo --bar 10
def foo [--bar:number] { if ($bar | empty?) { echo "empty" } { echo $bar } }; foo --bar 10
"#
);
@ -226,7 +226,7 @@ fn run_custom_command_with_flag_missing() {
let actual = nu!(
cwd: ".",
r#"
def foo [--bar:number] { if $(echo $bar | empty?) { echo "empty" } { echo $bar } }; foo
def foo [--bar:number] { if ($bar | empty?) { echo "empty" } { echo $bar } }; foo
"#
);
@ -325,7 +325,7 @@ fn set_variable() {
r#"
let x = 5
let y = 12
= $x + $y
$x + $y
"#
);
@ -396,7 +396,7 @@ fn run_dynamic_blocks() {
let actual = nu!(
cwd: ".",
r#"
let block = { echo "holaaaa" }; $block
let block = { echo "holaaaa" }; do $block
"#
);
assert_eq!(actual.out, "holaaaa");
@ -407,7 +407,7 @@ fn run_dynamic_blocks() {
fn argument_invocation_reports_errors() {
let actual = nu!(
cwd: ".",
"echo $(ferris_is_not_here.exe)"
"echo (ferris_is_not_here.exe)"
);
assert!(actual.err.contains("Command not found"));
@ -644,7 +644,7 @@ fn filesize_math() {
let actual = nu!(
cwd: ".",
r#"
= 100 * 10kb
100 * 10kb
"#
);
@ -658,7 +658,7 @@ fn filesize_math2() {
let actual = nu!(
cwd: ".",
r#"
= 100 / 10kb
100 / 10kb
"#
);
@ -670,7 +670,7 @@ fn filesize_math3() {
let actual = nu!(
cwd: ".",
r#"
= 100kb / 10
100kb / 10
"#
);
@ -681,7 +681,7 @@ fn filesize_math4() {
let actual = nu!(
cwd: ".",
r#"
= 100kb * 5
100kb * 5
"#
);
@ -693,7 +693,7 @@ fn filesize_math5() {
let actual = nu!(
cwd: ".",
r#"
= 1001 * 1kb
1001 * 1kb
"#
);
@ -705,7 +705,7 @@ fn filesize_math6() {
let actual = nu!(
cwd: ".",
r#"
= 1001 * 1mb
1001 * 1mb
"#
);
@ -717,7 +717,7 @@ fn filesize_math7() {
let actual = nu!(
cwd: ".",
r#"
= 1001 * 1gb
1001 * 1gb
"#
);
@ -753,7 +753,7 @@ fn duration_overflow() {
let actual = nu!(
cwd: ".", pipeline(
r#"
ls | get modified | each { = $it + 10000000000000000day }
ls | get modified | each { $it + 10000000000000000day }
"#)
);
@ -765,7 +765,7 @@ fn date_and_duration_overflow() {
let actual = nu!(
cwd: ".", pipeline(
r#"
ls | get modified | each { = $it + 1000000000day }
ls | get modified | each { $it + 1000000000day }
"#)
);