allow mut to take pipelines (#9658)

# Description

This extends the syntax fix for `let` (#9589) to `mut` as well.

Example: `mut x = "hello world" | str length; print $x`

closes #9634

# User-Facing Changes

`mut` now joins `let` in being able to be assigned from a pipeline

# 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 -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the
standard library

> **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:
JT
2023-07-12 06:36:34 +12:00
committed by GitHub
parent 942c66a9f3
commit ad11e25fc5
4 changed files with 207 additions and 179 deletions

View File

@ -5308,10 +5308,12 @@ pub fn parse_pipeline(
pipeline_index: usize,
) -> Pipeline {
if pipeline.commands.len() > 1 {
// Special case: allow `let` to consume the whole pipeline, eg) `let abc = "foo" | str length`
// Special case: allow `let` and `mut` to consume the whole pipeline, eg) `let abc = "foo" | str length`
match &pipeline.commands[0] {
LiteElement::Command(_, command) if !command.parts.is_empty() => {
if working_set.get_span_contents(command.parts[0]) == b"let" {
if working_set.get_span_contents(command.parts[0]) == b"let"
|| working_set.get_span_contents(command.parts[0]) == b"mut"
{
let mut new_command = LiteCommand {
comments: vec![],
parts: command.parts.clone(),
@ -5340,59 +5342,54 @@ pub fn parse_pipeline(
parse_builtin_commands(working_set, &new_command, is_subexpression);
if pipeline_index == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Nothing)
{
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
let let_decl_id = working_set.find_decl(b"let", &Type::Nothing);
let mut_decl_id = working_set.find_decl(b"mut", &Type::Nothing);
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
{
if Some(call.decl_id) == let_decl_id
|| Some(call.decl_id) == mut_decl_id
{
if call.decl_id == let_decl_id {
// Do an expansion
if let Some(Expression {
expr: Expr::Block(block_id),
..
}) = call.positional_iter_mut().nth(1)
// Do an expansion
if let Some(Expression {
expr: Expr::Block(block_id),
..
}) = call.positional_iter_mut().nth(1)
{
let block = working_set.get_block(*block_id);
let element = block.pipelines[0].elements[0].clone();
if let PipelineElement::Expression(prepend, expr) =
element
{
let block = working_set.get_block(*block_id);
if expr.has_in_variable(working_set) {
let new_expr = PipelineElement::Expression(
prepend,
wrap_expr_with_collect(working_set, &expr),
);
let element =
block.pipelines[0].elements[0].clone();
if let PipelineElement::Expression(prepend, expr) =
element
{
if expr.has_in_variable(working_set) {
let new_expr = PipelineElement::Expression(
prepend,
wrap_expr_with_collect(
working_set,
&expr,
),
);
let block =
working_set.get_block_mut(*block_id);
block.pipelines[0].elements[0] = new_expr;
}
let block =
working_set.get_block_mut(*block_id);
block.pipelines[0].elements[0] = new_expr;
}
}
continue;
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element =
wrap_element_with_collect(working_set, element);
}
continue;
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element = wrap_element_with_collect(working_set, element);
}
} else if element.has_in_variable(working_set) && !is_subexpression
{
*element = wrap_element_with_collect(working_set, element);
}
}
}
@ -5482,49 +5479,50 @@ pub fn parse_pipeline(
} => {
let mut pipeline = parse_builtin_commands(working_set, command, is_subexpression);
let let_decl_id = working_set.find_decl(b"let", &Type::Nothing);
let mut_decl_id = working_set.find_decl(b"mut", &Type::Nothing);
if pipeline_index == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Nothing) {
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
{
if Some(call.decl_id) == let_decl_id
|| Some(call.decl_id) == mut_decl_id
{
if call.decl_id == let_decl_id {
// Do an expansion
if let Some(Expression {
expr: Expr::Block(block_id),
..
}) = call.positional_iter_mut().nth(1)
{
let block = working_set.get_block(*block_id);
// Do an expansion
if let Some(Expression {
expr: Expr::Block(block_id),
..
}) = call.positional_iter_mut().nth(1)
{
let block = working_set.get_block(*block_id);
let element = block.pipelines[0].elements[0].clone();
let element = block.pipelines[0].elements[0].clone();
if let PipelineElement::Expression(prepend, expr) = element
{
if expr.has_in_variable(working_set) {
let new_expr = PipelineElement::Expression(
prepend,
wrap_expr_with_collect(working_set, &expr),
);
if let PipelineElement::Expression(prepend, expr) = element {
if expr.has_in_variable(working_set) {
let new_expr = PipelineElement::Expression(
prepend,
wrap_expr_with_collect(working_set, &expr),
);
let block = working_set.get_block_mut(*block_id);
block.pipelines[0].elements[0] = new_expr;
}
let block = working_set.get_block_mut(*block_id);
block.pipelines[0].elements[0] = new_expr;
}
}
continue;
} else if element.has_in_variable(working_set) && !is_subexpression
{
*element = wrap_element_with_collect(working_set, element);
}
continue;
} else if element.has_in_variable(working_set) && !is_subexpression {
*element = wrap_element_with_collect(working_set, element);
}
} else if element.has_in_variable(working_set) && !is_subexpression {
*element = wrap_element_with_collect(working_set, element);
}
}
}