package org.jtwig.parser.parboiled.node;
import org.jtwig.model.tree.CompositeNode;
import org.jtwig.model.tree.Node;
import org.jtwig.parser.addon.AddonParserProvider;
import org.jtwig.parser.parboiled.ParserContext;
import org.jtwig.parser.parboiled.base.BasicParser;
import org.jtwig.parser.parboiled.base.PositionTrackerParser;
import org.parboiled.Rule;
import org.parboiled.annotations.Label;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import static org.parboiled.Parboiled.createParser;
public class CompositeNodeParser extends NodeParser<CompositeNode> {
public CompositeNodeParser(ParserContext context) {
super(CompositeNodeParser.class, context);
createParser(NodeListParser.class, context);
}
@Override
@Label("Composite Node")
public Rule NodeRule() {
PositionTrackerParser positionTrackerParser = parserContext().parser(PositionTrackerParser.class);
NodeListParser nodeListParser = parserContext().parser(NodeListParser.class);
return Sequence(
positionTrackerParser.PushPosition(),
nodeListParser.List(),
push(new CompositeNode(
positionTrackerParser.pop(1),
nodeListParser.pop()
))
);
}
public static class NodeListParser extends BasicParser<Collection<Node>> {
final Collection<Class> contentParsers;
public NodeListParser(ParserContext context) {
super(NodeListParser.class, context);
contentParsers = new ArrayList<>(Arrays.<Class>asList(
BlockNodeParser.class,
EmbedNodeParser.class,
ForLoopNodeParser.class,
IfNodeParser.class,
ImportSelfNodeParser.class,
ImportNodeParser.class,
IncludeNodeParser.class,
MacroNodeParser.class,
OutputNodeParser.class,
SetNodeParser.class,
DoNodeParser.class,
FlushNodeParser.class,
VerbatimNodeParser.class,
AutoEscapeNodeParser.class,
ContentEscapeNodeParser.class,
FilterNodeParser.class,
TextNodeParser.class
));
contentParsers.addAll(extractExtraParsers(context.getAddOnParsers()));
}
private Collection<? extends Class> extractExtraParsers(Collection<AddonParserProvider> addOnParsers) {
Collection<Class> result = new ArrayList<>();
for (AddonParserProvider provider : addOnParsers) {
result.add(provider.parser());
}
return result;
}
Rule List() {
Rule[] rules = new Rule[contentParsers.size()];
int i = 0;
for (Class contentParser : contentParsers) {
NodeParser<Node> parser = (NodeParser<Node>) parserContext().parser(contentParser);
rules[i++] = Sequence(
parser.NodeRule(),
peek(1).add(parser.pop())
);
}
return Sequence(
push(new ArrayList<Node>()),
ZeroOrMore(
FirstOf(
FirstOf(rules),
parserContext().parser(CommentParser.class).Comment()
)
)
);
}
}
}