public Token nextToken()

in java/java.lexer/src/org/netbeans/lib/java/lexer/JavaLexer.java [244:1316]


    public Token<JavaTokenId> nextToken() {
        boolean stringLiteralContinuation = false;
        JavaTokenId lookupId = null;
        while(true) {
            int c = stringLiteralContinuation ? '"' : nextChar();
            switch (c) {
                case '#':
                    //Support for exotic identifiers has been removed 6999438
                    return token(JavaTokenId.ERROR);
                case '"': // string literal
                    if (lookupId == null) lookupId = JavaTokenId.STRING_LITERAL;
                    while (true) {
                        switch (nextChar()) {
                            case '"': // NOI18N
                                String text = input.readText().toString();
                                if (text.length() == 2 && !stringLiteralContinuation) {
                                    int mark = input.readLength();
                                    if (nextChar() != '"') {
                                        input.backup(1); //TODO: EOF???
                                        return token(lookupId);
                                    }
                                    int c2 = nextChar();
                                    while (Character.isWhitespace(c2) && c2 != '\n') {
                                        c2 = nextChar();
                                    }
                                    if (c2 != '\n') {
                                        input.backup(input.readLengthEOF()- mark);
                                        return token(lookupId);
                                    }
                                    lookupId = JavaTokenId.MULTILINE_STRING_LITERAL;
                                }
                                if (lookupId == JavaTokenId.MULTILINE_STRING_LITERAL) {
                                    if (text.endsWith("\"\"\"") && !text.endsWith("\\\"\"\"") && (text.length() > 6 || stringLiteralContinuation)) {
                                        return token(lookupId, stringLiteralContinuation ? PartType.END : PartType.COMPLETE);
                                    } else {
                                        break;
                                    }
                                }
                                
                                return token(lookupId, stringLiteralContinuation ? PartType.END : PartType.COMPLETE);
                            case '\\':
                                switch (nextChar()) {
                                    case '{':
                                        if (pendingStringLiteral != null) {
                                            literalHistory = new LiteralHistoryNode(pendingStringLiteral, pendingBraces, literalHistory);
                                        }
                                        pendingStringLiteral = lookupId;
                                        pendingBraces = 0;
                                        return token(lookupId, stringLiteralContinuation ? PartType.MIDDLE : PartType.START);
                                }
                                break;
                            case '\r': consumeNewline();
                            case '\n':
                                if (lookupId == JavaTokenId.MULTILINE_STRING_LITERAL) {
                                    break;
                                }
                            case EOF:
                                return tokenFactory.createToken(lookupId, //XXX: \n handling for exotic identifiers?
                                        input.readLength(), PartType.START);
                        }
                    }

                case '\'': // char literal
                    while (true)
                        switch (nextChar()) {
                            case '\'': // NOI18N
                                return token(JavaTokenId.CHAR_LITERAL);
                            case '\\':
                                nextChar(); // read escaped char
                                break;
                            case '\r': consumeNewline();
                            case '\n':
                            case EOF:
                                return tokenFactory.createToken(JavaTokenId.CHAR_LITERAL,
                                        input.readLength(), PartType.START);
                        }

                case '/':
                    switch (nextChar()) {
                        case '/': // in single-line comment
                            switch (nextChar()) {
                                case '/': return finishJavadocLineRun();
                                case '\r': consumeNewline();
                                case '\n':
                                case EOF:
                                    return token(JavaTokenId.LINE_COMMENT);
                            }
                            while (true)
                                switch (nextChar()) {
                                    case '\r': consumeNewline();
                                    case '\n':
                                    case EOF:
                                        return token(JavaTokenId.LINE_COMMENT);
                                }
                        case '=': // found /=
                            return token(JavaTokenId.SLASHEQ);
                        case '*': // in multi-line or javadoc comment
                            c = nextChar();
                            if (c == '*') { // either javadoc comment or empty multi-line comment /**/
                                    c = nextChar();
                                    if (c == '/')
                                        return token(JavaTokenId.BLOCK_COMMENT);
                                    while (true) { // in javadoc comment
                                        while (c == '*') {
                                            c = nextChar();
                                            if (c == '/')
                                                return token(JavaTokenId.JAVADOC_COMMENT);
                                            else if (c == EOF)
                                                return tokenFactory.createToken(JavaTokenId.JAVADOC_COMMENT,
                                                        input.readLength(), PartType.START);
                                        }
                                        if (c == EOF)
                                            return tokenFactory.createToken(JavaTokenId.JAVADOC_COMMENT,
                                                        input.readLength(), PartType.START);
                                        c = nextChar();
                                    }

                            } else { // in multi-line comment (and not after '*')
                                while (true) {
                                    c = nextChar();
                                    while (c == '*') {
                                        c = nextChar();
                                        if (c == '/')
                                            return token(JavaTokenId.BLOCK_COMMENT);
                                        else if (c == EOF)
                                            return tokenFactory.createToken(JavaTokenId.BLOCK_COMMENT,
                                                    input.readLength(), PartType.START);
                                    }
                                    if (c == EOF)
                                        return tokenFactory.createToken(JavaTokenId.BLOCK_COMMENT,
                                                input.readLength(), PartType.START);
                                }
                            }
                    } // end of switch()
                    backup(1);
                    return token(JavaTokenId.SLASH);

                case '=':
                    if (nextChar() == '=')
                        return token(JavaTokenId.EQEQ);
                    backup(1);
                    return token(JavaTokenId.EQ);

                case '>':
                    switch (nextChar()) {
                        case '>': // after >>
                            switch (c = nextChar()) {
                                case '>': // after >>>
                                    if (nextChar() == '=')
                                        return token(JavaTokenId.GTGTGTEQ);
                                    backup(1);
                                    return token(JavaTokenId.GTGTGT);
                                case '=': // >>=
                                    return token(JavaTokenId.GTGTEQ);
                            }
                            backup(1);
                            return token(JavaTokenId.GTGT);
                        case '=': // >=
                            return token(JavaTokenId.GTEQ);
                    }
                    backup(1);
                    return token(JavaTokenId.GT);

                case '<':
                    switch (nextChar()) {
                        case '<': // after <<
                            if (nextChar() == '=')
                                return token(JavaTokenId.LTLTEQ);
                            backup(1);
                            return token(JavaTokenId.LTLT);
                        case '=': // <=
                            return token(JavaTokenId.LTEQ);
                    }
                    backup(1);
                    return token(JavaTokenId.LT);

                case '+':
                    switch (nextChar()) {
                        case '+':
                            return token(JavaTokenId.PLUSPLUS);
                        case '=':
                            return token(JavaTokenId.PLUSEQ);
                    }
                    backup(1);
                    return token(JavaTokenId.PLUS);

                case '-':
                    switch (nextChar()) {
                        case '-':
                            return token(JavaTokenId.MINUSMINUS);
                        case '=':
                            return token(JavaTokenId.MINUSEQ);
                        case '>':
                            return token(JavaTokenId.ARROW);
                    }
                    backup(1);
                    return token(JavaTokenId.MINUS);

                case '*':
                    switch (nextChar()) {
                        case '/': // invalid comment end - */
                            return token(JavaTokenId.INVALID_COMMENT_END);
                        case '=':
                            return token(JavaTokenId.STAREQ);
                    }
                    backup(1);
                    return token(JavaTokenId.STAR);

                case '|':
                    switch (nextChar()) {
                        case '|':
                            return token(JavaTokenId.BARBAR);
                        case '=':
                            return token(JavaTokenId.BAREQ);
                    }
                    backup(1);
                    return token(JavaTokenId.BAR);

                case '&':
                    switch (nextChar()) {
                        case '&':
                            return token(JavaTokenId.AMPAMP);
                        case '=':
                            return token(JavaTokenId.AMPEQ);
                    }
                    backup(1);
                    return token(JavaTokenId.AMP);

                case '%':
                    if (nextChar() == '=')
                        return token(JavaTokenId.PERCENTEQ);
                    backup(1);
                    return token(JavaTokenId.PERCENT);

                case '^':
                    if (nextChar() == '=')
                        return token(JavaTokenId.CARETEQ);
                    backup(1);
                    return token(JavaTokenId.CARET);

                case '!':
                    if (nextChar() == '=')
                        return token(JavaTokenId.BANGEQ);
                    backup(1);
                    return token(JavaTokenId.BANG);

                case '.':
                    if ((c = nextChar()) == '.')
                        if (nextChar() == '.') { // ellipsis ...
                            return token(JavaTokenId.ELLIPSIS);
                        } else
                            backup(2);
                    else if ('0' <= c && c <= '9') { // float literal
                        return finishNumberLiteral(nextChar(), true);
                    } else
                        backup(1);
                    return token(JavaTokenId.DOT);

                case '~':
                    return token(JavaTokenId.TILDE);
                case ',':
                    return token(JavaTokenId.COMMA);
                case ';':
                    if (state != null) {
                        if (state >= 4 && state < 11) {
                            state = 3; // inside module decl
                        } else {
                            state = 1; // parsing module-info
                        }
                    }
                    return token(JavaTokenId.SEMICOLON);
                case ':':
                    if (nextChar() == ':')
                        return token(JavaTokenId.COLONCOLON);
                    backup(1);
                    return token(JavaTokenId.COLON);
                case '?':
                    return token(JavaTokenId.QUESTION);
                case '(':
                    if (state != null && state >= 12) {
                        state++;
                    }
                    return token(JavaTokenId.LPAREN);
                case ')':
                    if (state != null) {
                        if (state == 13) {
                            state = 1;
                        } else if (state > 13) {
                            state--;
                        }
                    }
                    return token(JavaTokenId.RPAREN);
                case '[':
                    return token(JavaTokenId.LBRACKET);
                case ']':
                    return token(JavaTokenId.RBRACKET);
                case '{':
                    if (pendingStringLiteral != null ) {
                        pendingBraces++;
                    }
                    if (state != null && state == 2) {
                        state = 3; // inside module decl
                    }
                    return token(JavaTokenId.LBRACE);
                case '}':
                    if (pendingStringLiteral != null && pendingBraces-- == 0) {
                        lookupId = pendingStringLiteral;
                        if (literalHistory == null) {
                            pendingStringLiteral = null;
                            pendingBraces = 0;
                        } else {
                            pendingStringLiteral = literalHistory.pendingStringLiteral;
                            pendingBraces = literalHistory.pendingBraces;
                            literalHistory = literalHistory.next;
                        }
                        stringLiteralContinuation = true;
                        break;
                    }
                    state = null;
                    return token(JavaTokenId.RBRACE);
                case '@':
                    if (state != null && state == 1) {
                        state = 12; // after annotation
                    }
                    return token(JavaTokenId.AT);

                case '0': // in a number literal
		    c = nextChar();
                    if (c == 'x' || c == 'X') { // in hexadecimal (possibly floating-point) literal
                        boolean inFraction = false;
                        boolean afterDigit = false;
                        while (true) {
                            switch (nextChar()) {
                                case '0': case '1': case '2': case '3': case '4':
                                case '5': case '6': case '7': case '8': case '9':
                                case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
                                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
                                    afterDigit = true;
                                    break;
                                case '.': // hex float literal
                                    if (!inFraction) {
                                        inFraction = true;
                                        afterDigit = false;
                                    } else { // two dots in the float literal
                                        return token(JavaTokenId.FLOAT_LITERAL_INVALID);
                                    }
                                    break;
                                case 'p': case 'P': // binary exponent
                                    return finishFloatExponent();
                                case 'l': case 'L':
                                    return token(JavaTokenId.LONG_LITERAL);
                                case '_':
                                    if (this.version >= 7 && afterDigit) {
                                        int cc = nextChar();
                                        backup(1);
                                        if (cc >= '0' && cc <= '9' || cc >= 'a' && cc <= 'f' || cc >= 'A' && cc <= 'F' || cc == '_') {
                                            break;
                                        }
                                    }
                                default:
                                    backup(1);
                                    // if float then before mandatory binary exponent => invalid
                                    return token(inFraction ? JavaTokenId.FLOAT_LITERAL_INVALID
                                            : JavaTokenId.INT_LITERAL);
                            }
                        } // end of while(true)
                    } else if (this.version >= 7 && (c == 'b' || c == 'B')) { // in binary literal
                        boolean afterDigit = false;
                        while (true) {
                            switch (nextChar()) {
                                case '0': case '1':
                                    afterDigit = true;
                                    break;
                                case 'l': case 'L':
                                    return token(JavaTokenId.LONG_LITERAL);
                                case '_':
                                    if (afterDigit) {
                                        int cc = nextChar();
                                        backup(1);
                                        if (cc == '0' || cc == '1' || cc == '_') {
                                            break;
                                        }
                                    }
                                default:
                                    backup(1);
                                    return token(JavaTokenId.INT_LITERAL);
                            }
                        }
                    }
                    return finishNumberLiteral(c, false);
                    
                case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                    return finishNumberLiteral(nextChar(), false);

                    
                // Keywords lexing    
                case 'a':
                    switch (c = nextChar()) {
                        case 'b':
                            if ((c = nextChar()) == 's'
                             && (c = nextChar()) == 't'
                             && (c = nextChar()) == 'r'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 'c'
                             && (c = nextChar()) == 't')
                                return keywordOrIdentifier(JavaTokenId.ABSTRACT);
                            break;
                        case 's':
                            if ((c = nextChar()) == 's'
                             && (c = nextChar()) == 'e'
                             && (c = nextChar()) == 'r'
                             && (c = nextChar()) == 't')
                                return (version >= 4)
                                        ? keywordOrIdentifier(JavaTokenId.ASSERT)
                                        : finishIdentifier();
                            break;
                    }
                    return finishIdentifier(c);

                case 'b':
                    switch (c = nextChar()) {
                        case 'o':
                            if ((c = nextChar()) == 'o'
                             && (c = nextChar()) == 'l'
                             && (c = nextChar()) == 'e'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 'n')
                                return keywordOrIdentifier(JavaTokenId.BOOLEAN);
                            break;
                        case 'r':
                            if ((c = nextChar()) == 'e'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 'k')
                                return keywordOrIdentifier(JavaTokenId.BREAK);
                            break;
                        case 'y':
                            if ((c = nextChar()) == 't'
                             && (c = nextChar()) == 'e')
                                return keywordOrIdentifier(JavaTokenId.BYTE);
                            break;
                    }
                    return finishIdentifier(c);

                case 'c':
                    switch (c = nextChar()) {
                        case 'a':
                            switch (c = nextChar()) {
                                case 's':
                                    if ((c = nextChar()) == 'e')
                                        return keywordOrIdentifier(JavaTokenId.CASE);
                                    break;
                                case 't':
                                    if ((c = nextChar()) == 'c'
                                     && (c = nextChar()) == 'h')
                                        return keywordOrIdentifier(JavaTokenId.CATCH);
                                    break;
                            }
                            break;
                        case 'h':
                            if ((c = nextChar()) == 'a'
                             && (c = nextChar()) == 'r')
                                return keywordOrIdentifier(JavaTokenId.CHAR);
                            break;
                        case 'l':
                            if ((c = nextChar()) == 'a'
                             && (c = nextChar()) == 's'
                             && (c = nextChar()) == 's')
                                return keywordOrIdentifier(JavaTokenId.CLASS);
                            break;
                        case 'o':
                            if ((c = nextChar()) == 'n') {
                                switch (c = nextChar()) {
                                    case 's':
                                        if ((c = nextChar()) == 't')
                                            return keywordOrIdentifier(JavaTokenId.CONST);
                                        break;
                                    case 't':
                                        if ((c = nextChar()) == 'i'
                                         && (c = nextChar()) == 'n'
                                         && (c = nextChar()) == 'u'
                                         && (c = nextChar()) == 'e')
                                            return keywordOrIdentifier(JavaTokenId.CONTINUE);
                                        break;
                                }
                            }
                            break;
                    }
                    return finishIdentifier(c);

                case 'd':
                    switch (c = nextChar()) {
                        case 'e':
                            if ((c = nextChar()) == 'f'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 'u'
                             && (c = nextChar()) == 'l'
                             && (c = nextChar()) == 't')
                                return keywordOrIdentifier(JavaTokenId.DEFAULT);
                            break;
                        case 'o':
                            switch (c = nextChar()) {
                                case 'u':
                                    if ((c = nextChar()) == 'b'
                                     && (c = nextChar()) == 'l'
                                     && (c = nextChar()) == 'e')
                                        return keywordOrIdentifier(JavaTokenId.DOUBLE);
                                    break;
                                default:
                                    return keywordOrIdentifier(JavaTokenId.DO, c);
                            }
                            break;
                    }
                    return finishIdentifier(c);

                case 'e':
                    switch (c = nextChar()) {
                        case 'l':
                            if ((c = nextChar()) == 's'
                             && (c = nextChar()) == 'e')
                                return keywordOrIdentifier(JavaTokenId.ELSE);
                            break;
                        case 'n':
                            if ((c = nextChar()) == 'u'
                             && (c = nextChar()) == 'm')
                                return (version >= 5)
                                        ? keywordOrIdentifier(JavaTokenId.ENUM)
                                        : finishIdentifier();
                            break;
                        case 'x':
                            switch (c = nextChar()) {
                                case 'p':
                                    if ((c = nextChar()) == 'o'
                                     && (c = nextChar()) == 'r'
                                     && (c = nextChar()) == 't'
                                     && (c = nextChar()) == 's'
                                     && state != null && state == 3) {
                                        Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.EXPORTS);
                                        if (kwOrId.id() == JavaTokenId.EXPORTS) {
                                            state = 5; // after exports
                                        }
                                        return kwOrId;
                                    }
                                    break;
                                case 't':
                                    if ((c = nextChar()) == 'e'
                                     && (c = nextChar()) == 'n'
                                     && (c = nextChar()) == 'd'
                                     && (c = nextChar()) == 's')
                                        return keywordOrIdentifier(JavaTokenId.EXTENDS);
                                    break;
                            }
                            break;
                    }
                    return finishIdentifier(c);

                case 'f':
                    switch (c = nextChar()) {
                        case 'a':
                            if ((c = nextChar()) == 'l'
                             && (c = nextChar()) == 's'
                             && (c = nextChar()) == 'e')
                                return keywordOrIdentifier(JavaTokenId.FALSE);
                            break;
                        case 'i':
                            if ((c = nextChar()) == 'n'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 'l')
                                switch (c = nextChar()) {
                                    case 'l':
                                        if ((c = nextChar()) == 'y')
                                            return keywordOrIdentifier(JavaTokenId.FINALLY);
                                        break;
                                    default:
                                        return keywordOrIdentifier(JavaTokenId.FINAL, c);
                                }
                            break;
                        case 'l':
                            if ((c = nextChar()) == 'o'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 't')
                                return keywordOrIdentifier(JavaTokenId.FLOAT);
                            break;
                        case 'o':
                            if ((c = nextChar()) == 'r')
                                return keywordOrIdentifier(JavaTokenId.FOR);
                            break;
                    }
                    return finishIdentifier(c);

                case 'g':
                    if ((c = nextChar()) == 'o'
                     && (c = nextChar()) == 't'
                     && (c = nextChar()) == 'o')
                        return keywordOrIdentifier(JavaTokenId.GOTO);
                    return finishIdentifier(c);
                    
                case 'i':
                    switch (c = nextChar()) {
                        case 'f':
                            return keywordOrIdentifier(JavaTokenId.IF);
                        case 'm':
                            if ((c = nextChar()) == 'p') {
                                switch (c = nextChar()) {
                                    case 'l':
                                        if ((c = nextChar()) == 'e'
                                         && (c = nextChar()) == 'm'
                                         && (c = nextChar()) == 'e'
                                         && (c = nextChar()) == 'n'
                                         && (c = nextChar()) == 't'
                                         && (c = nextChar()) == 's')
                                            return keywordOrIdentifier(JavaTokenId.IMPLEMENTS);
                                        break;
                                    case 'o':
                                        if ((c = nextChar()) == 'r'
                                         && (c = nextChar()) == 't') {
                                            if (state != null && state == 1) {
                                                state = 11; // after import
                                            }
                                            return keywordOrIdentifier(JavaTokenId.IMPORT);
                                        }
                                        break;
                                }
                            }
                            break;
                        case 'n':
                            switch (c = nextChar()) {
                                case 's':
                                    if ((c = nextChar()) == 't'
                                     && (c = nextChar()) == 'a'
                                     && (c = nextChar()) == 'n'
                                     && (c = nextChar()) == 'c'
                                     && (c = nextChar()) == 'e'
                                     && (c = nextChar()) == 'o'
                                     && (c = nextChar()) == 'f')
                                        return keywordOrIdentifier(JavaTokenId.INSTANCEOF);
                                    break;
                                case 't':
                                    switch (c = nextChar()) {
                                        case 'e':
                                            if ((c = nextChar()) == 'r'
                                             && (c = nextChar()) == 'f'
                                             && (c = nextChar()) == 'a'
                                             && (c = nextChar()) == 'c'
                                             && (c = nextChar()) == 'e')
                                                return keywordOrIdentifier(JavaTokenId.INTERFACE);
                                            break;
                                        default:
                                            return keywordOrIdentifier(JavaTokenId.INT, c);
                                    }
                                    break;
                            }
                            break;
                    }
                    return finishIdentifier(c);

                case 'l':
                    if ((c = nextChar()) == 'o'
                     && (c = nextChar()) == 'n'
                     && (c = nextChar()) == 'g')
                        return keywordOrIdentifier(JavaTokenId.LONG);
                    return finishIdentifier(c);

                case 'm':
                    if ((c = nextChar()) == 'o'
                     && (c = nextChar()) == 'd'
                     && (c = nextChar()) == 'u'
                     && (c = nextChar()) == 'l'
                     && (c = nextChar()) == 'e'
                     && state != null && state == 1) {
                        Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.MODULE);
                        if (kwOrId.id() == JavaTokenId.MODULE) {
                            state = 2; // after module
                        }
                        return kwOrId;
                    }
                    return finishIdentifier(c);

                case 'n':
                    switch (c = nextChar()) {
                        case 'a':
                            if ((c = nextChar()) == 't'
                             && (c = nextChar()) == 'i'
                             && (c = nextChar()) == 'v'
                             && (c = nextChar()) == 'e')
                                return keywordOrIdentifier(JavaTokenId.NATIVE);
                            break;
                        case 'e':
                            if ((c = nextChar()) == 'w')
                                return keywordOrIdentifier(JavaTokenId.NEW);
                            break;
                        case 'u':
                            if ((c = nextChar()) == 'l'
                             && (c = nextChar()) == 'l')
                                return keywordOrIdentifier(JavaTokenId.NULL);
                            break;
                    }
                    return finishIdentifier(c);

                case 'o':
                    if ((c = nextChar()) == 'p'
                     && (c = nextChar()) == 'e'
                     && (c = nextChar()) == 'n'
                     && state != null && state >= 1)
                        switch (c = nextChar()) {
                            case 's':
                                if (state == 3) {
                                    Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.OPENS);
                                    if (kwOrId.id() == JavaTokenId.OPENS) {
                                        state = 6; // after opens
                                    }
                                    return kwOrId;
                                }
                                break;
                            default:
                                if (state == 1) {
                                    return keywordOrIdentifier(JavaTokenId.OPEN, c);
                                }
                        }
                    return finishIdentifier(c);

                case 'p':
                    switch (c = nextChar()) {
                        case 'a':
                            if ((c = nextChar()) == 'c'
                             && (c = nextChar()) == 'k'
                             && (c = nextChar()) == 'a'
                             && (c = nextChar()) == 'g'
                             && (c = nextChar()) == 'e')
                                return keywordOrIdentifier(JavaTokenId.PACKAGE);
                            break;
                        case 'r':
                            switch (c = nextChar()) {
                                case 'i':
                                    if ((c = nextChar()) == 'v'
                                     && (c = nextChar()) == 'a'
                                     && (c = nextChar()) == 't'
                                     && (c = nextChar()) == 'e')
                                        return keywordOrIdentifier(JavaTokenId.PRIVATE);
                                    break;
                                case 'o':
                                    switch (c = nextChar()) {
                                        case 't':
                                            if ((c = nextChar()) == 'e'
                                             && (c = nextChar()) == 'c'
                                             && (c = nextChar()) == 't'
                                             && (c = nextChar()) == 'e'
                                             && (c = nextChar()) == 'd')
                                                return keywordOrIdentifier(JavaTokenId.PROTECTED);
                                            break;
                                        case 'v':
                                            if ((c = nextChar()) == 'i'
                                             && (c = nextChar()) == 'd'
                                             && (c = nextChar()) == 'e'
                                             && (c = nextChar()) == 's'
                                             && state != null && state == 3) {
                                                Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.PROVIDES);
                                                if (kwOrId.id() == JavaTokenId.PROVIDES) {
                                                    state = 8; // after provides
                                                }
                                                return kwOrId;
                                            }
                                            break;
                                    }
                                    break;
                            }
                            break;
                        case 'u':
                            if ((c = nextChar()) == 'b'
                             && (c = nextChar()) == 'l'
                             && (c = nextChar()) == 'i'
                             && (c = nextChar()) == 'c')
                                return keywordOrIdentifier(JavaTokenId.PUBLIC);
                            break;
                    }
                    return finishIdentifier(c);

                case 'r':
                    if ((c = nextChar()) == 'e') {
                        switch (c = nextChar()) {
                            case 'q':
                                if ((c = nextChar()) == 'u'
                                 && (c = nextChar()) == 'i'
                                 && (c = nextChar()) == 'r'
                                 && (c = nextChar()) == 'e'
                                 && (c = nextChar()) == 's'
                                 && state != null && state == 3) {
                                    Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.REQUIRES);
                                    if (kwOrId.id() == JavaTokenId.REQUIRES) {
                                        state = 4; // after requires
                                    }
                                    return kwOrId;
                                }
                                break;
                            case 't':    
                                if ((c = nextChar()) == 'u'
                                 && (c = nextChar()) == 'r'
                                 && (c = nextChar()) == 'n')
                                    return keywordOrIdentifier(JavaTokenId.RETURN);
                                break;
                        }
                    }
                    return finishIdentifier(c);

                case 's':
                    switch (c = nextChar()) {
                        case 'h':
                            if ((c = nextChar()) == 'o'
                             && (c = nextChar()) == 'r'
                             && (c = nextChar()) == 't')
                                return keywordOrIdentifier(JavaTokenId.SHORT);
                            break;
                        case 't':
                            switch (c = nextChar()) {
                                case 'a':
                                    if ((c = nextChar()) == 't'
                                     && (c = nextChar()) == 'i'
                                     && (c = nextChar()) == 'c')
                                        return keywordOrIdentifier(JavaTokenId.STATIC);
                                    break;
                                case 'r':
                                    if ((c = nextChar()) == 'i'
                                     && (c = nextChar()) == 'c'
                                     && (c = nextChar()) == 't'
                                     && (c = nextChar()) == 'f'
                                     && (c = nextChar()) == 'p')
                                        return keywordOrIdentifier(JavaTokenId.STRICTFP);
                                    break;
                            }
                            break;
                        case 'u':
                            if ((c = nextChar()) == 'p'
                             && (c = nextChar()) == 'e'
                             && (c = nextChar()) == 'r')
                                return keywordOrIdentifier(JavaTokenId.SUPER);
                            break;
                        case 'w':
                            if ((c = nextChar()) == 'i'
                             && (c = nextChar()) == 't'
                             && (c = nextChar()) == 'c'
                             && (c = nextChar()) == 'h')
                                return keywordOrIdentifier(JavaTokenId.SWITCH);
                            break;
                        case 'y':
                            if ((c = nextChar()) == 'n'
                             && (c = nextChar()) == 'c'
                             && (c = nextChar()) == 'h'
                             && (c = nextChar()) == 'r'
                             && (c = nextChar()) == 'o'
                             && (c = nextChar()) == 'n'
                             && (c = nextChar()) == 'i'
                             && (c = nextChar()) == 'z'
                             && (c = nextChar()) == 'e'
                             && (c = nextChar()) == 'd')
                                return keywordOrIdentifier(JavaTokenId.SYNCHRONIZED);
                            break;
                    }
                    return finishIdentifier(c);

                case 't':
                    switch (c = nextChar()) {
                        case 'h':
                            switch (c = nextChar()) {
                                case 'i':
                                    if ((c = nextChar()) == 's')
                                        return keywordOrIdentifier(JavaTokenId.THIS);
                                    break;
                                case 'r':
                                    if ((c = nextChar()) == 'o'
                                     && (c = nextChar()) == 'w')
                                        switch (c = nextChar()) {
                                            case 's':
                                                return keywordOrIdentifier(JavaTokenId.THROWS);
                                            default:
                                                return keywordOrIdentifier(JavaTokenId.THROW, c);
                                        }
                                    break;
                            }
                            break;
                        case 'o':
                            if (state != null && (state == 5 || state == 6)) {
                                Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.TO);
                                if (kwOrId.id() == JavaTokenId.TO) {
                                    state = 9; // after to
                                }
                                return kwOrId;
                            }
                            break;
                        case 'r':
                            switch (c = nextChar()) {
                                case 'a':
                                    if ((c = nextChar()) == 'n'
                                     && (c = nextChar()) == 's'
                                     && (c = nextChar()) == 'i') {
                                        switch (c = nextChar()) {
                                            case 'e':
                                                if ((c = nextChar()) == 'n'
                                                 && (c = nextChar()) == 't')
                                                    return keywordOrIdentifier(JavaTokenId.TRANSIENT);
                                                break;
                                            case 't':
                                                if ((c = nextChar()) == 'i'
                                                 && (c = nextChar()) == 'v'
                                                 && (c = nextChar()) == 'e'
                                                 && state != null && state == 4)
                                                    return keywordOrIdentifier(JavaTokenId.TRANSITIVE);
                                                break;
                                        }
                                    }
                                    break;
                                case 'u':
                                    if ((c = nextChar()) == 'e')
                                        return keywordOrIdentifier(JavaTokenId.TRUE);
                                    break;
                                case 'y':
                                    return keywordOrIdentifier(JavaTokenId.TRY);
                            }
                            break;
                    }
                    return finishIdentifier(c);

                case 'u':
                    if ((c = nextChar()) == 's'
                     && (c = nextChar()) == 'e'
                     && (c = nextChar()) == 's'
                     && state != null && state == 3) {
                        Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.USES);
                        if (kwOrId.id() == JavaTokenId.USES) {
                            state = 7; // after uses
                        }
                        return kwOrId;
                    }
                    return finishIdentifier(c);

                case 'v':
                    switch ((c = nextChar())) {
                        case 'a':
                            if ((c = nextChar()) == 'r') {
                                c = nextChar();
                                // Check whether the given char is non-ident and if so then return keyword
                                if (c != EOF && !Character.isJavaIdentifierPart(c = translateSurrogates(c)) &&
                                    version >= 10) {
                                    // For surrogate 2 chars must be backed up
                                    backup((c >= Character.MIN_SUPPLEMENTARY_CODE_POINT) ? 2 : 1);

                                    int len = input.readLength();

                                    Token next = nextToken();
                                    boolean varKeyword = false;

                                    if (AFTER_VAR_TOKENS.contains(next.id())) {
                                        do {
                                            next = nextToken();
                                        } while (next != null && AFTER_VAR_TOKENS.contains(next.id()));

                                        varKeyword = next != null && next.id() == JavaTokenId.IDENTIFIER;
                                    }

                                    input.backup(input.readLengthEOF()- len);

                                    assert input.readLength() == len;

                                    if (varKeyword) {
                                        return token(JavaTokenId.VAR);
                                    }
                                } else {
                                    // For surrogate 2 chars must be backed up
                                    backup((c >= Character.MIN_SUPPLEMENTARY_CODE_POINT) ? 2 : 1);
                                }
                            }
                            c = nextChar();
                            break;
                        case 'o':
                            switch (c = nextChar()) {
                                case 'i':
                                    if ((c = nextChar()) == 'd')
                                        return keywordOrIdentifier(JavaTokenId.VOID);
                                    break;
                                case 'l':
                                    if ((c = nextChar()) == 'a'
                                     && (c = nextChar()) == 't'
                                     && (c = nextChar()) == 'i'
                                     && (c = nextChar()) == 'l'
                                     && (c = nextChar()) == 'e')
                                        return keywordOrIdentifier(JavaTokenId.VOLATILE);
                                    break;
                            }
                            break;
                    }
                    return finishIdentifier(c);

                case 'w':
                    switch (c = nextChar()) {
                        case 'h':
                            if ((c = nextChar()) == 'i'
                             && (c = nextChar()) == 'l'
                             && (c = nextChar()) == 'e')
                                return keywordOrIdentifier(JavaTokenId.WHILE);
                            break;
                        case 'i':
                            if ((c = nextChar()) == 't'
                             && (c = nextChar()) == 'h'
                             && state != null && state == 8) {
                                Token<JavaTokenId> kwOrId = keywordOrIdentifier(JavaTokenId.WITH);
                                if (kwOrId.id() == JavaTokenId.WITH) {
                                    state = 10; // after with
                                }
                                return kwOrId;
                            }
                            break;
                    }
                    return finishIdentifier(c);

                // Rest of lowercase letters starting identifiers
                case 'h': case 'j': case 'k':
                case 'q': case 'x': case 'y': case 'z':
                // Uppercase letters starting identifiers
                case 'A': case 'B': case 'C': case 'D': case 'E':
                case 'F': case 'G': case 'H': case 'I': case 'J':
                case 'K': case 'L': case 'M': case 'N': case 'O':
                case 'P': case 'Q': case 'R': case 'S': case 'T':
                case 'U': case 'V': case 'W': case 'X': case 'Y':
                case 'Z':
                case '$':
                    return finishIdentifier();
                    
                case '_':
                    if (this.version >= 9)
                        return keywordOrIdentifier(JavaTokenId.UNDERSCORE);
                    return finishIdentifier();
                    
                // All Character.isWhitespace(c) below 0x80 follow
                // ['\t' - '\r'] and [0x1c - ' ']
                case '\t':
                case '\n':
                case 0x0b:
                case '\f':
                case '\r':
                case 0x1c:
                case 0x1d:
                case 0x1e:
                case 0x1f:
                    if (state != null && state >= 12) {
                        state = 1;
                    }
                    return finishWhitespace();
                case ' ':
                    c = nextChar();
                    if (c == EOF || !Character.isWhitespace(c)) { // Return single space as flyweight token
                        backup(1);
                        return   input.readLength() == 1
                               ? tokenFactory.getFlyweightToken(JavaTokenId.WHITESPACE, " ")
                               : tokenFactory.createToken(JavaTokenId.WHITESPACE);
                    }
                    return finishWhitespace();

                case EOF:
                    return null;

                default:
                    if (c >= 0x80) { // lowSurr ones already handled above
                        c = translateSurrogates(c);
                        if (Character.isJavaIdentifierStart(c))
                            return finishIdentifier();
                        if (Character.isWhitespace(c))
                            return finishWhitespace();
                    }

                    // Invalid char
                    return token(JavaTokenId.ERROR);
            } // end of switch (c)
        } // end of while(true)
    }