Bug fixed (FREEMARKER-70): The usage of loop variable built-ins, like 
loopVar?index, was disallowed by the parser inside interpolations that are 
inside a string literal expression (as in <#list 1..3 as 
loopVar>${'${loopVar?index}'}</#list>), saying that there's no loop variable in 
scope with loopVar name.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/056bf1cd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/056bf1cd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/056bf1cd

Branch: refs/heads/2.3-gae
Commit: 056bf1cd7e59740af304b2566caacd921378a5bd
Parents: 924a420
Author: ddekany <ddek...@apache.org>
Authored: Sat Aug 12 00:20:32 2017 +0200
Committer: ddekany <ddek...@apache.org>
Committed: Sat Aug 12 00:20:32 2017 +0200

----------------------------------------------------------------------
 src/main/java/freemarker/core/StringLiteral.java | 12 +++++-------
 src/main/javacc/FTL.jj                           | 19 +++++++++++++------
 src/manual/en_US/book.xml                        | 13 +++++++++++++
 .../java/freemarker/core/ListErrorsTest.java     |  5 +++++
 4 files changed, 36 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/056bf1cd/src/main/java/freemarker/core/StringLiteral.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/StringLiteral.java 
b/src/main/java/freemarker/core/StringLiteral.java
index c2b69a6..7c25623 100644
--- a/src/main/java/freemarker/core/StringLiteral.java
+++ b/src/main/java/freemarker/core/StringLiteral.java
@@ -41,15 +41,13 @@ final class StringLiteral extends Expression implements 
TemplateScalarModel {
     }
     
     /**
-     * @param parentTkMan
-     *            The token source of the template that contains this string 
literal. As of this writing, we only need
-     *            this to share the {@code namingConvetion} with that.
+     * @param parentParser
+     *            The parser of the template that contains this string literal.
      */
-    void parseValue(FMParserTokenManager parentTkMan, OutputFormat 
outputFormat) throws ParseException {
+    void parseValue(FMParser parentParser, OutputFormat outputFormat) throws 
ParseException {
         // The way this works is incorrect (the literal should be parsed 
without un-escaping),
         // but we can't fix this backward compatibly.
         if (value.length() > 3 && (value.indexOf("${") >= 0 || 
value.indexOf("#{") >= 0)) {
-            
             Template parentTemplate = getTemplate();
             ParserConfiguration pcfg = parentTemplate.getParserConfiguration();
 
@@ -65,12 +63,12 @@ final class StringLiteral extends Expression implements 
TemplateScalarModel {
                 
                 FMParser parser = new FMParser(parentTemplate, false, tkMan, 
pcfg);
                 // We continue from the parent parser's current state:
-                parser.setupStringLiteralMode(parentTkMan, outputFormat);
+                parser.setupStringLiteralMode(parentParser, outputFormat);
                 try {
                     dynamicValue = parser.StaticTextAndInterpolations();
                 } finally {
                     // The parent parser continues from this parser's current 
state:
-                    parser.tearDownStringLiteralMode(parentTkMan);
+                    parser.tearDownStringLiteralMode(parentParser);
                 }
             } catch (ParseException e) {
                 e.setTemplateName(parentTemplate.getSourceName());

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/056bf1cd/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index 175614c..2963a41 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -78,7 +78,7 @@ public class FMParser {
     private ParserConfiguration pCfg;
 
     /** Keeps track of #list and #foreach nesting. */
-    private List/*<ParserIteratorBlockContext>*/ iteratorBlockContexts;
+    private List<ParserIteratorBlockContext> iteratorBlockContexts;
     
     /**
      * Keeps track of the nesting depth of directives that support #break.
@@ -273,7 +273,9 @@ public class FMParser {
         }
     }
     
-    void setupStringLiteralMode(FMParserTokenManager parentTokenSource, 
OutputFormat outputFormat) {
+    void setupStringLiteralMode(FMParser parentParser, OutputFormat 
outputFormat) {
+        FMParserTokenManager parentTokenSource = parentParser.token_source;
+         
         token_source.initialNamingConvention = 
parentTokenSource.initialNamingConvention;
         token_source.namingConvention = parentTokenSource.namingConvention;
         token_source.namingConventionEstabilisher = 
parentTokenSource.namingConventionEstabilisher;
@@ -285,9 +287,14 @@ public class FMParser {
             // Emulate bug, where the string literal parser haven't inherited 
the IcI:
             incompatibleImprovements = _TemplateAPI.VERSION_INT_2_3_0;
         }
+        
+        // So that loop variable built-ins, like ?index, works inside the 
interpolations in the string literal:
+        iteratorBlockContexts = parentParser.iteratorBlockContexts;
     }
 
-    void tearDownStringLiteralMode(FMParserTokenManager parentTokenSource) {
+    void tearDownStringLiteralMode(FMParser parentParser) {
+        // If the naming convention was established inside the string literal, 
it's inherited by the parent:
+        FMParserTokenManager parentTokenSource = parentParser.token_source; 
         parentTokenSource.namingConvention = token_source.namingConvention;
         parentTokenSource.namingConventionEstabilisher = 
token_source.namingConventionEstabilisher;
     }
@@ -507,7 +514,7 @@ public class FMParser {
     
     private ParserIteratorBlockContext pushIteratorBlockContext() {
         if (iteratorBlockContexts == null) {
-            iteratorBlockContexts = new ArrayList(4);
+            iteratorBlockContexts = new 
ArrayList<ParserIteratorBlockContext>(4);
         }
         ParserIteratorBlockContext newCtx = new ParserIteratorBlockContext();
         iteratorBlockContexts.add(newCtx);
@@ -527,7 +534,7 @@ public class FMParser {
             throws ParseException {
         int size = iteratorBlockContexts != null ? 
iteratorBlockContexts.size() : 0;
         for (int i = size - 1; i >= 0; i--) {
-            ParserIteratorBlockContext ctx = (ParserIteratorBlockContext) 
iteratorBlockContexts.get(i);
+            ParserIteratorBlockContext ctx = iteratorBlockContexts.get(i);
             if (loopVarName.equals(ctx.loopVarName) || 
loopVarName.equals(ctx.loopVar2Name)) {
                 if (ctx.kind == ITERATOR_BLOCK_KIND_USER_DIRECTIVE) {
                                throw new ParseException(
@@ -2297,7 +2304,7 @@ StringLiteral StringLiteral(boolean interpolate) :
         result.setLocation(template, t, t);
         if (interpolate && !raw) {
             // TODO: This logic is broken. It can't handle literals that 
contains both ${...} and $\{...}. 
-            if (t.image.indexOf("${") >= 0 || t.image.indexOf("#{") >= 0) 
result.parseValue(token_source, outputFormat);
+            if (t.image.indexOf("${") >= 0 || t.image.indexOf("#{") >= 0) 
result.parseValue(this, outputFormat);
         }
         return result;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/056bf1cd/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 6d6d6f9..03c42b0 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -26926,6 +26926,19 @@ TemplateModel x = env.getVariable("x");  // get 
variable x</programlisting>
             </listitem>
 
             <listitem>
+              <para>Bug fixed (<link
+              
xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-70";>FREEMARKER-70</link>):
+              The usage of loop variable built-ins, like
+              <literal><replaceable>loopVar</replaceable>?index</literal>, was
+              disallowed by the parser inside interpolations that are inside a
+              string literal expression (as in <literal>&lt;#list 1..3 as
+              loopVar&gt;${'${loopVar?index}'}&lt;/#list&gt;</literal>),
+              saying that there's no loop variable in scope with
+              <literal><replaceable>loopVar</replaceable></literal>
+              name.</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>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/056bf1cd/src/test/java/freemarker/core/ListErrorsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/ListErrorsTest.java 
b/src/test/java/freemarker/core/ListErrorsTest.java
index 60ca7e6..7a4aaa4 100644
--- a/src/test/java/freemarker/core/ListErrorsTest.java
+++ b/src/test/java/freemarker/core/ListErrorsTest.java
@@ -47,6 +47,11 @@ public class ListErrorsTest extends TemplateTest {
                 + "</#list>",
                 "1@0[3,4@0]1@0; 2@1[3,4@0]2@1; ");
     }
+    
+    @Test
+    public void stringInterpolationBugFixTest() throws IOException, 
TemplateException {
+        assertOutput("<#list 1..3 as x>${'${x?index}'}</#list>", "012");
+    }
 
     @Test
     public void testInvalidItemsParseTime() throws IOException, 
TemplateException {

Reply via email to