diff --git a/org.eclipse.jdt.core.compiler.batch/grammar/java.g b/org.eclipse.jdt.core.compiler.batch/grammar/java.g index 27be6b66892..24c09fed474 100644 --- a/org.eclipse.jdt.core.compiler.batch/grammar/java.g +++ b/org.eclipse.jdt.core.compiler.batch/grammar/java.g @@ -233,7 +233,7 @@ Goal ::= '->' YieldStatement Goal ::= '->' SwitchLabelCaseLhs -- JEP 409 Sealed types Reconnaissance mission. Goal ::= RestrictedIdentifiersealed Modifiersopt -Goal ::= RestrictedIdentifierpermits PermittedSubtypes +Goal ::= RestrictedIdentifierpermits PermittedTypes -- jsr 427 -- Goal ::= BeginCaseElement Pattern Goal ::= RestrictedIdentifierWhen Expression @@ -2412,14 +2412,14 @@ ClassHeaderImplementsopt ::= $empty ClassHeaderImplementsopt -> ClassHeaderImplements /:$readableName ClassHeaderImplements:/ --- Production name hardcoded in parser. Must be ::= and not -> -PermittedSubtypes ::= ClassTypeList -/:$readableName PermittedSubtypes:/ +-- Production name hardcoded in scanner. Must be ::= and not -> +PermittedTypes ::= ClassTypeList +/:$readableName PermittedTypes:/ PermittedTypesopt -> $empty PermittedTypesopt ::= RestrictedIdentifierpermits ClassTypeList /.$putCase consumePermittedTypes(); $break ./ -/:$readableName PermittedTypes:/ +/:$readableName PermittedTypesopt:/ /:$compliance 17:/ InterfaceMemberDeclarationsopt ::= $empty @@ -3206,4 +3206,3 @@ UNDERSCORE ::= '_' $end -- need a carriage return after the $end - diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java index ffb8cd9c4ea..2122b880329 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -4765,10 +4765,9 @@ protected void consumeInterfaceHeaderName1() { } protected void consumePermittedTypes() { int length = this.astLengthStack[this.astLengthPtr--]; - //permitted types this.astPtr -= length; TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr]; - typeDecl.restrictedIdentifierStart= this.intStack[this.intPtr--]; + typeDecl.restrictedIdentifierStart = this.intStack[this.intPtr--]; System.arraycopy( this.astStack, this.astPtr + 1, @@ -4779,7 +4778,7 @@ protected void consumePermittedTypes() { rejectIllegalTypeAnnotations(typeReference); } typeDecl.bodyStart = typeDecl.permittedTypes[length-1].sourceEnd + 1; - this.listLength = 0; // reset after having read super-interfaces + this.listLength = 0; // reset after having read permitted types. // recovery if (this.currentElement != null) { this.lastCheckPoint = typeDecl.bodyStart; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java index b0510fa94c3..b7890367c06 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java @@ -18,8 +18,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.function.Predicate; - import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.InvalidInputException; import org.eclipse.jdt.internal.compiler.CompilationResult; @@ -3445,7 +3443,7 @@ else if ((data[index] == 'o') && (data[++index] == 'd') && !ScannerHelper.isJavaIdentifierPart(data[++index])) { this.currentPosition += 7; - int t = disambiguatesRestrictedIdentifierWithLookAhead(x-> !isInModuleDeclaration() && this.sourceLevel >= ClassFileConstants.JDK17, TokenNamenon_sealed, Goal.RestrictedIdentifierSealedGoal); + int t = disambiguatesRestrictedIdentifierWithLookAhead(TokenNamenon_sealed); if (t == TokenNamenon_sealed) { return TokenNamenon_sealed; } else { @@ -3527,11 +3525,9 @@ else if ((data[index] == 'o') && (data[++index] == 'i') && (data[++index] == 't') && (data[++index] == 's')) { - return disambiguatesRestrictedIdentifierWithLookAhead(x -> !isInModuleDeclaration() && this.sourceLevel >= ClassFileConstants.JDK17, - TokenNameRestrictedIdentifierpermits, - Goal.RestrictedIdentifierPermitsGoal); + return disambiguatesRestrictedIdentifierWithLookAhead(TokenNameRestrictedIdentifierpermits); } else - return TokenNameIdentifier; + return TokenNameIdentifier; } case 8 : if (areRestrictedModuleKeywordsActive() @@ -3631,9 +3627,7 @@ else if ((data[index] == 'c') && (data[++index] == 'l') && (data[++index] == 'e') && (data[++index] == 'd')) { - return disambiguatesRestrictedIdentifierWithLookAhead(x -> !isInModuleDeclaration() && this.sourceLevel >= ClassFileConstants.JDK17, - TokenNameRestrictedIdentifiersealed, - Goal.RestrictedIdentifierSealedGoal); + return disambiguatesRestrictedIdentifierWithLookAhead(TokenNameRestrictedIdentifiersealed); } else return TokenNameIdentifier; case 8 : @@ -4525,7 +4519,6 @@ public static boolean isKeyword(int token) { case TerminalTokens.TokenNameinstanceof: case TerminalTokens.TokenNamelong: case TerminalTokens.TokenNamenew: - case TerminalTokens.TokenNamenon_sealed: case TerminalTokens.TokenNamenull: case TerminalTokens.TokenNamenative: case TerminalTokens.TokenNamepublic: @@ -4554,6 +4547,7 @@ public static boolean isKeyword(int token) { case TerminalTokens.TokenNameRestrictedIdentifiersealed: case TerminalTokens.TokenNameRestrictedIdentifierpermits: case TerminalTokens.TokenNameRestrictedIdentifierWhen: + case TerminalTokens.TokenNamenon_sealed: // making explicit - not a (restricted) keyword but restricted identifier. //$FALL-THROUGH$ default: @@ -4621,8 +4615,8 @@ private static class Goal { static int BlockStatementoptRule = 0; static int YieldStatementRule = 0; static int SwitchLabelCaseLhsRule = 0; - static int[] RestrictedIdentifierSealedRule; - static int RestrictedIdentifierPermitsRule; + static int[] ModifiersoptRules; + static int PermittedTypesRule; static int[] PatternRules; static Goal LambdaParameterListGoal; @@ -4632,18 +4626,18 @@ private static class Goal { static Goal BlockStatementoptGoal; static Goal YieldStatementGoal; static Goal SwitchLabelCaseLhsGoal; - static Goal RestrictedIdentifierSealedGoal; - static Goal RestrictedIdentifierPermitsGoal; + static Goal SealedModifierGoal; + static Goal PermittedTypesGoal; static Goal PatternGoal; - static int[] RestrictedIdentifierSealedFollow = { TokenNameclass, TokenNameinterface, + static int[] SealedModifierFollow = { TokenNameclass, TokenNameinterface, TokenNameenum, TokenNameRestrictedIdentifierrecord };// Note: enum/record allowed as error flagging rules. - static int[] RestrictedIdentifierPermitsFollow = { TokenNameLBRACE }; + static int[] PermittedTypesFollow = { TokenNameLBRACE }; static int[] PatternCaseLabelFollow = {TokenNameCOLON, TokenNameARROW, TokenNameCOMMA, TokenNameBeginCaseExpr, TokenNameRestrictedIdentifierWhen}; static { - List ridSealed = new ArrayList<>(2); + List modifiersOptStates = new ArrayList<>(2); List patternStates = new ArrayList<>(); for (int i = 1; i <= ParserBasicInformation.NUM_RULES; i++) { // 0 == $acc // TODO: Change to switch @@ -4666,10 +4660,10 @@ private static class Goal { YieldStatementRule = i; else if ("Modifiersopt".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ - ridSealed.add(i); + modifiersOptStates.add(i); else - if ("PermittedSubtypes".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ - RestrictedIdentifierPermitsRule = i; + if ("PermittedTypes".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ + PermittedTypesRule = i; else if ("SwitchLabelCaseLhs".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ SwitchLabelCaseLhsRule = i; @@ -4683,7 +4677,7 @@ private static class Goal { if ("RecordPattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ patternStates.add(i); } - RestrictedIdentifierSealedRule = ridSealed.stream().mapToInt(Integer :: intValue).toArray(); // overkill but future-proof + ModifiersoptRules = modifiersOptStates.stream().mapToInt(Integer :: intValue).toArray(); // overkill but future-proof PatternRules = patternStates.stream().mapToInt(Integer :: intValue).toArray(); LambdaParameterListGoal = new Goal(TokenNameARROW, new int[] { TokenNameARROW }, LambdaParameterListRule); @@ -4693,8 +4687,8 @@ private static class Goal { BlockStatementoptGoal = new Goal(TokenNameLBRACE, new int [0], BlockStatementoptRule); YieldStatementGoal = new Goal(TokenNameARROW, new int [0], YieldStatementRule); SwitchLabelCaseLhsGoal = new Goal(TokenNameARROW, new int [0], SwitchLabelCaseLhsRule); - RestrictedIdentifierSealedGoal = new Goal(TokenNameRestrictedIdentifiersealed, RestrictedIdentifierSealedFollow, RestrictedIdentifierSealedRule); - RestrictedIdentifierPermitsGoal = new Goal(TokenNameRestrictedIdentifierpermits, RestrictedIdentifierPermitsFollow, RestrictedIdentifierPermitsRule); + SealedModifierGoal = new Goal(TokenNameRestrictedIdentifiersealed, SealedModifierFollow, ModifiersoptRules); + PermittedTypesGoal = new Goal(TokenNameRestrictedIdentifierpermits, PermittedTypesFollow, PermittedTypesRule); PatternGoal = new Goal(TokenNameBeginCaseElement, PatternCaseLabelFollow, PatternRules); } @@ -5227,14 +5221,34 @@ int disambiguatedRestrictedKeyword(int restrictedKeywordToken) { } return token; } -int disambiguatesRestrictedIdentifierWithLookAhead(Predicate checkPrecondition, int restrictedIdentifierToken, Goal goal) { - if (checkPrecondition.test(restrictedIdentifierToken)) { - VanguardParser vp = getNewVanguardParser(); - VanguardScanner vs = (VanguardScanner) vp.scanner; - vs.resetTo(this.currentPosition, this.eofPosition - 1); - if (vp.parse(goal) == VanguardParser.SUCCESS) - return restrictedIdentifierToken; +// TODO: Centralize all non-module contextual keyword recognition here. ATM, we handle sealed type related tokens. +int disambiguatesRestrictedIdentifierWithLookAhead(int restrictedIdentifierToken) { + if (isInModuleDeclaration()) + return TokenNameIdentifier; + + Goal goal; + switch (restrictedIdentifierToken) { + case TokenNameRestrictedIdentifiersealed: + case TokenNamenon_sealed: + if (this.sourceLevel < ClassFileConstants.JDK17) + return TokenNameIdentifier; + goal = Goal.SealedModifierGoal; + break; + case TokenNameRestrictedIdentifierpermits: + if (this.sourceLevel < ClassFileConstants.JDK17) + return TokenNameIdentifier; + goal = Goal.PermittedTypesGoal; + break; + default: + throw new UnsupportedOperationException("Unhandled contextual keyword"); //$NON-NLS-1$ } + + VanguardParser vp = getNewVanguardParser(); + VanguardScanner vs = (VanguardScanner) vp.scanner; + vs.resetTo(this.currentPosition, this.eofPosition - 1); + if (vp.parse(goal) == VanguardParser.SUCCESS) + return restrictedIdentifierToken; + return TokenNameIdentifier; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/parser20.rsc b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/parser20.rsc index 51fe637eb75..f652854a56a 100644 Binary files a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/parser20.rsc and b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/parser20.rsc differ diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/readableNames.props b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/readableNames.props index c49c05ba45e..d560d0b0da0 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/readableNames.props +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/readableNames.props @@ -250,8 +250,8 @@ PackageDeclarationName=PackageDeclarationName ParenthesizedCastNameAndBounds=ParenthesizedCastNameAndBounds ParenthesizedLambdaParameterList=ParenthesizedLambdaParameterList Pattern=Pattern -PermittedSubtypes=PermittedSubtypes -PermittedTypesopt=PermittedTypes +PermittedTypes=PermittedTypes +PermittedTypesopt=PermittedTypesopt PostDecrementExpression=PostDecrementExpression PostIncrementExpression=PostIncrementExpression PostfixExpression=Expression