Repository: incubator-freemarker Updated Branches: refs/heads/3 d0a9c2bb5 -> 557ee7c8c
Forward ported from 2.3-gae: Bug fixed: Comments were not allowed by the parser between the switch tag and the first case tag. See: 1dba510cc690898523e138385dd8eb4111b32453, c3672d96544e1cb96454410cd76a737ec4cf80e5 Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/ab5c1d88 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/ab5c1d88 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/ab5c1d88 Branch: refs/heads/3 Commit: ab5c1d883150d37ff45c977dc65fa00ee31b8824 Parents: d0a9c2b Author: ddekany <ddek...@apache.org> Authored: Sun Jul 9 17:18:49 2017 +0200 Committer: ddekany <ddek...@apache.org> Committed: Sun Jul 9 17:18:49 2017 +0200 ---------------------------------------------------------------------- .../core/templatesuite/expected/switch.txt | 2 + .../core/templatesuite/templates/switch.ftl | 3 + .../apache/freemarker/core/ASTDirSwitch.java | 33 ++++++++-- freemarker-core/src/main/javacc/FTL.jj | 66 ++++++++++++++++++-- 4 files changed, 93 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ab5c1d88/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/switch.txt ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/switch.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/switch.txt index 5d42785..d0dbd27 100644 --- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/switch.txt +++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/switch.txt @@ -63,6 +63,8 @@ [] +[] + "" "1234" "234" http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ab5c1d88/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/switch.ftl ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/switch.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/switch.ftl index 6bbab3c..c1b4cb7 100644 --- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/switch.ftl +++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/switch.ftl @@ -97,6 +97,7 @@ <#case 3> 3 <#switch x*2> + <#-- Comment is allowed here --> <#case 1> i1 <#break> @@ -122,6 +123,8 @@ <#case 1>sadas </#switch>] +[<#switch 213></#switch>] + <#-- Fall-through --> <#list [ 0, 1, 2, 3, 4 ] as x> "<#switch x><#case 1>1<#case 2>2<#case 3>3<#case 4>4</#switch>" http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ab5c1d88/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java index 069d70e..97d58c3 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java @@ -28,13 +28,20 @@ final class ASTDirSwitch extends ASTDirective { private ASTDirCase defaultCase; private final ASTExpression searched; + private int firstCaseIndex; /** * @param searched the expression to be tested. */ - ASTDirSwitch(ASTExpression searched) { + ASTDirSwitch(ASTExpression searched, ASTImplicitParent 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 } void addCase(ASTDirCase cas) { @@ -50,7 +57,7 @@ final class ASTDirSwitch extends ASTDirective { boolean processedCase = false; int ln = getChildCount(); try { - for (int i = 0; i < ln; i++) { + for (int i = firstCaseIndex; i < ln; i++) { ASTDirCase cas = (ASTDirCase) getChild(i); boolean processCase = false; @@ -91,8 +98,7 @@ final class ASTDirSwitch extends ASTDirective { buf.append('>'); int ln = getChildCount(); for (int i = 0; i < ln; i++) { - ASTDirCase cas = (ASTDirCase) getChild(i); - buf.append(cas.getCanonicalForm()); + buf.append(getChild(i).getCanonicalForm()); } buf.append("</").append(getASTNodeDescriptor()).append('>'); } @@ -125,5 +131,20 @@ final class ASTDirSwitch extends ASTDirective { boolean isNestedBlockRepeater() { return false; } - + + @Override + ASTElement postParseCleanup(boolean stripWhitespace) throws ParseException { + ASTElement 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 && !(getChild(i) instanceof ASTDirCase)) { + i++; + } + firstCaseIndex = i; + + return result; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ab5c1d88/freemarker-core/src/main/javacc/FTL.jj ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/javacc/FTL.jj b/freemarker-core/src/main/javacc/FTL.jj index 84608ea..7968e1e 100644 --- a/freemarker-core/src/main/javacc/FTL.jj +++ b/freemarker-core/src/main/javacc/FTL.jj @@ -3198,18 +3198,22 @@ ASTStaticText NoParse() : ASTDirSwitch Switch() : { ASTDirSwitch switchBlock; + ASTImplicitParent ignoredSectionBeforeFirstCase = null; ASTDirCase caseIns; ASTExpression switchExp; Token start, end; boolean defaultFound = false; } { - start = <SWITCH> - switchExp = ASTExpression() - <DIRECTIVE_END> + ( + start = <SWITCH> + switchExp = ASTExpression() + <DIRECTIVE_END> + [ ignoredSectionBeforeFirstCase = WhitespaceAndComments() ] + ) { breakableDirectiveNesting++; - switchBlock = new ASTDirSwitch(switchExp); + switchBlock = new ASTDirSwitch(switchExp, ignoredSectionBeforeFirstCase); } ( LOOKAHEAD(2) @@ -3241,7 +3245,6 @@ ASTDirCase ASTDirCase() : Token start; } { - [<STATIC_TEXT_WS>] ( start = <CASE> exp = ASTExpression() <DIRECTIVE_END> | @@ -3601,6 +3604,21 @@ ASTStaticText PCData() : } } +ASTStaticText WhitespaceText() : +{ + Token t = null, start = null; +} +{ + t = <STATIC_TEXT_WS> + { + if (stripText && mixedContentNesting == 1) return null; + + ASTStaticText result = new ASTStaticText(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. @@ -3753,6 +3771,44 @@ ASTElement FreeMarkerText() : } } +/** + * To be used between tags that in theory has nothing between, such between #switch and the first #case. + */ +ASTImplicitParent WhitespaceAndComments() : +{ + ASTImplicitParent nodes = new ASTImplicitParent(); + ASTElement 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 ASTStaticText 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 + && nodes.getChildCount() == 1 && nodes.getChild(0) instanceof ASTStaticText) { + return null; + } + nodes.setLocation(template, begin, elem); + return nodes; + } +} + void HeaderElement() : { Token key;