/*******************************************************************************
* Copyright (c) 2006, 2009 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.parser;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.InvalidInputException;
public class RecoveryScanner extends Scanner {
public static final char[] FAKE_IDENTIFIER= "$missing$".toCharArray(); //$NON-NLS-1$
private RecoveryScannerData data;
private int[] pendingTokens;
private int pendingTokensPtr= -1;
private char[] fakeTokenSource= null;
private boolean isInserted= true;
private boolean precededByRemoved= false;
private int skipNextInsertedTokens= -1;
public boolean record= true;
public RecoveryScanner(Scanner scanner, RecoveryScannerData data) {
super(false,
scanner.tokenizeWhiteSpace,
scanner.checkNonExternalizedStringLiterals,
scanner.sourceLevel,
scanner.complianceLevel,
scanner.taskTags,
scanner.taskPriorities,
scanner.isTaskCaseSensitive);
setData(data);
}
public RecoveryScanner(
boolean tokenizeWhiteSpace,
boolean checkNonExternalizedStringLiterals,
long sourceLevel,
long complianceLevel,
char[][] taskTags,
char[][] taskPriorities,
boolean isTaskCaseSensitive,
RecoveryScannerData data) {
super(false,
tokenizeWhiteSpace,
checkNonExternalizedStringLiterals,
sourceLevel,
complianceLevel,
taskTags,
taskPriorities,
isTaskCaseSensitive);
setData(data);
}
public void insertToken(int token, int completedToken, int position) {
insertTokens(new int[] { token }, completedToken, position);
}
private int[] reverse(int[] tokens) {
int length= tokens.length;
for (int i= 0, max= length / 2; i < max; i++) {
int tmp= tokens[i];
tokens[i]= tokens[length - i - 1];
tokens[length - i - 1]= tmp;
}
return tokens;
}
public void insertTokens(int[] tokens, int completedToken, int position) {
if (!this.record)
return;
if (completedToken > -1 && Parser.statements_recovery_filter[completedToken] != 0)
return;
this.data.insertedTokensPtr++;
if (this.data.insertedTokens == null) {
this.data.insertedTokens= new int[10][];
this.data.insertedTokensPosition= new int[10];
this.data.insertedTokenUsed= new boolean[10];
} else if (this.data.insertedTokens.length == this.data.insertedTokensPtr) {
int length= this.data.insertedTokens.length;
System.arraycopy(this.data.insertedTokens, 0, this.data.insertedTokens= new int[length * 2][], 0, length);
System.arraycopy(this.data.insertedTokensPosition, 0, this.data.insertedTokensPosition= new int[length * 2], 0, length);
System.arraycopy(this.data.insertedTokenUsed, 0, this.data.insertedTokenUsed= new boolean[length * 2], 0, length);
}
this.data.insertedTokens[this.data.insertedTokensPtr]= reverse(tokens);
this.data.insertedTokensPosition[this.data.insertedTokensPtr]= position;
this.data.insertedTokenUsed[this.data.insertedTokensPtr]= false;
}
public void replaceTokens(int token, int start, int end) {
replaceTokens(new int[] { token }, start, end);
}
public void replaceTokens(int[] tokens, int start, int end) {
if (!this.record)
return;
this.data.replacedTokensPtr++;
if (this.data.replacedTokensStart == null) {
this.data.replacedTokens= new int[10][];
this.data.replacedTokensStart= new int[10];
this.data.replacedTokensEnd= new int[10];
this.data.replacedTokenUsed= new boolean[10];
} else if (this.data.replacedTokensStart.length == this.data.replacedTokensPtr) {
int length= this.data.replacedTokensStart.length;
System.arraycopy(this.data.replacedTokens, 0, this.data.replacedTokens= new int[length * 2][], 0, length);
System.arraycopy(this.data.replacedTokensStart, 0, this.data.replacedTokensStart= new int[length * 2], 0, length);
System.arraycopy(this.data.replacedTokensEnd, 0, this.data.replacedTokensEnd= new int[length * 2], 0, length);
System.arraycopy(this.data.replacedTokenUsed, 0, this.data.replacedTokenUsed= new boolean[length * 2], 0, length);
}
this.data.replacedTokens[this.data.replacedTokensPtr]= reverse(tokens);
this.data.replacedTokensStart[this.data.replacedTokensPtr]= start;
this.data.replacedTokensEnd[this.data.replacedTokensPtr]= end;
this.data.replacedTokenUsed[this.data.replacedTokensPtr]= false;
}
public void removeTokens(int start, int end) {
if (!this.record)
return;
this.data.removedTokensPtr++;
if (this.data.removedTokensStart == null) {
this.data.removedTokensStart= new int[10];
this.data.removedTokensEnd= new int[10];
this.data.removedTokenUsed= new boolean[10];
} else if (this.data.removedTokensStart.length == this.data.removedTokensPtr) {
int length= this.data.removedTokensStart.length;
System.arraycopy(this.data.removedTokensStart, 0, this.data.removedTokensStart= new int[length * 2], 0, length);
System.arraycopy(this.data.removedTokensEnd, 0, this.data.removedTokensEnd= new int[length * 2], 0, length);
System.arraycopy(this.data.removedTokenUsed, 0, this.data.removedTokenUsed= new boolean[length * 2], 0, length);
}
this.data.removedTokensStart[this.data.removedTokensPtr]= start;
this.data.removedTokensEnd[this.data.removedTokensPtr]= end;
this.data.removedTokenUsed[this.data.removedTokensPtr]= false;
}
public int getNextToken() throws InvalidInputException {
if (this.pendingTokensPtr > -1) {
int nextToken= this.pendingTokens[this.pendingTokensPtr--];
if (nextToken == TerminalTokens.TokenNameIdentifier) {
this.fakeTokenSource= FAKE_IDENTIFIER;
} else {
this.fakeTokenSource= CharOperation.NO_CHAR;
}
return nextToken;
}
this.fakeTokenSource= null;
this.precededByRemoved= false;
if (this.data.insertedTokens != null) {
for (int i= 0; i <= this.data.insertedTokensPtr; i++) {
if (this.data.insertedTokensPosition[i] == this.currentPosition - 1 && i > this.skipNextInsertedTokens) {
this.data.insertedTokenUsed[i]= true;
this.pendingTokens= this.data.insertedTokens[i];
this.pendingTokensPtr= this.data.insertedTokens[i].length - 1;
this.isInserted= true;
this.startPosition= this.currentPosition;
this.skipNextInsertedTokens= i;
int nextToken= this.pendingTokens[this.pendingTokensPtr--];
if (nextToken == TerminalTokens.TokenNameIdentifier) {
this.fakeTokenSource= FAKE_IDENTIFIER;
} else {
this.fakeTokenSource= CharOperation.NO_CHAR;
}
return nextToken;
}
}
this.skipNextInsertedTokens= -1;
}
int previousLocation= this.currentPosition;
int currentToken= super.getNextToken();
if (this.data.replacedTokens != null) {
for (int i= 0; i <= this.data.replacedTokensPtr; i++) {
if (this.data.replacedTokensStart[i] >= previousLocation &&
this.data.replacedTokensStart[i] <= this.startPosition &&
this.data.replacedTokensEnd[i] >= this.currentPosition - 1) {
this.data.replacedTokenUsed[i]= true;
this.pendingTokens= this.data.replacedTokens[i];
this.pendingTokensPtr= this.data.replacedTokens[i].length - 1;
this.fakeTokenSource= FAKE_IDENTIFIER;
this.isInserted= false;
this.currentPosition= this.data.replacedTokensEnd[i] + 1;
int nextToken= this.pendingTokens[this.pendingTokensPtr--];
if (nextToken == TerminalTokens.TokenNameIdentifier) {
this.fakeTokenSource= FAKE_IDENTIFIER;
} else {
this.fakeTokenSource= CharOperation.NO_CHAR;
}
return nextToken;
}
}
}
if (this.data.removedTokensStart != null) {
for (int i= 0; i <= this.data.removedTokensPtr; i++) {
if (this.data.removedTokensStart[i] >= previousLocation &&
this.data.removedTokensStart[i] <= this.startPosition &&
this.data.removedTokensEnd[i] >= this.currentPosition - 1) {
this.data.removedTokenUsed[i]= true;
this.currentPosition= this.data.removedTokensEnd[i] + 1;
this.precededByRemoved= false;
return getNextToken();
}
}
}
return currentToken;
}
public char[] getCurrentIdentifierSource() {
if (this.fakeTokenSource != null)
return this.fakeTokenSource;
return super.getCurrentIdentifierSource();
}
public char[] getCurrentTokenSourceString() {
if (this.fakeTokenSource != null)
return this.fakeTokenSource;
return super.getCurrentTokenSourceString();
}
public char[] getCurrentTokenSource() {
if (this.fakeTokenSource != null)
return this.fakeTokenSource;
return super.getCurrentTokenSource();
}
public RecoveryScannerData getData() {
return this.data;
}
public boolean isFakeToken() {
return this.fakeTokenSource != null;
}
public boolean isInsertedToken() {
return this.fakeTokenSource != null && this.isInserted;
}
public boolean isReplacedToken() {
return this.fakeTokenSource != null && !this.isInserted;
}
public boolean isPrecededByRemovedToken() {
return this.precededByRemoved;
}
public void setData(RecoveryScannerData data) {
if (data == null) {
this.data= new RecoveryScannerData();
} else {
this.data= data;
}
}
public void setPendingTokens(int[] pendingTokens) {
this.pendingTokens= pendingTokens;
this.pendingTokensPtr= pendingTokens.length - 1;
}
}