/******************************************************************************* * 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(); } }