| /******************************************************************************* |
| * Copyright (c) 2006, 2012 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.aspectj.org.eclipse.jdt.internal.compiler.parser; |
| |
| import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; |
| import org.aspectj.org.eclipse.jdt.core.compiler.InvalidInputException; |
| |
| public class RecoveryScanner extends Scanner { |
| public static final char[] FAKE_IDENTIFIER = "$missing$".toCharArray(); //$NON-NLS-1$ |
| |
| private RecoveryScannerData data; |
| |
| private int[] pendingTokens; |
| private int pendingTokensPtr = -1; |
| private char[] fakeTokenSource = null; |
| private boolean isInserted = true; |
| private boolean precededByRemoved = false; |
| private int skipNextInsertedTokens = -1; |
| |
| public boolean record = true; |
| |
| public RecoveryScanner(Scanner scanner, RecoveryScannerData data) { |
| super(false, |
| scanner.tokenizeWhiteSpace, |
| scanner.checkNonExternalizedStringLiterals, |
| scanner.sourceLevel, |
| scanner.complianceLevel, |
| scanner.taskTags, |
| scanner.taskPriorities, |
| scanner.isTaskCaseSensitive); |
| setData(data); |
| } |
| |
| public RecoveryScanner( |
| boolean tokenizeWhiteSpace, |
| boolean checkNonExternalizedStringLiterals, |
| long sourceLevel, |
| long complianceLevel, |
| char[][] taskTags, |
| char[][] taskPriorities, |
| boolean isTaskCaseSensitive, |
| RecoveryScannerData data) { |
| super(false, |
| tokenizeWhiteSpace, |
| checkNonExternalizedStringLiterals, |
| sourceLevel, |
| complianceLevel, |
| taskTags, |
| taskPriorities, |
| isTaskCaseSensitive); |
| setData(data); |
| } |
| |
| public void insertToken(int token, int completedToken, int position) { |
| insertTokens(new int []{token}, completedToken, position); |
| } |
| |
| private int[] reverse(int[] tokens) { |
| int length = tokens.length; |
| for(int i = 0, max = length / 2; i < max; i++) { |
| int tmp = tokens[i]; |
| tokens[i] = tokens[length - i - 1]; |
| tokens[length - i - 1] = tmp; |
| } |
| return tokens; |
| } |
| public void insertTokens(int[] tokens, int completedToken, int position) { |
| if(!this.record) return; |
| |
| if(completedToken > -1 && Parser.statements_recovery_filter[completedToken] != 0) return; |
| |
| this.data.insertedTokensPtr++; |
| if(this.data.insertedTokens == null) { |
| this.data.insertedTokens = new int[10][]; |
| this.data.insertedTokensPosition = new int[10]; |
| this.data.insertedTokenUsed = new boolean[10]; |
| } else if(this.data.insertedTokens.length == this.data.insertedTokensPtr) { |
| int length = this.data.insertedTokens.length; |
| System.arraycopy(this.data.insertedTokens, 0, this.data.insertedTokens = new int[length * 2][], 0, length); |
| System.arraycopy(this.data.insertedTokensPosition, 0, this.data.insertedTokensPosition = new int[length * 2], 0, length); |
| System.arraycopy(this.data.insertedTokenUsed, 0, this.data.insertedTokenUsed = new boolean[length * 2], 0, length); |
| } |
| this.data.insertedTokens[this.data.insertedTokensPtr] = reverse(tokens); |
| this.data.insertedTokensPosition[this.data.insertedTokensPtr] = position; |
| this.data.insertedTokenUsed[this.data.insertedTokensPtr] = false; |
| } |
| |
| public void replaceTokens(int token, int start, int end) { |
| replaceTokens(new int []{token}, start, end); |
| } |
| |
| public void replaceTokens(int[] tokens, int start, int end) { |
| if(!this.record) return; |
| this.data.replacedTokensPtr++; |
| if(this.data.replacedTokensStart == null) { |
| this.data.replacedTokens = new int[10][]; |
| this.data.replacedTokensStart = new int[10]; |
| this.data.replacedTokensEnd = new int[10]; |
| this.data.replacedTokenUsed= new boolean[10]; |
| } else if(this.data.replacedTokensStart.length == this.data.replacedTokensPtr) { |
| int length = this.data.replacedTokensStart.length; |
| System.arraycopy(this.data.replacedTokens, 0, this.data.replacedTokens = new int[length * 2][], 0, length); |
| System.arraycopy(this.data.replacedTokensStart, 0, this.data.replacedTokensStart = new int[length * 2], 0, length); |
| System.arraycopy(this.data.replacedTokensEnd, 0, this.data.replacedTokensEnd = new int[length * 2], 0, length); |
| System.arraycopy(this.data.replacedTokenUsed, 0, this.data.replacedTokenUsed = new boolean[length * 2], 0, length); |
| } |
| this.data.replacedTokens[this.data.replacedTokensPtr] = reverse(tokens); |
| this.data.replacedTokensStart[this.data.replacedTokensPtr] = start; |
| this.data.replacedTokensEnd[this.data.replacedTokensPtr] = end; |
| this.data.replacedTokenUsed[this.data.replacedTokensPtr] = false; |
| } |
| |
| public void removeTokens(int start, int end) { |
| if(!this.record) return; |
| this.data.removedTokensPtr++; |
| if(this.data.removedTokensStart == null) { |
| this.data.removedTokensStart = new int[10]; |
| this.data.removedTokensEnd = new int[10]; |
| this.data.removedTokenUsed = new boolean[10]; |
| } else if(this.data.removedTokensStart.length == this.data.removedTokensPtr) { |
| int length = this.data.removedTokensStart.length; |
| System.arraycopy(this.data.removedTokensStart, 0, this.data.removedTokensStart = new int[length * 2], 0, length); |
| System.arraycopy(this.data.removedTokensEnd, 0, this.data.removedTokensEnd = new int[length * 2], 0, length); |
| System.arraycopy(this.data.removedTokenUsed, 0, this.data.removedTokenUsed = new boolean[length * 2], 0, length); |
| } |
| this.data.removedTokensStart[this.data.removedTokensPtr] = start; |
| this.data.removedTokensEnd[this.data.removedTokensPtr] = end; |
| this.data.removedTokenUsed[this.data.removedTokensPtr] = false; |
| } |
| |
| protected int getNextToken0() throws InvalidInputException { |
| if(this.pendingTokensPtr > -1) { |
| int nextToken = this.pendingTokens[this.pendingTokensPtr--]; |
| if(nextToken == TerminalTokens.TokenNameIdentifier){ |
| this.fakeTokenSource = FAKE_IDENTIFIER; |
| } else { |
| this.fakeTokenSource = CharOperation.NO_CHAR; |
| } |
| return nextToken; |
| } |
| |
| this.fakeTokenSource = null; |
| this.precededByRemoved = false; |
| |
| if(this.data.insertedTokens != null) { |
| for (int i = 0; i <= this.data.insertedTokensPtr; i++) { |
| if(this.data.insertedTokensPosition[i] == this.currentPosition - 1 && i > this.skipNextInsertedTokens) { |
| this.data.insertedTokenUsed[i] = true; |
| this.pendingTokens = this.data.insertedTokens[i]; |
| this.pendingTokensPtr = this.data.insertedTokens[i].length - 1; |
| this.isInserted = true; |
| this.startPosition = this.currentPosition; |
| this.skipNextInsertedTokens = i; |
| int nextToken = this.pendingTokens[this.pendingTokensPtr--]; |
| if(nextToken == TerminalTokens.TokenNameIdentifier){ |
| this.fakeTokenSource = FAKE_IDENTIFIER; |
| } else { |
| this.fakeTokenSource = CharOperation.NO_CHAR; |
| } |
| return nextToken; |
| } |
| } |
| this.skipNextInsertedTokens = -1; |
| } |
| |
| int previousLocation = this.currentPosition; |
| int currentToken = super.getNextToken0(); |
| |
| if(this.data.replacedTokens != null) { |
| for (int i = 0; i <= this.data.replacedTokensPtr; i++) { |
| if(this.data.replacedTokensStart[i] >= previousLocation && |
| this.data.replacedTokensStart[i] <= this.startPosition && |
| this.data.replacedTokensEnd[i] >= this.currentPosition - 1) { |
| this.data.replacedTokenUsed[i] = true; |
| this.pendingTokens = this.data.replacedTokens[i]; |
| this.pendingTokensPtr = this.data.replacedTokens[i].length - 1; |
| this.fakeTokenSource = FAKE_IDENTIFIER; |
| this.isInserted = false; |
| this.currentPosition = this.data.replacedTokensEnd[i] + 1; |
| int nextToken = this.pendingTokens[this.pendingTokensPtr--]; |
| if(nextToken == TerminalTokens.TokenNameIdentifier){ |
| this.fakeTokenSource = FAKE_IDENTIFIER; |
| } else { |
| this.fakeTokenSource = CharOperation.NO_CHAR; |
| } |
| return nextToken; |
| } |
| } |
| } |
| if(this.data.removedTokensStart != null) { |
| for (int i = 0; i <= this.data.removedTokensPtr; i++) { |
| if(this.data.removedTokensStart[i] >= previousLocation && |
| this.data.removedTokensStart[i] <= this.startPosition && |
| this.data.removedTokensEnd[i] >= this.currentPosition - 1) { |
| this.data.removedTokenUsed[i] = true; |
| this.currentPosition = this.data.removedTokensEnd[i] + 1; |
| this.precededByRemoved = false; |
| return getNextToken0(); |
| } |
| } |
| } |
| return currentToken; |
| } |
| |
| public char[] getCurrentIdentifierSource() { |
| if(this.fakeTokenSource != null) return this.fakeTokenSource; |
| return super.getCurrentIdentifierSource(); |
| } |
| |
| public char[] getCurrentTokenSourceString() { |
| if(this.fakeTokenSource != null) return this.fakeTokenSource; |
| return super.getCurrentTokenSourceString(); |
| } |
| |
| public char[] getCurrentTokenSource() { |
| if(this.fakeTokenSource != null) return this.fakeTokenSource; |
| return super.getCurrentTokenSource(); |
| } |
| |
| public RecoveryScannerData getData() { |
| return this.data; |
| } |
| |
| public boolean isFakeToken() { |
| return this.fakeTokenSource != null; |
| } |
| |
| public boolean isInsertedToken() { |
| return this.fakeTokenSource != null && this.isInserted; |
| } |
| |
| public boolean isReplacedToken() { |
| return this.fakeTokenSource != null && !this.isInserted; |
| } |
| |
| public boolean isPrecededByRemovedToken() { |
| return this.precededByRemoved; |
| } |
| |
| public void setData(RecoveryScannerData data) { |
| if(data == null) { |
| this.data = new RecoveryScannerData(); |
| } else { |
| this.data = data; |
| } |
| } |
| |
| public void setPendingTokens(int[] pendingTokens) { |
| this.pendingTokens = pendingTokens; |
| this.pendingTokensPtr = pendingTokens.length - 1; |
| } |
| } |