package org.jtwig.parser.parboiled.expression; import org.apache.commons.lang3.StringEscapeUtils; import org.jtwig.model.expression.ConstantExpression; 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 static org.parboiled.Parboiled.createParser; public class StringExpressionParser extends ExpressionParser<ConstantExpression> { public StringExpressionParser(ParserContext context) { super(StringExpressionParser.class, context); createParser(StringParser.class, context); } @Override public Rule ExpressionRule() { PositionTrackerParser positionTrackerParser = parserContext().parser(PositionTrackerParser.class); StringParser stringParser = parserContext().parser(StringParser.class); return Sequence( positionTrackerParser.PushPosition(), stringParser.StringRule(), swap(), push(new ConstantExpression(positionTrackerParser.pop(), stringParser.pop().toString())) ); } public static class StringParser extends BasicParser<StringBuilder> { public StringParser(ParserContext context) { super(StringParser.class, context); } public Rule StringRule() { return Sequence( push(new StringBuilder()), FirstOf( StringWith('\''), StringWith('"') ) ); } Rule StringWith(char start) { return Sequence( String(start), ZeroOrMore( FirstOf( Escape(), Others(start) ) ), String(start) ); } Rule Others(char start) { return Sequence( Sequence(TestNot(AnyOf(new char[]{'\n', '\r', '\\', start})), ANY), run(peek().append(match())) ); } Rule Escape() { return Sequence(Sequence( '\\', ANY ), run(peek().append(StringEscapeUtils.unescapeJava(match()))) ); } boolean run (Object object) { return true; } } }