org.sonar.java.ast.parser.JavaGrammar.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.java.ast.parser.JavaGrammar.java

Source

/*
 * SonarQube Java
 * Copyright (C) 2012 SonarSource
 * dev@sonar.codehaus.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.java.ast.parser;

import com.sonar.sslr.api.GenericTokenType;
import org.apache.commons.lang.ArrayUtils;
import org.sonar.java.ast.api.JavaKeyword;
import org.sonar.java.ast.api.JavaTokenType;
import org.sonar.sslr.grammar.GrammarRuleKey;
import org.sonar.sslr.grammar.LexerlessGrammarBuilder;
import org.sonar.sslr.parser.LexerlessGrammar;

import java.util.Arrays;

import static org.sonar.java.ast.api.JavaKeyword.ABSTRACT;
import static org.sonar.java.ast.api.JavaKeyword.ASSERT;
import static org.sonar.java.ast.api.JavaKeyword.BOOLEAN;
import static org.sonar.java.ast.api.JavaKeyword.BREAK;
import static org.sonar.java.ast.api.JavaKeyword.BYTE;
import static org.sonar.java.ast.api.JavaKeyword.CASE;
import static org.sonar.java.ast.api.JavaKeyword.CATCH;
import static org.sonar.java.ast.api.JavaKeyword.CHAR;
import static org.sonar.java.ast.api.JavaKeyword.CLASS;
import static org.sonar.java.ast.api.JavaKeyword.CONTINUE;
import static org.sonar.java.ast.api.JavaKeyword.DEFAULT;
import static org.sonar.java.ast.api.JavaKeyword.DO;
import static org.sonar.java.ast.api.JavaKeyword.DOUBLE;
import static org.sonar.java.ast.api.JavaKeyword.ELSE;
import static org.sonar.java.ast.api.JavaKeyword.ENUM;
import static org.sonar.java.ast.api.JavaKeyword.EXTENDS;
import static org.sonar.java.ast.api.JavaKeyword.FALSE;
import static org.sonar.java.ast.api.JavaKeyword.FINAL;
import static org.sonar.java.ast.api.JavaKeyword.FINALLY;
import static org.sonar.java.ast.api.JavaKeyword.FLOAT;
import static org.sonar.java.ast.api.JavaKeyword.FOR;
import static org.sonar.java.ast.api.JavaKeyword.IF;
import static org.sonar.java.ast.api.JavaKeyword.IMPLEMENTS;
import static org.sonar.java.ast.api.JavaKeyword.IMPORT;
import static org.sonar.java.ast.api.JavaKeyword.INSTANCEOF;
import static org.sonar.java.ast.api.JavaKeyword.INT;
import static org.sonar.java.ast.api.JavaKeyword.INTERFACE;
import static org.sonar.java.ast.api.JavaKeyword.LONG;
import static org.sonar.java.ast.api.JavaKeyword.NATIVE;
import static org.sonar.java.ast.api.JavaKeyword.NEW;
import static org.sonar.java.ast.api.JavaKeyword.NULL;
import static org.sonar.java.ast.api.JavaKeyword.PACKAGE;
import static org.sonar.java.ast.api.JavaKeyword.PRIVATE;
import static org.sonar.java.ast.api.JavaKeyword.PROTECTED;
import static org.sonar.java.ast.api.JavaKeyword.PUBLIC;
import static org.sonar.java.ast.api.JavaKeyword.RETURN;
import static org.sonar.java.ast.api.JavaKeyword.SHORT;
import static org.sonar.java.ast.api.JavaKeyword.STATIC;
import static org.sonar.java.ast.api.JavaKeyword.STRICTFP;
import static org.sonar.java.ast.api.JavaKeyword.SUPER;
import static org.sonar.java.ast.api.JavaKeyword.SWITCH;
import static org.sonar.java.ast.api.JavaKeyword.SYNCHRONIZED;
import static org.sonar.java.ast.api.JavaKeyword.THIS;
import static org.sonar.java.ast.api.JavaKeyword.THROW;
import static org.sonar.java.ast.api.JavaKeyword.THROWS;
import static org.sonar.java.ast.api.JavaKeyword.TRANSIENT;
import static org.sonar.java.ast.api.JavaKeyword.TRUE;
import static org.sonar.java.ast.api.JavaKeyword.TRY;
import static org.sonar.java.ast.api.JavaKeyword.VOID;
import static org.sonar.java.ast.api.JavaKeyword.VOLATILE;
import static org.sonar.java.ast.api.JavaKeyword.WHILE;
import static org.sonar.java.ast.api.JavaPunctuator.AND;
import static org.sonar.java.ast.api.JavaPunctuator.ANDAND;
import static org.sonar.java.ast.api.JavaPunctuator.ANDEQU;
import static org.sonar.java.ast.api.JavaPunctuator.AT;
import static org.sonar.java.ast.api.JavaPunctuator.BANG;
import static org.sonar.java.ast.api.JavaPunctuator.BSR;
import static org.sonar.java.ast.api.JavaPunctuator.BSREQU;
import static org.sonar.java.ast.api.JavaPunctuator.COLON;
import static org.sonar.java.ast.api.JavaPunctuator.COMMA;
import static org.sonar.java.ast.api.JavaPunctuator.DBLECOLON;
import static org.sonar.java.ast.api.JavaPunctuator.DEC;
import static org.sonar.java.ast.api.JavaPunctuator.DIV;
import static org.sonar.java.ast.api.JavaPunctuator.DIVEQU;
import static org.sonar.java.ast.api.JavaPunctuator.DOT;
import static org.sonar.java.ast.api.JavaPunctuator.ELLIPSIS;
import static org.sonar.java.ast.api.JavaPunctuator.EQU;
import static org.sonar.java.ast.api.JavaPunctuator.EQUAL;
import static org.sonar.java.ast.api.JavaPunctuator.GE;
import static org.sonar.java.ast.api.JavaPunctuator.GT;
import static org.sonar.java.ast.api.JavaPunctuator.HAT;
import static org.sonar.java.ast.api.JavaPunctuator.HATEQU;
import static org.sonar.java.ast.api.JavaPunctuator.INC;
import static org.sonar.java.ast.api.JavaPunctuator.LBRK;
import static org.sonar.java.ast.api.JavaPunctuator.LE;
import static org.sonar.java.ast.api.JavaPunctuator.LPAR;
import static org.sonar.java.ast.api.JavaPunctuator.LPOINT;
import static org.sonar.java.ast.api.JavaPunctuator.LT;
import static org.sonar.java.ast.api.JavaPunctuator.LWING;
import static org.sonar.java.ast.api.JavaPunctuator.MINUS;
import static org.sonar.java.ast.api.JavaPunctuator.MINUSEQU;
import static org.sonar.java.ast.api.JavaPunctuator.MOD;
import static org.sonar.java.ast.api.JavaPunctuator.MODEQU;
import static org.sonar.java.ast.api.JavaPunctuator.NOTEQUAL;
import static org.sonar.java.ast.api.JavaPunctuator.OR;
import static org.sonar.java.ast.api.JavaPunctuator.OREQU;
import static org.sonar.java.ast.api.JavaPunctuator.OROR;
import static org.sonar.java.ast.api.JavaPunctuator.PLUS;
import static org.sonar.java.ast.api.JavaPunctuator.PLUSEQU;
import static org.sonar.java.ast.api.JavaPunctuator.QUERY;
import static org.sonar.java.ast.api.JavaPunctuator.RBRK;
import static org.sonar.java.ast.api.JavaPunctuator.RPAR;
import static org.sonar.java.ast.api.JavaPunctuator.RPOINT;
import static org.sonar.java.ast.api.JavaPunctuator.RWING;
import static org.sonar.java.ast.api.JavaPunctuator.SEMI;
import static org.sonar.java.ast.api.JavaPunctuator.SL;
import static org.sonar.java.ast.api.JavaPunctuator.SLEQU;
import static org.sonar.java.ast.api.JavaPunctuator.SR;
import static org.sonar.java.ast.api.JavaPunctuator.SREQU;
import static org.sonar.java.ast.api.JavaPunctuator.STAR;
import static org.sonar.java.ast.api.JavaPunctuator.STAREQU;
import static org.sonar.java.ast.api.JavaPunctuator.TILDA;
import static org.sonar.java.ast.api.JavaTokenType.CHARACTER_LITERAL;
import static org.sonar.java.ast.api.JavaTokenType.DOUBLE_LITERAL;
import static org.sonar.java.ast.api.JavaTokenType.FLOAT_LITERAL;
import static org.sonar.java.ast.api.JavaTokenType.IDENTIFIER;
import static org.sonar.java.ast.api.JavaTokenType.INTEGER_LITERAL;
import static org.sonar.java.ast.api.JavaTokenType.LONG_LITERAL;

public enum JavaGrammar implements GrammarRuleKey {

    COMPILATION_UNIT, PACKAGE_DECLARATION, IMPORT_DECLARATION, TYPE_DECLARATION,

    ANNOTATION, QUALIFIED_IDENTIFIER, QUALIFIED_IDENTIFIER_LIST,

    MODIFIER, CLASS_DECLARATION, ENUM_DECLARATION, INTERFACE_DECLARATION, ANNOTATION_TYPE_DECLARATION,

    TYPE_PARAMETERS, CLASS_TYPE, CLASS_TYPE_LIST, CLASS_BODY,

    CLASS_BODY_DECLARATION, CLASS_INIT_DECLARATION,

    BLOCK, MEMBER_DECL,

    FIELD_DECLARATION,

    GENERIC_METHOD_OR_CONSTRUCTOR_REST, TYPE, METHOD_DECLARATOR_REST, VARIABLE_DECLARATORS, VOID_METHOD_DECLARATOR_REST, CONSTRUCTOR_DECLARATOR_REST,

    FORMAL_PARAMETERS, DIM, METHOD_BODY,

    INTERFACE_BODY,

    INTERFACE_BODY_DECLARATION,

    INTERFACE_MEMBER_DECL,

    INTERFACE_METHOD_OR_FIELD_DECL, INTERFACE_GENERIC_METHOD_DECL, VOID_INTERFACE_METHOD_DECLARATORS_REST,

    INTERFACE_METHOD_OR_FIELD_REST,

    CONSTANT_DECLARATORS_REST, INTERFACE_METHOD_DECLARATOR_REST,

    CONSTANT_DECLARATOR_REST, CONSTANT_DECLARATOR,

    VARIABLE_INITIALIZER,

    ENUM_BODY,

    ENUM_CONSTANTS, ENUM_BODY_DECLARATIONS,

    ENUM_CONSTANT,

    ARGUMENTS,

    LOCAL_VARIABLE_DECLARATION_STATEMENT, VARIABLE_MODIFIERS, VARIABLE_DECLARATOR,

    FORMAL_PARAMETER, FORMAL_PARAMETER_DECLS, FORMAL_PARAMETERS_DECLS_REST,

    VARIABLE_DECLARATOR_ID,

    BLOCK_STATEMENTS, BLOCK_STATEMENT,

    STATEMENT, LABELED_STATEMENT, EXPRESSION_STATEMENT, IF_STATEMENT, WHILE_STATEMENT, FOR_STATEMENT, ASSERT_STATEMENT, SWITCH_STATEMENT, DO_STATEMENT, BREAK_STATEMENT, CONTINUE_STATEMENT, RETURN_STATEMENT, SYNCHRONIZED_STATEMENT, THROW_STATEMENT, EMPTY_STATEMENT,

    EXPRESSION, RESOURCE, PAR_EXPRESSION, FOR_INIT, FOR_UPDATE,

    CATCH_CLAUSE, CATCH_FORMAL_PARAMETER, CATCH_TYPE,

    FINALLY_, SWITCH_BLOCK_STATEMENT_GROUPS, STATEMENT_EXPRESSION,

    TRY_STATEMENT, TRY_WITH_RESOURCES_STATEMENT, RESOURCE_SPECIFICATION,

    SWITCH_BLOCK_STATEMENT_GROUP,

    SWITCH_LABEL,

    CONSTANT_EXPRESSION,

    BASIC_TYPE, TYPE_ARGUMENTS, TYPE_ARGUMENT, TYPE_PARAMETER, BOUND,

    CONDITIONAL_EXPRESSION, DEFAULT_VALUE,

    ANNOTATION_TYPE_BODY, ANNOTATION_TYPE_ELEMENT_DECLARATION, ANNOTATION_TYPE_ELEMENT_REST, ANNOTATION_METHOD_OR_CONSTANT_REST, ANNOTATION_METHOD_REST, ANNOTATION_REST, NORMAL_ANNOTATION_REST, ELEMENT_VALUE_PAIRS, ELEMENT_VALUE_PAIR, ELEMENT_VALUE, ELEMENT_VALUE_ARRAY_INITIALIZER, ELEMENT_VALUES, SINGLE_ELEMENT_ANNOTATION_REST,

    ASSIGNMENT_EXPRESSION, ASSIGNMENT_OPERATOR, CONDITIONAL_OR_EXPRESSION, CONDITIONAL_AND_EXPRESSION, INCLUSIVE_OR_EXPRESSION, EXCLUSIVE_OR_EXPRESSION, AND_EXPRESSION, EQUALITY_EXPRESSION, RELATIONAL_EXPRESSION, SHIFT_EXPRESSION, ADDITIVE_EXPRESSION, MULTIPLICATIVE_EXPRESSION, UNARY_EXPRESSION, PREFIX_OP, PRIMARY, SELECTOR, POST_FIX_OP, NON_WILDCARD_TYPE_ARGUMENTS, EXPLICIT_GENERIC_INVOCATION_SUFFIX, SUPER_SUFFIX, LITERAL, CREATOR, IDENTIFIER_SUFFIX, EXPLICIT_GENERIC_INVOCATION, INNER_CREATOR, DIM_EXPR, CREATED_NAME, CLASS_CREATOR_REST, DIAMOND, ARRAY_CREATOR_REST, ARRAY_INITIALIZER,

    EOF,

    LETTER_OR_DIGIT, KEYWORD, SPACING,

    METHOD_REFERENCE, LAMBDA_EXPRESSION, LAMBDA_PARAMETERS, LAMBDA_BODY, ARROW, UNARY_EXPRESSION_NOT_PLUS_MINUS, CAST_EXPRESSION;

    public static LexerlessGrammar createGrammar() {
        return createGrammarBuilder().build();
    }

    public static LexerlessGrammarBuilder createGrammarBuilder() {
        LexerlessGrammarBuilder b = LexerlessGrammarBuilder.create();

        punctuators(b);
        keywords(b);

        compilationsUnits(b);
        classDeclaration(b);
        interfaceDeclarations(b);
        enums(b);
        formalParameters(b);
        blocksAndStatements(b);
        expressions(b);
        types(b);
        annotations(b);
        literals(b);

        b.setRootRule(COMPILATION_UNIT);

        return b;
    }

    private static void punctuators(LexerlessGrammarBuilder b) {
        punctuator(b, AT, "@");
        punctuator(b, AND, "&", b.nextNot(b.firstOf("=", "&")));
        punctuator(b, ANDAND, "&&");
        punctuator(b, ANDEQU, "&=");
        punctuator(b, BANG, "!", b.nextNot("="));
        punctuator(b, BSR, ">>>", b.nextNot("="));
        punctuator(b, BSREQU, ">>>=");
        punctuator(b, COLON, ":");
        punctuator(b, DBLECOLON, "::");
        punctuator(b, COMMA, ",");
        punctuator(b, DEC, "--");
        punctuator(b, DIV, "/", b.nextNot("="));
        punctuator(b, DIVEQU, "/=");
        punctuator(b, DOT, ".");
        punctuator(b, ELLIPSIS, "...");
        punctuator(b, EQU, "=", b.nextNot("="));
        punctuator(b, EQUAL, "==");
        punctuator(b, GE, ">=");
        punctuator(b, GT, ">", b.nextNot(b.firstOf("=", ">")));
        punctuator(b, HAT, "^", b.nextNot("="));
        punctuator(b, HATEQU, "^=");
        punctuator(b, INC, "++");
        punctuator(b, LBRK, "[");
        punctuator(b, LT, "<", b.nextNot(b.firstOf("=", "<")));
        punctuator(b, LE, "<=");
        punctuator(b, LPAR, "(");
        punctuator(b, LWING, "{");
        punctuator(b, MINUS, "-", b.nextNot(b.firstOf("-", "=")));
        punctuator(b, MINUSEQU, "-=");
        punctuator(b, MOD, "%", b.nextNot("="));
        punctuator(b, MODEQU, "%=");
        punctuator(b, NOTEQUAL, "!=");
        punctuator(b, OR, "|", b.nextNot(b.firstOf("=", "|")));
        punctuator(b, OREQU, "|=");
        punctuator(b, OROR, "||");
        punctuator(b, PLUS, "+", b.nextNot(b.firstOf("=", "+")));
        punctuator(b, PLUSEQU, "+=");
        punctuator(b, QUERY, "?");
        punctuator(b, RBRK, "]");
        punctuator(b, RPAR, ")");
        punctuator(b, RWING, "}");
        punctuator(b, SEMI, ";");
        punctuator(b, SL, "<<", b.nextNot("="));
        punctuator(b, SLEQU, "<<=");
        punctuator(b, SR, ">>", b.nextNot(b.firstOf("=", ">")));
        punctuator(b, SREQU, ">>=");
        punctuator(b, STAR, "*", b.nextNot("="));
        punctuator(b, STAREQU, "*=");
        punctuator(b, TILDA, "~");

        punctuator(b, LPOINT, "<");
        punctuator(b, RPOINT, ">");

        punctuator(b, ARROW, "->");
    }

    private static void keywords(LexerlessGrammarBuilder b) {
        b.rule(LETTER_OR_DIGIT).is(javaIdentifierPart(b));
        for (JavaKeyword tokenType : JavaKeyword.values()) {
            b.rule(tokenType).is(tokenType.getValue(), b.nextNot(LETTER_OR_DIGIT), SPACING);
        }
        String[] keywords = JavaKeyword.keywordValues();
        Arrays.sort(keywords);
        ArrayUtils.reverse(keywords);
        b.rule(KEYWORD).is(b.firstOf(keywords[0], keywords[1], ArrayUtils.subarray(keywords, 2, keywords.length)),
                b.nextNot(LETTER_OR_DIGIT));
    }

    private static void punctuator(LexerlessGrammarBuilder b, GrammarRuleKey ruleKey, String value) {
        b.rule(ruleKey).is(value, SPACING);
    }

    private static void punctuator(LexerlessGrammarBuilder b, GrammarRuleKey ruleKey, String value,
            Object element) {
        b.rule(ruleKey).is(value, element, SPACING);
    }

    private static final String EXP_REGEXP = "(?:[Ee][+-]?+[0-9_]++)";
    private static final String BINARY_EXP_REGEXP = "(?:[Pp][+-]?+[0-9_]++)";
    private static final String FLOATING_LITERAL_WITHOUT_SUFFIX_REGEXP = "(?:" +
    // Decimal
            "[0-9][0-9_]*+\\.([0-9_]++)?+" + EXP_REGEXP + "?+" + "|" + "\\.[0-9][0-9_]*+" + EXP_REGEXP + "?+" + "|"
            + "[0-9][0-9_]*+" + EXP_REGEXP +
            // Hexadecimal
            "|" + "0[xX][0-9_a-fA-F]++\\.[0-9_a-fA-F]*+" + BINARY_EXP_REGEXP + "|" + "0[xX][0-9_a-fA-F]++"
            + BINARY_EXP_REGEXP + ")";

    private static final String INTEGER_LITERAL_REGEXP = "(?:" +
    // Hexadecimal
            "0[xX][0-9_a-fA-F]++" +
            // Binary (Java 7)
            "|" + "0[bB][01_]++" +
            // Decimal and Octal
            "|" + "[0-9][0-9_]*+" + ")";

    /**
     * 3.10. Literals
     */
    private static void literals(LexerlessGrammarBuilder b) {
        b.rule(SPACING)
                .is(b.skippedTrivia(whitespace(b)),
                        b.zeroOrMore(b.commentTrivia(b.firstOf(inlineComment(b), multilineComment(b))),
                                b.skippedTrivia(whitespace(b))))
                .skip();

        b.rule(EOF).is(b.token(GenericTokenType.EOF, b.endOfInput())).skip();

        b.rule(CHARACTER_LITERAL).is(characterLiteral(b), SPACING);
        b.rule(JavaTokenType.LITERAL).is(stringLiteral(b), SPACING);

        b.rule(FLOAT_LITERAL).is(b.regexp(FLOATING_LITERAL_WITHOUT_SUFFIX_REGEXP + "[fF]|[0-9][0-9_]*+[fF]"),
                SPACING);
        b.rule(DOUBLE_LITERAL).is(b.regexp(FLOATING_LITERAL_WITHOUT_SUFFIX_REGEXP + "[dD]?+|[0-9][0-9_]*+[dD]"),
                SPACING);

        b.rule(LONG_LITERAL).is(b.regexp(INTEGER_LITERAL_REGEXP + "[lL]"), SPACING);
        b.rule(INTEGER_LITERAL).is(b.regexp(INTEGER_LITERAL_REGEXP), SPACING);

        b.rule(IDENTIFIER).is(b.firstOf(b.next(ENUM), b.nextNot(KEYWORD)), javaIdentifier(b), SPACING);

        b.rule(LITERAL).is(b.firstOf(TRUE, FALSE, NULL, CHARACTER_LITERAL, JavaTokenType.LITERAL, FLOAT_LITERAL,
                DOUBLE_LITERAL, LONG_LITERAL, INTEGER_LITERAL));
    }

    private static Object characterLiteral(LexerlessGrammarBuilder b) {
        return b.sequence(b.next("'"), b.regexp("'([^'\\\\]*+(\\\\[\\s\\S])?+)*+'"));
    }

    private static Object stringLiteral(LexerlessGrammarBuilder b) {
        return b.sequence(b.next("\""), b.regexp("\"([^\"\\\\]*+(\\\\[\\s\\S])?+)*+\""));
    }

    private static Object whitespace(LexerlessGrammarBuilder b) {
        return b.regexp("\\s*+");
    }

    private static Object inlineComment(LexerlessGrammarBuilder b) {
        return b.regexp("//[^\\n\\r]*+");
    }

    private static Object multilineComment(LexerlessGrammarBuilder b) {
        return b.regexp("/\\*[\\s\\S]*?\\*\\/");
    }

    private static Object javaIdentifier(LexerlessGrammarBuilder b) {
        return b.regexp("\\p{javaJavaIdentifierStart}++\\p{javaJavaIdentifierPart}*+");
    }

    private static Object javaIdentifierPart(LexerlessGrammarBuilder b) {
        return b.regexp("\\p{javaJavaIdentifierPart}");
    }

    /**
     * 4. Types, Values and Variables
     */
    private static void types(LexerlessGrammarBuilder b) {
        b.rule(TYPE).is(b.firstOf(BASIC_TYPE, CLASS_TYPE), b.zeroOrMore(b.zeroOrMore(ANNOTATION), DIM));
        b.rule(CLASS_TYPE).is(b.zeroOrMore(ANNOTATION), IDENTIFIER, b.optional(TYPE_ARGUMENTS),
                b.zeroOrMore(DOT, b.zeroOrMore(ANNOTATION), IDENTIFIER, b.optional(TYPE_ARGUMENTS)));
        b.rule(CLASS_TYPE_LIST).is(CLASS_TYPE, b.zeroOrMore(COMMA, CLASS_TYPE));
        b.rule(TYPE_ARGUMENTS).is(LPOINT, TYPE_ARGUMENT, b.zeroOrMore(COMMA, TYPE_ARGUMENT), RPOINT);
        b.rule(TYPE_ARGUMENT).is(b.zeroOrMore(ANNOTATION), b.firstOf(TYPE,
                b.sequence(QUERY, b.optional(b.firstOf(EXTENDS, SUPER), b.zeroOrMore(ANNOTATION), TYPE))));
        b.rule(TYPE_PARAMETERS).is(LPOINT, TYPE_PARAMETER, b.zeroOrMore(COMMA, TYPE_PARAMETER), RPOINT);
        b.rule(TYPE_PARAMETER).is(b.zeroOrMore(ANNOTATION), IDENTIFIER, b.optional(EXTENDS, BOUND));
        b.rule(BOUND).is(CLASS_TYPE, b.zeroOrMore(AND, b.zeroOrMore(ANNOTATION), CLASS_TYPE));
        b.rule(MODIFIER).is(b.firstOf(ANNOTATION, PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, TRANSIENT,
                VOLATILE, SYNCHRONIZED, NATIVE, DEFAULT, STRICTFP));
    }

    /**
     * 7.3. Compilation Units
     */
    private static void compilationsUnits(LexerlessGrammarBuilder b) {
        b.rule(COMPILATION_UNIT).is(SPACING, b.optional(PACKAGE_DECLARATION), b.zeroOrMore(IMPORT_DECLARATION),
                b.zeroOrMore(TYPE_DECLARATION), EOF);

        b.rule(PACKAGE_DECLARATION).is(b.zeroOrMore(ANNOTATION), PACKAGE, QUALIFIED_IDENTIFIER, SEMI);
        b.rule(IMPORT_DECLARATION).is(IMPORT, b.optional(STATIC), QUALIFIED_IDENTIFIER, b.optional(DOT, STAR),
                SEMI);
        b.rule(TYPE_DECLARATION).is(b.firstOf(b.sequence(b.zeroOrMore(MODIFIER),
                b.firstOf(CLASS_DECLARATION, ENUM_DECLARATION, INTERFACE_DECLARATION, ANNOTATION_TYPE_DECLARATION)),
                SEMI));
    }

    /**
     * 8.1. Class Declaration
     */
    private static void classDeclaration(LexerlessGrammarBuilder b) {
        b.rule(CLASS_DECLARATION).is(CLASS, IDENTIFIER, b.optional(TYPE_PARAMETERS),
                b.optional(EXTENDS, CLASS_TYPE), b.optional(IMPLEMENTS, CLASS_TYPE_LIST), CLASS_BODY);

        b.rule(CLASS_BODY).is(LWING, b.zeroOrMore(CLASS_BODY_DECLARATION), RWING);
        b.rule(CLASS_BODY_DECLARATION)
                .is(b.firstOf(SEMI, CLASS_INIT_DECLARATION, b.sequence(b.zeroOrMore(MODIFIER), MEMBER_DECL)));
        b.rule(CLASS_INIT_DECLARATION).is(b.optional(STATIC), BLOCK);
        b.rule(MEMBER_DECL)
                .is(b.firstOf(b.sequence(TYPE_PARAMETERS, GENERIC_METHOD_OR_CONSTRUCTOR_REST),
                        b.sequence(TYPE, IDENTIFIER, METHOD_DECLARATOR_REST), FIELD_DECLARATION,
                        b.sequence(VOID, IDENTIFIER, VOID_METHOD_DECLARATOR_REST),
                        b.sequence(IDENTIFIER, CONSTRUCTOR_DECLARATOR_REST), INTERFACE_DECLARATION,
                        CLASS_DECLARATION, ENUM_DECLARATION, ANNOTATION_TYPE_DECLARATION));
        b.rule(FIELD_DECLARATION).is(TYPE, VARIABLE_DECLARATORS, SEMI);
        b.rule(GENERIC_METHOD_OR_CONSTRUCTOR_REST)
                .is(b.firstOf(b.sequence(b.firstOf(TYPE, VOID), IDENTIFIER, METHOD_DECLARATOR_REST),
                        b.sequence(IDENTIFIER, CONSTRUCTOR_DECLARATOR_REST)));
        b.rule(METHOD_DECLARATOR_REST).is(FORMAL_PARAMETERS, b.zeroOrMore(b.zeroOrMore(ANNOTATION), DIM),
                b.optional(THROWS, QUALIFIED_IDENTIFIER_LIST), b.firstOf(METHOD_BODY, SEMI));
        b.rule(VOID_METHOD_DECLARATOR_REST).is(FORMAL_PARAMETERS, b.optional(THROWS, QUALIFIED_IDENTIFIER_LIST),
                b.firstOf(METHOD_BODY, SEMI));
        b.rule(CONSTRUCTOR_DECLARATOR_REST).is(FORMAL_PARAMETERS, b.optional(THROWS, QUALIFIED_IDENTIFIER_LIST),
                METHOD_BODY);
        b.rule(METHOD_BODY).is(BLOCK);
    }

    /**
     * 8.9. Enums
     */
    private static void enums(LexerlessGrammarBuilder b) {
        b.rule(ENUM_DECLARATION).is(ENUM, IDENTIFIER, b.optional(IMPLEMENTS, CLASS_TYPE_LIST), ENUM_BODY);
        b.rule(ENUM_BODY).is(LWING, b.optional(ENUM_CONSTANTS), b.optional(COMMA),
                b.optional(ENUM_BODY_DECLARATIONS), RWING);
        b.rule(ENUM_CONSTANTS).is(ENUM_CONSTANT, b.zeroOrMore(COMMA, ENUM_CONSTANT));
        b.rule(ENUM_CONSTANT).is(b.zeroOrMore(ANNOTATION), IDENTIFIER, b.optional(ARGUMENTS),
                b.optional(CLASS_BODY));
        b.rule(ENUM_BODY_DECLARATIONS).is(SEMI, b.zeroOrMore(CLASS_BODY_DECLARATION));
    }

    /**
     * 9.1. Interface Declarations
     */
    private static void interfaceDeclarations(LexerlessGrammarBuilder b) {
        b.rule(INTERFACE_DECLARATION).is(INTERFACE, IDENTIFIER, b.optional(TYPE_PARAMETERS),
                b.optional(EXTENDS, CLASS_TYPE_LIST), INTERFACE_BODY);

        b.rule(INTERFACE_BODY).is(LWING, b.zeroOrMore(INTERFACE_BODY_DECLARATION), RWING);
        b.rule(INTERFACE_BODY_DECLARATION)
                .is(b.firstOf(b.sequence(b.zeroOrMore(MODIFIER), INTERFACE_MEMBER_DECL), SEMI));
        b.rule(INTERFACE_MEMBER_DECL)
                .is(b.firstOf(INTERFACE_METHOD_OR_FIELD_DECL, INTERFACE_GENERIC_METHOD_DECL,
                        b.sequence(VOID, IDENTIFIER, VOID_INTERFACE_METHOD_DECLARATORS_REST), INTERFACE_DECLARATION,
                        ANNOTATION_TYPE_DECLARATION, CLASS_DECLARATION, ENUM_DECLARATION));
        b.rule(INTERFACE_METHOD_OR_FIELD_DECL).is(TYPE, IDENTIFIER, INTERFACE_METHOD_OR_FIELD_REST);
        b.rule(INTERFACE_METHOD_OR_FIELD_REST)
                .is(b.firstOf(b.sequence(CONSTANT_DECLARATORS_REST, SEMI), INTERFACE_METHOD_DECLARATOR_REST));
        b.rule(INTERFACE_METHOD_DECLARATOR_REST).is(FORMAL_PARAMETERS, b.zeroOrMore(b.zeroOrMore(ANNOTATION), DIM),
                b.optional(THROWS, QUALIFIED_IDENTIFIER_LIST), b.firstOf(SEMI, BLOCK));
        b.rule(INTERFACE_GENERIC_METHOD_DECL).is(TYPE_PARAMETERS, b.firstOf(TYPE, VOID), IDENTIFIER,
                INTERFACE_METHOD_DECLARATOR_REST);
        b.rule(VOID_INTERFACE_METHOD_DECLARATORS_REST).is(FORMAL_PARAMETERS,
                b.optional(THROWS, QUALIFIED_IDENTIFIER_LIST), b.firstOf(SEMI, BLOCK));
        b.rule(CONSTANT_DECLARATORS_REST).is(CONSTANT_DECLARATOR_REST, b.zeroOrMore(COMMA, CONSTANT_DECLARATOR));
        b.rule(CONSTANT_DECLARATOR).is(IDENTIFIER, CONSTANT_DECLARATOR_REST);
        b.rule(CONSTANT_DECLARATOR_REST).is(b.zeroOrMore(DIM), EQU, VARIABLE_INITIALIZER);
    }

    /**
     * 8.4.1. Formal Parameters
     */
    private static void formalParameters(LexerlessGrammarBuilder b) {
        b.rule(FORMAL_PARAMETERS).is(LPAR, b.optional(FORMAL_PARAMETER_DECLS), RPAR);
        b.rule(FORMAL_PARAMETER).is(b.zeroOrMore(b.firstOf(FINAL, ANNOTATION)), TYPE, VARIABLE_DECLARATOR_ID);
        b.rule(FORMAL_PARAMETER_DECLS).is(b.zeroOrMore(b.firstOf(FINAL, ANNOTATION)), TYPE,
                FORMAL_PARAMETERS_DECLS_REST);
        b.rule(FORMAL_PARAMETERS_DECLS_REST)
                .is(b.firstOf(b.sequence(VARIABLE_DECLARATOR_ID, b.optional(COMMA, FORMAL_PARAMETER_DECLS)),
                        b.sequence(b.zeroOrMore(ANNOTATION), ELLIPSIS, VARIABLE_DECLARATOR_ID)));
        b.rule(VARIABLE_DECLARATOR_ID).is(IDENTIFIER, b.zeroOrMore(b.zeroOrMore(ANNOTATION), DIM));
    }

    /**
     * 9.7. Annotations
     */
    private static void annotations(LexerlessGrammarBuilder b) {
        b.rule(ANNOTATION_TYPE_DECLARATION).is(AT, INTERFACE, IDENTIFIER, ANNOTATION_TYPE_BODY);
        b.rule(ANNOTATION_TYPE_BODY).is(LWING, b.zeroOrMore(ANNOTATION_TYPE_ELEMENT_DECLARATION), RWING);
        b.rule(ANNOTATION_TYPE_ELEMENT_DECLARATION)
                .is(b.firstOf(b.sequence(b.zeroOrMore(MODIFIER), ANNOTATION_TYPE_ELEMENT_REST), SEMI));
        b.rule(ANNOTATION_TYPE_ELEMENT_REST)
                .is(b.firstOf(b.sequence(TYPE, IDENTIFIER, ANNOTATION_METHOD_OR_CONSTANT_REST, SEMI),
                        CLASS_DECLARATION, ENUM_DECLARATION, INTERFACE_DECLARATION, ANNOTATION_TYPE_DECLARATION));
        b.rule(ANNOTATION_METHOD_OR_CONSTANT_REST).is(b.firstOf(ANNOTATION_METHOD_REST, CONSTANT_DECLARATORS_REST));
        b.rule(ANNOTATION_METHOD_REST).is(LPAR, RPAR, b.optional(DEFAULT_VALUE));
        b.rule(DEFAULT_VALUE).is(DEFAULT, ELEMENT_VALUE);
        b.rule(ANNOTATION).is(AT, QUALIFIED_IDENTIFIER, b.optional(ANNOTATION_REST));
        b.rule(ANNOTATION_REST).is(b.firstOf(NORMAL_ANNOTATION_REST, SINGLE_ELEMENT_ANNOTATION_REST));
        b.rule(NORMAL_ANNOTATION_REST).is(LPAR, b.optional(ELEMENT_VALUE_PAIRS), RPAR);
        b.rule(ELEMENT_VALUE_PAIRS).is(ELEMENT_VALUE_PAIR, b.zeroOrMore(COMMA, ELEMENT_VALUE_PAIR));
        b.rule(ELEMENT_VALUE_PAIR).is(IDENTIFIER, EQU, ELEMENT_VALUE);
        b.rule(ELEMENT_VALUE).is(b.firstOf(CONDITIONAL_EXPRESSION, ANNOTATION, ELEMENT_VALUE_ARRAY_INITIALIZER));
        b.rule(ELEMENT_VALUE_ARRAY_INITIALIZER).is(LWING, b.optional(ELEMENT_VALUES), b.optional(COMMA), RWING);
        b.rule(ELEMENT_VALUES).is(ELEMENT_VALUE, b.zeroOrMore(COMMA, ELEMENT_VALUE));
        b.rule(SINGLE_ELEMENT_ANNOTATION_REST).is(LPAR, ELEMENT_VALUE, RPAR);
    }

    /**
     * 14. Blocks and Statements
     */
    private static void blocksAndStatements(LexerlessGrammarBuilder b) {
        // 14.2. Blocks
        b.rule(BLOCK).is(LWING, BLOCK_STATEMENTS, RWING);
        b.rule(BLOCK_STATEMENTS).is(b.zeroOrMore(BLOCK_STATEMENT));
        b.rule(BLOCK_STATEMENT).is(b.firstOf(LOCAL_VARIABLE_DECLARATION_STATEMENT,
                b.sequence(b.zeroOrMore(MODIFIER), b.firstOf(CLASS_DECLARATION, ENUM_DECLARATION)), STATEMENT));

        // 14.4. Local Variable Declaration Statements
        b.rule(LOCAL_VARIABLE_DECLARATION_STATEMENT).is(b.optional(VARIABLE_MODIFIERS), TYPE, VARIABLE_DECLARATORS,
                SEMI);
        b.rule(VARIABLE_MODIFIERS).is(b.oneOrMore(b.firstOf(ANNOTATION, FINAL)));
        b.rule(VARIABLE_DECLARATORS).is(VARIABLE_DECLARATOR, b.zeroOrMore(COMMA, VARIABLE_DECLARATOR));
        b.rule(VARIABLE_DECLARATOR).is(IDENTIFIER, b.zeroOrMore(DIM), b.optional(EQU, VARIABLE_INITIALIZER));

        // 14.5. Statements
        b.rule(STATEMENT)
                .is(b.firstOf(BLOCK, ASSERT_STATEMENT, IF_STATEMENT, FOR_STATEMENT, WHILE_STATEMENT, DO_STATEMENT,
                        TRY_STATEMENT, SWITCH_STATEMENT, SYNCHRONIZED_STATEMENT, RETURN_STATEMENT, THROW_STATEMENT,
                        BREAK_STATEMENT, CONTINUE_STATEMENT, LABELED_STATEMENT, EXPRESSION_STATEMENT,
                        EMPTY_STATEMENT));

        // 14.6. The Empty Statement
        b.rule(EMPTY_STATEMENT).is(SEMI);
        // 14.7. Labeled Statements
        b.rule(LABELED_STATEMENT).is(IDENTIFIER, COLON, STATEMENT);
        // 14.8. Expression Statements
        b.rule(EXPRESSION_STATEMENT).is(STATEMENT_EXPRESSION, SEMI);
        // 14.9. The if Statement
        b.rule(IF_STATEMENT).is(IF, PAR_EXPRESSION, STATEMENT, b.optional(ELSE, STATEMENT));
        // 14.10. The assert Statement
        b.rule(ASSERT_STATEMENT).is(ASSERT, EXPRESSION, b.optional(COLON, EXPRESSION), SEMI);

        // 14.11. The switch statement
        b.rule(SWITCH_STATEMENT).is(SWITCH, PAR_EXPRESSION, LWING, SWITCH_BLOCK_STATEMENT_GROUPS, RWING);
        b.rule(SWITCH_BLOCK_STATEMENT_GROUPS).is(b.zeroOrMore(SWITCH_BLOCK_STATEMENT_GROUP));
        b.rule(SWITCH_BLOCK_STATEMENT_GROUP).is(SWITCH_LABEL, BLOCK_STATEMENTS);
        b.rule(SWITCH_LABEL)
                .is(b.firstOf(b.sequence(CASE, CONSTANT_EXPRESSION, COLON), b.sequence(DEFAULT, COLON)));

        // 14.12. The while Statement
        b.rule(WHILE_STATEMENT).is(WHILE, PAR_EXPRESSION, STATEMENT);
        // 14.13. The do Statement
        b.rule(DO_STATEMENT).is(DO, STATEMENT, WHILE, PAR_EXPRESSION, SEMI);

        // 14.14. The for Statement
        b.rule(FOR_STATEMENT)
                .is(b.firstOf(
                        b.sequence(FOR, LPAR, b.optional(FOR_INIT), SEMI, b.optional(EXPRESSION), SEMI,
                                b.optional(FOR_UPDATE), RPAR, STATEMENT),
                        b.sequence(FOR, LPAR, FORMAL_PARAMETER, COLON, EXPRESSION, RPAR, STATEMENT)));
        b.rule(FOR_INIT)
                .is(b.firstOf(b.sequence(b.zeroOrMore(b.firstOf(FINAL, ANNOTATION)), TYPE, VARIABLE_DECLARATORS),
                        b.sequence(STATEMENT_EXPRESSION, b.zeroOrMore(COMMA, STATEMENT_EXPRESSION))));
        b.rule(FOR_UPDATE).is(STATEMENT_EXPRESSION, b.zeroOrMore(COMMA, STATEMENT_EXPRESSION));

        // 14.15. The break Statement
        b.rule(BREAK_STATEMENT).is(BREAK, b.optional(IDENTIFIER), SEMI);
        // 14.16. The continue Statement
        b.rule(CONTINUE_STATEMENT).is(CONTINUE, b.optional(IDENTIFIER), SEMI);
        // 14.17. The return Statement
        b.rule(RETURN_STATEMENT).is(RETURN, b.optional(EXPRESSION), SEMI);
        // 14.18. The throw Statement
        b.rule(THROW_STATEMENT).is(THROW, EXPRESSION, SEMI);
        // 14.19. The synchronized Statement
        b.rule(SYNCHRONIZED_STATEMENT).is(SYNCHRONIZED, PAR_EXPRESSION, BLOCK);

        // 14.20. The try Statement
        b.rule(TRY_STATEMENT)
                .is(b.firstOf(
                        b.sequence(TRY, BLOCK,
                                b.firstOf(b.sequence(b.oneOrMore(CATCH_CLAUSE), b.optional(FINALLY_)), FINALLY_)),
                        TRY_WITH_RESOURCES_STATEMENT));
        b.rule(TRY_WITH_RESOURCES_STATEMENT).is(TRY, RESOURCE_SPECIFICATION, BLOCK, b.zeroOrMore(CATCH_CLAUSE),
                b.optional(FINALLY_));
        b.rule(RESOURCE_SPECIFICATION).is(LPAR, RESOURCE, b.zeroOrMore(SEMI, RESOURCE), b.optional(SEMI), RPAR);
        b.rule(RESOURCE).is(b.optional(VARIABLE_MODIFIERS), CLASS_TYPE, VARIABLE_DECLARATOR_ID, EQU, EXPRESSION);

        b.rule(CATCH_CLAUSE).is(CATCH, LPAR, CATCH_FORMAL_PARAMETER, RPAR, BLOCK);
        b.rule(CATCH_FORMAL_PARAMETER).is(b.optional(VARIABLE_MODIFIERS), CATCH_TYPE, VARIABLE_DECLARATOR_ID);
        b.rule(CATCH_TYPE).is(QUALIFIED_IDENTIFIER, b.zeroOrMore(OR, QUALIFIED_IDENTIFIER));

        b.rule(FINALLY_).is(FINALLY, BLOCK);
    }

    /**
     * 15. Expressions
     */
    private static void expressions(LexerlessGrammarBuilder b) {
        b.rule(STATEMENT_EXPRESSION).is(EXPRESSION);
        b.rule(CONSTANT_EXPRESSION).is(EXPRESSION);
        b.rule(EXPRESSION).is(ASSIGNMENT_EXPRESSION);
        b.rule(ASSIGNMENT_EXPRESSION)
                .is(CONDITIONAL_EXPRESSION, b.zeroOrMore(ASSIGNMENT_OPERATOR, CONDITIONAL_EXPRESSION))
                .skipIfOneChild();
        b.rule(ASSIGNMENT_OPERATOR).is(b.firstOf(EQU, PLUSEQU, MINUSEQU, STAREQU, DIVEQU, ANDEQU, OREQU, HATEQU,
                MODEQU, SLEQU, SREQU, BSREQU));
        b.rule(CONDITIONAL_EXPRESSION)
                .is(CONDITIONAL_OR_EXPRESSION, b.zeroOrMore(QUERY, EXPRESSION, COLON, CONDITIONAL_OR_EXPRESSION))
                .skipIfOneChild();
        b.rule(CONDITIONAL_OR_EXPRESSION)
                .is(CONDITIONAL_AND_EXPRESSION, b.zeroOrMore(OROR, CONDITIONAL_AND_EXPRESSION)).skipIfOneChild();
        b.rule(CONDITIONAL_AND_EXPRESSION)
                .is(INCLUSIVE_OR_EXPRESSION, b.zeroOrMore(ANDAND, INCLUSIVE_OR_EXPRESSION)).skipIfOneChild();
        b.rule(INCLUSIVE_OR_EXPRESSION).is(EXCLUSIVE_OR_EXPRESSION, b.zeroOrMore(OR, EXCLUSIVE_OR_EXPRESSION))
                .skipIfOneChild();
        b.rule(EXCLUSIVE_OR_EXPRESSION).is(AND_EXPRESSION, b.zeroOrMore(HAT, AND_EXPRESSION)).skipIfOneChild();
        b.rule(AND_EXPRESSION).is(EQUALITY_EXPRESSION, b.zeroOrMore(AND, EQUALITY_EXPRESSION)).skipIfOneChild();
        b.rule(EQUALITY_EXPRESSION)
                .is(RELATIONAL_EXPRESSION, b.zeroOrMore(b.firstOf(EQUAL, NOTEQUAL), RELATIONAL_EXPRESSION))
                .skipIfOneChild();
        b.rule(RELATIONAL_EXPRESSION).is(SHIFT_EXPRESSION, b.zeroOrMore(
                b.firstOf(b.sequence(b.firstOf(GE, GT, LE, LT), SHIFT_EXPRESSION), b.sequence(INSTANCEOF, TYPE))))
                .skipIfOneChild();
        b.rule(SHIFT_EXPRESSION).is(ADDITIVE_EXPRESSION, b.zeroOrMore(b.firstOf(SL, BSR, SR), ADDITIVE_EXPRESSION))
                .skipIfOneChild();
        b.rule(ADDITIVE_EXPRESSION)
                .is(MULTIPLICATIVE_EXPRESSION, b.zeroOrMore(b.firstOf(PLUS, MINUS), MULTIPLICATIVE_EXPRESSION))
                .skipIfOneChild();
        b.rule(MULTIPLICATIVE_EXPRESSION)
                .is(UNARY_EXPRESSION, b.zeroOrMore(b.firstOf(STAR, DIV, MOD), UNARY_EXPRESSION)).skipIfOneChild();
        b.rule(UNARY_EXPRESSION_NOT_PLUS_MINUS)
                .is(b.firstOf(CAST_EXPRESSION, METHOD_REFERENCE,
                        b.sequence(PRIMARY, b.zeroOrMore(SELECTOR), b.zeroOrMore(POST_FIX_OP)),
                        b.sequence(TILDA, UNARY_EXPRESSION), b.sequence(BANG, UNARY_EXPRESSION)))
                .skipIfOneChild();
        b.rule(CAST_EXPRESSION).is(LPAR, b.firstOf(b.sequence(BASIC_TYPE, RPAR, UNARY_EXPRESSION),
                b.sequence(TYPE, b.zeroOrMore(AND, CLASS_TYPE), RPAR, UNARY_EXPRESSION_NOT_PLUS_MINUS)));
        b.rule(UNARY_EXPRESSION)
                .is(b.firstOf(b.sequence(PREFIX_OP, UNARY_EXPRESSION), UNARY_EXPRESSION_NOT_PLUS_MINUS))
                .skipIfOneChild();
        b.rule(PRIMARY)
                .is(b.firstOf(LAMBDA_EXPRESSION, PAR_EXPRESSION,
                        b.sequence(NON_WILDCARD_TYPE_ARGUMENTS,
                                b.firstOf(EXPLICIT_GENERIC_INVOCATION_SUFFIX, b.sequence(THIS, ARGUMENTS))),
                        b.sequence(THIS, b.optional(ARGUMENTS)), b.sequence(SUPER, SUPER_SUFFIX), LITERAL,
                        b.sequence(NEW, b.zeroOrMore(ANNOTATION), CREATOR),
                        b.sequence(QUALIFIED_IDENTIFIER, b.optional(IDENTIFIER_SUFFIX)),
                        b.sequence(BASIC_TYPE, b.zeroOrMore(DIM), DOT, CLASS), b.sequence(VOID, DOT, CLASS)));

        b.rule(METHOD_REFERENCE).is(b.firstOf(SUPER, TYPE, PRIMARY), DBLECOLON, b.optional(TYPE_ARGUMENTS),
                b.firstOf(NEW, IDENTIFIER));
        b.rule(IDENTIFIER_SUFFIX)
                .is(b.firstOf(
                        b.sequence(LBRK,
                                b.firstOf(b.sequence(RBRK, b.zeroOrMore(DIM), DOT, CLASS),
                                        b.sequence(EXPRESSION, RBRK))),
                        ARGUMENTS,
                        b.sequence(DOT,
                                b.firstOf(CLASS, EXPLICIT_GENERIC_INVOCATION, THIS, b.sequence(SUPER, ARGUMENTS),
                                        b.sequence(NEW, b.optional(NON_WILDCARD_TYPE_ARGUMENTS), INNER_CREATOR)))));
        b.rule(EXPLICIT_GENERIC_INVOCATION).is(NON_WILDCARD_TYPE_ARGUMENTS, EXPLICIT_GENERIC_INVOCATION_SUFFIX);
        b.rule(NON_WILDCARD_TYPE_ARGUMENTS).is(LPOINT, TYPE, b.zeroOrMore(COMMA, TYPE), RPOINT);
        b.rule(EXPLICIT_GENERIC_INVOCATION_SUFFIX)
                .is(b.firstOf(b.sequence(SUPER, SUPER_SUFFIX), b.sequence(IDENTIFIER, ARGUMENTS)));
        b.rule(PREFIX_OP).is(b.firstOf(INC, DEC, PLUS, MINUS));
        b.rule(POST_FIX_OP).is(b.firstOf(INC, DEC));
        b.rule(SELECTOR)
                .is(b.firstOf(b.sequence(DOT, IDENTIFIER, b.optional(ARGUMENTS)),
                        b.sequence(DOT, EXPLICIT_GENERIC_INVOCATION), b.sequence(DOT, THIS),
                        b.sequence(DOT, SUPER, SUPER_SUFFIX),
                        b.sequence(DOT, NEW, b.optional(NON_WILDCARD_TYPE_ARGUMENTS), INNER_CREATOR), DIM_EXPR));
        b.rule(SUPER_SUFFIX).is(b.firstOf(ARGUMENTS, b.sequence(DOT, IDENTIFIER, b.optional(ARGUMENTS)),
                b.sequence(DOT, NON_WILDCARD_TYPE_ARGUMENTS, IDENTIFIER, ARGUMENTS)));
        b.rule(BASIC_TYPE).is(b.zeroOrMore(ANNOTATION),
                b.firstOf(BYTE, SHORT, CHAR, INT, LONG, FLOAT, DOUBLE, BOOLEAN));
        b.rule(ARGUMENTS).is(LPAR, b.optional(EXPRESSION, b.zeroOrMore(COMMA, EXPRESSION)), RPAR);
        b.rule(CREATOR)
                .is(b.firstOf(b.sequence(b.optional(NON_WILDCARD_TYPE_ARGUMENTS), CREATED_NAME, CLASS_CREATOR_REST),
                        b.sequence(b.optional(NON_WILDCARD_TYPE_ARGUMENTS), b.firstOf(CLASS_TYPE, BASIC_TYPE),
                                ARRAY_CREATOR_REST)));
        b.rule(CREATED_NAME).is(b.zeroOrMore(ANNOTATION), IDENTIFIER, b.optional(NON_WILDCARD_TYPE_ARGUMENTS),
                b.zeroOrMore(DOT, b.zeroOrMore(ANNOTATION), IDENTIFIER, b.optional(NON_WILDCARD_TYPE_ARGUMENTS)));
        b.rule(INNER_CREATOR).is(IDENTIFIER, CLASS_CREATOR_REST);
        b.rule(ARRAY_CREATOR_REST).is(b.zeroOrMore(ANNOTATION), LBRK, b.firstOf(
                b.sequence(RBRK, b.zeroOrMore(DIM), ARRAY_INITIALIZER),
                b.sequence(EXPRESSION, RBRK, b.zeroOrMore(DIM_EXPR), b.zeroOrMore(b.zeroOrMore(ANNOTATION), DIM))));
        b.rule(CLASS_CREATOR_REST).is(b.optional(b.firstOf(DIAMOND, TYPE_ARGUMENTS)), ARGUMENTS,
                b.optional(CLASS_BODY));
        b.rule(DIAMOND).is(LT, GT);
        b.rule(ARRAY_INITIALIZER).is(LWING,
                b.optional(VARIABLE_INITIALIZER, b.zeroOrMore(COMMA, VARIABLE_INITIALIZER)), b.optional(COMMA),
                RWING);
        b.rule(VARIABLE_INITIALIZER).is(b.firstOf(ARRAY_INITIALIZER, EXPRESSION));
        b.rule(PAR_EXPRESSION).is(LPAR, EXPRESSION, RPAR);
        b.rule(QUALIFIED_IDENTIFIER).is(b.zeroOrMore(ANNOTATION), IDENTIFIER,
                b.zeroOrMore(DOT, b.zeroOrMore(ANNOTATION), IDENTIFIER));
        b.rule(QUALIFIED_IDENTIFIER_LIST).is(QUALIFIED_IDENTIFIER, b.zeroOrMore(COMMA, QUALIFIED_IDENTIFIER));
        b.rule(DIM).is(LBRK, RBRK);
        b.rule(DIM_EXPR).is(b.zeroOrMore(ANNOTATION), LBRK, EXPRESSION, RBRK);

        //Java 8 lambda expressions.
        b.rule(LAMBDA_EXPRESSION).is(LAMBDA_PARAMETERS, ARROW, LAMBDA_BODY);
        b.rule(LAMBDA_PARAMETERS)
                .is(b.firstOf(b.sequence(LPAR, b.optional(IDENTIFIER, b.zeroOrMore(COMMA, IDENTIFIER)), RPAR),
                        FORMAL_PARAMETERS, IDENTIFIER));
        b.rule(LAMBDA_BODY).is(b.firstOf(BLOCK, EXPRESSION));

    }

    private final String internalName;

    private JavaGrammar() {
        String name = name();
        StringBuilder sb = new StringBuilder();
        int i = 0;
        while (i < name.length()) {
            if (name.charAt(i) == '_' && i + 1 < name.length()) {
                i++;
                sb.append(name.charAt(i));
            } else {
                sb.append(Character.toLowerCase(name.charAt(i)));
            }
            i++;
        }
        this.internalName = sb.toString();
    }

    @Override
    public String toString() {
        // This allows to keep compatibility with old XPath expressions
        return internalName;
    }

}