Skip to content

Commit 720996d

Browse files
authored
Merge pull request #322 from bkiers/317-pop-out-after-comment-in-tag
[317] Pop out of mode when no tokens can possibly be created
2 parents e7cf576 + da17303 commit 720996d

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed

src/main/antlr4/liquid/parser/v4/LiquidLexer.g4

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@ mode IN_TAG;
188188
mode IN_TAG_ID;
189189
WS2 : WhitespaceChar+ -> channel(HIDDEN);
190190

191-
CommentInTagId : ( '#' ( {!linebreakOrTagEndAhead()}? . )* [ \t\r\n]* )+ -> channel(HIDDEN);
191+
// When we encounter a comment in this "IN_TAG_ID" mode, there is no need to try to create more tokens
192+
// since that will always result in an `InvalidEndTag` token. After all, a "#" comment consumes all
193+
// characters until it "sees" an end-tag. Just pop out in that case.
194+
CommentInTagId : ( '#' ( {!linebreakOrTagEndAhead()}? . )* [ \t\r\n]* )+ -> channel(HIDDEN), popMode;
192195

193196
InvalidEndTag
194197
: ( '}}' SpaceOrTab* LineBreak? {stripSpacesAroundTags && stripSingleLine}?

src/main/antlr4/liquid/parser/v4/LiquidParser.g4

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ tag
8282
| include_relative_tag
8383
| continue_tag
8484
| simple_tag
85+
| empty_tag
8586
| other_tag
8687
;
8788

@@ -112,6 +113,11 @@ simple_tag
112113
: TagStart SimpleTagId other_tag_parameters? TagEnd
113114
;
114115

116+
// A tag like `{% # inline comment %}` is considered empty: `{% %}`
117+
empty_tag
118+
: TagStart TagEnd
119+
;
120+
115121
raw_tag
116122
: TagStart RawStart raw_body RawEnd TagEnd
117123
;

src/main/java/liqp/nodes/BlockNode.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ public List<LNode> getChildren() {
3333
public Object render(TemplateContext context) {
3434
ObjectAppender.Controller builder = context.newObjectAppender(children.size());
3535
for (LNode node : children) {
36+
37+
// Since tags can be "empty", `node` can be null, in which case we simply continue.
38+
// For example, the tag `{% # inline comment %}` is considered "empty" since there is nothing inside.
39+
if (node == null) {
40+
continue;
41+
}
42+
3643
Object value = node.render(context);
3744
if (value == null) {
3845
continue;

src/test/java/liqp/TemplateTest.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,34 @@ public Object apply(Object value, TemplateContext context, Object... params) {
325325
assertEquals("15.0", rendered);
326326
}
327327

328+
// https://github.com/bkiers/Liqp/issues/317
329+
@Test
330+
public void testInlineComment() {
331+
332+
String source =
333+
"{% # this is a comment %}\n" +
334+
"\n" +
335+
"{% # for i in (1..3) -%}\n" +
336+
" i={{ i }}\n" +
337+
"{% # endfor %}\n" +
338+
"\n" +
339+
"{%\n" +
340+
" ###############################\n" +
341+
" # This is a comment\n" +
342+
" # across multiple lines\n" +
343+
" ###############################\n" +
344+
"%}";
345+
346+
String expected =
347+
"\n" +
348+
"\n" +
349+
"i=\n" +
350+
"\n" +
351+
"\n";
352+
353+
assertThat(TemplateParser.DEFAULT.parse(source).render(), is(expected));
354+
}
355+
328356
private Map<String, Object> getDeepData() {
329357
Map<String, Object> data = new HashMap<>();
330358
Map<?,?> secondIndex = Collections.singletonMap("e", "ok");
@@ -355,5 +383,4 @@ public void testWalk() {
355383
String res = TemplateParser.DEFAULT.parse("{{foo.a}}").toStringTree();
356384
assertNotNull(res);
357385
}
358-
359386
}

src/test/java/liqp/parser/v4/LiquidLexerTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ public void testOtherRaw() {
577577
assertThat(tokenise("{%raw%}?").get(2).getType(), is(LiquidLexer.OtherRaw));
578578
}
579579

580+
// https://github.com/bkiers/Liqp/issues/317
580581
@Test
581582
public void testInlineComment() {
582583

@@ -599,6 +600,48 @@ public void testInlineComment() {
599600
" ###############################-\n"));
600601
}
601602

603+
// https://github.com/bkiers/Liqp/issues/317
604+
@Test
605+
public void testInlineCommentInTag() {
606+
String source =
607+
"{% # for i in (1..3) -%}\n" +
608+
"{{ i }}\n" +
609+
"{% # endfor %}";
610+
611+
List<Token> tokens = tokenise(source);
612+
613+
Object[][] expected = {
614+
new Object[] { LiquidLexer.TagStart, "{%"},
615+
new Object[] { LiquidLexer.WS2, " "},
616+
new Object[] { LiquidLexer.CommentInTagId, "# for i in (1..3) "},
617+
new Object[] { LiquidLexer.TagEnd, "-%}\n"},
618+
new Object[] { LiquidLexer.OutStart, "{{"},
619+
new Object[] { LiquidLexer.WS, " "},
620+
new Object[] { LiquidLexer.Id, "i"},
621+
new Object[] { LiquidLexer.WS, " "},
622+
new Object[] { LiquidLexer.OutEnd, "}}"},
623+
new Object[] { LiquidLexer.Other, "\n"},
624+
new Object[] { LiquidLexer.TagStart, "{%"},
625+
new Object[] { LiquidLexer.WS2, " "},
626+
new Object[] { LiquidLexer.CommentInTagId, "# endfor "},
627+
new Object[] { LiquidLexer.TagEnd, "%}"}
628+
};
629+
630+
assertThat(tokens.size(), is(expected.length));
631+
632+
int index = 0;
633+
634+
for (Object[] test : expected) {
635+
636+
Token token = tokens.get(index);
637+
638+
assertThat(token.getType(), is(test[0]));
639+
assertThat(token.getText(), is(test[1]));
640+
641+
index++;
642+
}
643+
}
644+
602645
private static Token singleToken(String source) {
603646
return singleToken(source, false, true);
604647
}

0 commit comments

Comments
 (0)