org.eclipse.jdt.internal.compiler.parser.RecoveryScanner.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.compiler.parser.RecoveryScanner.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2014 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * 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,
                scanner.previewEnabled);
        setData(data);
    }

    public RecoveryScanner(boolean tokenizeWhiteSpace, boolean checkNonExternalizedStringLiterals, long sourceLevel,
            long complianceLevel, char[][] taskTags, char[][] taskPriorities, boolean isTaskCaseSensitive,
            boolean isPreviewEnabled, RecoveryScannerData data) {
        super(false, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, sourceLevel, complianceLevel, taskTags,
                taskPriorities, isTaskCaseSensitive, isPreviewEnabled);
        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 insertTokenAhead(int token, int index) {
        if (!this.record)
            return;

        int length = this.data.insertedTokens[index].length;
        int[] tokens = new int[length + 1];
        System.arraycopy(this.data.insertedTokens[index], 0, tokens, 1, length);
        tokens[0] = token;
        this.data.insertedTokens[index] = tokens;
    }

    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;
    }

    @Override
    protected int getNextToken0() throws InvalidInputException {
        if (this.pendingTokensPtr > -1) {
            int pendingToken = this.pendingTokens[this.pendingTokensPtr--];
            if (pendingToken == TerminalTokens.TokenNameIdentifier) {
                this.fakeTokenSource = FAKE_IDENTIFIER;
            } else {
                this.fakeTokenSource = CharOperation.NO_CHAR;
            }
            return pendingToken;
        }

        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 pendingToken = this.pendingTokens[this.pendingTokensPtr--];
                    if (pendingToken == TerminalTokens.TokenNameIdentifier) {
                        this.fakeTokenSource = FAKE_IDENTIFIER;
                    } else {
                        this.fakeTokenSource = CharOperation.NO_CHAR;
                    }
                    return pendingToken;
                }
            }
            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 pendingToken = this.pendingTokens[this.pendingTokensPtr--];
                    if (pendingToken == TerminalTokens.TokenNameIdentifier) {
                        this.fakeTokenSource = FAKE_IDENTIFIER;
                    } else {
                        this.fakeTokenSource = CharOperation.NO_CHAR;
                    }
                    return pendingToken;
                }
            }
        }
        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;
    }

    @Override
    public char[] getCurrentIdentifierSource() {
        if (this.fakeTokenSource != null)
            return this.fakeTokenSource;
        return super.getCurrentIdentifierSource();
    }

    @Override
    public char[] getCurrentTokenSourceString() {
        if (this.fakeTokenSource != null)
            return this.fakeTokenSource;
        return super.getCurrentTokenSourceString();
    }

    @Override
    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;
    }
}