Open modulovalue opened 9 months ago
The spec-parser follows the specification, the analyzer is ... better. We should probably fix the spec. So, technically a bug, but let's consider whether we should fix the spec instead.
The grammar for constant patterns is:
constantPattern ::= booleanLiteral
| nullLiteral
| '-'? numericLiteral
| stringLiteral
| symbolLiteral
| qualifiedName
| constObjectExpression
| 'const' typeArguments? '[' elements? ']'
| 'const' typeArguments? '{' elements? '}'
| 'const' '(' expression ')'
That grammar does not allow const (0,)
, the parentheses around '(' expression ')'
are syntactically part of the constant pattern syntax.
We could add a | 'const' recordLiteralNoConst
as well, since it's syntactically unambiguous, and it works.
Arguably, you can remove the const
and have a record pattern instead, but if that contains a lot of const
s, it might be shorter to write:
case const (Token("watermelon"), Token("cataloupe")):
than
case (const Token("watermelon"), const Token("cataloupe")):
Here's a variant of the original example that is derivable in the specified grammar:
void main() {
if ((0,) case const ((0,))) print("foo");
}
Both dart
and dart analyze
and DartPad accept this program. As @lrhn mentions,
We could add a
| 'const' recordLiteralNoConst
in order to extend the language such that the original example can be derived. This seems to be the behavior which is already implemented, and it is also consistent with the existing constant patterns for collection literals and <constObjectExpression>
: They are just special cases that allow us to avoid those extra ()
in the general const (<expression>)
form.
Interestingly, the specification grammar in Dart.g still succeeds in parsing all language tests after changing | 'const' '(' <expression> ')'
to | 'const' <expression>
. So we might very well be able to eliminate those parentheses entirely. The cases involving collection literals would still be parsed by the preceeding alternatives (same as today), because of the ordered nature of the Dart grammar.
The problem with omitting parentheses is that it makes const a && b
ambiguous.
Right, that would presumably parse as const (a && b)
if b
parses as an expression, and as (const a) && b
if b
only parses as a pattern, and that would probably not be very readable even if it does work (especially if b
parses as an expression, but was intended as a pattern ;-).
With that, I think adding | 'const' recordLiteralNoConst
looks good! (.. and it is presumably just a spec change, because the tools do this already).
Consider the following program:
It compiles without errors, prints out
foo
and terminates successfully on DartPad.However, a parser compiled from the ANTLR-grammar seems to reject this program.
These are the parse trees that the analyzer and ANTLR report:
It appears that either the implementation is not meant to support records as
constantPattern
s, or that the spec is missing, e.g., recordPatterns with a leading const as a production in theconstantPattern
production rule.