blob: 8927ec7482e7769b188e3d8a3a40031e05582e17 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.parser;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.compiler.ast.Statement;
public abstract class CommitRollbackParser implements TerminalTokens, ParserBasicInformation {
// resumeOnSyntaxError codes:
protected static final int HALT = 0; // halt and throw up hands.
protected static final int RESTART = 1; // stacks adjusted, alternate goal from check point.
protected static final int RESUME = 2; // stacks untouched, just continue from where left off.
public Scanner scanner;
public int currentToken;
protected int kurrentToken; // copy of currentToken as it is trampled over all over the place :-(
public CommitRollbackParser snapShot;
private static final int[] RECOVERY_TOKENS = new int [] { TokenNameSEMICOLON, TokenNameRPAREN,};
protected CommitRollbackParser createSnapShotParser() {
return new Parser();
}
protected void commit() {
if (this.snapShot == null) {
this.snapShot = createSnapShotParser();
}
this.snapShot.copyState(this);
}
public void copyState(CommitRollbackParser commitRollbackParser) {
// Subclasses should implement.
}
protected int getNextToken() {
try {
return this.scanner.getNextToken();
} catch (InvalidInputException e) {
return TokenNameEOF;
}
}
protected void shouldStackAssistNode() {
// Not relevant here.
}
// We get here on real syntax error or syntax error triggered by fake EOF at completion site, never due to triggered recovery.
protected int fallBackToSpringForward(Statement unused) {
int nextToken;
boolean atCompletionSite = false;
int automatonState = automatonState();
// If triggered fake EOF at completion site, see if the real next token would have passed muster.
if (this.kurrentToken == TokenNameEOF) {
if (this.scanner.eofPosition < this.scanner.source.length) {
atCompletionSite = true;
this.scanner.eofPosition = this.scanner.source.length;
nextToken = getNextToken();
if (automatonWillShift(nextToken, automatonState)) {
this.currentToken = this.kurrentToken = nextToken;
return RESUME;
}
} else {
nextToken = TokenNameEOF;
}
} else {
nextToken = this.kurrentToken;
}
if (nextToken == TokenNameEOF)
return HALT; // don't know how to proceed.
this.scanner.ungetToken(nextToken); // spit out what has been bitten more than we can chew.
// OK, next token is no good to resume "in place", attempt some local repair. FIXME: need to make sure we don't get stuck keep reducing empty statements !!
for (int i = 0, length = RECOVERY_TOKENS.length; i < length; i++) {
if (automatonWillShift(RECOVERY_TOKENS[i], automatonState)) {
this.currentToken = this.kurrentToken = RECOVERY_TOKENS[i];
return RESUME;
}
}
// OK, no in place resumption, no local repair, fast forward to next statement.
if (this.snapShot == null)
return RESTART;
this.copyState(this.snapShot);
if (atCompletionSite) {
this.currentToken = TokenNameSEMICOLON;
shouldStackAssistNode();
return RESUME;
}
this.currentToken = this.scanner.fastForward(unused);
return RESUME;
}
public abstract int automatonState();
public abstract boolean automatonWillShift(int nextToken, int lastAction);
}