21:31 | <shu> | rbuckton: (or anyone else who is a grammar expert): i don't understand the await using cover grammar |
21:32 | <shu> | the stage 3 spec draft has this: |
21:33 | <shu> | CoverAwaitExpressionAndAwaitUsingDeclarationHead and AwaitExpression are exactly the same. how can you refine a grammar with the same grammar? |
21:38 | <shu> | the intention must've been that await using x in StatementItemList position is parsed in its entire 3 tokens by AwaitUsingDeclaration instead of the first 2 tokens by AwaitExpression, but i don't think you can express that by having a cover grammar for the first two tokens only |
21:38 | <shu> | i don't know how else to express this though |
21:39 | <shu> | or wait, is that how cover grammars work? |
21:42 | <rbuckton> | It works the same way as CoverCallExpressionAndAsyncArrowHead , which refines to CallMemberExpression (which is identical) |
21:46 | <rbuckton> | The difference is that you can parse the cover in places you can't parse AwaitExpression on its own, such as await using x . await using isn't a legal AwaitExpression if an identifier follows it on the same line, but its parse can be reused for AwaitUsingDeclaration |
21:48 | <rbuckton> | Just like async(x) is a valid call expression as long as it's not followed by a => (or any other illegal token) |
21:48 | <shu> | oh huh, i see |
21:49 | <rbuckton> | The cover is essentially eagerly parsing out the syntax. Some covers allow more tokens than what any single refinement might use, but that isn't always the case. |
21:51 | <shu> | i'm trying to understand why this can't be expressed as AwaitUsingDeclaration: await [ntl] using [ntl] BindingList without a cover |
21:57 | <shu> | it's still the case that there's no valid parse of that sequence of tokens with an AwaitExpression |
22:00 | <rbuckton> | Given the source text await using x = y , you have two potential parses for await using : An ExpressionStatement containing an AwaitExpresion, or a LexicalDeclaration containing an AwaitUsingDeclaration. You have to consider both parses as equally viable until they are not. For ExpressionStatement, you descend through Expression to parse await using , but ExpressionStatement must end in a ; . Since x is not ; , it's not a valid ExpressionStatement. For LexicalDeclaration, you can parse await using followed by an identifier and that matches an AwaitUsingDeclaration.It's only after both of these potential parses fail that ASI is considered, and a ; would only be inserted after await using if there was a line terminator before the x . |
22:01 | <rbuckton> | Given the source
The same process occurs, except the NLT restriction means AwaitUsingDeclaration isn't a valid parse in that case |
22:04 | <shu> | ah, it's ASI |
22:04 | <shu> | got it |
22:04 | <shu> | well that's also fucking terrible |
22:06 | <rbuckton> | In TypeScript I just do two token lookahead. If I'm on await and the next token is using , I check that the token that follows it is not an Identifier on the same line. |
22:08 | <rbuckton> | We try to say that ECMA262 is LR(1), but we have a single two-token lookahead with [ lookahead != `let` `[` ] for ExpressionStatement that violates that. |
22:10 | <rbuckton> | Maybe we could have done the same for AwaitExpression (i.e., ```await[lookahead != using` Identifier] UnaryExpression``), but I don't think we want more two-token lookahead in ECMA262. |
22:17 | <shu> | well |
22:17 | <shu> | it seems likely an implementation will use two-token lookahead to implement this cover |
22:17 | <shu> | why obscure reality? |