tc39 / proposal-extractors

Extractors for ECMAScript
http://tc39.es/proposal-extractors/
MIT License
200 stars 3 forks source link

Grammar ambiguity with `let`/`var` and LineTerminator #24

Open rbuckton opened 3 months ago

rbuckton commented 3 months ago

This was originally raised by @waldemarhorwat during the April 2024 TC39 plenary.

The current proposal grammar introduces a parser ambiguity in the following case:

let x
(a) = b

The above example is currently valid JavaScript code that would now be interpreted as an ExtractorBindingPattern.

This specific case can be resolved via a [no LineTerminator here] assertion, but @waldemarhorwat expressed concerns about this somehow affecting function calls as well:

WH: [...] that’s where the problem arises because now we’d have a no-line-break restriction inside some function calls, which makes function calls inconsistent depending on where they appear. That’s a usability issue [...]

— Meeting notes - April 11, 2024

My interpretation of this comment is that Waldemar is speaking about "function calls" in the general sense of how the extractor syntax F(a) = b shares an (intentional) resemblance to normal function call syntax F(a). If we only introduce the NLT into the ExtractorBindingPattern syntax but not the ExtractorAssignmentPattern syntax, then there is an inconsistency between the two:

// interpreted as `let a;` followed by `(a) = b;`
let x
(a) = b

// interpreted as the extractor `x(a) = b;`
x
(a) = b

However, if we introduce an NLT into the ExtractorAssignmentPattern syntax then there is a new ambiguity that is introduced as

x
(a) = b

is still interpreted as x(a) = b, but is not interpreted as an extractor, since x(a) = b is already legal JavaScript that currently always throws on assignment since the left-hand side is not a Reference. With this change, it would become an Early Error enforced by static semantics when validating the cover grammar (which we already do for other assignment patterns).

As I see it, we have two options:

  1. Introduce an NLT in ExtractorBindingPattern but not ExtractorAssignmentPattern. ExtractorBindingPattern would be mildly inconsistent with ExtractorAssignmentPattern, but ExtractorAssignmentPattern would remain consistent with a normal CallExpression.
  2. Introduce an NLT in both ExtractorBindingPattern and ExtractorAssignmentPattern. ExtractorBindingPattern and ExtractorAssignmentPattern would be consistent with each other, but mildly inconsistent with a normal CallExpression.

I should also note there is an additional NLT concern that must also be addressed in addition to the one discussed above:

let x
[a](b) = c

This would also require an NLT in ExtractorMemberExpression and also possibly an additional production parameter to indicate whether to enforce the NLT depending on the choice of option (1) or (2), above.

rbuckton commented 3 months ago

@waldemarhorwat: Can you clarify as to whether I have accurately described your concerns as presented at the last plenary session? Would you find the NLT inconsistency introduced by (1) a blocking concern for advancement?

waldemarhorwat commented 2 months ago

Yes, that's a good description of the issue I raised at the meeting.

I'm not in favor of introducing unusual NLT inconsistencies like this.

rbuckton commented 2 months ago

Would option 2 not be satisfactory? It maintains NLT consistency for all Extractor cases, though is mildly inconsistent with a normal function call. Though there is obvious overlap conceptually, extractors are not the same as calls.