X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java index 85aa0d2..4b163e0 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java @@ -1,576 +1,418 @@ /********************************************************************** -Copyright (c) 2000, 2002 IBM Corp. and others. -All rights reserved. This program and the accompanying materials -are made available under the terms of the Common Public License v1.0 -which accompanies this distribution, and is available at -http://www.eclipse.org/legal/cpl-v10.html - -Contributors: - IBM Corporation - Initial implementation - Klaus Hartlage - www.eclipseproject.de -**********************************************************************/ + Copyright (c) 2002 Widespace, OU and others. + All rights reserved. This program and the accompanying materials + are made available under the terms of the Common Public License v1.0 + which accompanies this distribution, and is available at + http://solareclipse.sourceforge.net/legal/cpl-v10.html + + Contributors: + Igor Malinin - initial contribution + + $Id: PHPPartitionScanner.java,v 1.27 2005-05-06 00:57:28 stefanbjarni Exp $ + **********************************************************************/ package net.sourceforge.phpeclipse.phpeditor.php; -import java.io.CharArrayWriter; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; +import net.sourceforge.phpeclipse.ui.text.rules.AbstractPartitioner; + +import org.eclipse.jface.text.Assert; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.rules.ICharacterScanner; -import org.eclipse.jface.text.rules.IPredicateRule; +import org.eclipse.jface.text.rules.IPartitionTokenScanner; import org.eclipse.jface.text.rules.IToken; -import org.eclipse.jface.text.rules.IWordDetector; -import org.eclipse.jface.text.rules.MultiLineRule; -import org.eclipse.jface.text.rules.RuleBasedPartitionScanner; import org.eclipse.jface.text.rules.Token; -import org.eclipse.jface.text.rules.WordRule; /** - * This scanner recognizes the JavaDoc comments and Java multi line comments. + * + * + * @author Igor Malinin */ -public class PHPPartitionScanner extends RuleBasedPartitionScanner { +public class PHPPartitionScanner implements IPartitionTokenScanner { + // public static final String JSP_DIRECTIVE = "__jsp_directive"; + // public static final String JSP_COMMENT = "__jsp_comment"; + //// public static final String JSP_TAG = "__jsp_tag"; + // public static final String JSP_DECLARATION = "__jsp_declaration"; + public static final String PHP_SCRIPTING_AREA = "__php_scripting_area "; - private final static String SKIP = "__skip"; //$NON-NLS-1$ - public final static String HTML_MULTILINE_COMMENT = "__html_multiline_comment"; //$NON-NLS-1$ - // public final static String JAVA_DOC= "__java_javadoc"; //$NON-NLS-1$ - public final static String PHP = "__php"; - // public final static String HTML = "__html"; + // public static final String JSP_EXPRESSION = "__jsp_expression"; - public final static IToken php = new Token(PHP); - // public final static IToken html = new Token(HTML); - public final static IToken comment = new Token(HTML_MULTILINE_COMMENT); + public static final int STATE_DEFAULT = 0; - protected final static char[] php0EndSequence = { '<', '?' }; - protected final static char[] php1EndSequence = { '<', '?', 'p', 'h', 'p' }; - protected final static char[] php2EndSequence = { '<', '?', 'P', 'H', 'P' }; + // public static final int STATE_TAG = 1; + // public static final int STATE_SCRIPT = 2; - private StringBuffer test; + private IDocument document; - public class PHPMultiLineRule extends MultiLineRule { + private int begin; - public PHPMultiLineRule(String startSequence, String endSequence, IToken token) { - super(startSequence, endSequence, token); - } + private int end; + + private int offset; + + private int length; + + private int position; + + private int state; - public PHPMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) { - super(startSequence, endSequence, token, escapeCharacter); + private Map tokens = new HashMap(); + + public PHPPartitionScanner() { + } + + /* + * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken() + */ + public IToken nextToken() { + offset += length; + + /* + * switch (state) { case STATE_TAG: return nextTagToken(); } + */ + + switch (read()) { + case ICharacterScanner.EOF: + state = STATE_DEFAULT; + return getToken(null); + + case '<': + switch (read()) { + case ICharacterScanner.EOF: + state = STATE_DEFAULT; + return getToken(null); + + case '?': // <%SCRIPLET <%@DIRECTIVE <%!DECLARATION <%=EXPRESSION <%--COMMENT + int ch = read(); + // if (Character.isWhitespace((char)ch)) { + // return nextJSPToken(PHP_SCRIPTING_AREA); + // } + switch (ch) { + case ICharacterScanner.EOF: + state = STATE_DEFAULT; + return getToken(PHP_SCRIPTING_AREA); + + // case '-': // <%- <%--COMMENT + // switch (read()) { + // case ICharacterScanner.EOF: + // case '-': // <%-- + // return nextCommentToken(); + // } + // + // break; + } + + return scanUntilPHPEndToken(PHP_SCRIPTING_AREA); + } + + unread(); } - protected boolean endSequenceDetected(ICharacterScanner scanner) { - int c; - int c2; + loop: while (true) { + switch (read()) { + case ICharacterScanner.EOF: + state = STATE_DEFAULT; + return getToken(null); + + case '<': + switch (read()) { + case ICharacterScanner.EOF: + state = STATE_DEFAULT; + return getToken(null); - boolean lineCommentMode = false; - boolean multiLineCommentMode = false; - boolean stringMode = false; + case '?': + unread(); + break; + + case '<': + unread(); + + default: + continue loop; + } + + unread(); + + state = STATE_DEFAULT; + return getToken(null); + } + } + } - char[][] delimiters = scanner.getLegalLineDelimiters(); - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '#') { + private IToken scanUntilPHPEndToken(String token) { + int ch = read(); + while (true) { + switch (ch) { + case ICharacterScanner.EOF: + state = STATE_DEFAULT; + return getToken(token); + case '"': // double quoted string + // read until end of double quoted string + if (!readUntilEscapedDQ()) { + state = STATE_DEFAULT; + return getToken(token); + } + break; + case '\'': // single quoted string + // read until end of single quoted string + if (!readUntilEscapedSQ()) { + state = STATE_DEFAULT; + return getToken(token); + } + break; + case '/': // comment start? + ch = read(); + switch (ch) { + case ICharacterScanner.EOF: + break; + case '/': // read until end of line - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (fEndSequence.length > 0 && c == fEndSequence[0]) { - // Check if the specified end sequence has been found. - if (sequenceDetected(scanner, fEndSequence, true)) - return true; - } else if (c == '\n') { - break; - } - } - continue; - } else if (c == '/' && (c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '/') { - // read until end of line - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (fEndSequence.length > 0 && c == fEndSequence[0]) { - // Check if the specified end sequence has been found. - if (sequenceDetected(scanner, fEndSequence, true)) - return true; - } else if (c == '\n') { - break; - } - } - continue; - } else if (c == '*') { - // multi-line comment - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '*' && (c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '/') { - break; - } - scanner.unread(); - } - } - - continue; - } else { - scanner.unread(); - } - } else if (c == '"') { - // string mode - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '\\') { - c = scanner.read(); - } else if (c == '"') { - break; - } - } - continue; - } else if (c == '\'') { - // string mode - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '\\') { - c = scanner.read(); - } else if (c == '\'') { - break; - } - } + readSingleLine(); + break; + case '*': + // read until end of comment + readMultiLineComment(); + break; + default: continue; } - - if (c == fEscapeCharacter) { - // Skip the escaped character. - scanner.read(); - } else if (fEndSequence.length > 0 && c == fEndSequence[0]) { - // Check if the specified end sequence has been found. - if (sequenceDetected(scanner, fEndSequence, true)) - return true; - } else if (fBreaksOnEOL) { - // Check for end of line since it can be used to terminate the pattern. - for (int i = 0; i < delimiters.length; i++) { - if (c == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], false)) - return true; - } + break; + case '#': // line comment + // read until end of line + readSingleLine(); + break; + case '?': + ch = read(); + switch (ch) { + case ICharacterScanner.EOF: + case '>': + state = STATE_DEFAULT; + return getToken(token); + + case '?': + continue; } - } - boolean phpMode = false; - if (c == ICharacterScanner.EOF) { - phpMode = true; } - scanner.unread(); - return phpMode; + + ch = read(); } } - // public class HTMLMultiLineRule extends MultiLineRule { - // - // public HTMLMultiLineRule(String startSequence, String endSequence, IToken token) { - // super(startSequence, endSequence, token); - // } - // - // public HTMLMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) { - // super(startSequence, endSequence, token, escapeCharacter); - // } + // private IToken nextCommentToken() { + // int ch = read(); + // loop: while (true) { + // switch (ch) { + // case ICharacterScanner.EOF: + // break loop; // - // protected boolean endSequenceDetected(ICharacterScanner scanner) { - // int c; + // case '-': // - --%> + // ch = read(); + // switch (ch) { + // case ICharacterScanner.EOF: + // break loop; // - // char[][] delimiters = scanner.getLegalLineDelimiters(); - // while ((c = scanner.read()) != ICharacterScanner.EOF) { - // if (c == '<') { - // // scanner.unread(); - // if (sequenceDetected(scanner, php2EndSequence, true)) { - // // + // ch = read(); + // switch (ch) { + // case ICharacterScanner.EOF: + // break loop; // - // } - // scanner.unread(); - // return false; - // } + // case '%': // --% --%> + // ch = read(); + // switch (ch) { + // case ICharacterScanner.EOF: + // case '>': + // break loop; + // } // - // protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { + // continue loop; // - // if (resume) { + // case '-': // --- ---%> + // unread(); + // continue loop; + // } // - // if (endSequenceDetected(scanner)) - // return fToken; + // ch = read(); + // continue loop; + // } + // } // - // } else { + // ch = read(); + // } // - // int c = scanner.read(); - // // if (c == fStartSequence[0]) { - // // if (sequenceDetected(scanner, fStartSequence, false)) { - // if (endSequenceDetected(scanner)) - // return fToken; - // // } - // // } - // } - // - // scanner.unread(); - // return Token.UNDEFINED; - // } - // - // public IToken evaluate(ICharacterScanner scanner, boolean resume) { - // if (fColumn == UNDEFINED) - // return doEvaluate(scanner, resume); - // - // int c = scanner.read(); - // scanner.unread(); - // // if (c == fStartSequence[0]) - // return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED); - // // else - // // return Token.UNDEFINED; - // } - // } - - public class HTMLPatternRule implements IPredicateRule { - - protected static final int UNDEFINED = -1; - - /** The token to be returned on success */ - protected IToken fToken; - - /** The pattern's column constrain */ - protected int fColumn = UNDEFINED; - /** The pattern's escape character */ - protected char fEscapeCharacter; - /** Indicates whether end of line termines the pattern */ - protected boolean fBreaksOnEOL; - - /** - * Creates a rule for the given starting and ending sequence. - * When these sequences are detected the rule will return the specified token. - * Alternatively, the sequence can also be ended by the end of the line. - * Any character which follows the given escapeCharacter will be ignored. - * - * @param startSequence the pattern's start sequence - * @param endSequence the pattern's end sequence, null is a legal value - * @param token the token which will be returned on success - * @param escapeCharacter any character following this one will be ignored - * @param indicates whether the end of the line also termines the pattern - */ - public HTMLPatternRule(IToken token) { - fToken = token; - fEscapeCharacter = (char) 0; - fBreaksOnEOL = false; - } + // return getToken(JSP_COMMENT); + // } - /** - * Sets a column constraint for this rule. If set, the rule's token - * will only be returned if the pattern is detected starting at the - * specified column. If the column is smaller then 0, the column - * constraint is considered removed. - * - * @param column the column in which the pattern starts - */ - public void setColumnConstraint(int column) { - if (column < 0) - column = UNDEFINED; - fColumn = column; - } + private IToken getToken(String type) { + length = position - offset; - /** - * Evaluates this rules without considering any column constraints. - * - * @param scanner the character scanner to be used - * @return the token resulting from this evaluation - */ - protected IToken doEvaluate(ICharacterScanner scanner) { - return doEvaluate(scanner, false); + if (length == 0) { + return Token.EOF; } - /** - * Evaluates this rules without considering any column constraints. Resumes - * detection, i.e. look sonly for the end sequence required by this rule if the - * resume flag is set. - * - * @param scanner the character scanner to be used - * @param resume true if detection should be resumed, false otherwise - * @return the token resulting from this evaluation - * @since 2.0 - */ - protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { - - if (resume) { - - if (endSequenceDetected(scanner)) - return fToken; + if (type == null) { + return Token.UNDEFINED; + } - } else { + IToken token = (IToken) tokens.get(type); + if (token == null) { + token = new Token(type); + tokens.put(type, token); + } - int c = scanner.read(); - // if (c == fStartSequence[0]) { - // if (sequenceDetected(scanner, fStartSequence, false)) { - if (endSequenceDetected(scanner)) - return fToken; - // } - // } - } + return token; + } - scanner.unread(); - return Token.UNDEFINED; + private int read() { + if (position >= end) { + return ICharacterScanner.EOF; } - /* - * @see IRule#evaluate - */ - public IToken evaluate(ICharacterScanner scanner) { - return evaluate(scanner, false); + try { + return document.getChar(position++); + } catch (BadLocationException e) { + --position; + return ICharacterScanner.EOF; } + } - /** - * Returns whether the end sequence was detected. As the pattern can be considered - * ended by a line delimiter, the result of this method is true if the - * rule breaks on the end of the line, or if the EOF character is read. - * - * @param scanner the character scanner to be used - * @return true if the end sequence has been detected - */ - protected boolean endSequenceDetected(ICharacterScanner scanner) { - int c; - - char[][] delimiters = scanner.getLegalLineDelimiters(); - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '<') { - // scanner.unread(); - if (sequenceDetected(scanner, php2EndSequence, true)) { - // = end) { + return false; + } + try { + char ch; + while (true) { + ch = document.getChar(position++); + if (ch == '\\') { + ch = document.getChar(position++); // ignore escaped character + } else if (ch == '"') { + return true; } - } - scanner.unread(); + } catch (BadLocationException e) { + --position; + } + return false; + } + + private boolean readUntilEscapedSQ() { + // search last single quoted character + if (position >= end) { return false; } - - /** - * Returns whether the next characters to be read by the character scanner - * are an exact match with the given sequence. No escape characters are allowed - * within the sequence. If specified the sequence is considered to be found - * when reading the EOF character. - * - * @param scanner the character scanner to be used - * @param sequence the sequence to be detected - * @param eofAllowed indicated whether EOF terminates the pattern - * @return true if the given sequence has been detected - */ - protected boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) { - for (int i = 1; i < sequence.length; i++) { - int c = scanner.read(); - if (c == ICharacterScanner.EOF && eofAllowed) { + try { + char ch; + while (true) { + ch = document.getChar(position++); + if (ch == '\\') { + ch = document.getChar(position++); // ignore escaped character + } else if (ch == '\'') { return true; - } else if (c != sequence[i]) { - // Non-matching character detected, rewind the scanner back to the start. - scanner.unread(); - for (int j = i - 1; j > 0; j--) - scanner.unread(); - return false; } } - - return true; + } catch (BadLocationException e) { + --position; } + return false; + } - /* - * @see IPredicateRule#evaluate(ICharacterScanner, boolean) - * @since 2.0 - */ - public IToken evaluate(ICharacterScanner scanner, boolean resume) { - if (fColumn == UNDEFINED) - return doEvaluate(scanner, resume); - - int c = scanner.read(); - scanner.unread(); - // if (c == fStartSequence[0]) - return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED); - // else - // return Token.UNDEFINED; + private void readSingleLine() { + if (position >= end) { + return; } + try { + while (document.getChar(position++) != '\n') { - /* - * @see IPredicateRule#getSuccessToken() - * @since 2.0 - */ - public IToken getSuccessToken() { - return fToken; + } + } catch (BadLocationException e) { + --position; + return; } } - /** - * Detector for empty comments. - */ - static class EmptyCommentDetector implements IWordDetector { - /* (non-Javadoc) - * Method declared on IWordDetector - */ - public boolean isWordStart(char c) { - return (c == '/'); + private void readMultiLineComment() { + if (position >= end) { + return; } - - /* (non-Javadoc) - * Method declared on IWordDetector - */ - public boolean isWordPart(char c) { - return (c == '*' || c == '/'); - } - }; - - /** - * - */ - static class WordPredicateRule extends WordRule implements IPredicateRule { - - private IToken fSuccessToken; - - public WordPredicateRule(IToken successToken) { - super(new EmptyCommentDetector()); - fSuccessToken = successToken; - addWord("/**/", fSuccessToken); + try { + char ch; + while (true) { + ch = document.getChar(position++); + if (ch == '*') { + if (document.getChar(position) == '/') { + position++; + break; + } + } + } + } catch (BadLocationException e) { + --position; + return; } + } - /* - * @see org.eclipse.jface.text.rules.IPredicateRule#evaluate(ICharacterScanner, boolean) - */ - public IToken evaluate(ICharacterScanner scanner, boolean resume) { - return super.evaluate(scanner); - } + private void unread() { + --position; + } - /* - * @see org.eclipse.jface.text.rules.IPredicateRule#getSuccessToken() - */ - public IToken getSuccessToken() { - return fSuccessToken; + /* + * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset() + */ + public int getTokenOffset() { + if (AbstractPartitioner.DEBUG) { + Assert.isTrue(offset >= 0, Integer.toString(offset)); } - }; + return offset; + } - /** - * Creates the partitioner and sets up the appropriate rules. + /* + * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength() */ - public PHPPartitionScanner() { - super(); - - // IToken php = new Token(PHP); - // IToken html = new Token(HTML); - // IToken comment = new Token(HTML_MULTILINE_COMMENT); - - List rules = new ArrayList(); - - // Add rule for single line comments. - // rules.add(new EndOfLineRule("//", Token.UNDEFINED)); - - // Add rule for strings and character constants. - // rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\')); - // rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\')); - - // Add special case word rule. - // rules.add(new WordPredicateRule(comment)); - - // Add rules for multi-line comments and javadoc. - //rules.add(new MultiLineRule("/**", "*/", javaDoc)); - // rules.add(new HTMLMultiLineRule("<", "", comment)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); + public int getTokenLength() { + return length; + } - // rules.add(new HTMLPatternRule(html)); // "<", " -1) { + // int delta= offset - partitionOffset; + // if (delta > 0) { + // this.setRange(document, partitionOffset, length + delta); + // return; + // } + // } + setRange(document, partitionOffset, length); } - // public IToken nextToken() { - // - // if (fContentType == null || fRules == null) - // return getNextToken(); - // - // fTokenOffset= fOffset; - // fColumn= UNDEFINED; - // boolean resume= (fPartitionOffset < fOffset); - // - // IPredicateRule rule; - // IToken token; - // - // for (int i= 0; i < fRules.length; i++) { - // rule= (IPredicateRule) fRules[i]; - // token= rule.getSuccessToken(); - // if (fContentType.equals(token.getData())) { - // if (resume) - // fTokenOffset= fPartitionOffset; - // token= rule.evaluate(this, resume); - // if (!token.isUndefined()) { - // fContentType= null; - // return token; - // } - // } - // } - // - // fContentType= null; - // return getNextToken(); - // } - // - // public IToken getNextToken() { - // - // IToken token; - // - // while (true) { - // - // fTokenOffset= fOffset; - // fColumn= UNDEFINED; - // - // if (fRules != null) { - // for (int i= 0; i < fRules.length; i++) { - // token= (fRules[i].evaluate(this)); - // if (!token.isUndefined()) - // return token; - // } - // } - // - // if (read() == EOF) - // return Token.EOF; - // else - // return fDefaultReturnToken; - // } - // } -} + // private boolean isContinuationPartition(IDocument document, int offset) { + // try { + // String type = document.getContentType(offset - 1); + // + // if (type != IDocument.DEFAULT_CONTENT_TYPE) { + // return true; + // } + // } catch (BadLocationException e) {} + // + // return false; + // } +} \ No newline at end of file