mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
Switch let/let-env family to init with math expressions (#8545)
# Description This is an experiment to see what switching the `let/let-env` family to math expressions for initialisers would be like. # User-Facing Changes This would require any commands you call from `let x = <command here>` (and similar family) to call the command in parentheses. `let x = (foo)` to call `foo`. # 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 > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` # 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.
This commit is contained in:
parent
0f4a073eaf
commit
2f8a52d256
13 changed files with 68 additions and 21 deletions
|
@ -21,7 +21,7 @@ impl Command for Const {
|
|||
.required("const_name", SyntaxShape::VarWithOptType, "constant name")
|
||||
.required(
|
||||
"initial_value",
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::MathExpression)),
|
||||
"equals sign followed by constant value",
|
||||
)
|
||||
.category(Category::Core)
|
||||
|
|
|
@ -20,7 +20,7 @@ impl Command for If {
|
|||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("if")
|
||||
.input_output_types(vec![(Type::Any, Type::Any)])
|
||||
.required("cond", SyntaxShape::Expression, "condition to check")
|
||||
.required("cond", SyntaxShape::MathExpression, "condition to check")
|
||||
.required(
|
||||
"then_block",
|
||||
SyntaxShape::Block,
|
||||
|
|
|
@ -22,7 +22,7 @@ impl Command for Let {
|
|||
.required("var_name", SyntaxShape::VarWithOptType, "variable name")
|
||||
.required(
|
||||
"initial_value",
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::MathExpression)),
|
||||
"equals sign followed by value",
|
||||
)
|
||||
.category(Category::Core)
|
||||
|
|
|
@ -22,7 +22,7 @@ impl Command for Mut {
|
|||
.required("var_name", SyntaxShape::VarWithOptType, "variable name")
|
||||
.required(
|
||||
"initial_value",
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::MathExpression)),
|
||||
"equals sign followed by value",
|
||||
)
|
||||
.category(Category::Core)
|
||||
|
|
|
@ -21,7 +21,7 @@ impl Command for While {
|
|||
Signature::build("while")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
||||
.allow_variants_without_examples(true)
|
||||
.required("cond", SyntaxShape::Expression, "condition to check")
|
||||
.required("cond", SyntaxShape::MathExpression, "condition to check")
|
||||
.required(
|
||||
"block",
|
||||
SyntaxShape::Block,
|
||||
|
|
2
crates/nu-command/src/env/let_env.rs
vendored
2
crates/nu-command/src/env/let_env.rs
vendored
|
@ -24,7 +24,7 @@ impl Command for LetEnv {
|
|||
.required("var_name", SyntaxShape::String, "variable name")
|
||||
.required(
|
||||
"initial_value",
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::MathExpression)),
|
||||
"equals sign followed by value",
|
||||
)
|
||||
.category(Category::Env)
|
||||
|
|
|
@ -172,7 +172,7 @@ fn use_export_env_combined() {
|
|||
"spam.nu",
|
||||
r#"
|
||||
alias bar = foo
|
||||
export-env { let-env FOO = bar }
|
||||
export-env { let-env FOO = (bar) }
|
||||
def foo [] { 'foo' }
|
||||
"#,
|
||||
)]);
|
||||
|
|
|
@ -698,6 +698,29 @@ pub fn eval_expression_with_input(
|
|||
input = eval_subexpression(engine_state, stack, block, input)?;
|
||||
}
|
||||
|
||||
elem @ Expression {
|
||||
expr: Expr::FullCellPath(full_cell_path),
|
||||
..
|
||||
} => match &full_cell_path.head {
|
||||
Expression {
|
||||
expr: Expr::Subexpression(block_id),
|
||||
span,
|
||||
..
|
||||
} => {
|
||||
let block = engine_state.get_block(*block_id);
|
||||
|
||||
// FIXME: protect this collect with ctrl-c
|
||||
input = eval_subexpression(engine_state, stack, block, input)?;
|
||||
let value = input.into_value(*span);
|
||||
input = value
|
||||
.follow_cell_path(&full_cell_path.tail, false)?
|
||||
.into_pipeline_data()
|
||||
}
|
||||
_ => {
|
||||
input = eval_expression(engine_state, stack, elem)?.into_pipeline_data();
|
||||
}
|
||||
},
|
||||
|
||||
elem => {
|
||||
input = eval_expression(engine_state, stack, elem)?.into_pipeline_data();
|
||||
}
|
||||
|
|
|
@ -3102,7 +3102,10 @@ pub fn parse_let_or_const(
|
|||
working_set,
|
||||
spans,
|
||||
&mut idx,
|
||||
&SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
&SyntaxShape::Keyword(
|
||||
b"=".to_vec(),
|
||||
Box::new(SyntaxShape::MathExpression),
|
||||
),
|
||||
expand_aliases_denylist,
|
||||
);
|
||||
error = error.or(err);
|
||||
|
@ -3236,7 +3239,10 @@ pub fn parse_mut(
|
|||
working_set,
|
||||
spans,
|
||||
&mut idx,
|
||||
&SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
&SyntaxShape::Keyword(
|
||||
b"=".to_vec(),
|
||||
Box::new(SyntaxShape::MathExpression),
|
||||
),
|
||||
expand_aliases_denylist,
|
||||
);
|
||||
error = error.or(err);
|
||||
|
|
|
@ -71,7 +71,12 @@ pub fn is_math_expression_like(
|
|||
return false;
|
||||
}
|
||||
|
||||
if bytes == b"true" || bytes == b"false" || bytes == b"null" || bytes == b"not" {
|
||||
if bytes == b"true"
|
||||
|| bytes == b"false"
|
||||
|| bytes == b"null"
|
||||
|| bytes == b"not"
|
||||
|| bytes == b"if"
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1112,12 +1117,12 @@ pub fn parse_call(
|
|||
for word_span in spans[cmd_start..].iter() {
|
||||
// Find the longest group of words that could form a command
|
||||
|
||||
if is_math_expression_like(working_set, *word_span, expand_aliases_denylist) {
|
||||
let bytes = working_set.get_span_contents(*word_span);
|
||||
if bytes != b"true" && bytes != b"false" && bytes != b"null" && bytes != b"not" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if is_math_expression_like(working_set, *word_span, expand_aliases_denylist) {
|
||||
// let bytes = working_set.get_span_contents(*word_span);
|
||||
// if bytes != b"true" && bytes != b"false" && bytes != b"null" && bytes != b"not" {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
name_spans.push(*word_span);
|
||||
|
||||
|
@ -4993,7 +4998,20 @@ pub fn parse_math_expression(
|
|||
|
||||
let first_span = working_set.get_span_contents(spans[0]);
|
||||
|
||||
if first_span == b"not" {
|
||||
if first_span == b"if" {
|
||||
// If expression
|
||||
if spans.len() > 1 {
|
||||
return parse_call(working_set, spans, spans[0], expand_aliases_denylist, false);
|
||||
} else {
|
||||
return (
|
||||
garbage(spans[0]),
|
||||
Some(ParseError::Expected(
|
||||
"expression".into(),
|
||||
Span::new(spans[0].end, spans[0].end),
|
||||
)),
|
||||
);
|
||||
}
|
||||
} else if first_span == b"not" {
|
||||
if spans.len() > 1 {
|
||||
let (remainder, err) = parse_math_expression(
|
||||
working_set,
|
||||
|
|
|
@ -27,7 +27,7 @@ impl Command for Let {
|
|||
.required("var_name", SyntaxShape::VarWithOptType, "variable name")
|
||||
.required(
|
||||
"initial_value",
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::MathExpression)),
|
||||
"equals sign followed by value",
|
||||
)
|
||||
}
|
||||
|
@ -1555,7 +1555,7 @@ mod input_types {
|
|||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("if")
|
||||
.required("cond", SyntaxShape::Expression, "condition to check")
|
||||
.required("cond", SyntaxShape::MathExpression, "condition to check")
|
||||
.required(
|
||||
"then_block",
|
||||
SyntaxShape::Block,
|
||||
|
|
|
@ -146,7 +146,7 @@ fn date_comparison() -> TestResult {
|
|||
#[test]
|
||||
fn let_sees_input() -> TestResult {
|
||||
run_test(
|
||||
r#"def c [] { let x = str length; $x }; "hello world" | c"#,
|
||||
r#"def c [] { let x = (str length); $x }; "hello world" | c"#,
|
||||
"11",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ fn module_def_import_uses_internal_command() -> TestResult {
|
|||
#[test]
|
||||
fn module_env_import_uses_internal_command() -> TestResult {
|
||||
run_test(
|
||||
r#"module foo { def b [] { "2" }; export-env { let-env a = b } }; use foo; $env.a"#,
|
||||
r#"module foo { def b [] { "2" }; export-env { let-env a = (b) } }; use foo; $env.a"#,
|
||||
"2",
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue