private void generateNode()

in antlr-based-bootstrap/peg/Generator.java [297:464]


    private void generateNode(int offset, Tree rule, Tree node, boolean shouldBePrivate, String funcName, HashSet<Tree> visited) {
        int type = node.getType();
        if (type == STRING || type == NUMBER || type == ID || !visited.add(node)) return;

        boolean isPrivate = shouldBePrivate || grammarRoot.equals(Rule.name(rule));
        out(offset, "// " +(isPrivate?"private":"")+ node.toStringTree());
        boolean isRule = node.getParent() == rule;
        boolean firstNonTrivial = node == Rule.firstNotTrivial(rule);
        final boolean recoverRoot = firstNonTrivial && Rule.attribute(rule, "recoverRoot", false);

        out(offset++, (isPrivate || !isRule ? "private " : "public ") + "static boolean " + funcName + "(PsiBuilder builder_, boolean optional_, int level_) {");
        if (node.getChildCount() == 0 && type == SEQ) {
            out(offset, "return true;");
            out(--offset, "}");
            return;
        }

        String debugFuncName = funcName; // + ":" + node.toStringTree();
        out(offset, "if (!recursion_guard_(builder_, level_, \"" + debugFuncName +"\")) return false;");
        List<Tree> children = getChildren(node);
        if (isTrivialNode(node)) {
            Tree child = node.getChild(0);
            out(offset, "return " + generateNodeCall(rule, child, getNextName(funcName, 0), "optional_") + ";");
            out(--offset, "}");
            newLine();
            generateNode(offset, rule, child, shouldBePrivate, getNextName(funcName, 0), visited);
            return;
        }

        final int pin = firstNonTrivial && type == SEQ? Rule.attribute(rule, "pin", children.size()) : children.size();
        if (!children.isEmpty() && (pin <= 0 || pin > children.size())) {
            throw new IllegalArgumentException("wrong pin in "+funcName+": "+ pin + " [1, "+children.size()+"]");
        }
        out(offset, "boolean result_ = " + (type == ZEROMORE || type == OPT) + ";");
        if (type == SEQ && pin > 0 && pin < children.size()) {
            out(offset, "boolean pinned_;");
        }
        if (!isPrivate && (type == SEQ || type == CHOICE || type == ONEMORE || type == ZEROMORE)) {
            out(offset, "final int start_ = builder_.getCurrentOffset();");
        }
        out(offset, "final Marker marker_ = builder_.mark();");
        out(offset++, "try {");

        if (type == CHOICE || recoverRoot) {
            out(offset, "enterErrorRecording(builder_, level_);");
        }

        for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) {
            Tree child = children.get(i);

            boolean optional = type == OPT || type == ZEROMORE;
            String nodeCall = generateNodeCall(rule, child, getNextName(funcName, i), Boolean.toString(optional));
            switch (type) {
                case CHOICE: {
                    out(offset++, (i > 0? "if (!result_) ":"")+"{");
                    out(offset, "Marker m_ = builder_.mark();");
                    out(offset++, "try {");
                    out(offset, "result_ = " + nodeCall+";");
                    out(--offset, "}");
                    out(offset++, "finally {");
                    out(offset++, "if (!result_) {");
                    out(offset, "m_.rollbackTo();");
                    out(--offset, "}");
                    out(offset++, "else {");
                    out(offset, "m_.drop();");
                    out(--offset, "}");
                    out(--offset, "}");
                    out(--offset, "}");
                    break;
                }
                case SEQ: {
                    if (i == pin) out(offset, "pinned_ = result_;");
                    if (i >= pin) out(offset, "result_ = result_ && (" +nodeCall + " || pinned_);");
                    else if (i > 0) out(offset, "result_ = result_ && " + nodeCall + ";");
                    else out(offset, "result_ = "+nodeCall + ";");
                    break;
                }
                case OPT: {
                    out(offset, nodeCall + ";");
                    break;
                }
                case ONEMORE:
                    out(offset, "result_ = " + nodeCall + ";");
                    nodeCall = generateNodeCall(rule, child, getNextName(funcName, i), Boolean.toString(true));
                    // fall through
                case ZEROMORE: {
                    out(offset, "int offset_ = builder_.getCurrentOffset();");
                    out(offset++, "while (!builder_.eof() && " + nodeCall +") {");
                    out(offset++, "if (offset_ == builder_.getCurrentOffset()) {");
                    out(offset, "builder_.error(\"Empty element parsed in "+debugFuncName+"\");");
                    out(offset, "break;");
                    out(--offset, "}");
                    out(offset, "offset_ = builder_.getCurrentOffset();");
                    out(--offset, "}");
                    break;
                }
                case AND: {
                    out(offset, "result_ = " + nodeCall+";");
                    break;
                }
                case NOT: {
                    out(offset, "result_ = !" + nodeCall+";");
                    break;
                }
                default: throw new AssertionError(GrammarParser.tokenNames[type]);
            }
        }
        out(--offset, "}");
        out(offset++, "finally {");

        if (type == CHOICE && !recoverRoot) {
            out(offset, "result_ = exitErrorRecording(builder_, result_, level_, " + recoverRoot + ");");
        }
        if (!isPrivate) {
            String elementType = getElementType(rule);
            if (type == SEQ || type == CHOICE || type == ONEMORE || type == ZEROMORE) {
                out(offset, "LighterASTNode last_ = result_? builder_.getLatestDoneMarker() : null;");
                out(offset++, "if (last_ != null && last_.getStartOffset() == start_ && type_extends_(last_.getTokenType(), "+elementType+")) {");
                out(offset, "marker_.drop();");
                out(--offset, "}");
                out(offset++, "else if (result_) {");
            }
            else {
                out(offset++, "if (result_) {");
            }
            out(offset, "marker_.done("+ elementType +");");
            out(--offset, "}");
            if (recoverRoot) {
                out(offset++, "else {");
                out(offset, "marker_.rollbackTo();");
                out(--offset, "}");
            }
            else {
                out(offset++, "else if (optional_) {");
                out(offset, "marker_.rollbackTo();");
                out(--offset, "}");
                out(offset++, "else {");
                out(offset, "marker_.drop();");
                out(--offset, "}");
            }
        }
        else {
            if (type == AND || type == NOT) {
                out(offset, "marker_.rollbackTo();");
            }
            else if (type != OPT && type != ZEROMORE) {
                out(offset++, "if (!result_ && optional_) {");
                out(offset, "marker_.rollbackTo();");
                out(--offset, "}");
                out(offset++, "else {");
                out(offset, "marker_.drop();");
                out(--offset, "}");
            }
            else {
                out(offset, "marker_.drop();");
            }
        }
        if (recoverRoot) {
            out(offset, "result_ = exitErrorRecording(builder_, result_, level_, " + recoverRoot + ");");
        }
        out(--offset, "}");
        out(offset, "return result_;");
        out(--offset, "}");
        newLine();
        for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) {
            generateNode(offset, rule, children.get(i), true, getNextName(funcName, i), visited);
        }
    }