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