gt:       fTokenLength -= getLastLength(fLast);
context: /*
   * Copyright (c) 2012-2017 Red Hat, Inc.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *   Red Hat, Inc. - initial API and implementation
   */
  package org.eclipse.che.ide.ext.java.client.editor;
  
  import java.util.List;
  import javax.inject.Inject;
  import org.eclipse.che.ide.api.editor.partition.PartitionScanner;
  import org.eclipse.che.ide.api.editor.partition.StringCharacterScanner;
  import org.eclipse.che.ide.api.editor.text.rules.Token;
  import org.eclipse.che.ide.api.editor.text.rules.TokenImpl;
  import org.eclipse.che.ide.ext.java.jdt.JavaPartitions;
  import org.eclipse.che.ide.ext.java.jdt.text.rules.CharacterScanner;
  
  /**
   * This scanner recognizes the JavaDoc comments, Java multi line comments, Java single line
   * comments, Java strings and Java characters.
   */
  public class JavaPartitionScanner implements PartitionScanner, JavaPartitions {
  
    // states
    private static final int JAVA = 0;
    private static final int SINGLE_LINE_COMMENT = 1;
    private static final int MULTI_LINE_COMMENT = 2;
    private static final int JAVADOC = 3;
    private static final int CHARACTER = 4;
    private static final int STRING = 5;
  
    // 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 content. */
    private final StringCharacterScanner fScanner = new StringCharacterScanner();
  
    /** 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 boolean fEmulate = false;
    private int fJavaOffset;
    private int fJavaLength;
  
    private final Token[] fTokens =
        new Token[] {
          new TokenImpl(null),
          new TokenImpl(JAVA_SINGLE_LINE_COMMENT),
          new TokenImpl(JAVA_MULTI_LINE_COMMENT),
          new TokenImpl(JAVA_DOC),
          new TokenImpl(JAVA_CHARACTER),
          new TokenImpl(JAVA_STRING)
        };
  
    public JavaPartitionScanner(boolean emulate) {
      fEmulate = emulate;
    }
  
    @Inject
    public JavaPartitionScanner() {
      this(false);
    }
  
    /*
     * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
     */
    public Token nextToken() {
  
      // emulate JavaPartitionScanner
      if (fEmulate) {
        if (fJavaOffset != -1 && fTokenOffset + fTokenLength != fJavaOffset + fJavaLength) {
          fTokenOffset += fTokenLength;
          return fTokens[JAVA];
        } else {
          fJavaOffset = -1;
          fJavaLength = 0;
        }
      }
  
      fTokenOffset += fTokenLength;
      fTokenLength = fPrefixLength;
  
      while (true) {
        final int ch = fScanner.read();
  
        // characters
        switch (ch) {
          case CharacterScanner.EOF:
            if (fTokenLength > 0) {
              fLast = NONE; // ignore last
              return preFix(fState, JAVA, NONE, 0);
  
            } else {
              fLast = NONE;
              fPrefixLength = 0;
              return TokenImpl.EOF;
            }
  
          case '\r':
            // emulate JavaPartitionScanner
            if (!fEmulate && fLast != CARRIAGE_RETURN) {
              fLast = CARRIAGE_RETURN;
              fTokenLength++;
              continue;
  
            } else {
  
              switch (fState) {
                case SINGLE_LINE_COMMENT:
                case CHARACTER:
                case STRING:
                  if (fTokenLength > 0) {
                    final Token token = fTokens[fState];
  
                    // emulate JavaPartitionScanner
                    if (fEmulate) {
                      fTokenLength++;
                      fLast = NONE;
                      fPrefixLength = 0;
                    } else {
                      fLast = CARRIAGE_RETURN;
                      fPrefixLength = 1;
                    }
  
                    fState = JAVA;
                    return token;
  
                  } else {
                    consume();
                    continue;
                  }
  
                default:
                  consume();
                  continue;
              }
            }
  
          case '\n':
            switch (fState) {
              case SINGLE_LINE_COMMENT:
              case CHARACTER:
              case STRING:
                // assert(fTokenLength > 0);
                return postFix(fState);
  
              default:
                consume();
                continue;
            }
  
          default:
            if (!fEmulate && fLast == CARRIAGE_RETURN) {
              switch (fState) {
                case SINGLE_LINE_COMMENT:
                case CHARACTER:
                case STRING:
                  int last;
                  int newState;
                  switch (ch) {
                    case '/':
                      last = SLASH;
                      newState = JAVA;
                      break;
  
                    case '*':
                      last = STAR;
                      newState = JAVA;
                      break;
  
                    case '\'':
                      last = NONE;
                      newState = CHARACTER;
                      break;
  
                    case '"':
                      last = NONE;
                      newState = STRING;
                      break;
  
                    case '\r':
                      last = CARRIAGE_RETURN;
                      newState = JAVA;
                      break;
  
                    case '\\':
                      last = BACKSLASH;
                      newState = JAVA;
                      break;
  
                    default:
                      last = NONE;
                      newState = JAVA;
                      break;
                  }
  
                  fLast = NONE; // ignore fLast
                  return preFix(fState, newState, last, 1);
  
                default:
                  break;
              }
            }
        }
  
        // states
        switch (fState) {
          case JAVA:
            switch (ch) {
              case '/':
                if (fLast == SLASH) {
                  if (fTokenLength - getLastLength(fLast) > 0) {
                    return preFix(JAVA, SINGLE_LINE_COMMENT, NONE, 2);
                  } else {
                    preFix(JAVA, 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(JAVA, MULTI_LINE_COMMENT, SLASH_STAR, 2);
                  } else {
                    preFix(JAVA, MULTI_LINE_COMMENT, SLASH_STAR, 2);
                    fTokenOffset += fTokenLength;
                    fTokenLength = fPrefixLength;
                    break;
                  }
  
                } else {
                  consume();
                  break;
                }
  
              case '\'':
                fLast = NONE; // ignore fLast
                if (fTokenLength > 0) {
                  return preFix(JAVA, CHARACTER, NONE, 1);
                } else {
                  preFix(JAVA, CHARACTER, NONE, 1);
                  fTokenOffset += fTokenLength;
                  fTokenLength = fPrefixLength;
                  break;
                }
  
              case '"':
                fLast = NONE; // ignore fLast
                if (fTokenLength > 0) {
                  return preFix(JAVA, STRING, NONE, 1);
                } else {
                  preFix(JAVA, STRING, NONE, 1);
                  fTokenOffset += fTokenLength;
                  fTokenLength = fPrefixLength;
                  break;
                }
  
              default:
                consume();
                break;
            }
            break;
  
          case SINGLE_LINE_COMMENT:
            consume();
            break;
  
          case JAVADOC:
            switch (ch) {
              case '/':
                switch (fLast) {
                  case SLASH_STAR_STAR:
                    return postFix(MULTI_LINE_COMMENT);
  
                  case STAR:
                    return postFix(JAVADOC);
  
                  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 = JAVADOC;
                } else {
                  fTokenLength++;
                  fLast = STAR;
                }
                break;
  
              case '/':
                if (fLast == STAR) {
                  return postFix(MULTI_LINE_COMMENT);
                } else {
                  consume();
                  break;
                }
  
              default:
                consume();
                break;
            }
            break;
  
          case STRING:
            switch (ch) {
              case '\\':
                fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
                fTokenLength++;
                break;
  
              case '\"':
                if (fLast != BACKSLASH) {
                  return postFix(STRING);
  
                } else {
                  consume();
                  break;
                }
  
              default:
                consume();
                break;
            }
            break;
  
          case CHARACTER:
            switch (ch) {
              case '\\':
                fLast = (fLast == BACKSLASH) ? NONE : BACKSLASH;
                fTokenLength++;
                break;
  
              case '\'':
                if (fLast != BACKSLASH) {
                  return postFix(CHARACTER);
  
                } else {
                  consume();
                  break;
                }
  
              default:
                consume();
                break;
            }
            break;
          default:
            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 Token postFix(int state) {
      fTokenLength++;
      fLast = NONE;
      fState = JAVA;
      fPrefixLength = 0;
      return fTokens[state];
    }
  
    private final Token preFix(int state, int newState, int last, int prefixLength) {
      // emulate JavaPartitionScanner
      if (fEmulate && 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 {
  