private boolean generateExternalCall()

in src/org/intellij/grammar/livePreview/LivePreviewParser.java [424:512]


  private boolean generateExternalCall(PsiBuilder builder,
                                       int level,
                                       BnfRule rule,
                                       List<BnfExpression> expressions,
                                       String nextName,
                                       Map<String, Parser> externalArguments) {
    List<BnfExpression> callParameters = expressions;
    List<String> metaParameterNames;
    String method = expressions.size() > 0 ? expressions.get(0).getText() : null;
    BnfRule targetRule = method == null ? null : myFile.getRule(method);
    // handle external rule call: substitute and merge arguments from external expression and rule definition
    if (targetRule != null) {
      metaParameterNames = GrammarUtil.collectMetaParameters(targetRule, targetRule.getExpression());
      if (Rule.isExternal(targetRule)) {
        callParameters = GrammarUtil.getExternalRuleExpressions(targetRule);
        method = callParameters.get(0).getText();
        if (metaParameterNames.size() < expressions.size() - 1) {
          callParameters = ContainerUtil.concat(callParameters, expressions.subList(metaParameterNames.size() + 1, expressions.size()));
        }
        if (myFile.getRule(method) == null) {
          // not supported
          return false;
        }
      }
    }
    else {
      // Hard-coded extensions:
      if ("eof".equals(method) && expressions.size() == 1) {
        return eof(builder, level);
      }
      else if ("anything".equals(method) && expressions.size() == 2) {
        BnfExpression finalNested = expressions.get(1);
        parseAsTree(ErrorState.get(builder), builder, level + 1, DUMMY_BLOCK, true, TOKEN_ADVANCER,
                    (builder14, level14) -> generateNodeCall(builder14, level14, rule, finalNested, getNextName(nextName, 0), Collections.emptyMap()));
        return true;
      }
      // not supported
      return false;
    }
    if (callParameters.size() <= 1) {
      return rule(builder, level, targetRule, externalArguments);
    }
    Map<String, Parser> argumentMap = new HashMap<>();
    for (int i = 1, len = Math.min(callParameters.size(), metaParameterNames.size() + 1); i < len; i++) {
      BnfExpression nested = callParameters.get(i);
      String argument = nested.getText();
      String argName = metaParameterNames.get(i - 1);
      String argNextName;
      int metaIdx;
      if (argument.startsWith("<<") && (metaIdx = metaParameterNames.indexOf(argument)) > -1) {
        nested = expressions.get(metaIdx + 1);
        argNextName = getNextName(nextName, metaIdx);
      }
      else {
        argNextName = getNextName(nextName, i - 1);
      }
      BnfExpression finalNested = nested;
      if (nested instanceof BnfReferenceOrToken || nested instanceof BnfLiteralExpression) {
        BnfRule argRule = nested instanceof BnfReferenceOrToken? myFile.getRule(nested.getText()) : null;
        argumentMap.put(argName, (builder13, level13) -> {
          if (argRule != null) {
            return rule(builder13, level13, argRule, Collections.emptyMap());
          }
          else {
            return generateNodeCall(builder13, level13, rule, finalNested, nextName, Collections.emptyMap());
          }
        });
      }
      else if (nested instanceof BnfExternalExpression) {
        List<BnfExpression> expressionList = ((BnfExternalExpression)nested).getExpressionList();
        boolean metaRule = Rule.isMeta(rule) || Rule.isExternal(rule);
        if (metaRule && expressionList.size() == 1) {
          // parameter
          argumentMap.put(argName, externalArguments.get("<<" + expressionList.get(0).getText() + ">>"));
        }
        else {
          argumentMap.put(argName, (builder12, level12) -> generateNodeCall(builder12, level12, targetRule, finalNested, argNextName, externalArguments));
        }
      }
      else {
        argumentMap.put(argName,
                        (builder1, level1) -> generateNodeCall(builder1, level1, targetRule, finalNested, argNextName, externalArguments));
      }
    }
    if (Rule.isExternal(targetRule)) {
      return generateExternalCall(builder, level, targetRule, callParameters, targetRule.getName(), argumentMap);
    }
    return rule(builder, level, targetRule, argumentMap);
  }