org.eclipse.jdt.internal.compiler.parser.RecoveryScanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* Copyright (c) 2006, 2014 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.parser;
import java.util.Arrays;
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,
scanner.previewEnabled);
setData(data);
}
public RecoveryScanner(
boolean tokenizeWhiteSpace,
boolean checkNonExternalizedStringLiterals,
long sourceLevel,
long complianceLevel,
char[][] taskTags,
char[][] taskPriorities,
boolean isTaskCaseSensitive,
boolean isPreviewEnabled,
RecoveryScannerData data) {
super(false,
tokenizeWhiteSpace,
checkNonExternalizedStringLiterals,
sourceLevel,
complianceLevel,
taskTags,
taskPriorities,
isTaskCaseSensitive,
isPreviewEnabled);
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 filterTokens(tokens);
}
public void insertTokens(int[] tokens, int completedToken, int position) {
if(!this.record) return;
tokens = filterTokens(tokens);
if (tokens.length == 0)
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 insertTokenAhead(int token, int index) {
if(!this.record) return;
if (token == TerminalTokens.TokenNameRestrictedIdentifierrecord)
return;
int length = this.data.insertedTokens[index].length;
int [] tokens = new int [length + 1];
System.arraycopy(this.data.insertedTokens[index], 0, tokens, 1, length);
tokens[0] = token;
this.data.insertedTokens[index] = tokens;
}
public void replaceTokens(int token, int start, int end) {
replaceTokens(new int []{token}, start, end);
}
int[] filterTokens(int[] tokens) {
// if (this.sourceLevel >= ClassFileConstants.JDK14)
// return tokens;
return Arrays.stream(tokens)
.filter(x -> x != TerminalTokens.TokenNameRestrictedIdentifierrecord)
.toArray();
}
public void replaceTokens(int[] tokens, int start, int end) {
if(!this.record) return;
tokens = filterTokens(tokens);
if (tokens.length == 0)
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;
}
@Override
protected int getNextToken0() throws InvalidInputException {
if(this.pendingTokensPtr > -1) {
int pendingToken = this.pendingTokens[this.pendingTokensPtr--];
if(pendingToken == TerminalTokens.TokenNameIdentifier){
this.fakeTokenSource = FAKE_IDENTIFIER;
} else {
this.fakeTokenSource = CharOperation.NO_CHAR;
}
return pendingToken;
}
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 pendingToken = this.pendingTokens[this.pendingTokensPtr--];
if(pendingToken == TerminalTokens.TokenNameIdentifier){
this.fakeTokenSource = FAKE_IDENTIFIER;
} else {
this.fakeTokenSource = CharOperation.NO_CHAR;
}
return pendingToken;
}
}
this.skipNextInsertedTokens = -1;
}
int previousLocation = this.currentPosition;
int currentToken = super.getNextToken0();
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 pendingToken = this.pendingTokens[this.pendingTokensPtr--];
if(pendingToken == TerminalTokens.TokenNameIdentifier){
this.fakeTokenSource = FAKE_IDENTIFIER;
} else {
this.fakeTokenSource = CharOperation.NO_CHAR;
}
return pendingToken;
}
}
}
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 getNextToken0();
}
}
}
return currentToken;
}
@Override
public char[] getCurrentIdentifierSource() {
if(this.fakeTokenSource != null) return this.fakeTokenSource;
return super.getCurrentIdentifierSource();
}
@Override
public char[] getCurrentTokenSourceString() {
if(this.fakeTokenSource != null) return this.fakeTokenSource;
return super.getCurrentTokenSourceString();
}
@Override
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;
}
}