/******************************************************************************* * Copyright (c) 2005, 2008 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 org2.eclipse.php.internal.core.ast.rewrite; /******************************************************************************* * Copyright (c) 2000, 2006 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 *******************************************************************************/ import java.io.IOException; import java_cup.sym; import java_cup.runtime.Symbol; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org2.eclipse.php.internal.core.ast.scanner.AstLexer; import org2.eclipse.php.internal.core.ast.util.RandomAccessCharArrayReader; import com.aptana.core.logging.IdeLog; import com.aptana.editor.php.epl.PHPEplPlugin; /** * Wraps a scanner and offers convenient methods for finding tokens */ public class TokenScanner { public static final int END_OF_FILE = sym.EOF; public static final int LEXICAL_ERROR = 20002; @SuppressWarnings("nls") private static final String[] MODIFIERS = { "public", "private", "protected", "static", "abstract", "final" }; // public static final int DOCUMENT_ERROR= 20003; private AstLexer scanner; private RandomAccessCharArrayReader charReader; private Symbol currentToken; private int offset; /** * Creates a TokenScanner * * @param scanner * The scanner to be wrapped. * @param content * The char array content of the scanner. * @throws IOException */ public TokenScanner(AstLexer scanner, char[] content) throws IOException { this.scanner = scanner; this.charReader = new RandomAccessCharArrayReader(content); this.scanner.yyreset(this.charReader); this.scanner.resetCommentList(); } /** * Returns the wrapped scanner * * @return IScanner */ public AstLexer getScanner() { return this.scanner; } /** * Sets the scanner offset to the given offset. * * @param offset * The offset to set * @throws IOException */ public void setOffset(int offset) { this.offset = offset; charReader.reset(offset); try { scanner.yyreset(charReader); scanner.setInScriptingState(); scanner.resetCommentList(); } catch (IOException e) { IdeLog.logError(PHPEplPlugin.getDefault(), "Error setting a PHP token-scanner offset", e); //$NON-NLS-1$ } } /** * @return Returns the offset after the current token */ public int getCurrentEndOffset() { if (currentToken != null) { return offset + currentToken.right; } return 0; } /** * @return Returns the start offset of the current token */ public int getCurrentStartOffset() { if (currentToken != null) { return offset + currentToken.left; } return 0; } /** * @return Returns the length of the current token */ public int getCurrentLength() { return getCurrentEndOffset() - getCurrentStartOffset(); } /** * Reads the next token. Comments are always ignored. * * @return Return the token {@link Symbol}. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public Symbol readNext() throws CoreException { currentToken = null; try { currentToken = this.scanner.next_token(); } catch (Exception e) { throw new CoreException(createError(LEXICAL_ERROR, e.getMessage(), e)); } if (currentToken.sym == END_OF_FILE) { throw new CoreException(createError(END_OF_FILE, "End Of File", null)); //$NON-NLS-1$ } return currentToken; } /** * Reads the next token from the given offset. Comments are always ignored. * * @param offset * The offset to start reading from. * @return Returns the token {@link Symbol}. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public Symbol readNext(int offset) throws CoreException { setOffset(offset); return readNext(); } /** * Reads the next token from the given offset and returns the start offset * of the token. Comments are always ignored. * * @param offset * The offset to start reading from. * @return Returns the start position of the next token. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public int getNextStartOffset(int offset) throws CoreException { readNext(offset); return getCurrentStartOffset(); } /** * Reads the next token from the given offset and returns the offset after * the token. Comments are always ignored. * * @param offset * The offset to start reading from. * @return Returns the start position of the next token. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public int getNextEndOffset(int offset) throws CoreException { readNext(offset); return getCurrentEndOffset(); } /** * Reads until a token is reached. * * @param tok * The token to read to. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public void readToToken(Symbol tok) throws CoreException { currentToken = null; do { currentToken = readNext(); } while (currentToken != null && currentToken.sym != tok.sym); } /** * Reads until a token is reached, starting from the given offset. * * @param tok * The token to read to. * @param offset * The offset to start reading from. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public void readToToken(Symbol tok, int offset) throws CoreException { setOffset(offset); readToToken(tok); } /** * Reads from the given offset until a token is reached and returns the * start offset of the token. * * @param token * The token to be found. * @param startOffset * The offset to start reading from. * @return Returns the start position of the found token. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public int getTokenStartOffset(Symbol token, int startOffset) throws CoreException { readToToken(token, startOffset); return getCurrentStartOffset(); } /** * Reads from the given offset until a token is reached and returns the * offset after the token. * * @param token * The token to be found. * @param startOffset * Offset to start reading from * @return Returns the end position of the found token. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public int getTokenEndOffset(Symbol token, int startOffset) throws CoreException { readToToken(token, startOffset); return getCurrentEndOffset(); } /** * Reads from the given offset until a token is reached and returns the * offset after the previous token. * * @param token * The token to be found. * @param startOffset * The offset to start scanning from. * @return Returns the end offset of the token previous to the given token. * @exception CoreException * Thrown when the end of the file has been reached (code * END_OF_FILE) or a lexical error was detected while * scanning (code LEXICAL_ERROR) */ public int getPreviousTokenEndOffset(Symbol token, int startOffset) throws CoreException { setOffset(startOffset); int res = startOffset; Symbol curr = readNext(); while (curr != null && curr.sym != token.sym) { res = getCurrentEndOffset(); curr = readNext(); } return res; } /** * Returns if the token is a comment. The tokens that we read from the * scanner are always non-comments. The comments are save in a separate * structure in the lexer. * * @param token * @return false */ public static boolean isComment(Symbol token) { // The tokens that we read from the scanner are always non-comments. // The comments are save in a separate structure in the lexer. return false; } /** * Returns true if and only if the token's value is one of the modifiers: * "public", "private", "protected", "static", "abstract", "final". * * @param token * A {@link Symbol} token. * @return True, if the token's value is a modifier; False, otherwise. */ public static boolean isModifier(Symbol token) { if (token == null || token.value == null) { return false; } for (String modifier : MODIFIERS) { if (token.value.equals(modifier)) { return true; } } return false; } public static IStatus createError(int code, String message, Throwable throwable) { return new Status(IStatus.ERROR, PHPEplPlugin.PLUGIN_ID, code, message, throwable); } }