Description
Java 21 extends patterns in 2 ways that affect patterns directly (relevant syntax shown with some alternatives omitted for brevity):
Patterns in switch statments can now include guard
SwitchLabel:
case CaseConstant { , CaseConstant }
case CasePattern [ Guard ]
case null [ , default ]
CasePattern:
Pattern
Guard:
when Expression
Record Patterns
Pattern:
TypePattern
RecordPattern
TypePattern:
LocalVariableDeclaration
RecordPattern:
ReferenceType ( [ PatternList ] )
PatternList :
Pattern { , Pattern }
Current state
Patterns: JavaParser currently only supports TypePatterns
in instanceof
expressions and represents these with a PatternExpr
.
Switch labels: Switch labels are represented as a list of Expressions
in the corresponding SwitchEntry
Proposed changes
1. Switch patterns
Since switch labels are currently represented as a single Expression
per label, I think the best solution in this case is to add a
class SwitchPattern {
Pattern pattern; // Using Pattern here, since this could also be a record pattern
Expression guard;
}
class to group these. The other option would be to add an Optional<Expression> guard
to all patterns and then have it be empty
for all non-switch patterns.
Another syntax change to consider is the case null [ , default ]
case. Currently, we can tell if a SwitchEntry
is the default
case by checking if the label list is empty, but with the option of having a shared null/default case, this would no longer be
true. The best solution I can think of for this is to add an isDefault
field to SwitchEntry
that will always be set in the
empty label case (meaning you can use either the empty label list or isDefault
to determine whether the entry is a default),
and will also be set in the shared null/default
case (in which case the empty label list check will return an incorrect result).
The other option I considered is to add some sort of DefaultExpr
as a placeholder, but I think that causes more trouble than it's worth.
2. Record patterns
This is the trickier change of the two. The ideal case would be to split PatternExpr
into 2 separate classes: TypePatternExpr
and
RecordPatternExpr
, both implementing a PatternExpr
interface/base class for generics. This would be a rather large change for
anyone currently using PatternExpr
, so an alternative could be to keep PatternExpr
as the representation for TypePattern
and to
use something like Pattern
as a common base for that and RecordPatternExpr
.
An option that avoids having two pattern classes for the different types would be to use PatternExpr
for both types of patterns.
To do this, we could add a NodeList<PatternExpr> patterns
field to PatternExpr
, which would be empty if the pattern is a TypePattern
and set to the patterns in the PatternList
otherwise. We would then also have to change the name
field of PatternExpr
to
Optional<SimpleName>
and set it to empty if the PatternExpr
is a RecordPattern
.