/******************************************************************************* * Copyright (c) 2000, 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.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; 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; 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 != 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(); } }