package org.jtwig.parser.parboiled.node; import org.jtwig.model.tree.ExtendsNode; import org.jtwig.model.tree.Node; import org.jtwig.parser.ParseException; import org.jtwig.parser.parboiled.ParserContext; import org.jtwig.parser.parboiled.base.*; import org.jtwig.parser.parboiled.expression.AnyExpressionParser; import org.jtwig.parser.parboiled.model.Keyword; import org.jtwig.util.ErrorMessageFormatter; import org.parboiled.Rule; import java.util.ArrayList; import java.util.Collection; import static org.parboiled.Parboiled.createParser; public class ExtendsNodeParser extends NodeParser<ExtendsNode> { public ExtendsNodeParser(ParserContext context) { super(ExtendsNodeParser.class, context); createParser(ExtendDefinitionsParser.class, context); } @Override public Rule NodeRule() { SpacingParser spacingParser = parserContext().parser(SpacingParser.class); LimitsParser limitsParser = parserContext().parser(LimitsParser.class); AnyExpressionParser anyExpressionParser = parserContext().parser(AnyExpressionParser.class); ExtendDefinitionsParser definitionsParser = parserContext().parser(ExtendDefinitionsParser.class); PositionTrackerParser positionTrackerParser = parserContext().parser(PositionTrackerParser.class); return Sequence( spacingParser.Spacing(), positionTrackerParser.PushPosition(), limitsParser.startCode(), spacingParser.Spacing(), parserContext().parser(LexicParser.class).Keyword(Keyword.EXTENDS), spacingParser.Spacing(), Mandatory(anyExpressionParser.ExpressionRule(), "Extends construct missing path expression"), spacingParser.Spacing(), Mandatory(limitsParser.endCode(), "Code island not closed"), spacingParser.Spacing(), definitionsParser.Definitions(), spacingParser.Spacing(), push(new ExtendsNode( positionTrackerParser.pop(2), anyExpressionParser.pop(1), definitionsParser.pop() )) ); } public static class ExtendDefinitionsParser extends BasicParser<Collection<Node>> { public ExtendDefinitionsParser(ParserContext context) { super(ExtendDefinitionsParser.class, context); } Rule Definitions () { OverrideBlockNodeParser blockNodeParser = parserContext().parser(OverrideBlockNodeParser.class); SetNodeParser setNodeParser = parserContext().parser(SetNodeParser.class); ImportNodeParser importNodeParser = parserContext().parser(ImportNodeParser.class); return Sequence( push(new ArrayList<Node>()), ZeroOrMore( FirstOf( Sequence( blockNodeParser.NodeRule(), peek(1).add(blockNodeParser.pop()) ), Sequence( setNodeParser.NodeRule(), peek(1).add(setNodeParser.pop()) ), Sequence( importNodeParser.NodeRule(), peek(1).add(importNodeParser.pop()) ), Sequence( parserContext().parser(CommentParser.class).Comment(), parserContext().parser(SpacingParser.class).Spacing() ), invalidConstruct() ), parserContext().parser(SpacingParser.class).Spacing() ) ); } public Rule invalidConstruct() { return Sequence( ANY, throwException("Extends templates only allow you to specify either block or set constructs") ); } public boolean throwException(String message) { throw new ParseException(ErrorMessageFormatter.errorMessage(parserContext().parser(PositionTrackerParser.class).currentPosition(), message)); } } }