Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java')
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java113
1 files changed, 93 insertions, 20 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
index c6e034923..df2f36595 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -367,6 +367,17 @@ public class Scanner implements TerminalTokens {
public boolean returnOnlyGreater = false;
public boolean insideRecovery = false;
+ /**
+ * Look back for the two most recent tokens.
+ * <ul>
+ * <li><code>lookBack[1]</code> is the previous token</li>
+ * <li><code>lookBack[0]</code> is the token before <code>lookBack[1]</code></li>
+ * </ul>
+ * As this look back is intended for resolving ambiguities and conflicts, it ignores whitespace and comments.
+ *
+ * @see #resetLookBack() Reset the look back and clear all stored tokens
+ * @see #addTokenToLookBack(int) Add a token to the look back, removing the oldest entry
+ */
int lookBack[] = new int[2]; // fall back to spring forward.
protected int nextToken = TokenNameNotAToken; // allows for one token push back, only the most recent token can be reliably ungotten.
private VanguardScanner vanguardScanner;
@@ -413,7 +424,8 @@ public Scanner(
this.tokenizeComments = tokenizeComments;
this.tokenizeWhiteSpace = tokenizeWhiteSpace;
this.sourceLevel = sourceLevel;
- this.lookBack[0] = this.lookBack[1] = this.nextToken = TokenNameNotAToken;
+ this.resetLookBack();
+ this.nextToken = TokenNameNotAToken;
this.consumingEllipsisAnnotations = false;
this.complianceLevel = complianceLevel;
this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals;
@@ -1619,8 +1631,7 @@ public int getNextToken() throws InvalidInputException {
}
if (this.activeParser == null) { // anybody interested in the grammatical structure of the program should have registered.
if (token != TokenNameWHITESPACE) {
- this.lookBack[0] = this.lookBack[1];
- this.lookBack[1] = token;
+ addTokenToLookBack(token);
this.multiCaseLabelComma = false;
}
return token;
@@ -1632,8 +1643,7 @@ public int getNextToken() throws InvalidInputException {
} else if (mayBeAtCasePattern(token)) {
token = disambiguateCasePattern(token, this);
}
- this.lookBack[0] = this.lookBack[1];
- this.lookBack[1] = token;
+ addTokenToLookBack(token);
this.multiCaseLabelComma = false;
return token;
}
@@ -3692,7 +3702,8 @@ public void resetTo(int begin, int end, boolean isModuleInfo, ScanContext contex
}
this.commentPtr = -1; // reset comment stack
this.foundTaskCount = 0;
- this.lookBack[0] = this.lookBack[1] = this.nextToken = TokenNameNotAToken;
+ resetLookBack();
+ this.nextToken = TokenNameNotAToken;
this.consumingEllipsisAnnotations = false;
//{ObjectTeams: lookahead on '->':
this._insideParameterMapping = false;
@@ -3702,7 +3713,27 @@ public void resetTo(int begin, int end, boolean isModuleInfo, ScanContext contex
this.scanContext = context == null ? getScanContext(begin) : context;
this.multiCaseLabelComma = false;
}
-
+/**
+ * @see #lookBack
+ */
+final void resetLookBack() {
+ this.lookBack[0] = this.lookBack[1] = TokenNameNotAToken;
+}
+/**
+ * @see #lookBack
+ */
+final void addTokenToLookBack(int newToken) {
+ // ignore whitespace and comments
+ switch (newToken) {
+ case TokenNameWHITESPACE:
+ case TokenNameCOMMENT_LINE:
+ case TokenNameCOMMENT_BLOCK:
+ case TokenNameCOMMENT_JAVADOC:
+ return;
+ }
+ this.lookBack[0] = this.lookBack[1];
+ this.lookBack[1] = newToken;
+}
private ScanContext getScanContext(int begin) {
if (!isInModuleDeclaration())
return ScanContext.INACTIVE;
@@ -4793,8 +4824,14 @@ private int internalScanIdentifierOrKeyword(int index, int length, char[] data)
&& (data[++index] == 't')
&& (data[++index] == 'h'))
return TokenNamewith;
- else
//{ObjectTeams: check for with, when keywords
+ else
+/* orig:
+ else if ((data[++index] == 'h')
+ && (data[++index] == 'e')
+ && (data[++index] == 'n'))
+ return disambiguatedRestrictedIdentifierWhen(TokenNameRestrictedIdentifierWhen);
+ :giro */
switch (data[++index]) {
case 'i':
if ( this._isOTSource
@@ -4806,7 +4843,7 @@ private int internalScanIdentifierOrKeyword(int index, int length, char[] data)
if ( this._isOTSource
&& (data[++index] == 'e')
&& (data[++index] == 'n'))
- return TokenNamewhen;
+ return disambiguatedRestrictedIdentifierWhen(TokenNameRestrictedIdentifierWhen);
}
//Markus Witte}
return TokenNameIdentifier;
@@ -5278,6 +5315,8 @@ public String toStringAction(int act) {
switch (act) {
case TokenNameIdentifier :
return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ case TokenNameRestrictedIdentifierWhen :
+ return "when"; //$NON-NLS-1$
case TokenNameRestrictedIdentifierYield :
return "yield"; //$NON-NLS-1$
case TokenNameRestrictedIdentifierrecord :
@@ -5646,6 +5685,7 @@ public static boolean isKeyword(int token) {
case TerminalTokens.TokenNameRestrictedIdentifierrecord:
case TerminalTokens.TokenNameRestrictedIdentifiersealed:
case TerminalTokens.TokenNameRestrictedIdentifierpermits:
+ case TerminalTokens.TokenNameRestrictedIdentifierWhen:
// making explicit - not a (restricted) keyword but restricted identifier.
//$FALL-THROUGH$
default:
@@ -5694,8 +5734,7 @@ private static final class VanguardScanner extends Scanner {
token = TokenNameAT308;
}
}
- this.lookBack[0] = this.lookBack[1];
- this.lookBack[1] = token;
+ this.addTokenToLookBack(token);
this.multiCaseLabelComma = false;
return token == TokenNameEOF ? TokenNameNotAToken : token;
}
@@ -5714,8 +5753,10 @@ private static class Goal {
static int BlockStatementoptRule = 0;
static int YieldStatementRule = 0;
static int SwitchLabelCaseLhsRule = 0;
+ static int GuardRule = 0;
static int[] RestrictedIdentifierSealedRule;
static int[] RestrictedIdentifierPermitsRule;
+ static int[] RestrictedIdentifierWhenRule;
static int[] PatternRules;
static Goal LambdaParameterListGoal;
@@ -5727,12 +5768,15 @@ private static class Goal {
static Goal SwitchLabelCaseLhsGoal;
static Goal RestrictedIdentifierSealedGoal;
static Goal RestrictedIdentifierPermitsGoal;
+ static Goal RestrictedIdentifierWhenGoal;
static Goal PatternGoal;
+ static int[] EMPTY_FOLLOW_SET = new int[0];
static int[] RestrictedIdentifierSealedFollow = { TokenNameclass, TokenNameinterface,
TokenNameenum, TokenNameRestrictedIdentifierrecord };// Note: enum/record allowed as error flagging rules.
static int[] RestrictedIdentifierPermitsFollow = { TokenNameLBRACE };
- static int[] PatternCaseLabelFollow = {TokenNameCOLON, TokenNameARROW, TokenNameCOMMA, TokenNameBeginCaseExpr};
+ static int[] PatternCaseLabelFollow = {TokenNameCOLON, TokenNameARROW, TokenNameCOMMA, TokenNameBeginCaseExpr, TokenNameRestrictedIdentifierWhen};
+ static int[] GuardFollow = EMPTY_FOLLOW_SET;
static {
@@ -5771,17 +5815,18 @@ private static class Goal {
if ("TypePattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
patternStates.add(i);
else
- if ("PrimaryPattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
+ if ("Pattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
patternStates.add(i);
else
- if ("GuardedPattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
+ if ("ParenthesizedPattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
patternStates.add(i);
else
- if ("Pattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
+ if ("RecordPattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
patternStates.add(i);
else
- if ("ParenthesizedPattern".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
- patternStates.add(i);
+ if ("Expression".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
+ GuardRule = i;
+
}
RestrictedIdentifierSealedRule = ridSealed.stream().mapToInt(Integer :: intValue).toArray(); // overkill but future-proof
RestrictedIdentifierPermitsRule = ridPermits.stream().mapToInt(Integer :: intValue).toArray();
@@ -5796,6 +5841,7 @@ private static class Goal {
SwitchLabelCaseLhsGoal = new Goal(TokenNameARROW, new int [0], SwitchLabelCaseLhsRule);
RestrictedIdentifierSealedGoal = new Goal(TokenNameRestrictedIdentifiersealed, RestrictedIdentifierSealedFollow, RestrictedIdentifierSealedRule);
RestrictedIdentifierPermitsGoal = new Goal(TokenNameRestrictedIdentifierpermits, RestrictedIdentifierPermitsFollow, RestrictedIdentifierPermitsRule);
+ RestrictedIdentifierWhenGoal = new Goal(TokenNameRestrictedIdentifierWhen, GuardFollow, GuardRule);
PatternGoal = new Goal(TokenNameBeginCaseElement, PatternCaseLabelFollow, PatternRules);
}
@@ -5814,7 +5860,7 @@ private static class Goal {
boolean hasBeenReached(int act, int token) {
/*
- System.out.println("[Goal = " + Parser.name[Parser.non_terminal_index[Parser.lhs[this.rule]]] + "] " + "Saw: " + Parser.name[Parser.non_terminal_index[Parser.lhs[act]]] + "::" + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ System.out.println("[Goal = " + Parser.name[Parser.non_terminal_index[Parser.lhs[act]]] + "] " + "Saw: " + Parser.name[Parser.non_terminal_index[Parser.lhs[act]]] + "::" + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Parser.name[Parser.terminal_index[token]]);
*/
boolean foundRule = false;
@@ -6010,6 +6056,24 @@ protected final boolean mayBeAtCasePattern(int token) {
return (!isInModuleDeclaration() && JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(this.complianceLevel, this.previewEnabled))
&& (token == TokenNamecase || this.multiCaseLabelComma);
}
+protected boolean mayBeAtGuard(int token) {
+ if (isInModuleDeclaration())
+ return false;
+ if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(this.complianceLevel, this.previewEnabled))
+ return false;
+ /*
+ * A simple elimination optimization for some common possible cases. According to the JLS 19 including
+ * patterns-switch and record-patterns Section 14.30.1, a guard may only be preceded by either right parentheses or
+ * an identifier. However, we may still encounter comments, whitespace or the not-a-token token.
+ */
+ switch (this.lookBack[1]) {
+ case TokenNameRPAREN:
+ case TokenNameIdentifier:
+ case TokenNameNotAToken: // TODO is this useful? Some tests start scanning at "when", but this makes no sense as a Pattern is required by the JLS
+ return true;
+ }
+ return false;
+}
protected final boolean mayBeAtBreakPreview() {
return !isInModuleDeclaration() && this.breakPreviewAllowed && this.lookBack[1] != TokenNameARROW;
}
@@ -6114,7 +6178,7 @@ protected final boolean atTypeAnchor() { // Did the '@' we saw just now herald a
public void setActiveParser(ConflictedParser parser) {
this.activeParser = parser;
- this.lookBack[0] = this.lookBack[1] = TokenNameNotAToken; // no hand me downs please.
+ this.resetLookBack(); // no hand me downs please.
if (parser != null) {
this.insideModuleInfo = parser.isParsingModuleDeclaration();
}
@@ -6320,6 +6384,16 @@ int disambiguatedRestrictedIdentifiersealed(int restrictedIdentifierToken) {
return disambiguatesRestrictedIdentifierWithLookAhead(this::mayBeAtASealedRestricedIdentifier,
restrictedIdentifierToken, Goal.RestrictedIdentifierSealedGoal);
}
+int disambiguatedRestrictedIdentifierWhen(int restrictedIdentifierToken) {
+ // and here's the kludge
+ if (restrictedIdentifierToken != TokenNameRestrictedIdentifierWhen)
+ return restrictedIdentifierToken;
+ if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(this.complianceLevel, this.previewEnabled))
+ return TokenNameIdentifier;
+
+ return disambiguatesRestrictedIdentifierWithLookAhead(this::mayBeAtGuard,
+ restrictedIdentifierToken, Goal.RestrictedIdentifierWhenGoal);
+}
int disambiguatedRestrictedIdentifierYield(int restrictedIdentifierToken) {
// and here's the kludge
if (restrictedIdentifierToken != TokenNameRestrictedIdentifierYield)
@@ -6452,7 +6526,6 @@ protected int disambiguateArrowWithCaseExpr(Scanner scanner, int retToken) {
* Assumption: mayBeAtCasePattern(token) is true before calling this method.
*/
int disambiguateCasePattern(int token, Scanner scanner) {
- assert mayBeAtCasePattern(token);
int delta = token == TokenNamecase ? 4 : 0; // 4 for case.
final VanguardParser parser = getNewVanguardParser();
parser.scanner.resetTo(parser.scanner.currentPosition + delta, parser.scanner.eofPosition);

Back to the top