Avoid tokenizing `[]=` as a single token whereit cannot possibly be valid.
void main() {if([]==[]);} // ERROR at first `[]`
Results in parsing errors from both dart runand analysis when editing in VS Code. Parenthesizing works - for example
void main() {if(([])==[]);} // OK
Seems to have something to do with operators:
if([]+[]==[]); // ERROR at `[]+[]`
I would expect it to work without parenthesizing, just like a member access or invocation
void main()
{ if([].reversed=={}); // OK
}
Thoughts?
CC @johnniwinther @scheglov Either correct or incorrect behavior in parsing []== I think 😅 . I'm not sure which.
I tried checking with the latest grammar and it says
17.27 - ⟨equalityExpression⟩::=⟨relationalExpression⟩(⟨equalityOperator⟩⟨relationalExpression⟩)?
And then 17.28 says - ⟨relationalExpression⟩::=⟨bitwiseOrExpression⟩(⟨typeTest⟩|⟨typeCast⟩|⟨relationalOperator⟩⟨bitwiseOrExpression⟩)?
Where is specifying a list as an operand for equality defined?
@eernstg I guess the grammar supports this so it is a parser issue?
Sounds right!
@RohitSaily, the grammar in the language specification needs to be amended according to feature specifications of features that have been added to the language and implementation, but haven't yet been integrated into the language specification.
(Yes, it would have been great if the language specification already included all those recent changes, but we have prioritized creating the new features in the first place.)
As a supplement to the language specification, you can look into https://github.com/dart-lang/language/tree/main/accepted to find the feature specifications where grammar updates are described. Moreover, you can use Dart.g as a good approximation of the current grammar at any point in time.
Perhaps the tools are tokenizing the code such that []= is considered to be a single token (e.g., used when declaring an operator []=(...))?
The tokenization in Dart.g uses '[' ']' '=', exactly because it should be possible to recognize []= in the source code also when it is intended to be something which is not the name of the index setter. If it is considered useful or even important to reject a declaration like void operator [ ] = (_, _) because of the spaces then it can be done by checking the offsets of [ and ] and = after parsing has completed.
Tokenization as if ([]= = []) is what I expect too.
Normally I'd check how the formatter would lay it out, but that only works if the code parses.
Checking in DartPad:
- The analyzer underlines the three characters
[]=. - Adding a space, making it
if ([] ==[])removes the error.
Pretty certainly that's the issue, so I'd say "working as intended".
For if([]+[]==[]);, the error is also at the []=, which is not a valid expression token, making []+[]= not a valid expression.
The []= token isn't a useful token anywhere except after operator or #, so anywhere else the parser could perhaps be allowed to split it into [, ] and = (and then it may need to combine the = with what follows, which could get complicated).
@eernstg
As a supplement to the language specification, you can look into https://github.com/dart-lang/language/tree/main/accepted to find the feature specifications where grammar updates are described. Moreover, you can use Dart.g as a good approximation of the current grammar at any point in time.
Thanks for the resources, that is good to know. I searched throughout Dart.g but I still cannot see how a list literal in an equality expression can be derived from the grammar. Is that something that needs to still be added?
@lrhn
The []= token isn't a useful token anywhere except after operator or #, so anywhere else the parser could perhaps be allowed to split it into [, ] and = (and then it may need to combine the = with what follows, which could get complicated).
Sounds like a good solution to me.
Only thing I was wondering - is it possible to specify []= directly elsewhere eg as a function tear-off?
The only place the []= token occurs in the language grammar is the <operator> production, which only occurs in a declaration after operator and in a symbol literal after #. Those are the only two places that token can validly occur.
Keeping this open as a request to make []= not work as a single token in places where that token cannot occur.
(Or at least give better error messages when seeing []==.)