Spread operator for list literals#11006
Conversation
|
Your plan of action around the AST/ |
|
Regarding parsing, should It looks like If a user enters |
|
excited to see this become a thing 😇 this would help for things like that in the long term i think 👌 |
|
This comment is outdated. Original text: DetailsI made some changes to the parser to let it parse spread expressions, but I put it in a different branch in my fork and made a [PR](https://github.com/ysthakur/pull/1) in case we want to do the parsing in a different way, so we wouldn't have to revert a bunch of commits on this branch. (let me know if I should merge the PR if that makes reviewing the changes more convenient)The changes it makes are:
It doesn't check for stray spread operators yet, though. |
|
@ysthakur I'm excited about this. Please feel free to ping us if you need answers/help. |
|
I played with it and looks good. I didn't manage to break it! A few more tests covering potential edge cases would be nice, but otherwise looks good to me. I also tried nested spread ( The The manual span handling is a bit hacky, but we do it in other places in the parser, and in this PR it seems carefully checked. In our new parser experiment, that might eventually replace the current parser, we're trying to use a less error-prone style. |
|
@kubouch Do you mean that |
|
They are actually a valid syntax, so I think they shouldn't be treated as errors. |
Goes towards implementing #10598, which asks for a spread operator in lists, in records, and when calling commands (continuation of #11006, which only implements it in lists) # Description This PR is for adding a spread operator that can be used when building records. Additional functionality can be added later. Changes: - Previously, the `Expr::Record` variant held `(Expression, Expression)` pairs. It now holds instances of an enum `RecordItem` (the name isn't amazing) that allows either a key-value mapping or a spread operator. - `...` will be treated as the spread operator when it appears before `$`, `{`, or `(` inside records (no whitespace allowed in between) (not implemented yet) - The error message for duplicate columns now includes the column name itself, because if two spread records are involved in such an error, you can't tell which field was duplicated from the spans alone `...` will still be treated as a normal string outside records, and even in records, it is not treated as a spread operator when not followed immediately by a `$`, `{`, or `(`. # User-Facing Changes Users will be able to use `...` when building records. ``` > let rec = { x: 1, ...{ a: 2 } } > $rec ╭───┬───╮ │ x │ 1 │ │ a │ 2 │ ╰───┴───╯ > { foo: bar, ...$rec, baz: blah } ╭─────┬──────╮ │ foo │ bar │ │ x │ 1 │ │ a │ 2 │ │ baz │ blah │ ╰─────┴──────╯ ``` If you want to update a field of a record, you'll have to use `merge` instead: ``` > { ...$rec, x: 5 } Error: nu::shell::column_defined_twice × Record field or table column used twice: x ╭─[entry #2:1:1] 1 │ { ...$rec, x: 5 } · ──┬─ ┬ · │ ╰── field redefined here · ╰── field first defined here ╰──── > $rec | merge { x: 5 } ╭───┬───╮ │ x │ 5 │ │ a │ 2 │ ╰───┴───╯ ``` # Tests + Formatting # After Submitting
Goes towards implementing nushell#10598, which asks for a spread operator in lists, in records, and when calling commands (continuation of nushell#11006, which only implements it in lists) # Description This PR is for adding a spread operator that can be used when building records. Additional functionality can be added later. Changes: - Previously, the `Expr::Record` variant held `(Expression, Expression)` pairs. It now holds instances of an enum `RecordItem` (the name isn't amazing) that allows either a key-value mapping or a spread operator. - `...` will be treated as the spread operator when it appears before `$`, `{`, or `(` inside records (no whitespace allowed in between) (not implemented yet) - The error message for duplicate columns now includes the column name itself, because if two spread records are involved in such an error, you can't tell which field was duplicated from the spans alone `...` will still be treated as a normal string outside records, and even in records, it is not treated as a spread operator when not followed immediately by a `$`, `{`, or `(`. # User-Facing Changes Users will be able to use `...` when building records. ``` > let rec = { x: 1, ...{ a: 2 } } > $rec ╭───┬───╮ │ x │ 1 │ │ a │ 2 │ ╰───┴───╯ > { foo: bar, ...$rec, baz: blah } ╭─────┬──────╮ │ foo │ bar │ │ x │ 1 │ │ a │ 2 │ │ baz │ blah │ ╰─────┴──────╯ ``` If you want to update a field of a record, you'll have to use `merge` instead: ``` > { ...$rec, x: 5 } Error: nu::shell::column_defined_twice × Record field or table column used twice: x ╭─[entry nushell#2:1:1] 1 │ { ...$rec, x: 5 } · ──┬─ ┬ · │ ╰── field redefined here · ╰── field first defined here ╰──── > $rec | merge { x: 5 } ╭───┬───╮ │ x │ 5 │ │ a │ 2 │ ╰───┴───╯ ``` # Tests + Formatting # After Submitting
Goes towards implementing nushell#10598, which asks for a spread operator in lists, in records, and when calling commands (continuation of nushell#11006, which only implements it in lists) # Description This PR is for adding a spread operator that can be used when building records. Additional functionality can be added later. Changes: - Previously, the `Expr::Record` variant held `(Expression, Expression)` pairs. It now holds instances of an enum `RecordItem` (the name isn't amazing) that allows either a key-value mapping or a spread operator. - `...` will be treated as the spread operator when it appears before `$`, `{`, or `(` inside records (no whitespace allowed in between) (not implemented yet) - The error message for duplicate columns now includes the column name itself, because if two spread records are involved in such an error, you can't tell which field was duplicated from the spans alone `...` will still be treated as a normal string outside records, and even in records, it is not treated as a spread operator when not followed immediately by a `$`, `{`, or `(`. # User-Facing Changes Users will be able to use `...` when building records. ``` > let rec = { x: 1, ...{ a: 2 } } > $rec ╭───┬───╮ │ x │ 1 │ │ a │ 2 │ ╰───┴───╯ > { foo: bar, ...$rec, baz: blah } ╭─────┬──────╮ │ foo │ bar │ │ x │ 1 │ │ a │ 2 │ │ baz │ blah │ ╰─────┴──────╯ ``` If you want to update a field of a record, you'll have to use `merge` instead: ``` > { ...$rec, x: 5 } Error: nu::shell::column_defined_twice × Record field or table column used twice: x ╭─[entry nushell#2:1:1] 1 │ { ...$rec, x: 5 } · ──┬─ ┬ · │ ╰── field redefined here · ╰── field first defined here ╰──── > $rec | merge { x: 5 } ╭───┬───╮ │ x │ 5 │ │ a │ 2 │ ╰───┴───╯ ``` # Tests + Formatting # After Submitting
Goes towards implementing #10598
Description
This PR is for adding a spread operator that can be used when building lists. Additional functionality can be added later.
Changes:
...as the spread operator when it appears before$,[, or(inside lists (no whitespace allowed in between)Spreadvariant in theExprenumPossible problem: Inside
parse_list_expression, since...$foois a single token, theSpanrepresenting...$foohas to be modified to only include$foobeforeparse_multispan_valuecan be called. It seems like it's merely icky and wouldn't actually cause any problems, but it's worth reviewing anyway....is still treated as a normal string outside lists, and even in lists, it is not treated as a spread operator when not followed immediately by a$,[, or(.User-Facing Changes
The
...operator will be allowed only inside lists, before variables, lists, and subexpressions in parentheses.In certain situations,
...can simplify building lists, letting you avoid++,prepend, andappend:Spreading a homogeneous list inside another homogeneous list preserves the type:
TODO more examples?
The
...bit is highlighted the same color as other operators.Tests + Formatting
The current tests cover these cases:
[ ...[ ...[ ...[ a ] b ] c ] d ])list<int>spread inside alist<int>evaluates to alist<int>, mixing types results in alist<any>)After Submitting