/******************************************************************************* * 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.eclipse.jdt.internal.compiler.parser; import org.eclipse.jdt.core.compiler.CharOperation; import 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; } }