-
Notifications
You must be signed in to change notification settings - Fork 93
Description
Precedence of expression-pattern
The language grammar currently contains these productions:
constant_pattern
: constant_expression
;
constant_expression
: expression
;These imply that a pattern can be, syntactically, any expression.
However, because patterns appear within expressions, ambiguity can arise.
This document describes how we resolve these ambiguities.
Note: The grammar in grammar.md does not contain the full grammar for patterns.
In fact, we do not accept expressions looser than conditional_expression; none of them make sense for patterns.
So the basic grammar should be
constant_pattern
: conditional_expression // restricted to be a valid constant expression
;Expanded patterns grammar
We expand the pattern grammar to exclude expressions (i.e. the constant pattern),
so that we can explicitly include expressions at an appropriate precedence for the context.
In the Roslyn compiler, which uses a recursive descent parser,
we accomplish this by passing a precedence level to the function that parses a pattern.
We can express this in ANTLR:
// any pattern except a constant pattern
pattern_no_expression
: declaration_pattern
| var_pattern
| positional_pattern
| property_pattern
| discard_pattern
;
// any pattern
pattern
: pattern_no_expression
| conditional_expression // restricted to be a valid constant expression
;The is pattern expression
The grammar is currently written
relational_expression
: relational_expression 'is' pattern
;The is pattern expression would introduce an ambiguity in cases such as
_ = A is B is C;This could be interpreted syntactically as (A is B) is C or as A is (B is C). To eliminate this ambiguity, we restrict the pattern on the right-hand-side to an appropriate precedence:
relational_expression
: relational_expression 'is' pattern_no_expression
| relational_expression 'is' relational_expression // RHS restricted to be a valid constant expression
;switch expression arms
The grammar currently in the spec for switch expressions contains
switch_expression_arm
: pattern case_guard? '=>' switch_expression_arm_expression
;However, this can introduce a syntactic ambiguity if the pattern is a lambda expression:
_ = A switch {
a => b => c
}Is this a case trying to match the value of the constant expression a => b and yielding the value of c, or is it trying to match the constant expression a and yield the value b => c? Both are syntactically valid parses given the draft grammar. So we modify the grammar to eliminate the ambiguity:
switch_expression_arm
: pattern_no_expression case_guard? '=>' switch_expression_arm_expression
| null_coalescing_expression case_guard? '=>' switch_expression_arm_expression
;