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

org.sonar.erlang.parser.ErlangGrammarImpl Maven / Gradle / Ivy

There is a newer version: 1.1
Show newest version
/*
 * Sonar Erlang Plugin
 * Copyright (C) 2012 Tamas Kende
 * [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.erlang.parser;

import com.sonar.sslr.api.GenericTokenType;
import org.sonar.sslr.grammar.GrammarRuleKey;
import org.sonar.sslr.grammar.LexerlessGrammarBuilder;
import org.sonar.sslr.parser.LexerlessGrammar;

public enum ErlangGrammarImpl implements GrammarRuleKey {

  eof,

  stringLiteral,
  regularExpressionLiteral,

  numericLiteral,
  identifier,

  keyword,
  letterOrDigit,

  spacing,

  afterKeyword,
  andKeyword,
  andalsoKeyword,
  bandKeyword,
  beginKeyword,
  bnotKeyword,
  borKeyword,
  bslKeyword,
  bsrKeyword,
  bxorKeyword,
  caseKeyword,
  catchKeyword,
  condKeyword,
  divKeyword,
  endKeyword,
  funKeyword,
  ifKeyword,
  letKeyword,
  notKeyword,
  ofKeyword,
  orKeyword,
  orelseKeyword,
  queryKeyword,
  receiveKeyword,
  remKeyword,
  tryKeyword,
  whenKeyword,
  xorKeyword,

  // Punctuators
  arrow,
  arrowback,
  doublearrowback,
  lcurlybrace,
  rcurlybrace,
  lparenthesis,
  rparenthesis,
  lbracket,
  rbracket,
  dot,
  semi,
  comma,
  colon,
  matchop,
  plus,
  minus,
  star,
  div,
  lt,
  gt,
  le,
  ge,
  equal,
  notequal,
  equal2,
  notequal2,
  binstart,
  binend,
  listcomp,
  pipe,
  dollar,
  apostrophe,
  plusplus,
  minusminus,
  numbersign,
  exclamation,
  questionmark,

  module,
  functionDeclaration,
  moduleAttr,
  exportAttr,
  compileAttr,
  defineAttr,
  typeSpec,
  genericAttr,
  anyAttr,
  funcExport,
  expression,
  funcArity,
  functionClause,
  clauseHead,
  guardSequenceStart,
  funcDecl,
  clauseBody,
  pattern,
  literal,
  primaryExpression,
  listLiteral,
  tupleLiteral,
  binaryLiteral,
  assignmentExpression,
  memberExpression,
  funExpression,
  arguments,
  unaryExpression,
  multiplicativeExpression,
  additiveExpression,
  shiftExpression,
  relationalExpression,
  equalityExpression,
  bitwiseAndExpression,
  bitwiseXorExpression,
  bitwiseOrExpression,
  logicalAndExpression,
  logicalOrExpression,
  leftHandSideExpression,
  callExpression,
  callExpressionFirstMember,
  callExpressionSecondMember,
  qualifier,
  listOperationExpression,
  logicalXorExpression,
  shortCircuitOrElseExpression,
  shortCircuitAndAlsoExpression,
  binaryElement,
  binaryQualifier,
  expressionStatement,
  statement,
  ifExpression,
  caseExpression,
  receiveExpression,
  tryExpression,
  branchExps,
  branchExp,
  guardSequence,
  guard,
  guardExpression,
  functionDeclarationsNoName,
  functionDeclarationNoName,
  patternStatements,
  patternStatement,
  statements,
  sendExpression,
  catchExpression,
  afterExpression,
  catchPattern,
  catchPatternStatement,
  catchPatternStatements,
  blockExpression,
  macroLiteral,
  otherArithmeticExpression,
  ifdefAttr,
  ifndefAttr,
  elseAttr,
  endifAttr,
  flowControlAttr,
  recordAttr,
  spec,
  moduleHeadAttr,
  importAttr,
  recordField,
  fileAttr,
  behaviourAttr,
  moduleElements,
  moduleElement,
  atom,
  recordCreate,
  recordAccess,
  macroLiteralSimple,
  macroLiteralFunction,
  macroLiteralVarName,
  stringLiterals,
  stringConcatenation,
  guardedPattern, atomOrIdentifier, moduleAttrTags;

  public static final String EXP = "([Ee][-]?+[0-9_]++)";
  public static final String ESCAPE_SEQUENCE =
    "(\\$\\\\b)|(\\$\\\\d)|(\\$\\\\e)|(\\$\\\\f)|(\\$\\\\n)|(\\$\\\\r)|(\\$\\\\s)|(\\$\\\\t)|(\\$\\\\v)|(\\$\\\\')|(\\$\\\\\")|(\\$\\\\\\\\)"
      + "|(\\$\\\\\\^[A-Za-z])"
      + "|(\\$\\\\x\\{[A-F0-9]+\\})"
      + "|(\\$\\\\x[A-F0-9]{1,2})"
      + "|(\\$\\\\[0-7]{1,3})";

  public static final String NUMERIC_LITERAL = "(?:"
    + "[0-9]++\\.([0-9]++)" + EXP + "?"
    + "|[0-9]++\\#([0-9A-Fa-f]++)?+"
    + "|[0-9]++"
    + "|" + ESCAPE_SEQUENCE
    // parsing things like: '$a' or '$\]' '$\n'
    + "|\\$\\\\?[\\x00-\\x7F]"
    + ")";

  public static final String LITERAL = "(?:"
    + "\"([^\"\\\\]*+(\\\\[\\s\\S])?+)*+\")";

  public static final String COMMENT = "(?:"
    + "%[^\\n\\r]*+)";

  public static final String WHITESPACE = "[\\n\\r\\t\\u000B\\f\\u0020\\u00A0\\uFEFF\\p{Zs}]";

  public static final String IDENTIFIER = "^[A-Z_][a-zA-Z0-9_@]*";

  public static final String ATOM = "('[^'\\n\\r]*')|^[a-z][a-zA-Z0-9_@]*";

  // public static final String IDENTIFIER = "('[^'\n\r]*')"
  // + "|^(?!\\$)(\\p{javaJavaIdentifierStart}++[\\p{javaJavaIdentifierPart}@]*+)";

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

  public static LexerlessGrammarBuilder createGrammarBuilder() {
    LexerlessGrammarBuilder b = LexerlessGrammarBuilder.create();
    lexical(b);
    punctuators(b);
    keywords(b);
    expressions(b);
    branchAndGuardExpressions(b);
    statements(b);
    module(b);
    functions(b);

    b.setRootRule(module);

    return b;
  }

  /**
   * Lexical
   *
   * @param b
   */

  private static void lexical(LexerlessGrammarBuilder b) {
    b.rule(eof).is(b.token(GenericTokenType.EOF, b.endOfInput())).skip();

    // variable name (identifier): Uppercase letter or _ and may contain alphanumeric chars, underscore, and @
    b.rule(identifier).is(
      b.regexp(IDENTIFIER), spacing);

    // atom: lowercase letter and alphanumeric chars, underscore, and @ or anything between ''
    b.rule(atom).is(
      b.nextNot(keyword),
      b.regexp(ATOM), b.zeroOrMore(b.sequence(".", b.regexp(ATOM))), spacing);

    b.rule(numericLiteral).is(
      b.regexp(NUMERIC_LITERAL), spacing);

    // handle string concetanation ("..."\n[\r\t]"..." is one literal as
    // well this:
    // "asasd" ?MACRO "asdasd"
    b.rule(stringLiteral).is(
      b.sequence(b.regexp(LITERAL), spacing));

    /*
     * TODO use the keywords directly
     */
    b.rule(keyword).is(b.firstOf(
      "after",
      "andalso",
      "and",
      "band",
      "begin",
      "bnot",
      "bor",
      "bsl",
      "bsr",
      "bxor",
      "case",
      "catch",
      "cond",
      "div",
      "end",
      "fun",
      "if",
      "let",
      "not",
      "of",
      "orelse",
      "or",
      "query",
      "receive",
      "rem",
      "try",
      "when",
      "xor"), b.nextNot(letterOrDigit));

    b.rule(moduleAttrTags).is(b.firstOf(
      "ifdef",
      "ifndef",
      "else",
      "endif",
      "module",
      "export",
      "compile",
      "define",
      "import",
      "file",
      "behaviour",
      "on_load",
      "file",
      "include",
      "ignore_xref",
      "author",
      "include_lib",
      "export_type",
      "deprecated",
      "asn1_info"
      ));

    b.rule(letterOrDigit).is(b.regexp("\\p{javaJavaIdentifierPart}"));

    b.rule(spacing).is(
      b.skippedTrivia(b.regexp(WHITESPACE + "*")),
      b.zeroOrMore(b.commentTrivia(b.regexp(COMMENT)), b.skippedTrivia(b.regexp(WHITESPACE + "*")))
      ).skip();
  }

  private static void punctuators(LexerlessGrammarBuilder b) {
    b.rule(arrow).is(punctuator("->", b));
    b.rule(arrowback).is(punctuator("<-", b));
    b.rule(doublearrowback).is(punctuator("<=", b));
    b.rule(lcurlybrace).is(punctuator("{", b));
    b.rule(rcurlybrace).is(punctuator("}", b));
    b.rule(lparenthesis).is(punctuator("(", b));
    b.rule(rparenthesis).is(punctuator(")", b));
    b.rule(lbracket).is(punctuator("[", b));
    b.rule(rbracket).is(punctuator("]", b));
    b.rule(dot).is(punctuator(".", b));
    b.rule(semi).is(punctuator(";", b));
    b.rule(comma).is(punctuator(",", b));
    b.rule(colon).is(punctuator(":", b));
    b.rule(matchop).is(punctuator("=", b.nextNot(b.firstOf("=", "<", ":", "/")), b));
    b.rule(plus).is(punctuator("+", b.nextNot("+"), b));
    b.rule(minus).is(punctuator("-", b.nextNot(b.firstOf(">", "-")), b));
    b.rule(star).is(punctuator("*", b));
    b.rule(div).is(punctuator("/", b.nextNot("="), b));
    b.rule(lt).is(punctuator("<", b.nextNot(b.firstOf("=", "<")), b));
    b.rule(gt).is(punctuator(">", b.nextNot(b.firstOf("=", ">")), b));
    b.rule(le).is(punctuator("=<", b));
    b.rule(ge).is(punctuator(">=", b));
    b.rule(equal).is(punctuator("==", b));
    b.rule(notequal).is(punctuator("/=", b));
    b.rule(equal2).is(punctuator("=:=", b));
    b.rule(notequal2).is(punctuator("=/=", b));
    b.rule(binstart).is(punctuator("<<", b));
    b.rule(binend).is(punctuator(">>", b));
    b.rule(listcomp).is(punctuator("||", b));
    b.rule(pipe).is(punctuator("|", b.nextNot("|"), b));
    b.rule(dollar).is(punctuator("$", b));
    b.rule(apostrophe).is(punctuator("'", b));
    b.rule(plusplus).is(punctuator("++", b));
    b.rule(minusminus).is(punctuator("--", b));
    b.rule(numbersign).is(punctuator("#", b));
    b.rule(exclamation).is(punctuator("!", b));
    b.rule(questionmark).is(punctuator("?", b));
  }

  private static void keywords(LexerlessGrammarBuilder b) {
    b.rule(afterKeyword).is(keyword("after", b));
    b.rule(andKeyword).is(keyword("and", b));
    b.rule(andalsoKeyword).is(keyword("andalso", b));
    b.rule(bandKeyword).is(keyword("band", b));
    b.rule(beginKeyword).is(keyword("begin", b));
    b.rule(bnotKeyword).is(keyword("bnot", b));
    b.rule(borKeyword).is(keyword("bor", b));
    b.rule(bslKeyword).is(keyword("bsl", b));
    b.rule(bsrKeyword).is(keyword("bsr", b));
    b.rule(bxorKeyword).is(keyword("bxor", b));
    b.rule(caseKeyword).is(keyword("case", b));
    b.rule(catchKeyword).is(keyword("catch", b));
    b.rule(condKeyword).is(keyword("cond", b));
    b.rule(divKeyword).is(keyword("div", b));
    b.rule(endKeyword).is(keyword("end", b));
    b.rule(funKeyword).is(keyword("fun", b));
    b.rule(ifKeyword).is(keyword("if", b));
    b.rule(letKeyword).is(keyword("let", b));
    b.rule(notKeyword).is(keyword("not", b));
    b.rule(ofKeyword).is(keyword("of", b));
    b.rule(orKeyword).is(keyword("or", b));
    b.rule(orelseKeyword).is(keyword("orelse", b));
    b.rule(queryKeyword).is(keyword("query", b));
    b.rule(receiveKeyword).is(keyword("receive", b));
    b.rule(remKeyword).is(keyword("rem", b));
    b.rule(tryKeyword).is(keyword("try", b));
    b.rule(whenKeyword).is(keyword("when", b));
    b.rule(xorKeyword).is(keyword("xor", b));
  }

  private static void module(LexerlessGrammarBuilder b) {
    b.rule(module).is(spacing, b.optional(moduleElements), eof);
    b.rule(moduleElements).is(b.oneOrMore(
      moduleElement
      ));

    b.rule(moduleElement).is(b.firstOf(moduleHeadAttr, b.sequence(macroLiteral, dot), functionDeclaration)).skipIfOneChild();

    b.rule(moduleHeadAttr).is(b.firstOf(moduleAttr, fileAttr, exportAttr, compileAttr, defineAttr,
      importAttr, typeSpec, spec, recordAttr, flowControlAttr, behaviourAttr, genericAttr, anyAttr)).skipIfOneChild();

    b.rule(recordAttr).is(minus, semiKeyword("record", b),
      lparenthesis,
      b.zeroOrMore(
        b.nextNot(b.sequence(rparenthesis, spacing, dot)),
        b.regexp("."), spacing),
      rparenthesis, dot);

    b.rule(flowControlAttr).is(
      b.firstOf(ifdefAttr, ifndefAttr),
      b.zeroOrMore(b.firstOf(moduleHeadAttr, functionDeclaration)),
      b.optional(elseAttr,
        b.zeroOrMore(b.firstOf(moduleHeadAttr, functionDeclaration))),
      endifAttr);

    b.rule(ifdefAttr).is(minus, semiKeyword("ifdef", b), lparenthesis, atomOrIdentifier, rparenthesis, dot);

    b.rule(ifndefAttr).is(minus, semiKeyword("ifndef", b), lparenthesis, atomOrIdentifier, rparenthesis, dot);

    b.rule(elseAttr).is(minus, semiKeyword("else", b), dot);

    b.rule(endifAttr).is(minus, semiKeyword("endif", b), dot);

    b.rule(moduleAttr).is(minus, semiKeyword("module", b), lparenthesis, atom, rparenthesis, dot);
    b.rule(exportAttr).is(minus, semiKeyword("export", b), lparenthesis, funcExport, rparenthesis, dot);
    b.rule(compileAttr).is(minus, semiKeyword("compile", b), lparenthesis, primaryExpression, rparenthesis, dot);

    b.rule(defineAttr).is(minus, semiKeyword("define", b),
      lparenthesis, b.firstOf(
        b.sequence(primaryExpression, comma, statement),
        b.sequence(funcDecl, comma, guardSequence)), rparenthesis, dot);

    b.rule(importAttr).is(minus, semiKeyword("import", b), lparenthesis, b.firstOf(macroLiteral, atom), comma,
      lbracket, funcArity, b.zeroOrMore(comma, funcArity), rbracket, rparenthesis, dot);

    b.rule(fileAttr).is(minus, semiKeyword("file", b), lparenthesis, primaryExpression, comma, primaryExpression,
      rparenthesis, dot);

    b.rule(behaviourAttr).is(minus, semiKeyword("behaviour", b), lparenthesis, atom, rparenthesis, dot);

    b.rule(genericAttr).is(
      minus,
      b.firstOf(
        semiKeyword("vsn", b),
        semiKeyword("on_load", b),
        semiKeyword("include", b),
        semiKeyword("file", b),
        semiKeyword("ignore_xref", b),
        semiKeyword("include_lib", b),
        semiKeyword("author", b),
        semiKeyword("export_type", b),
        semiKeyword("deprecated", b),
        semiKeyword("asn1_info", b)),
      lparenthesis, b.firstOf(funcArity, primaryExpression), rparenthesis, dot);

    b.rule(anyAttr).is(minus, b.sequence(b.nextNot(moduleAttrTags), atom), lparenthesis, primaryExpression, rparenthesis, dot);

    // TODO: is it possible to have something like: -export().?
    b.rule(funcExport).is(lbracket, b.zeroOrMore(funcArity, b.zeroOrMore(comma, funcArity)), rbracket);
  }

  private static void functions(LexerlessGrammarBuilder b) {
    b.rule(spec).is(minus, b.firstOf(semiKeyword("spec", b), semiKeyword("callback", b)),
      b.zeroOrMore(b.firstOf(b.regexp("\\.(\\.+|.)"), b.regexp("[^\\.]")), spacing), dot);

    b.rule(typeSpec).is(minus, b.firstOf(semiKeyword("type", b), semiKeyword("opaque", b)),
      b.zeroOrMore(b.firstOf(b.regexp("\\.(\\.+|.)"), b.regexp("[^\\.]")), spacing), dot);

    b.rule(functionDeclaration).is(functionClause, b.zeroOrMore(semi, functionClause), dot);
    b.rule(functionClause).is(clauseHead, arrow, clauseBody);
    b.rule(clauseHead).is(funcDecl, b.optional(guardSequenceStart));
    b.rule(clauseBody).is(statements);

    b.rule(funcArity).is(b.optional(literal, colon), literal, div, literal);

    b.rule(funcDecl).is(literal, arguments);
  }

  private static void expressions(LexerlessGrammarBuilder b) {
    b.rule(literal).is(b.firstOf(numericLiteral, atomOrIdentifier, macroLiteral));
    b.rule(atomOrIdentifier).is(b.firstOf(identifier, atom)).skip();

    b.rule(primaryExpression).is(
      b.firstOf(
        b.sequence(lparenthesis, expression, rparenthesis),
        literal,
        stringLiteral,
        listLiteral,
        tupleLiteral,
        binaryLiteral));

    b.rule(stringLiterals).is(
      b.firstOf(
        macroLiteralSimple,
        macroLiteralVarName,
        stringLiteral
        )).skip();

    b.rule(stringConcatenation).is(
      b.firstOf(
        b.sequence(stringLiterals, b.oneOrMore(stringLiterals)),
        primaryExpression)
      ).skipIfOneChild();

    b.rule(recordAccess).is(
      stringConcatenation,
      b.zeroOrMore(
        b.firstOf(
          b.sequence(numbersign, primaryExpression),
          b.sequence(macroLiteral, b.optional(".", primaryExpression)))
        )
      ).skipIfOneChild();

    b.rule(recordCreate).is(
      b.firstOf(
        recordAccess,
        b.oneOrMore(numbersign, primaryExpression)),
      b.optional(
        lcurlybrace,
        b.optional(assignmentExpression,
          b.zeroOrMore(comma, assignmentExpression)),
        rcurlybrace
        )
      ).skipIfOneChild();

    b.rule(guardedPattern).is(recordCreate, b.optional(guardSequenceStart)).skipIfOneChild();

    // should be refactored
    b.rule(listLiteral).is(lbracket, b.optional(
      b.firstOf(
        b.sequence(expression, listcomp, qualifier, b.zeroOrMore(comma, qualifier)),
        b.sequence(expression, b.zeroOrMore(b.firstOf(comma, expression)), b.optional(pipe, expression)))),
      rbracket);
    // this does not work
    b.rule(qualifier).is(b.firstOf(b.sequence(expression, arrowback, expression), expression));

    b.rule(macroLiteral).is(
      b.firstOf(
        macroLiteralVarName,
        macroLiteralFunction,
        macroLiteralSimple
        ));

    b.rule(macroLiteralSimple).is(questionmark, atomOrIdentifier);
    b.rule(macroLiteralFunction).is(questionmark, atomOrIdentifier, arguments);
    b.rule(macroLiteralVarName).is(questionmark, questionmark, identifier);

    b.rule(tupleLiteral).is(lcurlybrace, b.zeroOrMore(b.firstOf(comma, expression)), rcurlybrace);
    b.rule(binaryLiteral).is(binstart, b.firstOf(b.sequence(b.sequence(assignmentExpression, listcomp,
      b.oneOrMore(binaryQualifier)), b.zeroOrMore(b.firstOf(comma, assignmentExpression))), b.zeroOrMore(b.firstOf(
      comma, binaryElement))), binend);
    b.rule(binaryQualifier).is(b.firstOf(
      b.sequence(binaryLiteral, doublearrowback, expression), b.sequence(
        primaryExpression, arrowback, expression, b.zeroOrMore(comma, expression)
        )));

    b.rule(binaryElement).is(
      b.sequence(expression,
        b.optional(
          colon,
          b.firstOf(numericLiteral, atom, identifier, macroLiteral)),
        b.optional(
          div,
          /*
           * Hack for things like: 1024:32/little-float-dafaq
           */
          b.firstOf(
            numericLiteral,
            b.sequence(
              atom,
              b.oneOrMore(minus, atom)),
            atom)
          ),
        // and for things like: Part1:4/big-unsigned-integer-unit:8
        b.optional(colon, numericLiteral)
        )
      );
    b.rule(memberExpression).is(
      b.firstOf(ifExpression, funExpression, caseExpression, tryExpression, receiveExpression, blockExpression, guardedPattern))
      .skipIfOneChild();

    /**
     * It can be a record ref (originaly a.b['a']) as well
     */
    b.rule(callExpression).is(
      b.firstOf(
        b.sequence(b.optional(callExpressionFirstMember, colon), callExpressionSecondMember, arguments),
        memberExpression)).skipIfOneChild();
    // TODO Added by Dinesh to get rid of the AstNode.getChild(int) calls in IsTailRecursiveCheck.getArityFromCall(), but should be improved
    b.rule(callExpressionFirstMember).is(memberExpression);
    b.rule(callExpressionSecondMember).is(memberExpression);

    b.rule(arguments).is(lparenthesis, b.optional(expression, b.zeroOrMore(comma, expression)),
      rparenthesis);
    b.rule(unaryExpression).is(b.firstOf(
      // handle things like: -12, -A, -func(A), -(6+3), bnot A
      // TODO why do we have notKeyword and minus here??
      b.sequence(b.optional(b.firstOf(bnotKeyword, minus)), callExpression),
      b.sequence(notKeyword, callExpression))).skipIfOneChild();
    b.rule(otherArithmeticExpression).is(unaryExpression,
      b.zeroOrMore(b.firstOf(divKeyword, remKeyword), unaryExpression)).skipIfOneChild();
    b.rule(multiplicativeExpression).is(otherArithmeticExpression,
      b.zeroOrMore(b.firstOf(star, div), otherArithmeticExpression)).skipIfOneChild();
    b.rule(additiveExpression).is(multiplicativeExpression,
      b.zeroOrMore(b.firstOf(plus, minus), multiplicativeExpression)).skipIfOneChild();

    b.rule(shiftExpression).is(additiveExpression, b.zeroOrMore(b.firstOf(bslKeyword, bsrKeyword), additiveExpression))
      .skipIfOneChild();
    b.rule(relationalExpression).is(shiftExpression, b.zeroOrMore(b.firstOf(lt, gt, le, ge), shiftExpression))
      .skipIfOneChild();

    b.rule(equalityExpression).is(relationalExpression,
      b.zeroOrMore(b.firstOf(equal, notequal, equal2, notequal2), relationalExpression))
      .skipIfOneChild();

    b.rule(bitwiseAndExpression).is(equalityExpression, b.zeroOrMore(bandKeyword, equalityExpression)).skipIfOneChild();

    b.rule(bitwiseXorExpression).is(bitwiseAndExpression, b.zeroOrMore(bxorKeyword, bitwiseAndExpression))
      .skipIfOneChild();

    b.rule(bitwiseOrExpression).is(bitwiseXorExpression, b.zeroOrMore(borKeyword, bitwiseXorExpression))
      .skipIfOneChild();

    b.rule(logicalAndExpression).is(bitwiseOrExpression, b.zeroOrMore(andKeyword, bitwiseOrExpression))
      .skipIfOneChild();

    b.rule(logicalOrExpression).is(logicalAndExpression, b.zeroOrMore(orKeyword, logicalAndExpression))
      .skipIfOneChild();

    b.rule(logicalXorExpression).is(logicalOrExpression, b.zeroOrMore(xorKeyword, logicalOrExpression))
      .skipIfOneChild();

    b.rule(shortCircuitOrElseExpression).is(logicalXorExpression, b.zeroOrMore(orelseKeyword, logicalXorExpression))
      .skipIfOneChild();

    b.rule(shortCircuitAndAlsoExpression).is(shortCircuitOrElseExpression,
      b.zeroOrMore(andalsoKeyword, shortCircuitOrElseExpression)).skipIfOneChild();

    b.rule(listOperationExpression).is(shortCircuitAndAlsoExpression,
      b.zeroOrMore(b.firstOf(plusplus, minusminus), shortCircuitAndAlsoExpression)).skipIfOneChild();

    b.rule(assignmentExpression).is(listOperationExpression, b.optional(matchop, expression)).skipIfOneChild();

    b.rule(funExpression).is(funKeyword, b.firstOf(b.sequence(b.optional(memberExpression, colon), funcArity),
      b.sequence(functionDeclarationsNoName, endKeyword)), b.optional(arguments));
    b.rule(functionDeclarationsNoName).is(functionDeclarationNoName, b.zeroOrMore(semi,
      functionDeclarationNoName));
    b.rule(functionDeclarationNoName).is(arguments, b.optional(guardSequenceStart), arrow, statements);

    b.rule(sendExpression).is(assignmentExpression, b.optional(exclamation, assignmentExpression)).skipIfOneChild();

    b.rule(caseExpression).is(caseKeyword, expression, ofKeyword, patternStatements, endKeyword);

    b.rule(ifExpression).is(ifKeyword, branchExps, endKeyword);

    b.rule(tryExpression).is(tryKeyword, statements, b.optional(ofKeyword, patternStatements), b.firstOf(b.sequence(catchExpression,
      afterExpression), catchExpression, afterExpression), endKeyword);

    b.rule(afterExpression).is(afterKeyword, statements);

    b.rule(catchExpression).is(catchKeyword, catchPatternStatements);

    b.rule(receiveExpression).is(receiveKeyword, b.firstOf(b.sequence(patternStatements, b.optional(afterKeyword, expression, arrow,
      statements)), b.sequence(afterKeyword, expression, arrow, statements)), endKeyword);

    b.rule(blockExpression).is(beginKeyword, statements, endKeyword);

    b.rule(expression).is(b.optional(catchKeyword), sendExpression);
  }

  /**
   * A.4 Statement
   */
  private static void statements(LexerlessGrammarBuilder b) {
    b.rule(expressionStatement).is(expression);
    b.rule(statement).is(expressionStatement);
    b.rule(statements).is(statement, b.zeroOrMore(comma, statement));

  }

  public static void branchAndGuardExpressions(LexerlessGrammarBuilder b) {
    b.rule(branchExps).is(branchExp, b.zeroOrMore(semi, branchExp));
    b.rule(branchExp).is(guardSequence, arrow, statements);

    b.rule(patternStatements).is(patternStatement, b.zeroOrMore(semi, patternStatement));
    b.rule(patternStatement).is(pattern, b.optional(guardSequenceStart), arrow, statements);

    b.rule(catchPatternStatements).is(catchPatternStatement, b.zeroOrMore(semi, catchPatternStatement));
    b.rule(catchPatternStatement).is(catchPattern, b.optional(guardSequenceStart), arrow, statements);
    b.rule(pattern).is(assignmentExpression);
    b.rule(catchPattern).is(b.optional(atomOrIdentifier, colon), expression);

    b.rule(guardSequenceStart).is(whenKeyword, guardSequence);

    b.rule(guardSequence).is(guard, b.zeroOrMore(semi, guard));
    b.rule(guard).is(guardExpression, b.zeroOrMore(comma, guardExpression));
    b.rule(guardExpression).is(expression);
  }

  private static Object punctuator(String value, LexerlessGrammarBuilder b) {
    return b.sequence(value, spacing);
  }

  private static Object punctuator(String value, Object element, LexerlessGrammarBuilder b) {
    return b.sequence(value, element, spacing);
  }

  private static Object keyword(String value, LexerlessGrammarBuilder b) {
    return b.sequence(value, b.nextNot(letterOrDigit), spacing);
  }

  private static Object semiKeyword(String value, LexerlessGrammarBuilder b) {
    return b.sequence(value, b.nextNot(letterOrDigit), spacing);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy