public static void generateExpressionRoot()

in src/org/intellij/grammar/generator/ExpressionGeneratorHelper.java [43:202]


  public static void generateExpressionRoot(ExpressionHelper.ExpressionInfo info, ParserGenerator g) {
    Map<String, List<OperatorInfo>> opCalls = buildCallMap(info, g);
    Set<String> sortedOpCalls = opCalls.keySet();

    for (String s : info.toString().split("\n")) {
      g.out("// " + s);
    }

    // main entry
    String methodName = getFuncName(info.rootRule);
    String kernelMethodName = getNextName(methodName, 0);
    String frameName = quote(getRuleDisplayName(info.rootRule, true));
    String shortPB = g.shorten(g.C.PsiBuilderClass);
    String shortMarker = !g.G.generateFQN ? "Marker" : g.C.PsiBuilderClass + ".Marker";
    g.out("public static boolean %s(%s %s, int %s, int %s) {", methodName, shortPB, g.N.builder, g.N.level, g.N.priority);
    g.out("if (!recursion_guard_(%s, %s, \"%s\")) return false;", g.N.builder, g.N.level, methodName);

    if (frameName != null) {
      g.out("addVariant(%s, %s);", g.N.builder, frameName);
    }
    g.generateFirstCheck(info.rootRule, frameName, true);
    g.out("boolean %s, %s;", g.N.result, g.N.pinned);
    g.out("%s %s = enter_section_(%s, %s, _NONE_, %s);", shortMarker, g.N.marker, g.N.builder, g.N.level, frameName);

    boolean first = true;
    for (String opCall : sortedOpCalls) {
      List<OperatorInfo> operators = findOperators(opCalls.get(opCall), OperatorType.ATOM, OperatorType.PREFIX);
      if (operators.isEmpty()) continue;
      OperatorInfo operator = operators.get(0);
      if (operators.size() > 1) {
        g.addWarning("only first definition will be used for '" + operator.operator.getText() + "': " + operators);
      }
      String nodeCall = g.generateNodeCall(operator.rule, null, operator.rule.getName()).render(g.N);
      g.out("%s%s = %s;", first ? "" : format("if (!%s) ", g.N.result), g.N.result, nodeCall);
      first = false;
    }

    g.out("%s = %s;", g.N.pinned, g.N.result);
    g.out("%s = %s && %s(%s, %s + 1, %s);", g.N.result, g.N.result, kernelMethodName, g.N.builder, g.N.level, g.N.priority);
    g.out("exit_section_(%s, %s, %s, null, %s, %s, null);", g.N.builder, g.N.level, g.N.marker, g.N.result, g.N.pinned);
    g.out("return %s || %s;", g.N.result, g.N.pinned);
    g.out("}");
    g.newLine();

    // kernel
    g.out("public static boolean %s(%s %s, int %s, int %s) {", kernelMethodName, shortPB, g.N.builder, g.N.level, g.N.priority);
    g.out("if (!recursion_guard_(%s, %s, \"%s\")) return false;", g.N.builder, g.N.level, kernelMethodName);
    g.out("boolean %s = true;", g.N.result);
    g.out("while (true) {");
    g.out("%s %s = enter_section_(%s, %s, _LEFT_, null);", shortMarker, g.N.marker, g.N.builder, g.N.level);

    first = true;
    for (String opCall : sortedOpCalls) {
      List<OperatorInfo> operators = findOperators(opCalls.get(opCall), OperatorType.BINARY, OperatorType.N_ARY, OperatorType.POSTFIX);
      if (operators.isEmpty()) continue;
      OperatorInfo operator = operators.get(0);
      if (operators.size() > 1) {
        g.addWarning("only first definition will be used for '" + operator.operator.getText() + "': " + operators);
      }
      int priority = info.getPriority(operator.rule);
      int arg2Priority = operator.arg2 == null ? -1 : info.getPriority(operator.arg2);
      int argPriority = arg2Priority == -1 ? priority : arg2Priority - 1;

      String substCheck = "";
      if (operator.arg1 != null) {
        substCheck = format(" && leftMarkerIs(%s, %s)", g.N.builder, g.getElementType(operator.arg1));
      }
      g.out("%sif (%s < %d%s && %s) {", first ? "" : "else ", g.N.priority, priority, substCheck, opCall);
      first = false;
      String elementType = g.getElementType(operator.rule);
      boolean rightAssociative = getAttribute(operator.rule, KnownAttribute.RIGHT_ASSOCIATIVE);
      String tailCall = operator.tail == null ? null : g.generateNodeCall(
        operator.rule, operator.tail, getNextName(getFuncName(operator.rule), 1), ConsumeType.DEFAULT
      ).render(g.N);
      if (operator.type == OperatorType.BINARY) {
        String argCall = format("%s(%s, %s, %d)", methodName, g.N.builder, g.N.level, rightAssociative ? argPriority - 1 : argPriority);
        g.out("%s = %s;", g.N.result, tailCall == null ? argCall : format("report_error_(%s, %s)", g.N.builder, argCall));
        if (tailCall != null) g.out("%s = %s && %s;", g.N.result, tailCall, g.N.result);
      }
      else if (operator.type == OperatorType.N_ARY) {
        boolean checkEmpty = info.checkEmpty.contains(operator);
        if (checkEmpty) {
          g.out("int %s = current_position_(%s);", g.N.pos, g.N.builder);
        }
        g.out("while (true) {");
        g.out("%s = report_error_(%s, %s(%s, %s, %d));", g.N.result, g.N.builder, methodName, g.N.builder, g.N.level, argPriority);
        if (tailCall != null) g.out("%s = %s && %s;", g.N.result, tailCall, g.N.result);
        g.out("if (!%s) break;", opCall);
        if (checkEmpty) {
          g.out("if (!empty_element_parsed_guard_(%s, \"%s\", %s)) break;", g.N.builder, operator.rule.getName(), g.N.pos);
          g.out("%s = current_position_(%s);", g.N.pos, g.N.builder);
        }
        g.out("}");
      }
      else if (operator.type == OperatorType.POSTFIX) {
        g.out("%s = true;", g.N.result);
      }
      g.out("exit_section_(%s, %s, %s, %s, %s, true, null);", g.N.builder, g.N.level, g.N.marker, elementType, g.N.result);
      g.out("}");
    }
    if (first) {
      g.out("// no BINARY or POSTFIX operators present");
      g.out("break;");
    }
    else {
      g.out("else {");
      g.out("exit_section_(%s, %s, %s, null, false, false, null);", g.N.builder, g.N.level, g.N.marker);
      g.out("break;");
      g.out("}");
    }
    g.out("}");
    g.out("return %s;", g.N.result);
    g.out("}");

    // operators and tails
    Set<BnfExpression> visited = new HashSet<>();
    for (String opCall : sortedOpCalls) {
      for (OperatorInfo operator : opCalls.get(opCall)) {
        if (operator.type == OperatorType.ATOM) {
          if (Rule.isExternal(operator.rule)) continue;
          g.newLine();
          g.generateNode(operator.rule, operator.rule.getExpression(), getFuncName(operator.rule), visited);
          continue;
        }
        else if (operator.type == OperatorType.PREFIX) {
          g.newLine();
          String operatorFuncName = operator.rule.getName();
          g.out("public static boolean %s(%s %s, int %s) {", operatorFuncName, shortPB, g.N.builder, g.N.level);
          g.out("if (!recursion_guard_(%s, %s, \"%s\")) return false;", g.N.builder, g.N.level, operatorFuncName);
          g.generateFirstCheck(operator.rule, frameName, false);
          g.out("boolean %s, %s;", g.N.result, g.N.pinned);
          g.out("%s %s = enter_section_(%s, %s, _NONE_, null);", shortMarker, g.N.marker, g.N.builder, g.N.level);

          String elementType = g.getElementType(operator.rule);
          String tailCall = operator.tail == null ? null : g.generateNodeCall(
            operator.rule, operator.tail, getNextName(getFuncName(operator.rule), 1), ConsumeType.DEFAULT
          ).render(g.N);

          g.out("%s = %s;", g.N.result, opCall);
          g.out("%s = %s;", g.N.pinned, g.N.result);
          int priority = info.getPriority(operator.rule);
          int arg1Priority = operator.arg1 == null ? -1 : info.getPriority(operator.arg1);
          int argPriority = arg1Priority == -1 ? (priority == info.nextPriority - 1 ? -1 : priority) : arg1Priority - 1;
          g.out("%s = %s && %s(%s, %s, %d);", g.N.result, g.N.pinned, methodName, g.N.builder, g.N.level, argPriority);
          if (tailCall != null) {
            g.out("%s = %s && report_error_(%s, %s) && %s;", g.N.result, g.N.pinned, g.N.builder, tailCall, g.N.result);
          }
          String elementTypeRef = StringUtil.isNotEmpty(elementType) ? elementType : "null";
          g.out("exit_section_(%s, %s, %s, %s, %s, %s, null);", g.N.builder, g.N.level, g.N.marker, elementTypeRef,
                g.N.result, g.N.pinned);
          g.out("return %s || %s;", g.N.result, g.N.pinned);
          g.out("}");
        }
        g.generateNodeChild(operator.rule, operator.operator, getFuncName(operator.rule), 0, visited);
        if (operator.tail != null) {
          g.generateNodeChild(operator.rule, operator.tail, operator.rule.getName(), 1, visited);
        }
      }
    }
  }