Bug fixed: Comments were not allowed by the parser between the switch tag and the first case tag.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/1dba510c Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/1dba510c Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/1dba510c Branch: refs/heads/2.3 Commit: 1dba510cc690898523e138385dd8eb4111b32453 Parents: 9b87988 Author: ddekany <[email protected]> Authored: Sat Jul 8 19:33:39 2017 +0200 Committer: ddekany <[email protected]> Committed: Sat Jul 8 19:33:39 2017 +0200 ---------------------------------------------------------------------- src/main/java/freemarker/core/Case.java | 4 +- src/main/java/freemarker/core/SwitchBlock.java | 31 ++++++++-- src/main/javacc/FTL.jj | 66 +++++++++++++++++++-- src/manual/en_US/book.xml | 6 ++ 4 files changed, 95 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/1dba510c/src/main/java/freemarker/core/Case.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/Case.java b/src/main/java/freemarker/core/Case.java index c580c4d..6d23716 100644 --- a/src/main/java/freemarker/core/Case.java +++ b/src/main/java/freemarker/core/Case.java @@ -24,8 +24,8 @@ package freemarker.core; */ final class Case extends TemplateElement { - final int TYPE_CASE = 0; - final int TYPE_DEFAULT = 1; + static final int TYPE_CASE = 0; + static final int TYPE_DEFAULT = 1; Expression condition; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/1dba510c/src/main/java/freemarker/core/SwitchBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/SwitchBlock.java b/src/main/java/freemarker/core/SwitchBlock.java index cfa354c..15a5eea 100644 --- a/src/main/java/freemarker/core/SwitchBlock.java +++ b/src/main/java/freemarker/core/SwitchBlock.java @@ -30,13 +30,20 @@ final class SwitchBlock extends TemplateElement { private Case defaultCase; private final Expression searched; + private int firstCaseIndex; /** * @param searched the expression to be tested. */ - SwitchBlock(Expression searched) { + SwitchBlock(Expression searched, MixedContent ignoredSectionBeforeFirstCase) { this.searched = searched; - setChildBufferCapacity(4); + + int ignoredCnt = ignoredSectionBeforeFirstCase != null ? ignoredSectionBeforeFirstCase.getChildCount() : 0; + setChildBufferCapacity(ignoredCnt + 4); + for (int i = 0; i < ignoredCnt; i++) { + addChild(ignoredSectionBeforeFirstCase.getChild(i)); + } + firstCaseIndex = ignoredCnt; // Note that normally postParseCleanup will overwrite this } /** @@ -55,7 +62,7 @@ final class SwitchBlock extends TemplateElement { boolean processedCase = false; int ln = getChildCount(); try { - for (int i = 0; i < ln; i++) { + for (int i = firstCaseIndex; i < ln; i++) { Case cas = (Case) getChild(i); boolean processCase = false; @@ -94,8 +101,7 @@ final class SwitchBlock extends TemplateElement { buf.append('>'); int ln = getChildCount(); for (int i = 0; i < ln; i++) { - Case cas = (Case) getChild(i); - buf.append(cas.getCanonicalForm()); + buf.append(getChild(i).getCanonicalForm()); } buf.append("</").append(getNodeTypeSymbol()).append('>'); } @@ -128,5 +134,20 @@ final class SwitchBlock extends TemplateElement { boolean isNestedBlockRepeater() { return false; } + + @Override + TemplateElement postParseCleanup(boolean stripWhitespace) throws ParseException { + TemplateElement result = super.postParseCleanup(stripWhitespace); + + // The first #case might have shifted in the child array, so we have to find it again: + int ln = getChildCount(); + int i = 0; + while (i < ln && !(getChildAt(i) instanceof Case)) { + i++; + } + firstCaseIndex = i; + + return result; + } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/1dba510c/src/main/javacc/FTL.jj ---------------------------------------------------------------------- diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj index 94338af..fb6106d 100644 --- a/src/main/javacc/FTL.jj +++ b/src/main/javacc/FTL.jj @@ -3581,18 +3581,22 @@ TransformBlock Transform() : SwitchBlock Switch() : { SwitchBlock switchBlock; + MixedContent ignoredSectionBeforeFirstCase = null; Case caseIns; Expression switchExp; Token start, end; boolean defaultFound = false; } { - start = <SWITCH> - switchExp = Expression() - <DIRECTIVE_END> + ( + start = <SWITCH> + switchExp = Expression() + <DIRECTIVE_END> + [ ignoredSectionBeforeFirstCase = WhitespaceAndComments() ] + ) { breakableDirectiveNesting++; - switchBlock = new SwitchBlock(switchExp); + switchBlock = new SwitchBlock(switchExp, ignoredSectionBeforeFirstCase); } ( LOOKAHEAD(2) @@ -3624,7 +3628,6 @@ Case Case() : Token start; } { - [<STATIC_TEXT_WS>] ( start = <CASE> exp = Expression() <DIRECTIVE_END> | @@ -3990,6 +3993,21 @@ TextBlock PCData() : } } +TextBlock WhitespaceText() : +{ + Token t = null, start = null; +} +{ + t = <STATIC_TEXT_WS> + { + if (stripText && mixedContentNesting == 1 && !preventStrippings) return null; + + TextBlock result = new TextBlock(t.image, false); + result.setLocation(template, t, t); + return result; + } +} + /** * Production for dealing with unparsed content, * i.e. what is inside a comment or noparse tag. @@ -4150,6 +4168,44 @@ TemplateElement FreeMarkerText() : } } +/** + * To be used between tags that in theory has nothing between, such between #switch and the first #case. + */ +MixedContent WhitespaceAndComments() : +{ + MixedContent nodes = new MixedContent(); + TemplateElement elem, begin = null; +} +{ + ( + ( + elem = WhitespaceText() + | + elem = Comment() + ) + { + if (elem != null) { // not removed by stripText + if (begin == null) { + begin = elem; + } + nodes.addChild(elem); + } + } + )+ + { + if (begin == null // Was is removed by stripText? + // Nodes here won't be ever executed anyway, but whitespace stripping should still remove the + // lonely TextBlock from the AST, as that's purely source code formatting. If it's not lonely, then + // there must be a comment, in which case the generic whitespace stripping algorithm will kick in. + || stripWhitespace && !preventStrippings + && nodes.getChildCount() == 1 && nodes.getChild(0) instanceof TextBlock) { + return null; + } + nodes.setLocation(template, begin, elem); + return nodes; + } +} + void HeaderElement() : { Token key; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/1dba510c/src/manual/en_US/book.xml ---------------------------------------------------------------------- diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml index fbbee7e..3897385 100644 --- a/src/manual/en_US/book.xml +++ b/src/manual/en_US/book.xml @@ -26910,6 +26910,12 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> and <literal>and</literal> without <literal>\</literal> is not recognized for backward compatibility.</para> </listitem> + + <listitem> + <para>Bug fixed: Comments were not allowed by the parser between + the <literal>switch</literal> tag and the first + <literal>case</literal> tag.</para> + </listitem> </itemizedlist> </section>
