package net.sourceforge.phpdt.internal.ui.text; /* * (c) Copyright IBM Corp. 2000, 2001. * All Rights Reserved. */ import org.eclipse.jface.text.IDocument; 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; /** * This scanner recognizes the JavaDoc comments, Java multi line comments, Java single line comments, * Java strings and Java characters. */ public class FastJavaPartitionScanner implements IPartitionTokenScanner { // private final static String SKIP= "__skip"; //$NON-NLS-1$ // public final static String JAVA_STRING= "__php_string"; //$NON-NLS-1$ // public final static String JAVA_SINGLE_LINE_COMMENT= "__php_singleline_comment"; //$NON-NLS-1$ // public final static String JAVA_MULTI_LINE_COMMENT= "__php_multiline_comment"; //$NON-NLS-1$ // public final static String JAVA_DOC= "__php_phpdoc"; //$NON-NLS-1$ // states private static final int HTML= 0; private static final int SINGLE_LINE_COMMENT= 1; private static final int MULTI_LINE_COMMENT= 2; private static final int PHPDOC= 3; // private static final int CHARACTER= 4; private static final int STRING_SQ= 4; // single quote string private static final int STRING_DQ= 5; // double quote string private static final int PHP= 6; // double quote string // beginning of prefixes and postfixes private static final int NONE= 0; private static final int BACKSLASH= 1; // postfix for STRING and CHARACTER private static final int SLASH= 2; // prefix for SINGLE_LINE or MULTI_LINE or JAVADOC private static final int SLASH_STAR= 3; // prefix for MULTI_LINE_COMMENT or JAVADOC private static final int SLASH_STAR_STAR= 4; // prefix for MULTI_LINE_COMMENT or JAVADOC private static final int STAR= 5; // postfix for MULTI_LINE_COMMENT or JAVADOC private static final int CARRIAGE_RETURN=6; // postfix for STRING, CHARACTER and SINGLE_LINE_COMMENT /** The scanner. */ // private final BufferedRuleBasedScanner fScanner= new BufferedRuleBasedScanner(1000); private final BufferedDocumentScanner fScanner= new BufferedDocumentScanner(1000); // faster implementation /** The offset of the last returned token. */ private int fTokenOffset; /** The length of the last returned token. */ private int fTokenLength; /** The state of the scanner. */ private int fState; /** The last significant characters read. */ private int fLast; /** The amount of characters already read on first call to nextToken(). */ private int fPrefixLength; // emulate JavaPartitionScanner // private static final boolean fgEmulate= false; private int fJavaOffset; private int fJavaLength; private final IToken[] fTokens= new IToken[] { new Token(null), new Token(IPHPPartitions.PHP_SINGLELINE_COMMENT), new Token(IPHPPartitions.PHP_MULTILINE_COMMENT), new Token(IPHPPartitions.PHP_PHPDOC_COMMENT), new Token(IPHPPartitions.PHP_STRING_SQ), new Token(IPHPPartitions.PHP_STRING_DQ), new Token(IPHPPartitions.PHP_PARTITIONING), }; /* * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken() */ public IToken nextToken() { fTokenOffset += fTokenLength; fTokenLength= fPrefixLength; while (true) { final int ch= fScanner.read(); // characters switch (ch) { case ICharacterScanner.EOF: if (fTokenLength > 0) { fLast= NONE; // ignore last return preFix(fState, HTML, NONE, 0); } else { fLast= NONE; fPrefixLength= 0; return Token.EOF; } case '\r': if ( fLast != CARRIAGE_RETURN) { fLast= CARRIAGE_RETURN; fTokenLength++; continue; } else { switch (fState) { case SINGLE_LINE_COMMENT: // case CHARACTER: case STRING_SQ: case STRING_DQ: if (fTokenLength > 0) { IToken token= fTokens[fState]; // emulate JavaPartitionScanner // if (fgEmulate) { // fTokenLength++; // fLast= NONE; // fPrefixLength= 0; // } else { fLast= CARRIAGE_RETURN; fPrefixLength= 1; // } fState= HTML; return token; } else { consume(); continue; } default: consume(); continue; } } case '\n': switch (fState) { case SINGLE_LINE_COMMENT: // case CHARACTER: case STRING_SQ: case STRING_DQ: // assert(fTokenLength > 0); return postFix(fState); default: consume(); continue; } default: if ( fLast == CARRIAGE_RETURN) { switch (fState) { case SINGLE_LINE_COMMENT: // case CHARACTER: case STRING_SQ: case STRING_DQ: int last; int newState; switch (ch) { case '/': last= SLASH; newState= HTML; break; case '*': last= STAR; newState= HTML; break; case '\'': last= NONE; // newState= CHARACTER; newState= STRING_SQ; break; case '"': last= NONE; newState= STRING_DQ; break; case '\r': last= CARRIAGE_RETURN; newState= HTML; break; case '\\': last= BACKSLASH; newState= HTML; break; default: last= NONE; newState= HTML; break; } fLast= NONE; // ignore fLast return preFix(fState, newState, last, 1); default: break; } } } // states switch (fState) { case PHP: switch (ch) { case '/': if (fLast == SLASH) { if (fTokenLength - getLastLength(fLast) > 0) { return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2); } else { preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2); fTokenOffset += fTokenLength; fTokenLength= fPrefixLength; break; } } else { fTokenLength++; fLast= SLASH; break; } case '*': if (fLast == SLASH) { if (fTokenLength - getLastLength(fLast) > 0) return preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR, 2); else { preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR, 2); fTokenOffset += fTokenLength; fTokenLength= fPrefixLength; break; } } else { consume(); break; } case '\'': fLast= NONE; // ignore fLast if (fTokenLength > 0) return preFix(PHP, STRING_SQ, NONE, 1); else { preFix(PHP, STRING_SQ, NONE, 1); fTokenOffset += fTokenLength; fTokenLength= fPrefixLength; break; } case '"': fLast= NONE; // ignore fLast if (fTokenLength > 0) return preFix(PHP, STRING_DQ, NONE, 1); else { preFix(PHP, STRING_DQ, NONE, 1); fTokenOffset += fTokenLength; fTokenLength= fPrefixLength; break; } default: consume(); break; } break; case SINGLE_LINE_COMMENT: consume(); break; case PHPDOC: switch (ch) { case '/': switch (fLast) { case SLASH_STAR_STAR: return postFix(MULTI_LINE_COMMENT); case STAR: return postFix(PHPDOC); default: consume(); break; } break; case '*': fTokenLength++; fLast= STAR; break; default: consume(); break; } break; case MULTI_LINE_COMMENT: switch (ch) { case '*': if (fLast == SLASH_STAR) { fLast= SLASH_STAR_STAR; fTokenLength++; fState= PHPDOC; } else { fTokenLength++; fLast= STAR; } break; case '/': if (fLast == STAR) { return postFix(MULTI_LINE_COMMENT); } else { consume(); break; } default: consume(); break; } break; case STRING_DQ: switch (ch) { case '\\': fLast= (fLast == BACKSLASH) ? NONE : BACKSLASH; fTokenLength++; break; case '\"': if (fLast != BACKSLASH) { return postFix(STRING_DQ); } else { consume(); break; } default: consume(); break; } break; case STRING_SQ: switch (ch) { case '\\': fLast= (fLast == BACKSLASH) ? NONE : BACKSLASH; fTokenLength++; break; case '\'': if (fLast != BACKSLASH) { return postFix(STRING_SQ); } else { consume(); break; } default: consume(); break; } break; } } } private static final int getLastLength(int last) { switch (last) { default: return -1; case NONE: return 0; case CARRIAGE_RETURN: case BACKSLASH: case SLASH: case STAR: return 1; case SLASH_STAR: return 2; case SLASH_STAR_STAR: return 3; } } private final void consume() { fTokenLength++; fLast= NONE; } private final IToken postFix(int state) { fTokenLength++; fLast= NONE; fState= HTML; fPrefixLength= 0; return fTokens[state]; } private final IToken preFix(int state, int newState, int last, int prefixLength) { // emulate JavaPartitionScanner // if (fgEmulate && state == JAVA && (fTokenLength - getLastLength(fLast) > 0)) { // fTokenLength -= getLastLength(fLast); // fJavaOffset= fTokenOffset; // fJavaLength= fTokenLength; // fTokenLength= 1; // fState= newState; // fPrefixLength= prefixLength; // fLast= last; // return fTokens[state]; // // } else { fTokenLength -= getLastLength(fLast); fLast= last; fPrefixLength= prefixLength; IToken token= fTokens[state]; fState= newState; return token; // } } private static int getState(String contentType) { if (contentType == null) return HTML; else if (contentType.equals(IPHPPartitions.PHP_PARTITIONING)) return PHP; else if (contentType.equals(IPHPPartitions.PHP_SINGLELINE_COMMENT)) return SINGLE_LINE_COMMENT; else if (contentType.equals(IPHPPartitions.PHP_MULTILINE_COMMENT)) return MULTI_LINE_COMMENT; else if (contentType.equals(IPHPPartitions.PHP_PHPDOC_COMMENT)) return PHPDOC; else if (contentType.equals(IPHPPartitions.PHP_STRING_DQ)) return STRING_DQ; else if (contentType.equals(IPHPPartitions.PHP_STRING_SQ)) return STRING_SQ; // else if (contentType.equals(SKIP)) // return CHARACTER; else return HTML; } /* * @see IPartitionTokenScanner#setPartialRange(IDocument, int, int, String, int) */ public void setPartialRange(IDocument document, int offset, int length, String contentType, int partitionOffset) { fScanner.setRange(document, offset, length); fTokenOffset= partitionOffset; fTokenLength= 0; fPrefixLength= offset - partitionOffset; fLast= NONE; if (offset == partitionOffset) { // restart at beginning of partition fState= HTML; } else { fState= getState(contentType); } // emulate JavaPartitionScanner // if (fgEmulate) { // fJavaOffset= -1; // fJavaLength= 0; // } } /* * @see ITokenScanner#setRange(IDocument, int, int) */ public void setRange(IDocument document, int offset, int length) { fScanner.setRange(document, offset, length); fTokenOffset= offset; fTokenLength= 0; fPrefixLength= 0; fLast= NONE; fState= HTML; // emulate JavaPartitionScanner // if (fgEmulate) { // fJavaOffset= -1; // fJavaLength= 0; // } } /* * @see ITokenScanner#getTokenLength() */ public int getTokenLength() { return fTokenLength; } /* * @see ITokenScanner#getTokenOffset() */ public int getTokenOffset() { return fTokenOffset; } }