1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2004 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials
 
   4  * are made available under the terms of the Common Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.ui.text;
 
  13 import net.sourceforge.phpeclipse.ui.text.rules.AbstractPartitioner;
 
  16 //import org.eclipse.jface.text.Assert;
 
  17 import org.eclipse.core.runtime.Assert;
 
  18 import org.eclipse.jface.text.IDocument;
 
  19 import org.eclipse.jface.text.rules.ICharacterScanner;
 
  20 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
 
  21 import org.eclipse.jface.text.rules.IToken;
 
  22 import org.eclipse.jface.text.rules.Token;
 
  25  * This scanner recognizes the JavaDoc comments, Java multi line comments, Java
 
  26  * single line comments, Java strings.
 
  28 public class FastJavaPartitionScanner implements IPartitionTokenScanner,
 
  32         private static final int PHP = 0;
 
  34         private static final int SINGLE_LINE_COMMENT = 1;
 
  36         private static final int MULTI_LINE_COMMENT = 2;
 
  38         private static final int PHPDOC = 3;
 
  40         private static final int STRING_DQ = 4;
 
  42         private static final int STRING_SQ = 5;
 
  44         private static final int STRING_HEREDOC = 6;
 
  46         // beginning of prefixes and postfixes
 
  47         private static final int NONE = 0;
 
  49         private static final int BACKSLASH = 1; // postfix for STRING_DQ and
 
  52         private static final int SLASH = 2; // prefix for SINGLE_LINE or MULTI_LINE
 
  57         private static final int SLASH_STAR = 3; // prefix for MULTI_LINE_COMMENT
 
  62         private static final int SLASH_STAR_STAR = 4; // prefix for
 
  67         private static final int STAR = 5; // postfix for MULTI_LINE_COMMENT or
 
  71         private static final int CARRIAGE_RETURN = 6; // postfix for STRING_DQ,
 
  74         // SINGLE_LINE_COMMENT
 
  76         // private static final int HEREDOC = 7;
 
  79         private final BufferedDocumentScanner fScanner = new BufferedDocumentScanner(
 
  84         /** The offset of the last returned token. */
 
  85         private int fTokenOffset;
 
  87         /** The length of the last returned token. */
 
  88         private int fTokenLength;
 
  90         /** The state of the scanner. */
 
  93         /** The last significant characters read. */
 
  96         /** The amount of characters already read on first call to nextToken(). */
 
  97         private int fPrefixLength;
 
  99         // emulate JavaPartitionScanner
 
 100         private boolean fEmulate = false;
 
 102         private int fJavaOffset;
 
 104         private int fJavaLength;
 
 106         private final IToken[] fTokens = new IToken[] { new Token(null),
 
 107                         new Token(PHP_SINGLELINE_COMMENT),
 
 108                         new Token(PHP_MULTILINE_COMMENT), new Token(PHP_PHPDOC_COMMENT),
 
 109                         new Token(PHP_STRING_DQ), new Token(PHP_STRING_SQ),
 
 110                         new Token(PHP_STRING_HEREDOC) };
 
 112         public FastJavaPartitionScanner(boolean emulate) {
 
 116         public FastJavaPartitionScanner() {
 
 121          * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
 
 123         public IToken nextToken() {
 
 125                 // emulate JavaPartitionScanner
 
 127                         if (fJavaOffset != -1
 
 128                                         && fTokenOffset + fTokenLength != fJavaOffset + fJavaLength) {
 
 129                                 fTokenOffset += fTokenLength;
 
 137                 fTokenOffset += fTokenLength;
 
 138                 fTokenLength = fPrefixLength;
 
 141                         final int ch = fScanner.read();
 
 145                         case ICharacterScanner.EOF:
 
 146                                 if (fTokenLength > 0) {
 
 147                                         fLast = NONE; // ignore last
 
 148                                         return preFix(fState, PHP, NONE, 0);
 
 157                                 // emulate JavaPartitionScanner
 
 158                                 if (!fEmulate && fLast != CARRIAGE_RETURN) {
 
 159                                         fLast = CARRIAGE_RETURN;
 
 166                                         case SINGLE_LINE_COMMENT:
 
 170                                                 if (fTokenLength > 0) {
 
 171                                                         IToken token = fTokens[fState];
 
 173                                                         // emulate JavaPartitionScanner
 
 179                                                                 fLast = CARRIAGE_RETURN;
 
 199                                 case SINGLE_LINE_COMMENT:
 
 203                                         // assert(fTokenLength > 0);
 
 204                                         return postFix(fState);
 
 212                                 if (fState == SINGLE_LINE_COMMENT) {
 
 213                                         int nextch = fScanner.read();
 
 215                                                 // <h1>This is an <?php # echo 'simple' ?> example.</h1>
 
 219                                                 return postFix(fState);
 
 221                                                 // bug #1404228: Crash on <?php // comment ?>
 
 222                                                 if (nextch != ICharacterScanner.EOF) {
 
 229                                 if (!fEmulate && fLast == CARRIAGE_RETURN) {
 
 231                                         case SINGLE_LINE_COMMENT:
 
 250                                                         newState = STRING_SQ;
 
 255                                                         newState = STRING_DQ;
 
 259                                                         last = CARRIAGE_RETURN;
 
 274                                                 fLast = NONE; // ignore fLast
 
 275                                                 return preFix(fState, newState, last, 1);
 
 288                                         if (fTokenLength > 0) {
 
 289                                                 return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 1);
 
 291                                                 preFix(PHP, SINGLE_LINE_COMMENT, NONE, 1);
 
 292                                                 fTokenOffset += fTokenLength;
 
 293                                                 fTokenLength = fPrefixLength;
 
 297                                         if (fLast == SLASH) {
 
 298                                                 if (fTokenLength - getLastLength(fLast) > 0) {
 
 299                                                         return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2);
 
 301                                                         preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2);
 
 302                                                         fTokenOffset += fTokenLength;
 
 303                                                         fTokenLength = fPrefixLength;
 
 314                                         if (fLast == SLASH) {
 
 315                                                 if (fTokenLength - getLastLength(fLast) > 0)
 
 316                                                         return preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR,
 
 319                                                         preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR, 2);
 
 320                                                         fTokenOffset += fTokenLength;
 
 321                                                         fTokenLength = fPrefixLength;
 
 331                                         fLast = NONE; // ignore fLast
 
 332                                         if (fTokenLength > 0)
 
 333                                                 return preFix(PHP, STRING_SQ, NONE, 1);
 
 335                                                 preFix(PHP, STRING_SQ, NONE, 1);
 
 336                                                 fTokenOffset += fTokenLength;
 
 337                                                 fTokenLength = fPrefixLength;
 
 342                                         fLast = NONE; // ignore fLast
 
 343                                         if (fTokenLength > 0)
 
 344                                                 return preFix(PHP, STRING_DQ, NONE, 1);
 
 346                                                 preFix(PHP, STRING_DQ, NONE, 1);
 
 347                                                 fTokenOffset += fTokenLength;
 
 348                                                 fTokenLength = fPrefixLength;
 
 358                         case SINGLE_LINE_COMMENT:
 
 366                                         case SLASH_STAR_STAR:
 
 367                                                 return postFix(MULTI_LINE_COMMENT);
 
 370                                                 return postFix(PHPDOC);
 
 389                         case MULTI_LINE_COMMENT:
 
 392                                         if (fLast == SLASH_STAR) {
 
 393                                                 fLast = SLASH_STAR_STAR;
 
 404                                                 return postFix(MULTI_LINE_COMMENT);
 
 419                                         fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
 
 424                                         if (fLast != BACKSLASH) {
 
 425                                                 return postFix(STRING_DQ);
 
 440                                         fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
 
 445                                         if (fLast != BACKSLASH) {
 
 446                                                 return postFix(STRING_SQ);
 
 461                         // fLast= (fLast == BACKSLASH) ? NONE : BACKSLASH;
 
 466                         // if (fLast != BACKSLASH) {
 
 467                         // return postFix(CHARACTER);
 
 483         private static final int getLastLength(int last) {
 
 491                 case CARRIAGE_RETURN:
 
 500                 case SLASH_STAR_STAR:
 
 505         private final void consume() {
 
 510         private final IToken postFix(int state) {
 
 515                 return fTokens[state];
 
 518         private final IToken preFix(int state, int newState, int last,
 
 520                 // emulate JavaPartitionScanner
 
 521                 if (fEmulate && state == PHP
 
 522                                 && (fTokenLength - getLastLength(fLast) > 0)) {
 
 523                         fTokenLength -= getLastLength(fLast);
 
 524                         fJavaOffset = fTokenOffset;
 
 525                         fJavaLength = fTokenLength;
 
 528                         fPrefixLength = prefixLength;
 
 530                         return fTokens[state];
 
 533                         fTokenLength -= getLastLength(fLast);
 
 535                         fPrefixLength = prefixLength;
 
 536                         IToken token = fTokens[state];
 
 542         private static int getState(String contentType) {
 
 544                 if (contentType == null)
 
 547                 else if (contentType.equals(PHP_SINGLELINE_COMMENT))
 
 548                         return SINGLE_LINE_COMMENT;
 
 550                 else if (contentType.equals(PHP_MULTILINE_COMMENT))
 
 551                         return MULTI_LINE_COMMENT;
 
 553                 else if (contentType.equals(PHP_PHPDOC_COMMENT))
 
 556                 else if (contentType.equals(PHP_STRING_DQ))
 
 559                 else if (contentType.equals(PHP_STRING_SQ))
 
 562                 else if (contentType.equals(PHP_STRING_HEREDOC))
 
 563                         return STRING_HEREDOC;
 
 565                 // else if (contentType.equals(JAVA_CHARACTER))
 
 573          * @see IPartitionTokenScanner#setPartialRange(IDocument, int, int, String,
 
 576         public void setPartialRange(IDocument document, int offset, int length,
 
 577                         String contentType, int partitionOffset) {
 
 578                 fScanner.setRange(document, offset, length);
 
 579                 setRange(document, offset, length);
 
 580                 fTokenOffset = partitionOffset;
 
 582                 fPrefixLength = offset - partitionOffset;
 
 585                 if (offset == partitionOffset) {
 
 586                         // restart at beginning of partition
 
 589                         fState = getState(contentType);
 
 592                 // emulate JavaPartitionScanner
 
 600          * @see ITokenScanner#setRange(IDocument, int, int)
 
 602         public void setRange(IDocument document, int offset, int length) {
 
 603                 fScanner.setRange(document, offset, length);
 
 604                 fTokenOffset = offset;
 
 610                 // emulate JavaPartitionScanner
 
 618          * @see ITokenScanner#getTokenLength()
 
 620         public int getTokenLength() {
 
 625          * @see ITokenScanner#getTokenOffset()
 
 627         public int getTokenOffset() {
 
 628                 if (AbstractPartitioner.DEBUG) {
 
 629                         Assert.isTrue(fTokenOffset >= 0, Integer.toString(fTokenOffset));