/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-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; public class LexStream implements TerminalTokens { public static final int IS_AFTER_JUMP = 1; public static final int LBRACE_MISSING = 2; public class Token{ int kind; char[] name; int start; int end; int line; int flags; public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(name).append('[').append(kind).append(']'); buffer.append('{').append(start).append(',').append(end).append('}').append(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; 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 = tokenCache.length; boolean tokenNotFound = true; while(tokenNotFound) { try { int tokenKind = scanner.getNextToken(); if(tokenKind != TokenNameEOF) { int start = scanner.getCurrentTokenStartPosition(); int end = scanner.getCurrentTokenEndPosition(); if(!RangeUtil.isInInterval(start, end, intervalStartToSkip, intervalEndToSkip)) { Token token = new Token(); token.kind = tokenKind; token.name = scanner.getCurrentTokenSource(); token.start = start; token.end = end; token.line = scanner.getLineNumber(end); int pInterval = RangeUtil.getPreviousInterval(start, end, intervalStartToSkip, intervalEndToSkip); if(pInterval != previousInterval && (intervalFlagsToSkip[previousInterval + 1] & RangeUtil.IGNORE) == 0){ token.flags = IS_AFTER_JUMP; if((intervalFlagsToSkip[pInterval] & RangeUtil.LBRACE_MISSING) != 0){ token.flags |= LBRACE_MISSING; } } previousInterval = pInterval; tokenCache[++tokenCacheIndex % length] = token; tokenNotFound = false; } } else { int start = scanner.getCurrentTokenStartPosition(); int end = scanner.getCurrentTokenEndPosition(); Token token = new Token(); token.kind = tokenKind; token.name = CharOperation.NO_CHAR; token.start = start; token.end = end; token.line = scanner.getLineNumber(end); tokenCache[++tokenCacheIndex % length] = token; tokenCacheEOFIndex = 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 = tokenCache.length; if(index > this.tokenCacheIndex) { int tokensToRead = index - this.tokenCacheIndex; while(tokensToRead-- != 0) { readTokenFromScanner(); } } else if(this.tokenCacheIndex - length >= index) { return null; } return tokenCache[index % length]; } public int getToken() { return currentIndex = next(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() { currentIndex = -1; } public void reset(int i) { 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 - 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(scanner.source); if(currentIndex < 0) { res.append(source); } else { Token token = token(currentIndex); int curtokKind = token.kind; int curtokStart = token.start; int curtokEnd = token.end; int previousEnd = -1; for (int i = 0; i < intervalStartToSkip.length; i++) { int intervalStart = intervalStartToSkip[i]; int intervalEnd = 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(); } }