Skip to content

Commit

Permalink
Improved parsing of flavor-specific tag 'include_relative'
Browse files Browse the repository at this point in the history
* In Jekyll style, 'include_relative' was represented as token SimpleTag,
  instead of IncludeRelative, as expected since PR #288.
* As a consequence, filename components were parsed as separate parameters
  instead of token file_name_or_output. This behaviour got unnoticed only
  because all parameters were incorrectly concatenated into one string
  (to be fixed outside of this commit)
* In Liquid style, tag 'include_relative' is not defined (token InvalidTagId),
  but can be defined as a custom block (token SimpleBlock) or a tag (SimpleTag).
* To facilitate flavor-specific lexical analysis, flag isLiquidStyleInclude was
  was added to LiquidLexer; same code as in the LiquidParser since #196
  • Loading branch information
pmenhart committed Apr 23, 2024
1 parent 4d5600c commit eb97f95
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 33 deletions.
38 changes: 25 additions & 13 deletions src/main/antlr4/liquid/parser/v4/LiquidLexer.g4
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
lexer grammar LiquidLexer;

@lexer::members {
private boolean liquidStyleInclude = true;
private boolean stripSpacesAroundTags = false;
private boolean stripSingleLine = false;
private java.util.LinkedList<Token> tokens = new java.util.LinkedList<>();
private java.util.Set<String> blocks = new java.util.HashSet<String>();
private java.util.Set<String> tags = new java.util.HashSet<String>();
private java.util.Stack<String> customBlockState = new java.util.Stack<String>();
public LiquidLexer(CharStream charStream, boolean stripSpacesAroundTags, java.util.Set<String> blocks, java.util.Set<String> tags) {
this(charStream, stripSpacesAroundTags, false, blocks, tags);
private boolean isLiquidStyleInclude(){
return liquidStyleInclude;
}

public LiquidLexer(CharStream charStream, boolean stripSpacesAroundTags) {
this(charStream, stripSpacesAroundTags, false, new java.util.HashSet<String>(), new java.util.HashSet<String>());
private boolean isJekyllStyleInclude(){
return !liquidStyleInclude;
}

public LiquidLexer(CharStream charStream, boolean stripSpacesAroundTags, boolean stripSingleLine, java.util.Set<String> blocks, java.util.Set<String> tags) {
public LiquidLexer(CharStream charStream, boolean isLiquidStyleInclude, boolean stripSpacesAroundTags, java.util.Set<String> blocks, java.util.Set<String> tags) {
this(charStream, isLiquidStyleInclude, stripSpacesAroundTags, false, blocks, tags);
}

public LiquidLexer(CharStream charStream, boolean isLiquidStyleInclude, boolean stripSpacesAroundTags) {
this(charStream, isLiquidStyleInclude, stripSpacesAroundTags, false, new java.util.HashSet<String>(), new java.util.HashSet<String>());
}

public LiquidLexer(CharStream charStream, boolean isLiquidStyleInclude, boolean stripSpacesAroundTags, boolean stripSingleLine, java.util.Set<String> blocks, java.util.Set<String> tags) {
this(charStream);
this.liquidStyleInclude = isLiquidStyleInclude;
this.stripSpacesAroundTags = stripSpacesAroundTags;
this.stripSingleLine = stripSingleLine;
this.blocks = blocks;
Expand Down Expand Up @@ -206,14 +216,16 @@ mode IN_TAG_ID;
// otherwise it is an invalid tag
// BUT it also can be programed manually, so even if not supported flavour, we must respect
// user-defined tags OR blocks
String text = getText();
if (blocks.contains(text)) {
setType(BlockId);
customBlockState.push(text);
} else if (tags.contains(text)) {
setType(SimpleTagId);
} else {
setType(InvalidTagId);
if (isLiquidStyleInclude()) {
String text = getText();
if (blocks.contains(text)) {
setType(BlockId);
customBlockState.push(text);
} else if (tags.contains(text)) {
setType(SimpleTagId);
} else {
setType(InvalidTagId);
}
}
} -> popMode;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/liqp/Template.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class Template {
Set<String> tagNames = this.templateParser.insertions.getTagNames();

this.templateSize = stream.size();
LiquidLexer lexer = new LiquidLexer(stream, this.templateParser.isStripSpacesAroundTags(),
LiquidLexer lexer = new LiquidLexer(stream, this.templateParser.liquidStyleInclude, this.templateParser.isStripSpacesAroundTags(),
this.templateParser.isStripSingleLine(), blockNames, tagNames);
this.sourceLocation = location;
try {
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/liqp/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static LNode getNode(String source, String rule) throws Exception {
public static LNode getNode(String source, String rule, TemplateParser templateParser)
throws Exception {

LiquidLexer lexer = new LiquidLexer(CharStreams.fromString("{{ " + source + " }}"));
LiquidLexer lexer = new LiquidLexer(CharStreams.fromString("{{ " + source + " }}"), templateParser.liquidStyleInclude, templateParser.stripSpacesAroundTags);
LiquidParser parser = new LiquidParser(new CommonTokenStream(lexer), templateParser.liquidStyleInclude, templateParser.evaluateInOutputTag, templateParser.errorMode);

LiquidParser.OutputContext root = parser.output();
Expand Down
37 changes: 19 additions & 18 deletions src/test/java/liqp/parser/v4/LiquidLexerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,23 @@ public void testInclude() {
assertThat(tokenise("{%include").get(1).getType(), is(LiquidLexer.Include));
}

// IncludeRelative : 'include_relative' { conditional };
@Test
public void testIncludeRelative() {
assertThat("tag 'include_relative' is defined only in Jekyll style",
tokenise("{%include_relative").get(1).getType(), is(LiquidLexer.InvalidTagId));
}

@Test
public void testIncludeRelativeCustomTag() {
HashSet<String> tags = new HashSet<>();
tags.add("include_relative");
List<Token> tokens = tokenise("{%include_relative%}", new HashSet<String>(), tags);

assertThat("Custom tag or block 'include_relative' can be defined in Liquid style",
tokens.get(1).getType(), is(LiquidLexer.SimpleTagId));
}

// With : 'with';
@Test
public void testWith() {
Expand Down Expand Up @@ -598,13 +615,9 @@ private static List<Token> tokenise(String source, boolean stripSpacesAroundTags
return tokens;
}

static CommonTokenStream commonTokenStream(String source) {
return commonTokenStream(source, false);
}

static CommonTokenStream commonTokenStream(String source, boolean stripSpacesAroundTags, Set<String> blocks, Set<String> tags) {

LiquidLexer lexer = new LiquidLexer(CharStreams.fromString(source), stripSpacesAroundTags, blocks, tags);
boolean isLiquidStyleInclude = true; // No tests for Jekyll style of includes, yet
LiquidLexer lexer = new LiquidLexer(CharStreams.fromString(source), isLiquidStyleInclude, stripSpacesAroundTags, blocks, tags);

lexer.addErrorListener(new BaseErrorListener(){
@Override
Expand All @@ -616,16 +629,4 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int
return new CommonTokenStream(lexer);
}

static CommonTokenStream commonTokenStream(String source, boolean stripSpacesAroundTags) {
LiquidLexer lexer = new LiquidLexer(CharStreams.fromString(source), stripSpacesAroundTags);

lexer.addErrorListener(new BaseErrorListener(){
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
throw new RuntimeException(e);
}
});

return new CommonTokenStream(lexer);
}
}

0 comments on commit eb97f95

Please sign in to comment.