blob: 601308fbaaefcd4ca2ce4105122b5bb97cd14ee1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2012 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.diagnose;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.compiler.parser.Scanner;
import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
import org.eclipse.jdt.internal.compiler.util.Util;
public class LexStream implements TerminalTokens {
public static final int IS_AFTER_JUMP = 1;
public static final int LBRACE_MISSING = 2;
public static class Token{
int kind;
char[] name;
int start;
int end;
int line;
int flags;
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(this.name).append('[').append(this.kind).append(']');
buffer.append('{').append(this.start).append(',').append(this.end).append('}').append(this.line);
return buffer.toString();
}
}
private int tokenCacheIndex;
private int tokenCacheEOFIndex;
private Token[] tokenCache;
private int currentIndex = -1;
private Scanner scanner;
private int[] intervalStartToSkip;
private int[] intervalEndToSkip;
private int[] intervalFlagsToSkip;
private int previousInterval = -1;
private int currentInterval = -1;
private boolean awaitingColonColon;
public LexStream(int size, Scanner scanner, int[] intervalStartToSkip, int[] intervalEndToSkip, int[] intervalFlagsToSkip, int firstToken, int init, int eof) {
this.tokenCache = new Token[size];
this.tokenCacheIndex = 0;
this.tokenCacheEOFIndex = Integer.MAX_VALUE;
this.tokenCache[0] = new Token();
this.tokenCache[0].kind = firstToken;
this.tokenCache[0].name = CharOperation.NO_CHAR;
this.tokenCache[0].start = init;
this.tokenCache[0].end = init;
this.tokenCache[0].line = 0;
this.intervalStartToSkip = intervalStartToSkip;
this.intervalEndToSkip = intervalEndToSkip;
this.intervalFlagsToSkip = intervalFlagsToSkip;
this.awaitingColonColon = false;
scanner.resetTo(init, eof);
this.scanner = scanner;
}
private void readTokenFromScanner(){
int length = this.tokenCache.length;
boolean tokenNotFound = true;
while(tokenNotFound) {
try {
int tokenKind = this.scanner.getNextToken();
if (tokenKind == TokenNameBeginTypeArguments) {
this.awaitingColonColon = true;
} else if (tokenKind == TokenNameCOLON_COLON) {
this.awaitingColonColon = false;
}
if(tokenKind != TokenNameEOF) {
int start = this.scanner.getCurrentTokenStartPosition();
int end = this.scanner.getCurrentTokenEndPosition();
int nextInterval = this.currentInterval + 1;
if(this.intervalStartToSkip.length == 0 ||
nextInterval >= this.intervalStartToSkip.length ||
start < this.intervalStartToSkip[nextInterval]) {
Token token = new Token();
token.kind = tokenKind;
token.name = this.scanner.getCurrentTokenSource();
token.start = start;
token.end = end;
token.line = Util.getLineNumber(end, this.scanner.lineEnds, 0, this.scanner.linePtr);
if(this.currentInterval != this.previousInterval && (this.intervalFlagsToSkip[this.currentInterval] & RangeUtil.IGNORE) == 0){
token.flags = IS_AFTER_JUMP;
if((this.intervalFlagsToSkip[this.currentInterval] & RangeUtil.LBRACE_MISSING) != 0){
token.flags |= LBRACE_MISSING;
}
}
this.previousInterval = this.currentInterval;
this.tokenCache[++this.tokenCacheIndex % length] = token;
tokenNotFound = false;
} else {
this.scanner.resetTo(this.intervalEndToSkip[++this.currentInterval] + 1, this.scanner.eofPosition - 1);
}
} else {
int start = this.scanner.getCurrentTokenStartPosition();
int end = this.scanner.getCurrentTokenEndPosition();
Token token = new Token();
token.kind = tokenKind;
token.name = CharOperation.NO_CHAR;
token.start = start;
token.end = end;
token.line = Util.getLineNumber(end, this.scanner.lineEnds, 0, this.scanner.linePtr);
this.tokenCache[++this.tokenCacheIndex % length] = token;
this.tokenCacheEOFIndex = this.tokenCacheIndex;
tokenNotFound = false;
}
} catch (InvalidInputException e) {
// return next token
}
}
}
public Token token(int index) {
if(index < 0) {
Token eofToken = new Token();
eofToken.kind = TokenNameEOF;
eofToken.name = CharOperation.NO_CHAR;
return eofToken;
}
if(this.tokenCacheEOFIndex >= 0 && index > this.tokenCacheEOFIndex) {
return token(this.tokenCacheEOFIndex);
}
int length = this.tokenCache.length;
if(index > this.tokenCacheIndex) {
int tokensToRead = index - this.tokenCacheIndex;
while(tokensToRead-- != 0) {
readTokenFromScanner();
}
} else if(this.tokenCacheIndex - length >= index) {
return null;
}
return this.tokenCache[index % length];
}
public int getToken() {
return this.currentIndex = next(this.currentIndex);
}
public int previous(int tokenIndex) {
return tokenIndex > 0 ? tokenIndex - 1 : 0;
}
public int next(int tokenIndex) {
return tokenIndex < this.tokenCacheEOFIndex ? tokenIndex + 1 : this.tokenCacheEOFIndex;
}
public boolean afterEol(int i) {
return i < 1 ? true : line(i - 1) < line(i);
}
public void reset() {
this.currentIndex = -1;
}
public void reset(int i) {
this.currentIndex = previous(i);
}
public int badtoken() {
return 0;
}
public int kind(int tokenIndex) {
return token(tokenIndex).kind;
}
public char[] name(int tokenIndex) {
return token(tokenIndex).name;
}
public int line(int tokenIndex) {
return token(tokenIndex).line;
}
public int start(int tokenIndex) {
return token(tokenIndex).start;
}
public int end(int tokenIndex) {
return token(tokenIndex).end;
}
public int flags(int tokenIndex) {
return token(tokenIndex).flags;
}
public boolean isInsideStream(int index) {
if(this.tokenCacheEOFIndex >= 0 && index > this.tokenCacheEOFIndex) {
return false;
} else if(index > this.tokenCacheIndex) {
return true;
} else if(this.tokenCacheIndex - this.tokenCache.length >= index) {
return false;
} else {
return true;
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer res = new StringBuffer();
String source = new String(this.scanner.source);
if(this.currentIndex < 0) {
int previousEnd = -1;
for (int i = 0; i < this.intervalStartToSkip.length; i++) {
int intervalStart = this.intervalStartToSkip[i];
int intervalEnd = this.intervalEndToSkip[i];
res.append(source.substring(previousEnd + 1, intervalStart));
res.append('<');
res.append('@');
res.append(source.substring(intervalStart, intervalEnd + 1));
res.append('@');
res.append('>');
previousEnd = intervalEnd;
}
res.append(source.substring(previousEnd + 1));
} else {
Token token = token(this.currentIndex);
int curtokKind = token.kind;
int curtokStart = token.start;
int curtokEnd = token.end;
int previousEnd = -1;
for (int i = 0; i < this.intervalStartToSkip.length; i++) {
int intervalStart = this.intervalStartToSkip[i];
int intervalEnd = this.intervalEndToSkip[i];
if(curtokStart >= previousEnd && curtokEnd <= intervalStart) {
res.append(source.substring(previousEnd + 1, curtokStart));
res.append('<');
res.append('#');
res.append(source.substring(curtokStart, curtokEnd + 1));
res.append('#');
res.append('>');
res.append(source.substring(curtokEnd+1, intervalStart));
} else {
res.append(source.substring(previousEnd + 1, intervalStart));
}
res.append('<');
res.append('@');
res.append(source.substring(intervalStart, intervalEnd + 1));
res.append('@');
res.append('>');
previousEnd = intervalEnd;
}
if(curtokStart >= previousEnd) {
res.append(source.substring(previousEnd + 1, curtokStart));
res.append('<');
res.append('#');
if(curtokKind == TokenNameEOF) {
res.append("EOF#>"); //$NON-NLS-1$
} else {
res.append(source.substring(curtokStart, curtokEnd + 1));
res.append('#');
res.append('>');
res.append(source.substring(curtokEnd+1));
}
} else {
res.append(source.substring(previousEnd + 1));
}
}
return res.toString();
}
public boolean awaitingColonColon() {
return this.awaitingColonColon;
}
}