Skip to content

Commit

Permalink
AST & generator changes for list of patterns
Browse files Browse the repository at this point in the history
Signed-off-by: David Thompson <[email protected]>
  • Loading branch information
datho7561 committed Jan 18, 2024
1 parent a1aa591 commit bf4ca9b
Show file tree
Hide file tree
Showing 41 changed files with 897 additions and 534 deletions.
2 changes: 1 addition & 1 deletion org.eclipse.jdt.core.compiler.batch/grammar/java.g
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,7 @@ CaseLabelConstantElement ::= ConstantExpression
-- following 'null' in CASE_EXPRESSION - passes through existing grammar
-- CaseLabelElement -> 'null'

CaseLabelElement ::= 'default'
CaseLabelConstantElement ::= 'default'
/.$putCase consumeCaseLabelElement(CaseLabelKind.CASE_DEFAULT); $break ./
/:$readableName CaseLabelElement:/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2577,7 +2577,7 @@ public interface IProblem {
int IllegalRecordPattern = TypeRelated + 1941;

/**
* @since 3.36
* @since 3.37
*/
int CaseLabelWithPatternMustHaveExactlyOnePattern = Internal + 1942;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,14 @@ private Expression getFirstValidExpression(BlockScope scope, SwitchStatement swi
if (e instanceof Pattern) {
scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH,
e.sourceStart, e.sourceEnd);
if (this.constantExpressions.length > 1) {
scope.problemReporter().illegalCaseLabelWithMultiplePatterns(this.constantExpressions[1], this.constantExpressions[this.constantExpressions.length - 1]);
return e;
if (this.constantExpressions.length > 1 || e instanceof GuardedPattern gp && gp.patterns.length > 1) {
PatternVariableCounter myVisitor = new PatternVariableCounter();
this.traverse(myVisitor, scope);
if (myVisitor.numVars > 0) {
scope.problemReporter().illegalCaseLabelWithMultiplePatterns(this);
}
}
return e;
} else if (e instanceof NullLiteral) {
scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH,
e.sourceStart, e.sourceEnd);
Expand Down Expand Up @@ -559,4 +563,24 @@ public LocalDeclaration getLocalDeclaration() {
return patternVariableIntroduced;
}

private class PatternVariableCounter extends ASTVisitor {

public int numVars = 0;

@Override
public boolean visit(TypePattern pattern, BlockScope scope) {
if (pattern.local != null && (pattern.local.name.length != 1 || pattern.local.name[0] != '_') && !"\\u005F".equals(pattern.local.name.toString())) { //$NON-NLS-1$
this.numVars++;
}
return true;
}

@Override
public boolean visit(RecordPattern pattern, BlockScope scope) {
if (pattern.local != null && (pattern.local.name.length != 1 || pattern.local.name[0] != '_') && !"\\u005F".equals(pattern.local.name.toString())) { //$NON-NLS-1$
this.numVars++;
}
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,49 @@

public class GuardedPattern extends Pattern {

public Pattern primaryPattern;
public Pattern[] patterns;
public Expression condition;
int thenInitStateIndex1 = -1;
int thenInitStateIndex2 = -1;
public int restrictedIdentifierStart = -1; // used only for 'when' restricted keyword.

public GuardedPattern(Pattern primaryPattern, Expression conditionalAndExpression) {
this.primaryPattern = primaryPattern;
public GuardedPattern(Pattern patterns[], Expression conditionalAndExpression) {
this.patterns = patterns;
this.condition = conditionalAndExpression;
this.sourceStart = primaryPattern.sourceStart;
if (patterns.length > 0) {
this.sourceStart = this.patterns[0].sourceStart;
} else {
this.sourceStart = conditionalAndExpression.sourceStart;
}
this.sourceEnd = conditionalAndExpression.sourceEnd;
}
@Override
public void collectPatternVariablesToScope(LocalVariableBinding[] variables, BlockScope scope) {
this.primaryPattern.collectPatternVariablesToScope(variables, scope);
addPatternVariablesWhenTrue(this.primaryPattern.getPatternVariablesWhenTrue());
for (Pattern pattern : this.patterns) {
pattern.collectPatternVariablesToScope(variables, scope);
addPatternVariablesWhenTrue(pattern.getPatternVariablesWhenTrue());
}
this.condition.collectPatternVariablesToScope(getPatternVariablesWhenTrue(), scope);
addPatternVariablesWhenTrue(this.condition.getPatternVariablesWhenTrue());
}

@Override
public LocalDeclaration getPatternVariable() {
return this.primaryPattern.getPatternVariable();
if (this.patterns.length == 1) {
return this.patterns[0].getPatternVariable();
}
return null;
}

@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
flowInfo = this.primaryPattern.analyseCode(currentScope, flowContext, flowInfo);
this.thenInitStateIndex1 = currentScope.methodScope().recordInitializationStates(flowInfo);
if (this.patterns.length >= 1) {
flowInfo = this.patterns[0].analyseCode(currentScope, flowContext, flowInfo);
this.thenInitStateIndex1 = currentScope.methodScope().recordInitializationStates(flowInfo);
}
for (int i = 1; i < this.patterns.length; i++) {
flowInfo = this.patterns[i].analyseCode(currentScope, flowContext, flowInfo);
}
FlowInfo mergedFlow = this.condition.analyseCode(currentScope, flowContext, flowInfo);
mergedFlow = mergedFlow.safeInitsWhenTrue();
this.thenInitStateIndex2 = currentScope.methodScope().recordInitializationStates(mergedFlow);
Expand All @@ -66,7 +80,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel) {
this.thenTarget = new BranchLabel(codeStream);
this.elseTarget = new BranchLabel(codeStream);
this.primaryPattern.generateOptimizedBoolean(currentScope, codeStream, this.thenTarget, this.elseTarget);
for (Pattern pattern : this.patterns ) {
pattern.generateOptimizedBoolean(currentScope, codeStream, this.thenTarget, this.elseTarget);
}
Constant cst = this.condition.optimizedBooleanConstant();

setGuardedElseTarget(currentScope, this.elseTarget);
Expand Down Expand Up @@ -105,11 +121,19 @@ public boolean isAlwaysTrue() {
}
@Override
public boolean coversType(TypeBinding type) {
return this.primaryPattern.coversType(type) && isAlwaysTrue();
if (!isAlwaysTrue()) {
return false;
}
for (Pattern pattern : this.patterns) {
if (pattern.coversType(type)) {
return true;
}
}
return false;
}
@Override
public Pattern primary() {
return this.primaryPattern;
return this.patterns.length >= 1 ? this.patterns[0] : null;
}

@Override
Expand All @@ -119,16 +143,21 @@ public void resolve(BlockScope scope) {

@Override
public boolean dominates(Pattern p) {
if (isAlwaysTrue())
return this.primaryPattern.dominates(p);
if (isAlwaysTrue()) {
for (Pattern pattern : this. patterns) {
if (pattern.dominates(p)) {
return true;
}
}
}
return false;
}

@Override
public TypeBinding resolveType(BlockScope scope) {
if (this.resolvedType != null || this.primaryPattern == null)
if (this.resolvedType != null || this.primary() == null)
return this.resolvedType;
this.resolvedType = this.primaryPattern.resolveType(scope);
this.resolvedType = this.primary().resolveType(scope);
// The following call (as opposed to resolveType() ensures that
// the implicitConversion code is set properly and thus the correct
// unboxing calls are generated.
Expand Down Expand Up @@ -158,30 +187,37 @@ public boolean visit(
return false;
}
}, scope);
return this.resolvedType = this.primaryPattern.resolvedType;
return this.resolvedType = this.primary().resolvedType;
}

@Override
public TypeBinding resolveAtType(BlockScope scope, TypeBinding u) {
if (this.resolvedType == null || this.primaryPattern == null)
if (this.resolvedType == null || this.primary() == null)
return null;
if (this.primaryPattern.coversType(u))
return this.primaryPattern.resolveAtType(scope, u);
if (this.primary().coversType(u))
return this.primary().resolveAtType(scope, u);

return this.resolvedType; //else leave the pattern untouched for now.
}

@Override
public StringBuilder printExpression(int indent, StringBuilder output) {
this.primaryPattern.print(indent, output).append(" when "); //$NON-NLS-1$
for (int i = 0; i < this.patterns.length; i++) {
this.patterns[i].print(indent, output);
if (i < this.patterns.length - 1) {
output.append(", "); //$NON-NLS-1$
}
}
output.append(" when "); //$NON-NLS-1$
return this.condition.print(indent, output);
}

@Override
public void traverse(ASTVisitor visitor, BlockScope scope) {
if (visitor.visit(this, scope)) {
if (this.primaryPattern != null)
this.primaryPattern.traverse(visitor, scope);
for (Pattern pattern : this.patterns) {
pattern.traverse(visitor, scope);
}
if (this.condition != null)
this.condition.traverse(visitor, scope);
}
Expand All @@ -190,28 +226,32 @@ public void traverse(ASTVisitor visitor, BlockScope scope) {
@Override
public void suspendVariables(CodeStream codeStream, BlockScope scope) {
codeStream.removeNotDefinitelyAssignedVariables(scope, this.thenInitStateIndex1);
this.primaryPattern.suspendVariables(codeStream, scope);
if (this.primary() != null) {
this.primary().suspendVariables(codeStream, scope);
}
}
@Override
public void resumeVariables(CodeStream codeStream, BlockScope scope) {
codeStream.addDefinitelyAssignedVariables(scope, this.thenInitStateIndex2);
this.primaryPattern.resumeVariables(codeStream, scope);
if (this.primary() != null) {
this.primary().resumeVariables(codeStream, scope);
}
}
@Override
public void resolveWithExpression(BlockScope scope, Expression expression) {
this.primaryPattern.resolveWithExpression(scope, expression);
this.primary().resolveWithExpression(scope, expression);
}
@Override
protected boolean isPatternTypeCompatible(TypeBinding other, BlockScope scope) {
return this.primaryPattern.isPatternTypeCompatible(other, scope);
return this.primary().isPatternTypeCompatible(other, scope);
}
@Override
public void wrapupGeneration(CodeStream codeStream) {
this.primaryPattern.wrapupGeneration(codeStream);
this.primary().wrapupGeneration(codeStream);
}
@Override
protected void generatePatternVariable(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel,
BranchLabel falseLabel) {
this.primaryPattern.generatePatternVariable(currentScope, codeStream, trueLabel, falseLabel);
this.primary().generatePatternVariable(currentScope, codeStream, trueLabel, falseLabel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7420,7 +7420,7 @@ protected void consumeRule(int act) {
case 478 : if (DEBUG) { System.out.println("CaseLabelConstantElement ::= ConstantExpression"); } //$NON-NLS-1$
consumeCaseLabelElement(CaseLabelKind.CASE_EXPRESSION); break;

case 479 : if (DEBUG) { System.out.println("CaseLabelElement ::= default"); } //$NON-NLS-1$
case 479 : if (DEBUG) { System.out.println("CaseLabelConstantElement ::= default"); } //$NON-NLS-1$
consumeCaseLabelElement(CaseLabelKind.CASE_DEFAULT); break;

case 484 : if (DEBUG) { System.out.println("CasePatternList ::= CasePatternList COMMA CasePattern"); } //$NON-NLS-1$
Expand Down Expand Up @@ -10339,10 +10339,18 @@ protected void consumeTypeParameterWithExtendsAndBounds() {
protected void consumeGuard() {
Expression guardExpr = this.expressionStack[this.expressionPtr--];
this.expressionLengthPtr--;
Expression pattern = this.expressionStack[this.expressionPtr];
GuardedPattern gPattern = new GuardedPattern((Pattern)pattern, guardExpr);
int patternLength = this.expressionLengthStack[this.expressionLengthPtr--];
Pattern[] patterns = new Pattern[patternLength];
System.arraycopy(
this.expressionStack,
this.expressionPtr - patternLength + 1,
patterns,
0,
patternLength);
this.expressionPtr -= patternLength;
GuardedPattern gPattern = new GuardedPattern(patterns, guardExpr);
gPattern.restrictedIdentifierStart = this.intStack[this.intPtr--];
this.expressionStack[this.expressionPtr] = gPattern;
pushOnExpressionStack(gPattern);
}
protected void consumeTypePattern() {
//name
Expand Down Expand Up @@ -10422,10 +10430,6 @@ protected void consumeRecordPattern() {
} else {
recPattern.patterns = ASTNode.NO_TYPE_PATTERNS;
}
// clear the fake modifiers created by Modifiersopt
// (expressionsLength should be 0)
int modifiersoptExpressionsLength = this.expressionLengthStack[this.expressionLengthPtr--];
this.expressionPtr -= modifiersoptExpressionsLength;
checkForDiamond(recPattern.type);
this.intPtr -= 3; // 2 for '(' and ')' and one for the 0 pushed by consumeReferenceType()
problemReporter().validateJavaFeatureSupport(JavaFeature.RECORD_PATTERNS, type.sourceStart, sourceEnd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ public interface ParserBasicInformation {
MAX_LA = 1,
NUM_RULES = 956,
NUM_TERMINALS = 140,
NUM_NON_TERMINALS = 443,
NUM_SYMBOLS = 583,
NUM_NON_TERMINALS = 442,
NUM_SYMBOLS = 582,
START_STATE = 3127,
EOFT_SYMBOL = 63,
EOLT_SYMBOL = 63,
EOFT_SYMBOL = 64,
EOLT_SYMBOL = 64,
ACCEPT_ACTION = 18662,
ERROR_ACTION = 18663;
}
Loading

0 comments on commit bf4ca9b

Please sign in to comment.