private NodeList<Stmt> parseStatementsFor( String symbol, GExpansion expansion, NodeList<FormalParameter> hintParams, boolean optional) { NodeList<Stmt> stmts = emptyList(); switch (expansion.kind) { case Sequence: stmts = stmts.appendAll(parseStatementsForChildren(symbol, expansion, hintParams, false)); break; case ZeroOrOne: { if (expansion.children.size() == 1 && expansion.children.get(0).kind == GExpansion.Kind.Choice) { stmts = stmts.appendAll(parseStatementsForChildren(symbol, expansion, hintParams, true)); } else { stmts = stmts.append( ifStmt( matchCondition( symbol, expansion, hintParams, hintParams.map(p -> p.id().get().name())), blockStmt() .withStmts( parseStatementsForChildren(symbol, expansion, hintParams, false)))); } break; } case ZeroOrMore: { stmts = stmts.append( whileStmt( matchCondition( symbol, expansion, hintParams, hintParams.map(p -> p.id().get().name())), blockStmt() .withStmts( parseStatementsForChildren(symbol, expansion, hintParams, false)))); break; } case OneOrMore: { stmts = stmts.append( doStmt( blockStmt() .withStmts( parseStatementsForChildren(symbol, expansion, hintParams, false)), matchCondition( symbol, expansion, hintParams, hintParams.map(p -> p.id().get().name())))); break; } case Choice: { List<IfStmt> expansionsIfStmt = expansion .children .stream() .map( e -> ifStmt( matchCondition( symbol, e, hintParams, hintParams.map(p -> p.id().get().name())), blockStmt() .withStmts(parseStatementsFor(symbol, e, hintParams, false)))) .collect(Collectors.toList()); Collections.reverse(expansionsIfStmt); stmts = stmts.append( listOf(expansionsIfStmt) .foldRight( (Stmt) (optional ? null : blockStmt() .withStmts( listOf( throwStmt( methodInvocationExpr( name("produceParseException")) .withArgs( listOf( firstTerminalsOf(expansion) .stream() .map(this::prefixedConstant) .collect( Collectors.toList()))))))), (ifThenClause, elseClause) -> optional && elseClause == null ? ifThenClause : ifThenClause.withElseStmt(elseClause))); break; } case NonTerminal: { Expr call = methodInvocationExpr(name("parse" + upperCaseFirst(expansion.symbol))) .withArgs(expansion.hints.appendAll(expansion.arguments)); stmts = stmts.append( expressionStmt( expansion.name == null ? call : assignExpr(name(expansion.name), AssignOp.Normal, call))); break; } case Terminal: { Expr argument = prefixedConstant(expansion.symbol); Expr call = methodInvocationExpr(name("parse")).withArgs(listOf(argument)); stmts = stmts.append( expressionStmt( expansion.name == null ? call : assignExpr(name(expansion.name), AssignOp.Normal, call))); break; } case Action: { stmts = stmts.appendAll(expansion.action); break; } default: } return stmts; }