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 0157acb..62687dd 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,501 +1,383 @@ -/** - * 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 - * Created on 05.03.2003 - * - * @author Stefan Langer (musk) - * @version $Revision: 1.22 $ - */ +/********************************************************************** + 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.30 2005-09-30 18:10:36 axelcl Exp $ + **********************************************************************/ package net.sourceforge.phpeclipse.phpeditor.php; -import java.util.ArrayList; 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.ITypedRegion; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IPartitionTokenScanner; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; /** - * + * + * + * @author Igor Malinin */ public class PHPPartitionScanner implements IPartitionTokenScanner { - private static final boolean DEBUG = false; - - private boolean fInString = false; - private boolean fInDoubString = false; - private IDocument fDocument = null; - private int fOffset = -1; - private String fContentType = IPHPPartitionScannerConstants.HTML; - private String fPrevContentType = IPHPPartitionScannerConstants.HTML; - private boolean partitionBorder = false; - private int fTokenOffset; - private int fEnd = -1; - private int fLength; - private int fCurrentLength; - private int fFileType; - private Map tokens = new HashMap(); + public static final String PHP_SCRIPTING_AREA = "__php_scripting_area "; - public PHPPartitionScanner() { - this(IPHPPartitionScannerConstants.PHP_FILE); - } - - public PHPPartitionScanner(int fileType) { - this.tokens.put(IPHPPartitionScannerConstants.PHP, new Token(IPHPPartitionScannerConstants.PHP)); - this.tokens.put( - IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT, - new Token(IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT)); - this.tokens.put(IPHPPartitionScannerConstants.HTML, new Token(IPHPPartitionScannerConstants.HTML)); - this.tokens.put( - IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT, - new Token(IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT)); - - this.tokens.put(IPHPPartitionScannerConstants.SMARTY, new Token(IPHPPartitionScannerConstants.SMARTY)); - this.tokens.put( - IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT, - new Token(IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT)); - - this.tokens.put(IDocument.DEFAULT_CONTENT_TYPE, new Token(IDocument.DEFAULT_CONTENT_TYPE)); - fFileType = fileType; - } + public static final int STATE_DEFAULT = 0; - private IToken getToken(String type) { - fLength = fCurrentLength; - if (DEBUG) { + // public static final int STATE_TAG = 1; + // public static final int STATE_SCRIPT = 2; - try { - if (fLength <= 0) { - int line = fDocument.getLineOfOffset(fOffset); - System.err.println("Error at " + line + " offset:" + String.valueOf(fOffset - fDocument.getLineOffset(line))); - } - } catch (BadLocationException e) { // should never happen - // TODO Write stacktrace to log - e.printStackTrace(); - } - } - Assert.isTrue(fLength > 0, "Partition length <= 0!"); - fCurrentLength = 0; - // String can never cross partition borders so reset string detection - fInString = false; - fInDoubString = false; - IToken token = (IToken) this.tokens.get(type); - Assert.isNotNull(token, "Token for type \"" + type + "\" not found!"); - if (DEBUG) { - System.out.println("Partition: fTokenOffset=" + fTokenOffset + " fContentType=" + type + " fLength=" + fLength); - } - return token; - } + private IDocument document; - /* (non-Javadoc) - * @see org.eclipse.jface.text.rules.IPartitionTokenScanner#setPartialRange(org.eclipse.jface.text.IDocument, int, int, java.lang.String, int) - */ - public void setPartialRange(IDocument document, int offset, int length, String contentType, int partitionOffset) { - if (DEBUG) { - System.out.println("*****"); - System.out.println("PartialRange: contentType=" + contentType + " partitionOffset=" + partitionOffset); - } +// private int begin; - try { - if (partitionOffset > -1) { - partitionBorder = false; - // because of strings we have to parse the whole partition - this.setRange(document, partitionOffset, offset - partitionOffset + length); - // sometimes we get a wrong partition so we retrieve the partition - // directly from the document - fContentType = fDocument.getContentType(partitionOffset); - } else - this.setRange(document, offset, length); + private int end; - } catch (BadLocationException e) { - // should never happen - // TODO print stack trace to log - // fall back just scan the whole document again - this.setRange(document, 0, fDocument.getLength()); - } + private int offset; - } + private int length; - /* (non-Javadoc) - * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength() - */ - public int getTokenLength() { - return fLength; - } + private int position; - /* (non-Javadoc) - * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset() - */ - public int getTokenOffset() { - return fTokenOffset; +// private int state; + + private Map tokens = new HashMap(); + + public PHPPartitionScanner() { } - /* (non-Javadoc) + /* * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken() */ public IToken nextToken() { - int c; + 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 '?': // 5) { - unread(5); - IToken token = getToken(fContentType); - // save previouse contenttype - //TODO build stack for previouse contenttype - fPrevContentType = fContentType; - - fContentType = IPHPPartitionScannerConstants.PHP; - - return token; - } else - fContentType = IPHPPartitionScannerConstants.PHP; - - // remember offset of this partition - fTokenOffset = fOffset - 5; - fCurrentLength = 5; - } else if ( - !isInString(IPHPPartitionScannerConstants.PHP) - && fContentType != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT - && checkPattern(new char[] { '?' }, false)) { - if (fContentType != IPHPPartitionScannerConstants.PHP && fCurrentLength > 2) { - unread(2); - IToken token = getToken(fContentType); - // save previouse contenttype - fPrevContentType = fContentType; - fContentType = IPHPPartitionScannerConstants.PHP; - return token; - } else - fContentType = IPHPPartitionScannerConstants.PHP; - // remember offset of this partition - fTokenOffset = fOffset - 2; - fCurrentLength = 2; - } else if ( - !isInString(IPHPPartitionScannerConstants.PHP) - && (fContentType != IPHPPartitionScannerConstants.PHP) // BUG #769044 - && (fContentType != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT) // BUG #769044 - && checkPattern(new char[] { '!', '-', '-' })) { // return previouse partition - if (fContentType != IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT && fCurrentLength > 4) { - unread(4); - IToken token = getToken(fContentType); - fContentType = IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT; - return token; - } else - fContentType = IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT; - - fTokenOffset = fOffset - 4; - fCurrentLength = 4; - } - break; - case '?' : - if (!isInString(IPHPPartitionScannerConstants.PHP) && fContentType == IPHPPartitionScannerConstants.PHP) { - if ((c = read()) == '>') { - if (fPrevContentType != null) - fContentType = fPrevContentType; - else - fContentType = IPHPPartitionScannerConstants.HTML; - partitionBorder = true; - return getToken(IPHPPartitionScannerConstants.PHP); - } else if (c != ICharacterScanner.EOF) - unread(); - } - break; - case '-' : - if (!isInString(IPHPPartitionScannerConstants.PHP) - && fContentType == IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT - && checkPattern(new char[] { '-', '>' })) { - fContentType = IPHPPartitionScannerConstants.HTML; - partitionBorder = true; - return getToken(IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT); - } + 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); + + case '?': + unread(); break; - case '{' : // SMARTY code starts here ? - if (fFileType == IPHPPartitionScannerConstants.SMARTY_FILE) { - if ((c = read()) == '*') { - if (DEBUG) { - System.out.println( - "SMARTYDOC_TOKEN start " - + fTokenOffset - + " fContentType=" - + fContentType - + " fLength=" - + fLength - + " fOffset=" - + fOffset - + " fCurrentLength=" - + fCurrentLength); - } - if (fContentType != IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT && fCurrentLength > 2) { - // SMARTY doc code starts here - unread(2); - IToken token = getToken(fContentType); - fContentType = IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT; - return token; - // } else if (fContentType == IPHPPartitionScannerConstants.HTML && fOffset == 2) { - // fContentType = IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT; - } else { // if (fContentType == IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT) { - fContentType = IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT; - fTokenOffset = fOffset - 2; - fCurrentLength = 2; - } - break; - } - if (DEBUG) { - System.out.println( - "SMARTY_TOKEN start " - + fTokenOffset - + " fContentType=" - + fContentType - + " fLength=" - + fLength - + " fOffset=" - + fOffset); - } - if (c != ICharacterScanner.EOF) { - unread(); - } - if (fContentType != IPHPPartitionScannerConstants.SMARTY && fCurrentLength > 1) { - unread(1); - IToken token = getToken(fContentType); - fContentType = IPHPPartitionScannerConstants.SMARTY; - return token; - // } else if (fContentType == IPHPPartitionScannerConstants.HTML && fOffset==1) { - // fContentType = IPHPPartitionScannerConstants.SMARTY; - } else { - fContentType = IPHPPartitionScannerConstants.SMARTY; - fTokenOffset = fOffset - 1; - fCurrentLength = 1; - } - } + + case '<': + unread(); + + default: + continue loop; + } + + unread(); + +// state = STATE_DEFAULT; + return getToken(null); + } + } + } + + 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 '}' : // SMARTY code ends here ? - if (fFileType == IPHPPartitionScannerConstants.SMARTY_FILE && fContentType == IPHPPartitionScannerConstants.SMARTY) { - if (DEBUG) { - System.out.println( - "SMARTY_TOKEN end " - + fTokenOffset - + " fContentType=" - + fContentType - + " fLength=" - + fLength - + " fOffset=" - + fOffset); - } - fContentType = IPHPPartitionScannerConstants.HTML; - partitionBorder = true; - return getToken(IPHPPartitionScannerConstants.SMARTY); + case '/': + // read until end of line + if (!readSingleLine()) { +// state = STATE_DEFAULT; + return getToken(token); } break; - case '/' : - if (!isInString(IPHPPartitionScannerConstants.PHP) && (c = read()) == '*') { // MULTINE COMMENT JAVASCRIPT, CSS, PHP - if (fContentType == IPHPPartitionScannerConstants.PHP && fCurrentLength > 2) { - unread(2); - IToken token = getToken(fContentType); - fContentType = IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT; - return token; - } else if (fContentType == IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT) { - fTokenOffset = fOffset - 2; - fCurrentLength = 2; - } - - } else if (!isInString(IPHPPartitionScannerConstants.PHP) && c != ICharacterScanner.EOF) - unread(); - break; - case '*' : - if (!isInString(IPHPPartitionScannerConstants.PHP) && (c = read()) == '/') { - if (fContentType == IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT) { - fContentType = IPHPPartitionScannerConstants.PHP; - partitionBorder = true; - return getToken(IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT); - } else if (fContentType == IPHPPartitionScannerConstants.CSS_MULTILINE_COMMENT) { - } else if (fContentType == IPHPPartitionScannerConstants.JS_MULTILINE_COMMENT) { - } - } else if (fFileType == IPHPPartitionScannerConstants.SMARTY_FILE && (c = read()) == '}') { - if (DEBUG) { - System.out.println( - "SMARTYDOC_TOKEN end " - + fTokenOffset - + " fContentType=" - + fContentType - + " fLength=" - + fLength - + " fOffset=" - + fOffset); - } - if (fContentType == IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT) { - fContentType = IPHPPartitionScannerConstants.HTML; - partitionBorder = true; - return getToken(IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT); - } - } else if (!isInString(IPHPPartitionScannerConstants.PHP) && c != ICharacterScanner.EOF) { - unread(); + case '*': + // read until end of comment + if (!readMultiLineComment()) { +// state = STATE_DEFAULT; + return getToken(token); } break; - case '\'' : - if (!fInDoubString) - fInString = !fInString; - break; - case '"' : - // toggle String mode - if (!fInString) - fInDoubString = !fInDoubString; - break; + default: + continue; + } + break; + case '#': // line comment + // read until end of line + if (!readSingleLine()) { +// state = STATE_DEFAULT; + return getToken(token); + } + break; + case '?': + ch = read(); + switch (ch) { + case ICharacterScanner.EOF: + case '>': +// state = STATE_DEFAULT; + return getToken(token); + + case '?': + continue; + default: + continue; + } } - } // end of file reached but we have to return the - // last partition. - return getToken(fContentType); + + ch = read(); + } } - /* (non-Javadoc) - * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(org.eclipse.jface.text.IDocument, int, int) - */ - public void setRange(IDocument document, int offset, int length) { - if (DEBUG) { - System.out.println("SET RANGE: offset=" + offset + " length=" + length); + + private IToken getToken(String type) { + length = position - offset; + + if (length == 0) { + return Token.EOF; } - fDocument = document; - fOffset = offset; - fTokenOffset = offset; - fCurrentLength = 0; - fLength = 0; - fEnd = fOffset + length; - fInString = false; - fInDoubString = false; - fContentType = IPHPPartitionScannerConstants.HTML; - // String[] prev = getPartitionStack(offset); +// if (length<0) { +// try { +// System.out.println("Length<0:"+document.get(offset,5)+""+length); +// } catch (BadLocationException e) { +// e.printStackTrace(); +// } +// } + + if (type == null) { + return Token.UNDEFINED; + } + + IToken token = (IToken) tokens.get(type); + if (token == null) { + token = new Token(type); + tokens.put(type, token); + } + + return token; } private int read() { - try { - if (fOffset < fEnd) { - fCurrentLength++; - return fDocument.getChar(fOffset++); - } + if (position >= end) { return ICharacterScanner.EOF; + } + + try { + return document.getChar(position++); } catch (BadLocationException e) { - // should never happen - // TODO write stacktrace to log - fOffset = fEnd; + --position; return ICharacterScanner.EOF; } } - private void unread() { - --fOffset; - --fCurrentLength; + private boolean readUntilEscapedDQ() { + // search last double quoted character + try { + char ch; + while (true) { + if (position >= end) { + return false; + } + ch = document.getChar(position++); + if (ch == '\\') { + if (position >= end) { + return false; + } + ch = document.getChar(position++); // ignore escaped character + } else if (ch == '"') { + return true; + } + } + } catch (BadLocationException e) { + --position; + } + return false; } - private void unread(int num) { - fOffset -= num; - fCurrentLength -= num; + private boolean readUntilEscapedSQ() { + // search last single quoted character + try { + char ch; + while (true) { + if (position >= end) { + return false; + } + ch = document.getChar(position++); + if (ch == '\\') { + if (position >= end) { + return false; + } + ch = document.getChar(position++); // ignore escaped character + } else if (ch == '\'') { + return true; + } + } + } catch (BadLocationException e) { + --position; + } + return false; } - private boolean checkPattern(char[] pattern) { - return checkPattern(pattern, false); + private boolean readSingleLine() { + try { + do { + if (position >= end) { + return false; + } + } while (document.getChar(position++) != '\n'); + return true; + } catch (BadLocationException e) { + --position; + } + return false; } - /** - * Check if next character sequence read from document is equals to - * the provided pattern. Pattern is read from left to right until the - * first character read doesn't match. If this happens all read characters are - * unread. - * @param pattern The pattern to check. - * @return true if pattern is equals else returns false. - */ - private boolean checkPattern(char[] pattern, boolean ignoreCase) { - int prevOffset = fOffset; - int prevLength = fCurrentLength; - for (int i = 0; i < pattern.length; i++) { - int c = read(); - - if (c == ICharacterScanner.EOF || !letterEquals(c, pattern[i], ignoreCase)) { - fOffset = prevOffset; - fCurrentLength = prevLength; - return false; + private boolean readMultiLineComment() { + try { + char ch; + while (true) { + if (position >= end) { + return false; + } + ch = document.getChar(position++); + if (ch == '*') { + if (position >= end) { + return false; + } + if (document.getChar(position) == '/') { + position++; + return true; + } + } } + } catch (BadLocationException e) { + --position; } + return false; + } - return true; + private void unread() { + --position; } - private boolean letterEquals(int test, char letter, boolean ignoreCase) { - if (test == letter) - return true; - else if (ignoreCase && Character.isLowerCase(letter) && test == Character.toUpperCase(letter)) - return true; - else if (ignoreCase && Character.isUpperCase(letter) && test == Character.toLowerCase(letter)) - return true; + /* + * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset() + */ + public int getTokenOffset() { + if (AbstractPartitioner.DEBUG) { + Assert.isTrue(offset >= 0, Integer.toString(offset)); + } + return offset; + } - return false; + /* + * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength() + */ + public int getTokenLength() { + return length; } - /** - * Checks wether the offset is in a String and the specified - * contenttype is the current content type. - * Strings are delimited, mutual exclusive, by a " or by a '. - * - * @param contentType The contenttype to check. - * @return true if the current offset is in a string else - * returns false. + /* + * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(IDocument, int, int) */ - private boolean isInString(String contentType) { - if (fContentType == contentType) - return (fInString || fInDoubString); - else - return false; + public void setRange(IDocument document, int offset, int length) { + this.document = document; +// this.begin = offset; + this.end = offset + length; + + this.offset = offset; + this.position = offset; + this.length = 0; } - /** - * Returns the previouse partition stack for the given offset. - * - * @param offset The offset to return the previouse partitionstack for. - * - * @return The stack as a string array. + /* + * @see org.eclipse.jface.text.rules.IPartitionTokenScanner */ - private String[] getPartitionStack(int offset) { - ArrayList types = new ArrayList(); - int tmpOffset = 0; - try { - ITypedRegion region = fDocument.getPartition(offset); - tmpOffset = region.getOffset(); - while (tmpOffset - 1 > 0) { - region = fDocument.getPartition(tmpOffset - 1); - tmpOffset = region.getOffset(); - types.add(0, region.getType()); - } - } catch (BadLocationException e) { - if (DEBUG) { - e.printStackTrace(); + public void setPartialRange(IDocument document, int offset, int length, String contentType, int partitionOffset) { +// state = STATE_DEFAULT; + if (partitionOffset > -1) { + int delta = offset - partitionOffset; + if (delta > 0) { + setRange(document, partitionOffset, length + delta); + return; } } - - String[] retVal = new String[types.size()]; - - retVal = (String[]) types.toArray(retVal); - return retVal; + setRange(document, partitionOffset, length); } -} + // 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