001: /*******************************************************************************
002: * Copyright (c) 2006 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;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.core.compiler.InvalidInputException;
014:
015: public class RecoveryScanner extends Scanner {
016: public static final char[] FAKE_IDENTIFIER = "$missing$".toCharArray(); //$NON-NLS-1$
017:
018: private RecoveryScannerData data;
019:
020: private int[] pendingTokens;
021: private int pendingTokensPtr = -1;
022: private char[] fakeTokenSource = null;
023: private boolean isInserted = true;
024: private boolean precededByRemoved = false;
025: private int skipNextInsertedTokens = -1;
026:
027: public boolean record = true;
028:
029: public RecoveryScanner(Scanner scanner, RecoveryScannerData data) {
030: super (false, scanner.tokenizeWhiteSpace,
031: scanner.checkNonExternalizedStringLiterals,
032: scanner.sourceLevel, scanner.complianceLevel,
033: scanner.taskTags, scanner.taskPriorities,
034: scanner.isTaskCaseSensitive);
035: this .setData(data);
036: }
037:
038: public void insertToken(int token, int completedToken, int position) {
039: insertTokens(new int[] { token }, completedToken, position);
040: }
041:
042: private int[] reverse(int[] tokens) {
043: int length = tokens.length;
044: for (int i = 0, max = length / 2; i < max; i++) {
045: int tmp = tokens[i];
046: tokens[i] = tokens[length - i - 1];
047: tokens[length - i - 1] = tmp;
048: }
049: return tokens;
050: }
051:
052: public void insertTokens(int[] tokens, int completedToken,
053: int position) {
054: if (!this .record)
055: return;
056:
057: if (completedToken > -1
058: && Parser.statements_recovery_filter[completedToken] != 0)
059: return;
060:
061: this .data.insertedTokensPtr++;
062: if (this .data.insertedTokens == null) {
063: this .data.insertedTokens = new int[10][];
064: this .data.insertedTokensPosition = new int[10];
065: this .data.insertedTokenUsed = new boolean[10];
066: } else if (this .data.insertedTokens.length == this .data.insertedTokensPtr) {
067: int length = this .data.insertedTokens.length;
068: System.arraycopy(this .data.insertedTokens, 0,
069: this .data.insertedTokens = new int[length * 2][],
070: 0, length);
071: System
072: .arraycopy(
073: this .data.insertedTokensPosition,
074: 0,
075: this .data.insertedTokensPosition = new int[length * 2],
076: 0, length);
077: System
078: .arraycopy(
079: this .data.insertedTokenUsed,
080: 0,
081: this .data.insertedTokenUsed = new boolean[length * 2],
082: 0, length);
083: }
084: this .data.insertedTokens[this .data.insertedTokensPtr] = reverse(tokens);
085: this .data.insertedTokensPosition[this .data.insertedTokensPtr] = position;
086: this .data.insertedTokenUsed[this .data.insertedTokensPtr] = false;
087: }
088:
089: public void replaceTokens(int token, int start, int end) {
090: replaceTokens(new int[] { token }, start, end);
091: }
092:
093: public void replaceTokens(int[] tokens, int start, int end) {
094: if (!this .record)
095: return;
096: this .data.replacedTokensPtr++;
097: if (this .data.replacedTokensStart == null) {
098: this .data.replacedTokens = new int[10][];
099: this .data.replacedTokensStart = new int[10];
100: this .data.replacedTokensEnd = new int[10];
101: this .data.replacedTokenUsed = new boolean[10];
102: } else if (this .data.replacedTokensStart.length == this .data.replacedTokensPtr) {
103: int length = this .data.replacedTokensStart.length;
104: System.arraycopy(this .data.replacedTokens, 0,
105: this .data.replacedTokens = new int[length * 2][],
106: 0, length);
107: System
108: .arraycopy(
109: this .data.replacedTokensStart,
110: 0,
111: this .data.replacedTokensStart = new int[length * 2],
112: 0, length);
113: System.arraycopy(this .data.replacedTokensEnd, 0,
114: this .data.replacedTokensEnd = new int[length * 2],
115: 0, length);
116: System
117: .arraycopy(
118: this .data.replacedTokenUsed,
119: 0,
120: this .data.replacedTokenUsed = new boolean[length * 2],
121: 0, length);
122: }
123: this .data.replacedTokens[this .data.replacedTokensPtr] = reverse(tokens);
124: this .data.replacedTokensStart[this .data.replacedTokensPtr] = start;
125: this .data.replacedTokensEnd[this .data.replacedTokensPtr] = end;
126: this .data.replacedTokenUsed[this .data.replacedTokensPtr] = false;
127: }
128:
129: public void removeTokens(int start, int end) {
130: if (!this .record)
131: return;
132: this .data.removedTokensPtr++;
133: if (this .data.removedTokensStart == null) {
134: this .data.removedTokensStart = new int[10];
135: this .data.removedTokensEnd = new int[10];
136: this .data.removedTokenUsed = new boolean[10];
137: } else if (this .data.removedTokensStart.length == this .data.removedTokensPtr) {
138: int length = this .data.removedTokensStart.length;
139: System.arraycopy(this .data.removedTokensStart, 0,
140: this .data.removedTokensStart = new int[length * 2],
141: 0, length);
142: System.arraycopy(this .data.removedTokensEnd, 0,
143: this .data.removedTokensEnd = new int[length * 2],
144: 0, length);
145: System
146: .arraycopy(
147: this .data.removedTokenUsed,
148: 0,
149: this .data.removedTokenUsed = new boolean[length * 2],
150: 0, length);
151: }
152: this .data.removedTokensStart[this .data.removedTokensPtr] = start;
153: this .data.removedTokensEnd[this .data.removedTokensPtr] = end;
154: this .data.removedTokenUsed[this .data.removedTokensPtr] = false;
155: }
156:
157: public int getNextToken() throws InvalidInputException {
158: if (this .pendingTokensPtr > -1) {
159: int nextToken = this .pendingTokens[this .pendingTokensPtr--];
160: if (nextToken == TerminalTokens.TokenNameIdentifier) {
161: this .fakeTokenSource = FAKE_IDENTIFIER;
162: } else {
163: this .fakeTokenSource = CharOperation.NO_CHAR;
164: }
165: return nextToken;
166: }
167:
168: this .fakeTokenSource = null;
169: this .precededByRemoved = false;
170:
171: if (this .data.insertedTokens != null) {
172: for (int i = 0; i <= this .data.insertedTokensPtr; i++) {
173: if (this .data.insertedTokensPosition[i] == this .currentPosition - 1
174: && i > skipNextInsertedTokens) {
175: this .data.insertedTokenUsed[i] = true;
176: this .pendingTokens = this .data.insertedTokens[i];
177: this .pendingTokensPtr = this .data.insertedTokens[i].length - 1;
178: this .isInserted = true;
179: this .startPosition = this .currentPosition;
180: this .skipNextInsertedTokens = i;
181: int nextToken = this .pendingTokens[this .pendingTokensPtr--];
182: if (nextToken == TerminalTokens.TokenNameIdentifier) {
183: this .fakeTokenSource = FAKE_IDENTIFIER;
184: } else {
185: this .fakeTokenSource = CharOperation.NO_CHAR;
186: }
187: return nextToken;
188: }
189: }
190: this .skipNextInsertedTokens = -1;
191: }
192:
193: int previousLocation = this .currentPosition;
194: int currentToken = super .getNextToken();
195:
196: if (this .data.replacedTokens != null) {
197: for (int i = 0; i <= this .data.replacedTokensPtr; i++) {
198: if (this .data.replacedTokensStart[i] >= previousLocation
199: && this .data.replacedTokensStart[i] <= this .startPosition
200: && this .data.replacedTokensEnd[i] >= this .currentPosition - 1) {
201: this .data.replacedTokenUsed[i] = true;
202: this .pendingTokens = this .data.replacedTokens[i];
203: this .pendingTokensPtr = this .data.replacedTokens[i].length - 1;
204: this .fakeTokenSource = FAKE_IDENTIFIER;
205: this .isInserted = false;
206: this .currentPosition = this .data.replacedTokensEnd[i] + 1;
207: int nextToken = this .pendingTokens[this .pendingTokensPtr--];
208: if (nextToken == TerminalTokens.TokenNameIdentifier) {
209: this .fakeTokenSource = FAKE_IDENTIFIER;
210: } else {
211: this .fakeTokenSource = CharOperation.NO_CHAR;
212: }
213: return nextToken;
214: }
215: }
216: }
217: if (this .data.removedTokensStart != null) {
218: for (int i = 0; i <= this .data.removedTokensPtr; i++) {
219: if (this .data.removedTokensStart[i] >= previousLocation
220: && this .data.removedTokensStart[i] <= this .startPosition
221: && this .data.removedTokensEnd[i] >= this .currentPosition - 1) {
222: this .data.removedTokenUsed[i] = true;
223: this .currentPosition = this .data.removedTokensEnd[i] + 1;
224: this .precededByRemoved = false;
225: return getNextToken();
226: }
227: }
228: }
229: return currentToken;
230: }
231:
232: public char[] getCurrentIdentifierSource() {
233: if (this .fakeTokenSource != null)
234: return this .fakeTokenSource;
235: return super .getCurrentIdentifierSource();
236: }
237:
238: public char[] getCurrentTokenSourceString() {
239: if (this .fakeTokenSource != null)
240: return this .fakeTokenSource;
241: return super .getCurrentTokenSourceString();
242: }
243:
244: public char[] getCurrentTokenSource() {
245: if (this .fakeTokenSource != null)
246: return this .fakeTokenSource;
247: return super .getCurrentTokenSource();
248: }
249:
250: public RecoveryScannerData getData() {
251: return this .data;
252: }
253:
254: public boolean isFakeToken() {
255: return this .fakeTokenSource != null;
256: }
257:
258: public boolean isInsertedToken() {
259: return this .fakeTokenSource != null && this .isInserted;
260: }
261:
262: public boolean isReplacedToken() {
263: return this .fakeTokenSource != null && !this .isInserted;
264: }
265:
266: public boolean isPrecededByRemovedToken() {
267: return this .precededByRemoved;
268: }
269:
270: public void setData(RecoveryScannerData data) {
271: if (data == null) {
272: this .data = new RecoveryScannerData();
273: } else {
274: this .data = data;
275: }
276: }
277:
278: public void setPendingTokens(int[] pendingTokens) {
279: this .pendingTokens = pendingTokens;
280: this .pendingTokensPtr = pendingTokens.length - 1;
281: }
282: }
|