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;
 
  15 import org.eclipse.jface.text.Assert;
 
  16 import org.eclipse.jface.text.IDocument;
 
  17 import org.eclipse.jface.text.rules.ICharacterScanner;
 
  18 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
 
  19 import org.eclipse.jface.text.rules.IToken;
 
  20 import org.eclipse.jface.text.rules.Token;
 
  23  * This scanner recognizes the JavaDoc comments, Java multi line comments, Java
 
  24  * single line comments, Java strings.
 
  26 public class FastJavaPartitionScanner implements IPartitionTokenScanner,
 
  30         private static final int PHP = 0;
 
  32         private static final int SINGLE_LINE_COMMENT = 1;
 
  34         private static final int MULTI_LINE_COMMENT = 2;
 
  36         private static final int PHPDOC = 3;
 
  38         private static final int STRING_DQ = 4;
 
  40         private static final int STRING_SQ = 5;
 
  42         private static final int STRING_HEREDOC = 6;
 
  44         // beginning of prefixes and postfixes
 
  45         private static final int NONE = 0;
 
  47         private static final int BACKSLASH = 1; // postfix for STRING_DQ and
 
  50         private static final int SLASH = 2; // prefix for SINGLE_LINE or MULTI_LINE
 
  55         private static final int SLASH_STAR = 3; // prefix for MULTI_LINE_COMMENT
 
  60         private static final int SLASH_STAR_STAR = 4; // prefix for
 
  65         private static final int STAR = 5; // postfix for MULTI_LINE_COMMENT or
 
  69         private static final int CARRIAGE_RETURN = 6; // postfix for STRING_DQ,
 
  72         // SINGLE_LINE_COMMENT
 
  74         // private static final int HEREDOC = 7;
 
  77         private final BufferedDocumentScanner fScanner = new BufferedDocumentScanner(
 
  82         /** The offset of the last returned token. */
 
  83         private int fTokenOffset;
 
  85         /** The length of the last returned token. */
 
  86         private int fTokenLength;
 
  88         /** The state of the scanner. */
 
  91         /** The last significant characters read. */
 
  94         /** The amount of characters already read on first call to nextToken(). */
 
  95         private int fPrefixLength;
 
  97         // emulate JavaPartitionScanner
 
  98         private boolean fEmulate = false;
 
 100         private int fJavaOffset;
 
 102         private int fJavaLength;
 
 104         private final IToken[] fTokens = new IToken[] { new Token(null),
 
 105                         new Token(PHP_SINGLELINE_COMMENT),
 
 106                         new Token(PHP_MULTILINE_COMMENT), new Token(PHP_PHPDOC_COMMENT),
 
 107                         new Token(PHP_STRING_DQ), new Token(PHP_STRING_SQ),
 
 108                         new Token(PHP_STRING_HEREDOC) };
 
 110         public FastJavaPartitionScanner(boolean emulate) {
 
 114         public FastJavaPartitionScanner() {
 
 119          * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
 
 121         public IToken nextToken() {
 
 123                 // emulate JavaPartitionScanner
 
 125                         if (fJavaOffset != -1
 
 126                                         && fTokenOffset + fTokenLength != fJavaOffset + fJavaLength) {
 
 127                                 fTokenOffset += fTokenLength;
 
 135                 fTokenOffset += fTokenLength;
 
 136                 fTokenLength = fPrefixLength;
 
 139                         final int ch = fScanner.read();
 
 143                         case ICharacterScanner.EOF:
 
 144                                 if (fTokenLength > 0) {
 
 145                                         fLast = NONE; // ignore last
 
 146                                         return preFix(fState, PHP, NONE, 0);
 
 155                                 // emulate JavaPartitionScanner
 
 156                                 if (!fEmulate && fLast != CARRIAGE_RETURN) {
 
 157                                         fLast = CARRIAGE_RETURN;
 
 164                                         case SINGLE_LINE_COMMENT:
 
 168                                                 if (fTokenLength > 0) {
 
 169                                                         IToken token = fTokens[fState];
 
 171                                                         // emulate JavaPartitionScanner
 
 177                                                                 fLast = CARRIAGE_RETURN;
 
 197                                 case SINGLE_LINE_COMMENT:
 
 201                                         // assert(fTokenLength > 0);
 
 202                                         return postFix(fState);
 
 210                                 if (fState == SINGLE_LINE_COMMENT) {
 
 211                                         int nextch = fScanner.read();
 
 213                                                 // <h1>This is an <?php # echo 'simple' ?> example.</h1>
 
 217                                                 return postFix(fState);
 
 219                                                 // bug #1404228: Crash on <?php // comment ?>
 
 220                                                 if (nextch != ICharacterScanner.EOF) {
 
 227                                 if (!fEmulate && fLast == CARRIAGE_RETURN) {
 
 229                                         case SINGLE_LINE_COMMENT:
 
 248                                                         newState = STRING_SQ;
 
 253                                                         newState = STRING_DQ;
 
 257                                                         last = CARRIAGE_RETURN;
 
 272                                                 fLast = NONE; // ignore fLast
 
 273                                                 return preFix(fState, newState, last, 1);
 
 286                                         if (fTokenLength > 0) {
 
 287                                                 return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 1);
 
 289                                                 preFix(PHP, SINGLE_LINE_COMMENT, NONE, 1);
 
 290                                                 fTokenOffset += fTokenLength;
 
 291                                                 fTokenLength = fPrefixLength;
 
 295                                         if (fLast == SLASH) {
 
 296                                                 if (fTokenLength - getLastLength(fLast) > 0) {
 
 297                                                         return preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2);
 
 299                                                         preFix(PHP, SINGLE_LINE_COMMENT, NONE, 2);
 
 300                                                         fTokenOffset += fTokenLength;
 
 301                                                         fTokenLength = fPrefixLength;
 
 312                                         if (fLast == SLASH) {
 
 313                                                 if (fTokenLength - getLastLength(fLast) > 0)
 
 314                                                         return preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR,
 
 317                                                         preFix(PHP, MULTI_LINE_COMMENT, SLASH_STAR, 2);
 
 318                                                         fTokenOffset += fTokenLength;
 
 319                                                         fTokenLength = fPrefixLength;
 
 329                                         fLast = NONE; // ignore fLast
 
 330                                         if (fTokenLength > 0)
 
 331                                                 return preFix(PHP, STRING_SQ, NONE, 1);
 
 333                                                 preFix(PHP, STRING_SQ, NONE, 1);
 
 334                                                 fTokenOffset += fTokenLength;
 
 335                                                 fTokenLength = fPrefixLength;
 
 340                                         fLast = NONE; // ignore fLast
 
 341                                         if (fTokenLength > 0)
 
 342                                                 return preFix(PHP, STRING_DQ, NONE, 1);
 
 344                                                 preFix(PHP, STRING_DQ, NONE, 1);
 
 345                                                 fTokenOffset += fTokenLength;
 
 346                                                 fTokenLength = fPrefixLength;
 
 356                         case SINGLE_LINE_COMMENT:
 
 364                                         case SLASH_STAR_STAR:
 
 365                                                 return postFix(MULTI_LINE_COMMENT);
 
 368                                                 return postFix(PHPDOC);
 
 387                         case MULTI_LINE_COMMENT:
 
 390                                         if (fLast == SLASH_STAR) {
 
 391                                                 fLast = SLASH_STAR_STAR;
 
 402                                                 return postFix(MULTI_LINE_COMMENT);
 
 417                                         fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
 
 422                                         if (fLast != BACKSLASH) {
 
 423                                                 return postFix(STRING_DQ);
 
 438                                         fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
 
 443                                         if (fLast != BACKSLASH) {
 
 444                                                 return postFix(STRING_SQ);
 
 459                         // fLast= (fLast == BACKSLASH) ? NONE : BACKSLASH;
 
 464                         // if (fLast != BACKSLASH) {
 
 465                         // return postFix(CHARACTER);
 
 481         private static final int getLastLength(int last) {
 
 489                 case CARRIAGE_RETURN:
 
 498                 case SLASH_STAR_STAR:
 
 503         private final void consume() {
 
 508         private final IToken postFix(int state) {
 
 513                 return fTokens[state];
 
 516         private final IToken preFix(int state, int newState, int last,
 
 518                 // emulate JavaPartitionScanner
 
 519                 if (fEmulate && state == PHP
 
 520                                 && (fTokenLength - getLastLength(fLast) > 0)) {
 
 521                         fTokenLength -= getLastLength(fLast);
 
 522                         fJavaOffset = fTokenOffset;
 
 523                         fJavaLength = fTokenLength;
 
 526                         fPrefixLength = prefixLength;
 
 528                         return fTokens[state];
 
 531                         fTokenLength -= getLastLength(fLast);
 
 533                         fPrefixLength = prefixLength;
 
 534                         IToken token = fTokens[state];
 
 540         private static int getState(String contentType) {
 
 542                 if (contentType == null)
 
 545                 else if (contentType.equals(PHP_SINGLELINE_COMMENT))
 
 546                         return SINGLE_LINE_COMMENT;
 
 548                 else if (contentType.equals(PHP_MULTILINE_COMMENT))
 
 549                         return MULTI_LINE_COMMENT;
 
 551                 else if (contentType.equals(PHP_PHPDOC_COMMENT))
 
 554                 else if (contentType.equals(PHP_STRING_DQ))
 
 557                 else if (contentType.equals(PHP_STRING_SQ))
 
 560                 else if (contentType.equals(PHP_STRING_HEREDOC))
 
 561                         return STRING_HEREDOC;
 
 563                 // else if (contentType.equals(JAVA_CHARACTER))
 
 571          * @see IPartitionTokenScanner#setPartialRange(IDocument, int, int, String,
 
 574         public void setPartialRange(IDocument document, int offset, int length,
 
 575                         String contentType, int partitionOffset) {
 
 576                 fScanner.setRange(document, offset, length);
 
 577                 setRange(document, offset, length);
 
 578                 fTokenOffset = partitionOffset;
 
 580                 fPrefixLength = offset - partitionOffset;
 
 583                 if (offset == partitionOffset) {
 
 584                         // restart at beginning of partition
 
 587                         fState = getState(contentType);
 
 590                 // emulate JavaPartitionScanner
 
 598          * @see ITokenScanner#setRange(IDocument, int, int)
 
 600         public void setRange(IDocument document, int offset, int length) {
 
 601                 fScanner.setRange(document, offset, length);
 
 602                 fTokenOffset = offset;
 
 608                 // emulate JavaPartitionScanner
 
 616          * @see ITokenScanner#getTokenLength()
 
 618         public int getTokenLength() {
 
 623          * @see ITokenScanner#getTokenOffset()
 
 625         public int getTokenOffset() {
 
 626                 if (AbstractPartitioner.DEBUG) {
 
 627                         Assert.isTrue(fTokenOffset >= 0, Integer.toString(fTokenOffset));