Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Rename Pattern to Bindings and share parsing logic with Assignment Target #1839

Merged
merged 46 commits into from
Dec 2, 2021

Conversation

MichaReiser
Copy link
Contributor

@MichaReiser MichaReiser commented Dec 1, 2021

Sorry, it seems this escalated quite a bit. I wasn't aware, that patterns are used in so many different places in our codebase

Summary

#1805 separated assignment targets out from patterns. This PR now renames the "remaining" patterns to bindings. Bindings are different from assignment targets because they bind a new name in the current scope and assign a value to it rather than assigning a value to an existing name.

This PR further restructures Patterns as specified in #1719.

  • Renames Pattern to JsAnyBinding
  • Replaces AssignPattern with JsBindingWithDefault
  • Deletes PatternOrExpr
  • Replace SinglePattern with JsIdentifierBinding
  • Replace RestPattern with JsArrayRestBinding and JsObjectRestBinding. Remove it from the Pattern union (only permitted inside of arrays/objects)
  • Rename ObjectPattern to JsObjectBinding
  • Replace KeyValuePattern with JsShorthandPropertyBinding and JsPropertyBinding
  • Rename ArrayPattern to JsArrayBinding
  • Remove ExprPattern
  • Unify SpreadElement and JsSpread
  • Deleted InitializedProp (not valid JS nor TS syntax???)

This PR extracts the common logic for parsing Patterns from assignment_target as traits into pattern.rs that I then used to parse bindings.

Part of #1725

Test Plan

Verified coverage, added new test cases.

All libs are now parsing without panicking. Performance is roughly the same

@github-actions
Copy link

github-actions bot commented Dec 1, 2021

Test262 comparison coverage results on ubuntu-latest

Test result main count This PR count Difference
Total 17608 17608 0
Passed 17068 17084 ✅ ⏫ +16
Failed 539 523 ✅ ⏬ -16
Panics 1 1 0
Coverage 96.93% 97.02% +0.09%

@github-actions
Copy link

github-actions bot commented Dec 1, 2021

Test262 comparison coverage results on windows-latest

Test result main count This PR count Difference
Total 17608 17608 0
Passed 17068 17084 ✅ ⏫ +16
Failed 539 523 ✅ ⏬ -16
Panics 1 1 0
Coverage 96.93% 97.02% +0.09%
Fixed tests (16):
xtask/src/coverage/test262/test\language\expressions\arrow-function\syntax\early-errors\arrowparameters-bindingidentifier-no-arguments.js
xtask/src/coverage/test262/test\language\expressions\arrow-function\syntax\early-errors\arrowparameters-bindingidentifier-no-eval.js
xtask/src/coverage/test262/test\language\expressions\async-arrow-function\await-as-param-ident-nested-arrow-parameter-position.js
xtask/src/coverage/test262/test\language\expressions\async-arrow-function\await-as-param-rest-nested-arrow-parameter-position.js
xtask/src/coverage/test262/test\language\expressions\async-arrow-function\await-as-param-nested-arrow-parameter-position.js
xtask/src/coverage/test262/test\language\expressions\async-arrow-function\early-errors-arrow-await-in-formals-default.js
xtask/src/coverage/test262/test\language\expressions\async-arrow-function\early-errors-arrow-await-in-formals.js
xtask/src/coverage/test262/test\language\expressions\class\class-name-ident-await-module.js
xtask/src/coverage/test262/test\language\expressions\class\class-name-ident-let.js
xtask/src/coverage/test262/test\language\expressions\object\cover-initialized-name.js
xtask/src/coverage/test262/test\language\future-reserved-words\let-strict.js
xtask/src/coverage/test262/test\language\reserved-words\await-module.js
xtask/src/coverage/test262/test\language\statements\class\class-name-ident-await-module.js
xtask/src/coverage/test262/test\language\statements\class\class-name-ident-let.js
xtask/src/coverage/test262/test\language\statements\labeled\value-await-module.js
xtask/src/coverage/test262/test\language\statements\let\syntax\identifier-let-allowed-as-lefthandside-expression-strict.js

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 1, 2021

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5eaade0
Status: ✅  Deploy successful!
Preview URL: https://2a0145de.tools-8rn.pages.dev

View logs


let mut opt = None;

if p.at(T![?]) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the TypeScript handling for now. The recovery logic here is incorrect and we need to re-think the logic now that assign pattern is no longer a thing

crates/rslint_parser/src/syntax/decl.rs Show resolved Hide resolved
@@ -898,42 +913,42 @@ pub fn primary_expr(p: &mut Parser) -> Option<CompletedMarker> {
} else {
// `async a => {}` and `async (a) => {}`
if p.state.potential_arrow_start
&& token_set![T![ident], T![yield], T!['(']].contains(p.nth(1))
&& token_set![T![ident], T![yield], T![await], T!['(']].contains(p.nth(1))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes an issue where async await => {} isn't recognized as a arrow function

{
let mut guard = p.with_state(ParserState {
let in_async_p = &mut *p.with_state(ParserState {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the parameters must be parsed with async set to true to detect if e.g. await is a valid or invalid identifier.

@@ -156,14 +156,6 @@ fn parse_object_member(p: &mut Parser) -> ParsedSyntax {
parse_method_object_member_body(p);
Present(m.complete(p, JS_METHOD_OBJECT_MEMBER))
} else if let Some(mut member_name) = member_name {
// test object_expr_assign_prop
// let b = { foo = 4, foo = bar }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't valid JS nor TS syntax...???

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not a valid syntax

@MichaReiser MichaReiser marked this pull request as ready for review December 1, 2021 09:06
@MichaReiser MichaReiser mentioned this pull request Dec 1, 2021
47 tasks
Copy link
Contributor

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a lot of code and it will take time for me to review. For now I leave some feedback and question:

  • we should add new tests to the formatter for array binding. It seems we don't have them, other than simple.js;
  • why did you use traits in this case? what's the endgame? The documentation doesn't explain that part and I can see you implemented the traits just once, which means that it could have been a struct or an enum;

crates/rslint_parser/src/parser/parsed_syntax.rs Outdated Show resolved Hide resolved
crates/rslint_parser/src/syntax/assignment_target.rs Outdated Show resolved Hide resolved
crates/rslint_parser/src/syntax/binding.rs Outdated Show resolved Hide resolved
crates/rslint_parser/src/syntax/decl.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/expr.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/expr.rs Show resolved Hide resolved
@@ -156,14 +156,6 @@ fn parse_object_member(p: &mut Parser) -> ParsedSyntax {
parse_method_object_member_body(p);
Present(m.complete(p, JS_METHOD_OBJECT_MEMBER))
} else if let Some(mut member_name) = member_name {
// test object_expr_assign_prop
// let b = { foo = 4, foo = bar }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not a valid syntax

crates/rslint_parser/src/syntax/pattern.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/pattern.rs Outdated Show resolved Hide resolved
@MichaReiser
Copy link
Contributor Author

It's a lot of code and it will take time for me to review. For now I leave some feedback and question:

Thanks for taking the time!

* we should add new tests to the formatter for array binding. It seems we don't have them, other than `simple.js`;

I'm not sure if that code is final. I just moved the files from the pattern to the bindings folder and renamed them. I don't know why git doesn't recognize the moves. I would leave it for now because this PR isn't touching the formatter code and we need to revisit all implementations anyway.

* why did you use traits in this case? what's the endgame? The documentation doesn't explain that part and I can see you implemented the traits just once, which means that it could have been a `struct` or an `enum`;

The traits are implemented twice: Once for Bindings and once for AssignmentTarget. For example, ObjectAssignmentTarget and ArrayAssignmentTarget both implement the ParseObjectPattern trait.

// let let = 5;
// const let = 5;
// let a, a;
pub(crate) fn parse_identifier_binding(p: &mut Parser) -> ConditionalParsedSyntax {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should start documenting those methods that are ConditionalParsedSyntax and explain why they return this type (and have it as a rule inside the CONTRIBUTING.md file). To be more precise, we know that ConditionalParsedSyntax can be used for different reasons (languages features, super language, browser version, etc.), although by looking at method, it's difficult to know. Having a documentation with some snippet might help?

We should explain what's the syntax that can differ.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that makes sense. I also need to revisit the ConditionalParsedSyntax. The way it currently works (where Absent values can be invalid too`) is super awkward to use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also still figuring this out. So far I thought it's a good idea to make the or_invalid_to_unknown conversion right inside of the parse function but it turned out that is dangerous.

For example, the class or function id, a single arrow function parameter or an object rest pattern don't support JsAnyBinding and, therefore, returning a JsUnknownBinding is invalid in these cases. So it seems, all we can do in these cases is to bubble up the error until we come to a place where we can handle it.

This is a bit annoying. An alternative would be to just add a diagnostic and keep the binding as is. This would certainly be easier but we then no longer have a strict rule when to use unknown:

  • any syntax error (additional syntax) -> Content is inside of an Unknown node
  • missing syntax -> Empty slot, handled in the AST facade

We need to get some more experience how to handle and we may come back to this change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bumped into this too while refactoring class.rs, where some function uses or_invalid_to_unknown under to hood but it is "hidden" and we don't know what's happening

crates/rslint_parser/src/syntax/binding.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/binding.rs Outdated Show resolved Hide resolved
crates/rslint_parser/src/syntax/class.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/decl.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/pattern.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/pattern.rs Outdated Show resolved Hide resolved
crates/rslint_parser/src/syntax/pattern.rs Show resolved Hide resolved
crates/rslint_parser/src/syntax/pattern.rs Outdated Show resolved Hide resolved
@MichaReiser
Copy link
Contributor Author

Update on await. It's a valid identifier in scripts (outside of async) functions but not in modules.

I added one more check to disallow let as an identifier in strict mode (see coverage improvements)

@MichaReiser MichaReiser merged commit 9f2cdc0 into main Dec 2, 2021
@MichaReiser MichaReiser deleted the feature/bindings branch December 2, 2021 13:32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants