All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.java.ast.parser.JavaGrammar Maven / Gradle / Ivy

There is a newer version: 3.2
Show newest version
/*
 * Sonar Java
 * Copyright (C) 2012 SonarSource
 * [email protected]
 *
 * 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.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,
  ENUM_CONSTANT_NAME,

  BASIC_TYPE,
  REFERENCE_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;

  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, 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, ">");
  }

  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.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(DIM));
    b.rule(REFERENCE_TYPE).is(b.firstOf(
        b.sequence(BASIC_TYPE, b.zeroOrMore(DIM)),
        b.sequence(CLASS_TYPE, b.zeroOrMore(DIM))));
    b.rule(CLASS_TYPE).is(IDENTIFIER, b.optional(TYPE_ARGUMENTS), b.zeroOrMore(DOT, 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.firstOf(
        REFERENCE_TYPE,
        b.sequence(QUERY, b.optional(b.firstOf(EXTENDS, SUPER), REFERENCE_TYPE))));
    b.rule(TYPE_PARAMETERS).is(LPOINT, TYPE_PARAMETER, b.zeroOrMore(COMMA, TYPE_PARAMETER), RPOINT);
    b.rule(TYPE_PARAMETER).is(IDENTIFIER, b.optional(EXTENDS, BOUND));
    b.rule(BOUND).is(CLASS_TYPE, b.zeroOrMore(AND, CLASS_TYPE));
    b.rule(MODIFIER).is(b.firstOf(
        ANNOTATION,
        PUBLIC,
        PROTECTED,
        PRIVATE,
        STATIC,
        ABSTRACT,
        FINAL,
        NATIVE,
        SYNCHRONIZED,
        TRANSIENT,
        VOLATILE,
        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(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(DIM), b.optional(THROWS, QUALIFIED_IDENTIFIER_LIST), SEMI);
    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), SEMI);
    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(ELLIPSIS, VARIABLE_DECLARATOR_ID)));
    b.rule(VARIABLE_DECLARATOR_ID).is(IDENTIFIER, b.zeroOrMore(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(CASE, ENUM_CONSTANT_NAME, COLON),
        b.sequence(DEFAULT, COLON)));
    b.rule(ENUM_CONSTANT_NAME).is(IDENTIFIER);

    // 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, REFERENCE_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).is(b.firstOf(
        b.sequence(PREFIX_OP, UNARY_EXPRESSION),
        b.sequence(LPAR, TYPE, RPAR, UNARY_EXPRESSION),
        b.sequence(PRIMARY, b.zeroOrMore(SELECTOR), b.zeroOrMore(POST_FIX_OP)))).skipIfOneChild();
    b.rule(PRIMARY).is(b.firstOf(
        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, 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(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, REFERENCE_TYPE, b.zeroOrMore(COMMA, REFERENCE_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,
        BANG,
        TILDA,
        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.rule(BASIC_TYPE).is(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(IDENTIFIER, b.optional(NON_WILDCARD_TYPE_ARGUMENTS), b.zeroOrMore(DOT, IDENTIFIER, b.optional(NON_WILDCARD_TYPE_ARGUMENTS)));
    b.rule(INNER_CREATOR).is(IDENTIFIER, CLASS_CREATOR_REST);
    b.rule(ARRAY_CREATOR_REST).is(LBRK, b.firstOf(
        b.sequence(RBRK, b.zeroOrMore(DIM), ARRAY_INITIALIZER),
        b.sequence(EXPRESSION, RBRK, b.zeroOrMore(DIM_EXPR), b.zeroOrMore(DIM))));
    b.rule(CLASS_CREATOR_REST).is(b.optional(DIAMOND), 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(IDENTIFIER, b.zeroOrMore(DOT, 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(LBRK, EXPRESSION, RBRK);
  }

  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;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy