001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.parser.diagnose;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.core.compiler.InvalidInputException;
014: import org.eclipse.jdt.internal.compiler.parser.Scanner;
015: import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
016: import org.eclipse.jdt.internal.compiler.util.Util;
017:
018: public class LexStream implements TerminalTokens {
019: public static final int IS_AFTER_JUMP = 1;
020: public static final int LBRACE_MISSING = 2;
021:
022: public static class Token {
023: int kind;
024: char[] name;
025: int start;
026: int end;
027: int line;
028: int flags;
029:
030: public String toString() {
031: StringBuffer buffer = new StringBuffer();
032: buffer.append(name).append('[').append(kind).append(']');
033: buffer.append('{').append(start).append(',').append(end)
034: .append('}').append(line);
035: return buffer.toString();
036: }
037:
038: }
039:
040: private int tokenCacheIndex;
041: private int tokenCacheEOFIndex;
042: private Token[] tokenCache;
043:
044: private int currentIndex = -1;
045:
046: private Scanner scanner;
047: private int[] intervalStartToSkip;
048: private int[] intervalEndToSkip;
049: private int[] intervalFlagsToSkip;
050:
051: private int previousInterval = -1;
052: private int currentInterval = -1;
053:
054: public LexStream(int size, Scanner scanner,
055: int[] intervalStartToSkip, int[] intervalEndToSkip,
056: int[] intervalFlagsToSkip, int firstToken, int init, int eof) {
057: this .tokenCache = new Token[size];
058: this .tokenCacheIndex = 0;
059: this .tokenCacheEOFIndex = Integer.MAX_VALUE;
060: this .tokenCache[0] = new Token();
061: this .tokenCache[0].kind = firstToken;
062: this .tokenCache[0].name = CharOperation.NO_CHAR;
063: this .tokenCache[0].start = init;
064: this .tokenCache[0].end = init;
065: this .tokenCache[0].line = 0;
066:
067: this .intervalStartToSkip = intervalStartToSkip;
068: this .intervalEndToSkip = intervalEndToSkip;
069: this .intervalFlagsToSkip = intervalFlagsToSkip;
070:
071: scanner.resetTo(init, eof);
072: this .scanner = scanner;
073: }
074:
075: private void readTokenFromScanner() {
076: int length = tokenCache.length;
077: boolean tokenNotFound = true;
078:
079: while (tokenNotFound) {
080: try {
081: int tokenKind = scanner.getNextToken();
082: if (tokenKind != TokenNameEOF) {
083: int start = scanner.getCurrentTokenStartPosition();
084: int end = scanner.getCurrentTokenEndPosition();
085:
086: int nextInterval = currentInterval + 1;
087: if (intervalStartToSkip.length == 0
088: || nextInterval >= intervalStartToSkip.length
089: || start < intervalStartToSkip[nextInterval]) {
090: Token token = new Token();
091: token.kind = tokenKind;
092: token.name = scanner.getCurrentTokenSource();
093: token.start = start;
094: token.end = end;
095: token.line = Util.getLineNumber(end,
096: scanner.lineEnds, 0, scanner.linePtr);
097:
098: if (currentInterval != previousInterval
099: && (intervalFlagsToSkip[currentInterval] & RangeUtil.IGNORE) == 0) {
100: token.flags = IS_AFTER_JUMP;
101: if ((intervalFlagsToSkip[currentInterval] & RangeUtil.LBRACE_MISSING) != 0) {
102: token.flags |= LBRACE_MISSING;
103: }
104: }
105: previousInterval = currentInterval;
106:
107: tokenCache[++tokenCacheIndex % length] = token;
108:
109: tokenNotFound = false;
110: } else {
111: scanner
112: .resetTo(
113: intervalEndToSkip[++currentInterval] + 1,
114: scanner.eofPosition - 1);
115: }
116: } else {
117: int start = scanner.getCurrentTokenStartPosition();
118: int end = scanner.getCurrentTokenEndPosition();
119: Token token = new Token();
120: token.kind = tokenKind;
121: token.name = CharOperation.NO_CHAR;
122: token.start = start;
123: token.end = end;
124: token.line = Util.getLineNumber(end,
125: scanner.lineEnds, 0, scanner.linePtr);
126:
127: tokenCache[++tokenCacheIndex % length] = token;
128:
129: tokenCacheEOFIndex = tokenCacheIndex;
130: tokenNotFound = false;
131: }
132: } catch (InvalidInputException e) {
133: // return next token
134: }
135: }
136: }
137:
138: public Token token(int index) {
139: if (index < 0) {
140: Token eofToken = new Token();
141: eofToken.kind = TokenNameEOF;
142: eofToken.name = CharOperation.NO_CHAR;
143: return eofToken;
144: }
145: if (this .tokenCacheEOFIndex >= 0
146: && index > this .tokenCacheEOFIndex) {
147: return token(this .tokenCacheEOFIndex);
148: }
149: int length = tokenCache.length;
150: if (index > this .tokenCacheIndex) {
151: int tokensToRead = index - this .tokenCacheIndex;
152: while (tokensToRead-- != 0) {
153: readTokenFromScanner();
154: }
155: } else if (this .tokenCacheIndex - length >= index) {
156: return null;
157: }
158:
159: return tokenCache[index % length];
160: }
161:
162: public int getToken() {
163: return currentIndex = next(currentIndex);
164: }
165:
166: public int previous(int tokenIndex) {
167: return tokenIndex > 0 ? tokenIndex - 1 : 0;
168: }
169:
170: public int next(int tokenIndex) {
171: return tokenIndex < this .tokenCacheEOFIndex ? tokenIndex + 1
172: : this .tokenCacheEOFIndex;
173: }
174:
175: public boolean afterEol(int i) {
176: return i < 1 ? true : line(i - 1) < line(i);
177: }
178:
179: public void reset() {
180: currentIndex = -1;
181: }
182:
183: public void reset(int i) {
184: currentIndex = previous(i);
185: }
186:
187: public int badtoken() {
188: return 0;
189: }
190:
191: public int kind(int tokenIndex) {
192: return token(tokenIndex).kind;
193: }
194:
195: public char[] name(int tokenIndex) {
196: return token(tokenIndex).name;
197: }
198:
199: public int line(int tokenIndex) {
200: return token(tokenIndex).line;
201: }
202:
203: public int start(int tokenIndex) {
204: return token(tokenIndex).start;
205: }
206:
207: public int end(int tokenIndex) {
208: return token(tokenIndex).end;
209: }
210:
211: public int flags(int tokenIndex) {
212: return token(tokenIndex).flags;
213: }
214:
215: public boolean isInsideStream(int index) {
216: if (this .tokenCacheEOFIndex >= 0
217: && index > this .tokenCacheEOFIndex) {
218: return false;
219: } else if (index > this .tokenCacheIndex) {
220: return true;
221: } else if (this .tokenCacheIndex - tokenCache.length >= index) {
222: return false;
223: } else {
224: return true;
225: }
226: }
227:
228: /* (non-Javadoc)
229: * @see java.lang.Object#toString()
230: */
231: public String toString() {
232: StringBuffer res = new StringBuffer();
233:
234: String source = new String(scanner.source);
235: if (currentIndex < 0) {
236: int previousEnd = -1;
237: for (int i = 0; i < intervalStartToSkip.length; i++) {
238: int intervalStart = intervalStartToSkip[i];
239: int intervalEnd = intervalEndToSkip[i];
240:
241: res.append(source.substring(previousEnd + 1,
242: intervalStart));
243: res.append('<');
244: res.append('@');
245: res.append(source.substring(intervalStart,
246: intervalEnd + 1));
247: res.append('@');
248: res.append('>');
249:
250: previousEnd = intervalEnd;
251: }
252: res.append(source.substring(previousEnd + 1));
253: } else {
254: Token token = token(currentIndex);
255: int curtokKind = token.kind;
256: int curtokStart = token.start;
257: int curtokEnd = token.end;
258:
259: int previousEnd = -1;
260: for (int i = 0; i < intervalStartToSkip.length; i++) {
261: int intervalStart = intervalStartToSkip[i];
262: int intervalEnd = intervalEndToSkip[i];
263:
264: if (curtokStart >= previousEnd
265: && curtokEnd <= intervalStart) {
266: res.append(source.substring(previousEnd + 1,
267: curtokStart));
268: res.append('<');
269: res.append('#');
270: res.append(source.substring(curtokStart,
271: curtokEnd + 1));
272: res.append('#');
273: res.append('>');
274: res.append(source.substring(curtokEnd + 1,
275: intervalStart));
276: } else {
277: res.append(source.substring(previousEnd + 1,
278: intervalStart));
279: }
280: res.append('<');
281: res.append('@');
282: res.append(source.substring(intervalStart,
283: intervalEnd + 1));
284: res.append('@');
285: res.append('>');
286:
287: previousEnd = intervalEnd;
288: }
289: if (curtokStart >= previousEnd) {
290: res.append(source.substring(previousEnd + 1,
291: curtokStart));
292: res.append('<');
293: res.append('#');
294: if (curtokKind == TokenNameEOF) {
295: res.append("EOF#>"); //$NON-NLS-1$
296: } else {
297: res.append(source.substring(curtokStart,
298: curtokEnd + 1));
299: res.append('#');
300: res.append('>');
301: res.append(source.substring(curtokEnd + 1));
302: }
303: } else {
304: res.append(source.substring(previousEnd + 1));
305: }
306: }
307:
308: return res.toString();
309: }
310: }
|