You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2015/10/04 21:17:05 UTC

[01/16] incubator-freemarker git commit: (Test class name typo...)

Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3 4b1550e78 -> d07ad04ce


(Test class name typo...)


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

Branch: refs/heads/2.3
Commit: 0c3e1461f937fa0115dd70a92c13ad1a0bd0e317
Parents: c798862
Author: ddekany <dd...@apache.org>
Authored: Tue Sep 29 02:23:05 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Sep 29 02:23:05 2015 +0200

----------------------------------------------------------------------
 .../freemarker/core/CoercionToTextualTest.java  | 119 +++++++++++++++++++
 .../freemarker/core/CorectionToTextualTest.java | 119 -------------------
 2 files changed, 119 insertions(+), 119 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0c3e1461/src/test/java/freemarker/core/CoercionToTextualTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/CoercionToTextualTest.java b/src/test/java/freemarker/core/CoercionToTextualTest.java
new file mode 100644
index 0000000..c35ace6
--- /dev/null
+++ b/src/test/java/freemarker/core/CoercionToTextualTest.java
@@ -0,0 +1,119 @@
+package freemarker.core;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import freemarker.template.Configuration;
+import freemarker.template.SimpleDate;
+import freemarker.template.TemplateDateModel;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateModelException;
+import freemarker.test.TemplateTest;
+
+@SuppressWarnings("boxing")
+public class CoercionToTextualTest extends TemplateTest {
+    
+    /** 2015-09-06T12:00:00Z */
+    private static long T = 1441540800000L;
+    private static TemplateDateModel TM = new SimpleDate(new Date(T), TemplateDateModel.DATETIME);
+    
+    @Test
+    public void testBasicStringBuiltins() throws IOException, TemplateException {
+        assertOutput("${s?upperCase}", "ABC");
+        assertOutput("${n?string?lowerCase}", "1.50e+03");
+        assertErrorContains("${n?lowerCase}", "convert", "string", "markup", "text/html");
+        assertOutput("${dt?string?lowerCase}", "2015-09-06t12:00:00z");
+        assertErrorContains("${dt?lowerCase}", "convert", "string", "markup", "text/html");
+        assertOutput("${b?upperCase}", "Y");
+        assertErrorContains("${m?upperCase}", "convertible to string", "HTMLOutputModel");
+    }
+
+    @Test
+    public void testEscBuiltin() throws IOException, TemplateException {
+        Configuration cfg = getConfiguration();
+        cfg.setOutputFormat(HTMLOutputFormat.INSTANCE);
+        cfg.setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY);
+        cfg.setBooleanFormat("<y>,<n>");
+        
+        assertOutput("${'a<b'?esc}", "a&lt;b");
+        assertOutput("${n?string?esc}", "1.50E+03");
+        assertOutput("${n?esc}", "1.50*10<sup>3</sup>");
+        assertOutput("${dt?string?esc}", "2015-09-06T12:00:00Z");
+        assertOutput("${dt?esc}", "2015-09-06<span class='T'>T</span>12:00:00Z");
+        assertOutput("${b?esc}", "&lt;y&gt;");
+        assertOutput("${m?esc}", "<p>M</p>");
+    }
+    
+    @Test
+    public void testStringOverloadedBuiltIns() throws IOException, TemplateException {
+        assertOutput("${s?contains('b')}", "y");
+        assertOutput("${n?string?contains('E')}", "y");
+        assertErrorContains("${n?contains('E')}", "convert", "string", "markup", "text/html");
+        assertErrorContains("${n?indexOf('E')}", "convert", "string", "markup", "text/html");
+        assertOutput("${dt?string?contains('0')}", "y");
+        assertErrorContains("${dt?contains('0')}", "convert", "string", "markup", "text/html");
+        assertErrorContains("${m?contains('0')}", "convertible to string", "HTMLOutputModel");
+        assertErrorContains("${m?indexOf('0')}", "convertible to string", "HTMLOutputModel");
+    }
+    
+    @Test
+    public void testMarkupStringBuiltIns() throws IOException, TemplateException {
+        assertErrorContains("${n?string?markupString}", "Expected", "markup", "string");
+        assertErrorContains("${n?markupString}", "Expected", "markup", "number");
+        assertErrorContains("${dt?markupString}", "Expected", "markup", "date");
+    }
+    
+    @Test
+    public void testSimpleInterpolation() throws IOException, TemplateException {
+        assertOutput("${s}", "abc");
+        assertOutput("${n?string}", "1.50E+03");
+        assertOutput("${n}", "1.50*10<sup>3</sup>");
+        assertOutput("${dt?string}", "2015-09-06T12:00:00Z");
+        assertOutput("${dt}", "2015-09-06<span class='T'>T</span>12:00:00Z");
+        assertOutput("${b}", "y");
+        assertOutput("${m}", "<p>M</p>");
+    }
+    
+    @Test
+    public void testConcatenation() throws IOException, TemplateException {
+        assertOutput("${s + '&'}", "abc&");
+        assertOutput("${n?string + '&'}", "1.50E+03&");
+        assertOutput("${n + '&'}", "1.50*10<sup>3</sup>&amp;");
+        assertOutput("${dt?string + '&'}", "2015-09-06T12:00:00Z&");
+        assertOutput("${dt + '&'}", "2015-09-06<span class='T'>T</span>12:00:00Z&amp;");
+        assertOutput("${b + '&'}", "y&");
+        assertOutput("${m + '&'}", "<p>M</p>&amp;");
+    }
+
+    @Test
+    public void testConcatenation2() throws IOException, TemplateException {
+        assertOutput("${'&' + s}", "&abc");
+        assertOutput("${'&' + n?string}", "&1.50E+03");
+        assertOutput("${'&' + n}", "&amp;1.50*10<sup>3</sup>");
+        assertOutput("${'&' + dt?string}", "&2015-09-06T12:00:00Z");
+        assertOutput("${'&' + dt}", "&amp;2015-09-06<span class='T'>T</span>12:00:00Z");
+        assertOutput("${'&' + b}", "&y");
+        assertOutput("${'&' + m}", "&amp;<p>M</p>");
+    }
+    
+    @Before
+    public void setup() throws TemplateModelException {
+        Configuration cfg = getConfiguration();
+        cfg.setCustomNumberFormats(Collections.singletonMap("G", PrintfGTemplateNumberFormatFactory.INSTANCE));
+        cfg.setCustomDateFormats(Collections.singletonMap("HI", HTMLISOTemplateDateFormatFactory.INSTANCE));
+        cfg.setNumberFormat("@G 3");
+        cfg.setDateTimeFormat("@HI");
+        cfg.setBooleanFormat("y,n");
+        
+        addToDataModel("s", "abc");
+        addToDataModel("n", 1500);
+        addToDataModel("dt", TM);
+        addToDataModel("b", Boolean.TRUE);
+        addToDataModel("m", HTMLOutputFormat.INSTANCE.fromMarkup("<p>M</p>"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/0c3e1461/src/test/java/freemarker/core/CorectionToTextualTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/CorectionToTextualTest.java b/src/test/java/freemarker/core/CorectionToTextualTest.java
deleted file mode 100644
index 968981a..0000000
--- a/src/test/java/freemarker/core/CorectionToTextualTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package freemarker.core;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Date;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import freemarker.template.Configuration;
-import freemarker.template.SimpleDate;
-import freemarker.template.TemplateDateModel;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateModelException;
-import freemarker.test.TemplateTest;
-
-@SuppressWarnings("boxing")
-public class CorectionToTextualTest extends TemplateTest {
-    
-    /** 2015-09-06T12:00:00Z */
-    private static long T = 1441540800000L;
-    private static TemplateDateModel TM = new SimpleDate(new Date(T), TemplateDateModel.DATETIME);
-    
-    @Test
-    public void testBasicStringBuiltins() throws IOException, TemplateException {
-        assertOutput("${s?upperCase}", "ABC");
-        assertOutput("${n?string?lowerCase}", "1.50e+03");
-        assertErrorContains("${n?lowerCase}", "convert", "string", "markup", "text/html");
-        assertOutput("${dt?string?lowerCase}", "2015-09-06t12:00:00z");
-        assertErrorContains("${dt?lowerCase}", "convert", "string", "markup", "text/html");
-        assertOutput("${b?upperCase}", "Y");
-        assertErrorContains("${m?upperCase}", "convertible to string", "HTMLOutputModel");
-    }
-
-    @Test
-    public void testEscBuiltin() throws IOException, TemplateException {
-        Configuration cfg = getConfiguration();
-        cfg.setOutputFormat(HTMLOutputFormat.INSTANCE);
-        cfg.setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY);
-        cfg.setBooleanFormat("<y>,<n>");
-        
-        assertOutput("${'a<b'?esc}", "a&lt;b");
-        assertOutput("${n?string?esc}", "1.50E+03");
-        assertOutput("${n?esc}", "1.50*10<sup>3</sup>");
-        assertOutput("${dt?string?esc}", "2015-09-06T12:00:00Z");
-        assertOutput("${dt?esc}", "2015-09-06<span class='T'>T</span>12:00:00Z");
-        assertOutput("${b?esc}", "&lt;y&gt;");
-        assertOutput("${m?esc}", "<p>M</p>");
-    }
-    
-    @Test
-    public void testStringOverloadedBuiltIns() throws IOException, TemplateException {
-        assertOutput("${s?contains('b')}", "y");
-        assertOutput("${n?string?contains('E')}", "y");
-        assertErrorContains("${n?contains('E')}", "convert", "string", "markup", "text/html");
-        assertErrorContains("${n?indexOf('E')}", "convert", "string", "markup", "text/html");
-        assertOutput("${dt?string?contains('0')}", "y");
-        assertErrorContains("${dt?contains('0')}", "convert", "string", "markup", "text/html");
-        assertErrorContains("${m?contains('0')}", "convertible to string", "HTMLOutputModel");
-        assertErrorContains("${m?indexOf('0')}", "convertible to string", "HTMLOutputModel");
-    }
-    
-    @Test
-    public void testMarkupStringBuiltIns() throws IOException, TemplateException {
-        assertErrorContains("${n?string?markupString}", "Expected", "markup", "string");
-        assertErrorContains("${n?markupString}", "Expected", "markup", "number");
-        assertErrorContains("${dt?markupString}", "Expected", "markup", "date");
-    }
-    
-    @Test
-    public void testSimpleInterpolation() throws IOException, TemplateException {
-        assertOutput("${s}", "abc");
-        assertOutput("${n?string}", "1.50E+03");
-        assertOutput("${n}", "1.50*10<sup>3</sup>");
-        assertOutput("${dt?string}", "2015-09-06T12:00:00Z");
-        assertOutput("${dt}", "2015-09-06<span class='T'>T</span>12:00:00Z");
-        assertOutput("${b}", "y");
-        assertOutput("${m}", "<p>M</p>");
-    }
-    
-    @Test
-    public void testConcatenation() throws IOException, TemplateException {
-        assertOutput("${s + '&'}", "abc&");
-        assertOutput("${n?string + '&'}", "1.50E+03&");
-        assertOutput("${n + '&'}", "1.50*10<sup>3</sup>&amp;");
-        assertOutput("${dt?string + '&'}", "2015-09-06T12:00:00Z&");
-        assertOutput("${dt + '&'}", "2015-09-06<span class='T'>T</span>12:00:00Z&amp;");
-        assertOutput("${b + '&'}", "y&");
-        assertOutput("${m + '&'}", "<p>M</p>&amp;");
-    }
-
-    @Test
-    public void testConcatenation2() throws IOException, TemplateException {
-        assertOutput("${'&' + s}", "&abc");
-        assertOutput("${'&' + n?string}", "&1.50E+03");
-        assertOutput("${'&' + n}", "&amp;1.50*10<sup>3</sup>");
-        assertOutput("${'&' + dt?string}", "&2015-09-06T12:00:00Z");
-        assertOutput("${'&' + dt}", "&amp;2015-09-06<span class='T'>T</span>12:00:00Z");
-        assertOutput("${'&' + b}", "&y");
-        assertOutput("${'&' + m}", "&amp;<p>M</p>");
-    }
-    
-    @Before
-    public void setup() throws TemplateModelException {
-        Configuration cfg = getConfiguration();
-        cfg.setCustomNumberFormats(Collections.singletonMap("G", PrintfGTemplateNumberFormatFactory.INSTANCE));
-        cfg.setCustomDateFormats(Collections.singletonMap("HI", HTMLISOTemplateDateFormatFactory.INSTANCE));
-        cfg.setNumberFormat("@G 3");
-        cfg.setDateTimeFormat("@HI");
-        cfg.setBooleanFormat("y,n");
-        
-        addToDataModel("s", "abc");
-        addToDataModel("n", 1500);
-        addToDataModel("dt", TM);
-        addToDataModel("b", Boolean.TRUE);
-        addToDataModel("m", HTMLOutputFormat.INSTANCE.fromMarkup("<p>M</p>"));
-    }
-
-}


[02/16] incubator-freemarker git commit: Documented that JDK 8 is needed for building.

Posted by dd...@apache.org.
Documented that JDK 8 is needed for building.


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

Branch: refs/heads/2.3
Commit: a361243146a62ca19552074e4b8d74d76ca9abb4
Parents: 0c3e146
Author: ddekany <dd...@apache.org>
Authored: Tue Sep 29 21:42:10 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Sep 29 21:42:10 2015 +0200

----------------------------------------------------------------------
 README.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a3612431/README.txt
----------------------------------------------------------------------
diff --git a/README.txt b/README.txt
index 5985918..f1aafc9 100644
--- a/README.txt
+++ b/README.txt
@@ -71,8 +71,8 @@ application already uses the related library.
 Building
 --------
 
-You need Apache Ant and Ivy be installed. (As of this writing it was
-tested with Ant 1.8.1 and Ivy 2.3.0.)
+You need JDK 8(!), Apache Ant and Ivy be installed. (As of this writing
+it was tested with Ant 1.8.1 and Ivy 2.3.0.)
 
 If you need to ensure compliance with certain J2SE versions, copy
 build.properties.sample into build.properties, and edit it


[06/16] incubator-freemarker git commit: `${...}` inside string literals is equivalent to using the `+` operator again. This rule was broken by `+` supporting markup operands, while `${...}` inside string literals didn't. Now similarly as `"foo " + someM

Posted by dd...@apache.org.
`${...}` inside string literals is equivalent to using the `+` operator again. This rule was broken by `+` supporting markup operands, while `${...}` inside string literals didn't. Now similarly as `"foo " + someMarkup` works and gives a markup result, `"foo ${someMarkup}"` does too.


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

Branch: refs/heads/2.3
Commit: fa6ac0eea88c38c816298b518c5d249d4599f93e
Parents: d8487ff
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 01:42:47 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 01:43:45 2015 +0200

----------------------------------------------------------------------
 .../freemarker/core/AddConcatExpression.java    |  32 +-----
 .../java/freemarker/core/DollarVariable.java    |  10 +-
 src/main/java/freemarker/core/EvalUtil.java     |  28 ++++-
 .../java/freemarker/core/Interpolation.java     |   9 ++
 .../java/freemarker/core/NumericalOutput.java   |  18 ++-
 .../java/freemarker/core/ParameterRole.java     |   1 +
 .../java/freemarker/core/StringLiteral.java     | 105 +++++++++++------
 src/main/javacc/FTL.jj                          |  66 ++++++++++-
 src/manual/book.xml                             | 114 ++++++++-----------
 .../java/freemarker/core/NumberFormatTest.java  |   4 +-
 .../java/freemarker/core/OutputFormatTest.java  |  23 +++-
 .../core/StringLiteralInterpolationTest.java    |  23 ++++
 src/test/java/freemarker/test/TemplateTest.java |   6 +-
 src/test/resources/freemarker/core/ast-1.ast    |  19 ++--
 .../resources/freemarker/core/ast-builtins.ast  |   3 -
 .../resources/freemarker/core/ast-range.ast     |   2 -
 .../freemarker/core/ast-strlitinterpolation.ast |  72 ++++++++++--
 .../freemarker/core/ast-strlitinterpolation.ftl |   8 +-
 .../AutoEscapingExample-stringLiteral2.ftlh     |   2 +-
 .../AutoEscapingExample-stringLiteral2.ftlh.out |   2 +-
 20 files changed, 364 insertions(+), 183 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/java/freemarker/core/AddConcatExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/AddConcatExpression.java b/src/main/java/freemarker/core/AddConcatExpression.java
index 7c1eb75..4dbfd78 100644
--- a/src/main/java/freemarker/core/AddConcatExpression.java
+++ b/src/main/java/freemarker/core/AddConcatExpression.java
@@ -85,18 +85,18 @@ final class AddConcatExpression extends Expression {
                         return new SimpleScalar(((String) leftOMOrStr).concat((String) rightOMOrStr));
                     } else { // rightOMOrStr instanceof TemplateMarkupOutputModel
                         TemplateMarkupOutputModel<?> rightMO = (TemplateMarkupOutputModel<?>) rightOMOrStr; 
-                        return concatMarkupOutputs(parent,
+                        return EvalUtil.concatMarkupOutputs(parent,
                                 rightMO.getOutputFormat().fromPlainTextByEscaping((String) leftOMOrStr),
                                 rightMO);
                     }                    
                 } else { // leftOMOrStr instanceof TemplateMarkupOutputModel 
                     TemplateMarkupOutputModel<?> leftMO = (TemplateMarkupOutputModel<?>) leftOMOrStr; 
                     if (rightOMOrStr instanceof String) {  // markup output
-                        return concatMarkupOutputs(parent,
+                        return EvalUtil.concatMarkupOutputs(parent,
                                 leftMO,
                                 leftMO.getOutputFormat().fromPlainTextByEscaping((String) rightOMOrStr));
                     } else { // rightOMOrStr instanceof TemplateMarkupOutputModel
-                        return concatMarkupOutputs(parent,
+                        return EvalUtil.concatMarkupOutputs(parent,
                                 leftMO,
                                 (TemplateMarkupOutputModel) rightOMOrStr);
                     }
@@ -124,32 +124,6 @@ final class AddConcatExpression extends Expression {
         }
     }
 
-    private static TemplateModel concatMarkupOutputs(TemplateObject parent, TemplateMarkupOutputModel leftMO,
-            TemplateMarkupOutputModel rightMO) throws TemplateModelException {
-        MarkupOutputFormat leftOF = leftMO.getOutputFormat();
-        MarkupOutputFormat rightOF = rightMO.getOutputFormat();
-        if (rightOF != leftOF) {
-            String rightPT;
-            String leftPT;
-            if ((rightPT = rightOF.getSourcePlainText(rightMO)) != null) {
-                return leftOF.concat(leftMO, leftOF.fromPlainTextByEscaping(rightPT));
-            } else if ((leftPT = leftOF.getSourcePlainText(leftMO)) != null) {
-                return rightOF.concat(rightOF.fromPlainTextByEscaping(leftPT), rightMO);
-            } else {
-                Object[] message = { "Concatenation left hand operand is in ", new _DelayedToString(leftOF),
-                        " format, while the right hand operand is in ", new _DelayedToString(rightOF),
-                        ". Conversion to common format wasn't possible." };
-                if (parent instanceof Expression) {
-                    throw new _TemplateModelException((Expression) parent, message);
-                } else {
-                    throw new _TemplateModelException(message);
-                }
-            }
-        } else {
-            return leftOF.concat(leftMO, rightMO);
-        }
-    }
-
     static TemplateModel _evalOnNumbers(Environment env, TemplateObject parent, Number first, Number second)
             throws TemplateException {
         ArithmeticEngine ae = EvalUtil.getArithmeticEngine(env, parent);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/java/freemarker/core/DollarVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/DollarVariable.java b/src/main/java/freemarker/core/DollarVariable.java
index a3abc31..2ecab8c 100644
--- a/src/main/java/freemarker/core/DollarVariable.java
+++ b/src/main/java/freemarker/core/DollarVariable.java
@@ -23,7 +23,6 @@ import java.io.IOException;
 import java.io.Writer;
 
 import freemarker.template.TemplateException;
-import freemarker.template.TemplateModel;
 import freemarker.template.utility.StringUtil;
 
 /**
@@ -57,10 +56,8 @@ final class DollarVariable extends Interpolation {
      */
     @Override
     void accept(Environment env) throws TemplateException, IOException {
-        final TemplateModel tm = escapedExpression.eval(env);
+        final Object moOrStr = calculateInterpolatedStringOrMarkup(env);
         final Writer out = env.getOut();
-        final Object moOrStr = EvalUtil.coerceModelToStringOrMarkup(
-                tm, escapedExpression, null, env);
         if (moOrStr instanceof String) {
             final String s = (String) moOrStr;
             if (autoEscape) {
@@ -94,6 +91,11 @@ final class DollarVariable extends Interpolation {
     }
 
     @Override
+    protected Object calculateInterpolatedStringOrMarkup(Environment env) throws TemplateException {
+        return EvalUtil.coerceModelToStringOrMarkup(escapedExpression.eval(env), escapedExpression, null, env);
+    }
+
+    @Override
     protected String dump(boolean canonical, boolean inStringLiteral) {
         StringBuilder sb = new StringBuilder();
         sb.append("${");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/java/freemarker/core/EvalUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/EvalUtil.java b/src/main/java/freemarker/core/EvalUtil.java
index ca21ac5..886308c 100644
--- a/src/main/java/freemarker/core/EvalUtil.java
+++ b/src/main/java/freemarker/core/EvalUtil.java
@@ -528,10 +528,36 @@ class EvalUtil {
         throw new NullPointerException("TemplateValueFormatter result can't be null");
     }
 
+    static TemplateMarkupOutputModel concatMarkupOutputs(TemplateObject parent, TemplateMarkupOutputModel leftMO,
+            TemplateMarkupOutputModel rightMO) throws TemplateException {
+        MarkupOutputFormat leftOF = leftMO.getOutputFormat();
+        MarkupOutputFormat rightOF = rightMO.getOutputFormat();
+        if (rightOF != leftOF) {
+            String rightPT;
+            String leftPT;
+            if ((rightPT = rightOF.getSourcePlainText(rightMO)) != null) {
+                return leftOF.concat(leftMO, leftOF.fromPlainTextByEscaping(rightPT));
+            } else if ((leftPT = leftOF.getSourcePlainText(leftMO)) != null) {
+                return rightOF.concat(rightOF.fromPlainTextByEscaping(leftPT), rightMO);
+            } else {
+                Object[] message = { "Concatenation left hand operand is in ", new _DelayedToString(leftOF),
+                        " format, while the right hand operand is in ", new _DelayedToString(rightOF),
+                        ". Conversion to common format wasn't possible." };
+                if (parent instanceof Expression) {
+                    throw new _MiscTemplateException((Expression) parent, message);
+                } else {
+                    throw new _MiscTemplateException(message);
+                }
+            }
+        } else {
+            return leftOF.concat(leftMO, rightMO);
+        }
+    }
+
     /**
      * Returns an {@link ArithmeticEngine} even if {@code env} is {@code null}, because we are in parsing phase.
      */
-    public static ArithmeticEngine getArithmeticEngine(Environment env, TemplateObject tObj) {
+    static ArithmeticEngine getArithmeticEngine(Environment env, TemplateObject tObj) {
         return env != null
                 ? env.getArithmeticEngine()
                 : tObj.getTemplate().getParserConfiguration().getArithmeticEngine();

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/java/freemarker/core/Interpolation.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Interpolation.java b/src/main/java/freemarker/core/Interpolation.java
index 733fafa..2dcb11a 100644
--- a/src/main/java/freemarker/core/Interpolation.java
+++ b/src/main/java/freemarker/core/Interpolation.java
@@ -18,6 +18,8 @@
  */
 package freemarker.core;
 
+import freemarker.template.TemplateException;
+
 abstract class Interpolation extends TemplateElement {
 
     protected abstract String dump(boolean canonical, boolean inStringLiteral);
@@ -31,4 +33,11 @@ abstract class Interpolation extends TemplateElement {
         return dump(true, true);
     }
 
+    /**
+     * Returns the already type-converted value that this interpolation will insert into the output.
+     * 
+     * @return A {@link String} or {@link TemplateMarkupOutputModel}. Not {@code null}.
+     */
+    protected abstract Object calculateInterpolatedStringOrMarkup(Environment env) throws TemplateException;
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/java/freemarker/core/NumericalOutput.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/NumericalOutput.java b/src/main/java/freemarker/core/NumericalOutput.java
index 0ded83f..c9028c6 100644
--- a/src/main/java/freemarker/core/NumericalOutput.java
+++ b/src/main/java/freemarker/core/NumericalOutput.java
@@ -60,6 +60,17 @@ final class NumericalOutput extends Interpolation {
 
     @Override
     void accept(Environment env) throws TemplateException, IOException {
+        String s = calculateInterpolatedStringOrMarkup(env);
+        Writer out = env.getOut();
+        if (autoEscapeOutputFormat != null) {
+            autoEscapeOutputFormat.output(s, out);
+        } else {
+            out.write(s);
+        }
+    }
+
+    @Override
+    protected String calculateInterpolatedStringOrMarkup(Environment env) throws TemplateException {
         Number num = expression.evalToNumber(env);
         
         FormatHolder fmth = formatCache;  // atomic sampling
@@ -85,12 +96,7 @@ final class NumericalOutput extends Interpolation {
         // Some locales may use non-Arabic digits, thus replacing the
         // decimal separator in the result of toString() is not enough.
         String s = fmth.format.format(num);
-        Writer out = env.getOut();
-        if (autoEscapeOutputFormat != null) {
-            autoEscapeOutputFormat.output(s, out);
-        } else {
-            out.write(s);
-        }
+        return s;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/java/freemarker/core/ParameterRole.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ParameterRole.java b/src/main/java/freemarker/core/ParameterRole.java
index d178881..1293d5c 100644
--- a/src/main/java/freemarker/core/ParameterRole.java
+++ b/src/main/java/freemarker/core/ParameterRole.java
@@ -62,6 +62,7 @@ final class ParameterRole {
     static final ParameterRole ARGUMENT_VALUE = new ParameterRole("argument value");
     static final ParameterRole CONTENT = new ParameterRole("content");
     static final ParameterRole EMBEDDED_TEMPLATE = new ParameterRole("embedded template");
+    static final ParameterRole VALUE_PART = new ParameterRole("value part");
     static final ParameterRole MINIMUM_DECIMALS = new ParameterRole("minimum decimals");
     static final ParameterRole MAXIMUM_DECIMALS = new ParameterRole("maximum decimals");
     static final ParameterRole NODE = new ParameterRole("node");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/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 051c0aa..aa32d3e 100644
--- a/src/main/java/freemarker/core/StringLiteral.java
+++ b/src/main/java/freemarker/core/StringLiteral.java
@@ -19,14 +19,12 @@
 
 package freemarker.core;
 
-import java.io.IOException;
 import java.io.StringReader;
-import java.util.Enumeration;
+import java.util.List;
 
 import freemarker.template.SimpleScalar;
 import freemarker.template.Template;
 import freemarker.template.TemplateException;
-import freemarker.template.TemplateExceptionHandler;
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateScalarModel;
 import freemarker.template.utility.StringUtil;
@@ -34,7 +32,9 @@ import freemarker.template.utility.StringUtil;
 final class StringLiteral extends Expression implements TemplateScalarModel {
     
     private final String value;
-    private TemplateElement dynamicValue;
+    
+    /** {@link List} of {@link String}-s and {@link Interpolation}-s. */
+    private List<Object> dynamicValue;
     
     StringLiteral(String value) {
         this.value = value;
@@ -45,8 +45,9 @@ final class StringLiteral extends Expression implements TemplateScalarModel {
      *            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.
      */
-    // TODO This should be the part of the "parent" parsing; now it contains hacks like those with namingConvention.  
-    void parseValue(FMParserTokenManager parentTkMan) throws ParseException {
+    void parseValue(FMParserTokenManager parentTkMan, OutputFormat outputFormat) throws ParseException {
+        // The way this work 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();
@@ -60,9 +61,9 @@ final class StringLiteral extends Expression implements TemplateScalarModel {
                 
                 FMParser parser = new FMParser(parentTemplate, false, tkMan, parentTemplate.getParserConfiguration());
                 // We continue from the parent parser's current state:
-                parser.setupStringLiteralMode(parentTkMan);
+                parser.setupStringLiteralMode(parentTkMan, outputFormat);
                 try {
-                    dynamicValue = parser.FreeMarkerText();
+                    dynamicValue = parser.StaticTextAndInterpolations();
                 } finally {
                     // The parent parser continues from this parser's current state:
                     parser.tearDownStringLiteralMode(parentTkMan);
@@ -77,7 +78,51 @@ final class StringLiteral extends Expression implements TemplateScalarModel {
     
     @Override
     TemplateModel _eval(Environment env) throws TemplateException {
-        return new SimpleScalar(evalAndCoerceToPlainText(env));
+        if (dynamicValue == null) {
+            return new SimpleScalar(value);
+        } else {
+            // This should behave like concatenating the values with `+`. Thus, an interpolated expression that
+            // returns markup promotes the result of the whole expression to markup.
+            
+            // Exactly one of these is non-null, depending on if the result will be plain text or markup, which can
+            // change during evaluation, depending on the result of the interpolations:
+            StringBuilder plainTextResult = null;
+            TemplateMarkupOutputModel<?> markupResult = null;
+            
+            for (Object part : dynamicValue) {
+                Object calcedPart =
+                        part instanceof String ? part
+                        : ((Interpolation) part).calculateInterpolatedStringOrMarkup(env);
+                if (markupResult != null) {
+                    TemplateMarkupOutputModel<?> partMO = calcedPart instanceof String
+                            ? markupResult.getOutputFormat().fromPlainTextByEscaping((String) calcedPart)
+                            : (TemplateMarkupOutputModel<?>) calcedPart;
+                    markupResult = EvalUtil.concatMarkupOutputs(this, markupResult, partMO);
+                } else { // We are using `plainTextOutput` (or nothing yet)
+                    if (calcedPart instanceof String) {
+                        String partStr = (String) calcedPart;
+                        if (plainTextResult == null) {
+                            plainTextResult = new StringBuilder(partStr);
+                        } else {
+                            plainTextResult.append(partStr);
+                        }
+                    } else { // `calcedPart` is TemplateMarkupOutputModel
+                        TemplateMarkupOutputModel<?> moPart = (TemplateMarkupOutputModel<?>) calcedPart;
+                        if (plainTextResult != null) {
+                            TemplateMarkupOutputModel<?> leftHandMO = moPart.getOutputFormat()
+                                    .fromPlainTextByEscaping(plainTextResult.toString());
+                            markupResult = EvalUtil.concatMarkupOutputs(this, leftHandMO, moPart);
+                            plainTextResult = null;
+                        } else {
+                            markupResult = moPart;
+                        }
+                    }
+                }
+            } // for each part
+            return markupResult != null ? markupResult
+                    : plainTextResult != null ? new SimpleScalar(plainTextResult.toString())
+                    : SimpleScalar.EMPTY_STRING;
+        }
     }
 
     public String getAsString() {
@@ -88,40 +133,22 @@ final class StringLiteral extends Expression implements TemplateScalarModel {
      * Tells if this is something like <tt>"${foo}"</tt>, which is usually a user mistake.
      */
     boolean isSingleInterpolationLiteral() {
-        return dynamicValue != null && dynamicValue.getChildCount() == 1
-                && dynamicValue.getChildAt(0) instanceof DollarVariable;
+        return dynamicValue != null && dynamicValue.size() == 1
+                && dynamicValue.get(0) instanceof Interpolation;
     }
     
     @Override
-    String evalAndCoerceToPlainText(Environment env) throws TemplateException {
-        if (dynamicValue == null) {
-            return value;
-        } else {
-            TemplateExceptionHandler teh = env.getTemplateExceptionHandler();
-            env.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
-            try {
-               return env.renderElementToString(dynamicValue);
-            } catch (IOException ioe) {
-                throw new _MiscTemplateException(ioe, env);
-            } finally {
-                env.setTemplateExceptionHandler(teh);
-            }
-        }
-    }
-
-    @Override
     public String getCanonicalForm() {
         if (dynamicValue == null) {
             return StringUtil.ftlQuote(value);
         } else {
             StringBuilder sb = new StringBuilder();
             sb.append('"');
-            for (Enumeration childrenEnum = dynamicValue.children(); childrenEnum.hasMoreElements(); ) {
-                TemplateElement child = (TemplateElement) childrenEnum.nextElement();
+            for (Object child : dynamicValue) {
                 if (child instanceof Interpolation) {
                     sb.append(((Interpolation) child).getCanonicalFormInStringLiteral());
                 } else {
-                    sb.append(StringUtil.FTLStringLiteralEnc(child.getCanonicalForm(), '"'));
+                    sb.append(StringUtil.FTLStringLiteralEnc((String) child, '"'));
                 }
             }
             sb.append('"');
@@ -150,19 +177,25 @@ final class StringLiteral extends Expression implements TemplateScalarModel {
 
     @Override
     int getParameterCount() {
-        return 1;
+        return dynamicValue == null ? 0 : dynamicValue.size();
     }
 
     @Override
     Object getParameterValue(int idx) {
-        if (idx != 0) throw new IndexOutOfBoundsException();
-        return dynamicValue;
+        checkIndex(idx);
+        return dynamicValue.get(idx);
+    }
+
+    private void checkIndex(int idx) {
+        if (dynamicValue == null || idx >= dynamicValue.size()) {
+            throw new IndexOutOfBoundsException();
+        }
     }
 
     @Override
     ParameterRole getParameterRole(int idx) {
-        if (idx != 0) throw new IndexOutOfBoundsException();
-        return ParameterRole.EMBEDDED_TEMPLATE;
+        checkIndex(idx);
+        return ParameterRole.VALUE_PART;
     }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index 9c6bae1..34f737b 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -254,13 +254,13 @@ public class FMParser {
         }
     }
     
-    void setupStringLiteralMode(FMParserTokenManager parentTokenSource) {
+    void setupStringLiteralMode(FMParserTokenManager parentTokenSource, OutputFormat outputFormat) {
         token_source.initialNamingConvention = parentTokenSource.initialNamingConvention;
         token_source.namingConvention = parentTokenSource.namingConvention;
         token_source.namingConventionEstabilisher = parentTokenSource.namingConventionEstabilisher;
         token_source.SwitchTo(NODIRECTIVE);
         
-        outputFormat = PlainTextOutputFormat.INSTANCE;
+        this.outputFormat = outputFormat;
         recalculateAutoEscapingField();                                
         if (incompatibleImprovements < _TemplateAPI.VERSION_INT_2_3_24) {
             // Emulate bug, where the string literal parser haven't inherited the IcI:
@@ -2271,7 +2271,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);
+            if (t.image.indexOf("${") >= 0 || t.image.indexOf("#{") >= 0) result.parseValue(token_source, outputFormat);
         }
         return result;
     }
@@ -4205,6 +4205,66 @@ Map ParamList() :
 }
 
 /**
+ * Parses the already un-escaped content of a string literal (input must not include the quotation marks).
+ *
+ * @return A {@link List} of {@link String}-s and {@link Interpolation}-s. 
+ */
+List<Object> StaticTextAndInterpolations() :
+{
+    Token t;
+    Interpolation interpolation;
+    StringBuilder staticTextCollector = null;
+    ArrayList<Object> parts = new ArrayList<Object>();
+}
+{
+    (
+	    (
+		    t = <STATIC_TEXT_WS>
+		    |
+		    t = <STATIC_TEXT_NON_WS>
+		    |
+		    t = <STATIC_TEXT_FALSE_ALARM>
+	    )
+	    {
+	       String s = t.image;
+	       if (!s.isEmpty()) {
+	           if (staticTextCollector == null) {
+	               staticTextCollector = new StringBuilder(t.image);
+	           } else {
+	               staticTextCollector.append(t.image);
+	           }
+	       }
+	    }
+	    |
+	    (
+	        LOOKAHEAD(<DOLLAR_INTERPOLATION_OPENING>)
+		    (
+		        interpolation = StringOutput()
+	        )
+		    |
+            LOOKAHEAD(<HASH_INTERPOLATION_OPENING>)
+		    (
+                interpolation = NumericalOutput()
+		    )
+	    )
+	    {
+            if (staticTextCollector != null) {
+                parts.add(staticTextCollector.toString());
+                staticTextCollector.setLength(0);
+            }
+            parts.add(interpolation);
+	    }
+    )*
+    {
+        if (staticTextCollector != null && staticTextCollector.length() != 0) {
+            parts.add(staticTextCollector.toString());
+        }
+        parts.trimToSize();
+        return parts;
+    }
+}
+
+/**
  * Root production to be used when parsing
  * an entire file.
  */

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/manual/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/book.xml b/src/manual/book.xml
index 6decbd9..3546923 100644
--- a/src/manual/book.xml
+++ b/src/manual/book.xml
@@ -2798,14 +2798,7 @@ baz
             literals <link linkend="dgui_template_valueinsertion">behaves
             similarly as in <phrase role="markedText">text</phrase>
             sections</link> (so it goes through the same <emphasis>locale
-            sensitive</emphasis> number and date/time formatting), except that
-            no automatic escaping will happen (the deprecated <link
-            linkend="ref.directive.escape">escaping by
-            <literal>escape</literal> directive</link> has no effect there,
-            nor <link linkend="dgui_misc_autoescaping">auto-escaping</link>
-            happens as <link
-            linkend="dgui_misc_autoescaping_stringliteral">explained
-            here</link>).</para>
+            sensitive</emphasis> number and date/time formatting).</para>
 
             <para>Example (assume that user is <quote>Big Joe</quote>):</para>
 
@@ -2865,17 +2858,6 @@ ${s} &lt;#-- Just to see what the value of s is --&gt;
               something like <literal>"someUrl?id=1234"</literal>, regardless
               of locale and format settings.</para>
             </warning>
-
-            <para>Note for advanced users that <literal>+</literal> is more
-            flexible than <literal>${<replaceable>...</replaceable>}</literal>
-            when it comes to handling <link
-            linkend="dgui_misc_autoescaping_movalues">markup output
-            values</link>, because <link
-            linkend="dgui_misc_autoescaping_concatenation"><literal>+</literal>
-            can have markup output result</link>, while <link
-            linkend="dgui_misc_autoescaping_stringliteral">string literal
-            interpolation can't</link>, as the literal must yield a
-            string.</para>
           </section>
 
           <section xml:id="dgui_template_exp_get_character">
@@ -5690,51 +5672,6 @@ XML:  &lt;p&gt;Test&lt;/p&gt;
 RTF:  \par Test</programlisting>
           </section>
 
-          <section xml:id="dgui_misc_autoescaping_stringliteral">
-            <title>Auto-escaping and ${...} inside string literals</title>
-
-            <para>Inside string literals (quoted text expressions), the <link
-            linkend="dgui_misc_autoescaping_outputformat">output format</link>
-            is <literal>plainText</literal>. Thus no auto-escaping will occur
-            there:</para>
-
-            <programlisting role="template">&lt;#-- We assume that we have "HTML" output format by default. --&gt;
-&lt;#assign s = "Foo &amp; bar"&gt;
-${s}
-${"${s} &amp; baz"}</programlisting>
-
-            <programlisting role="output">Foo &amp;amp; bar
-Foo &amp;amp; bar &amp;amp; baz</programlisting>
-
-            <para>Above, because inside the string literal
-            <literal>${s}</literal> did no auto-escaping, when we print the
-            whole string we don't end up with double-escaping.</para>
-
-            <para>The <literal>plainText</literal> output format only allows
-            the inserting of markup output values that were created by
-            escaping plain text
-            (<literal><replaceable>plainText</replaceable>?esc</literal>), as
-            those are trivially convertible back to plain text. Thus only such
-            markup output values can be insert into string literals with
-            <literal>${<replaceable>...</replaceable>}</literal> (the
-            <literal>+</literal> operator is more flexible, but see that
-            later):</para>
-
-            <programlisting role="template">&lt;#-- We assume that we have "HTML" output format by default. --&gt;
-
-&lt;#-- Markup output value created by escaping plain text: --&gt;
-&lt;#assign mo1 = "Foo &amp; bar"?esc&gt;
-
-&lt;#-- Markup output value created outherwise: --&gt;
-&lt;#assign mo2 = "&lt;p&gt;Foo"?no_esc&gt;
-
-${"${mo1} baz"}
-&lt;#attempt&gt;${"${mo2} baz"}&lt;#recover&gt;Failed&lt;/#attempt&gt;</programlisting>
-
-            <programlisting role="output">Foo &amp;amp; bar baz
-Failed</programlisting>
-          </section>
-
           <section xml:id="dgui_misc_autoescaping_concatenation">
             <title>Markup output values and the <quote>+</quote>
             operator</title>
@@ -5764,6 +5701,32 @@ ${"&lt;h1&gt;"?no_esc + "Foo &amp; bar" + "&lt;/h1&gt;"?no_esc}</programlisting>
             of conversions here</link>.)</para>
           </section>
 
+          <section xml:id="dgui_misc_autoescaping_stringliteral">
+            <title>Auto-escaping and ${...} inside string literals</title>
+
+            <para>A string <emphasis>expression</emphasis> like
+            <literal>"Hello ${name}!"</literal> is just a shorthand for
+            <literal>"Hello" + name + "!"</literal>, so that
+            <literal>${<replaceable>...</replaceable>}</literal> doesn't
+            auto-escape.</para>
+
+            <programlisting role="template">&lt;#-- We assume that we have "HTML" output format by default. --&gt;
+&lt;#assign name = "Foo &amp; Bar"&gt;
+
+&lt;#assign s = "&lt;p&gt;Hello ${name}!"&gt;
+${s}
+&lt;p&gt;Hello ${name}!
+
+To prove that s didn't contain the value escaped:
+${s?replace('&amp;'), 'and'}</programlisting>
+
+            <programlisting role="output">&amp;lt;p&amp;gt;Hello Foo &amp;amp; Bar!
+&lt;p&gt;Hello Foo &amp;amp; Bar!
+
+To prove that s didn't contain the value escaped:
+&amp;lt;p&amp;gt;Hello Foo and Bar!</programlisting>
+          </section>
+
           <section>
             <title>Combined output formats</title>
 
@@ -26158,6 +26121,18 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               which can't be loaded due to zip format errors in the error
               message.</para>
             </listitem>
+
+            <listitem>
+              <para>The non-public AST API of
+              <literal>freemarker.core.StringLiteral</literal>-s has been
+              changed. In principle it doesn't mater as it isn't a public API,
+              but some might used these regardless to introspect templates.
+              Earlier it had an <quote>embedded template</quote> parameter
+              inside, now it has 0 (for purely static string literals), one or
+              multiple <quote>value part</quote>-ts, which are
+              <literal>String</literal>-s and
+              <literal>Interpolation</literal>-s.</para>
+            </listitem>
           </itemizedlist>
         </section>
 
@@ -26267,6 +26242,17 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
+              <para><literal>${<replaceable>...</replaceable>}</literal>
+              inside string literals is equivalent to using the
+              <literal>+</literal> operator again. This rule was broken by
+              <literal>+</literal> supporting markup operands, while
+              <literal>${<replaceable>...</replaceable>}</literal> inside
+              string literals didn't. Now similarly as <literal>"foo " +
+              someMarkup</literal> works and gives a markup result,
+              <literal>"foo ${someMarkup}"</literal> does too.</para>
+            </listitem>
+
+            <listitem>
               <para>Added <literal>XHTMLOutputFormat</literal> and
               <literal>TemplateXHTMLOutputModel</literal>.</para>
             </listitem>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/java/freemarker/core/NumberFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/NumberFormatTest.java b/src/test/java/freemarker/core/NumberFormatTest.java
index ddfbf28..19d2cba 100644
--- a/src/test/java/freemarker/core/NumberFormatTest.java
+++ b/src/test/java/freemarker/core/NumberFormatTest.java
@@ -297,9 +297,7 @@ public class NumberFormatTest extends TemplateTest {
         assertOutput("<#escape x as x?html>" + commonFTL + "</#escape>", commonOutput);
         assertOutput("<#escape x as x?xhtml>" + commonFTL + "</#escape>", commonOutput);
         assertOutput("<#escape x as x?xml>" + commonFTL + "</#escape>", commonOutput);
-        // TODO: Should give markup, but currently does interpolation in plain text:
-        // assertOutput("${\"" + commonFTL + "\"}",
-        //        "1.23*10<sup>6</sup> cat:1.23*10<sup>6</sup> 1.23*10<sup>-5</sup>");
+        assertOutput("${\"" + commonFTL + "\"}", "1.23*10<sup>6</sup> cat:1.23*10<sup>6</sup> 1.23*10<sup>-5</sup>");
         assertErrorContains("<#ftl outputFormat='plainText'>" + commonFTL, "HTML", "plainText", "conversion");
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/java/freemarker/core/OutputFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/OutputFormatTest.java b/src/test/java/freemarker/core/OutputFormatTest.java
index f7614c3..b36761e 100644
--- a/src/test/java/freemarker/core/OutputFormatTest.java
+++ b/src/test/java/freemarker/core/OutputFormatTest.java
@@ -436,12 +436,21 @@ public class OutputFormatTest extends TemplateTest {
     }
 
     @Test
-    public void testStringLiteralTemplateModificationBug() throws IOException, TemplateException {
+    public void testStringLiteralInterpolation() throws IOException, TemplateException {
         Template t = new Template(null, "<#ftl outputFormat='XML'>${'&'} ${\"(${'&'})\"?noEsc}", getConfiguration());
         assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat());
-        assertOutput("${.outputFormat} ${'${.outputFormat}'} ${.outputFormat}", "undefined plainText undefined");
-        assertOutput("${'foo ${xmlPlain}'}", "foo a < {x'}");
-        assertErrorContains("${'${xmlMarkup}'}", "plainText", "XML", "conversion");
+        
+        assertOutput("${.outputFormat} ${'${.outputFormat}'} ${.outputFormat}",
+                "undefined undefined undefined");
+        assertOutput("<#ftl outputFormat='HTML'>${.outputFormat} ${'${.outputFormat}'} ${.outputFormat}",
+                "HTML HTML HTML");
+        assertOutput("${.outputFormat} <#outputFormat 'XML'>${'${.outputFormat}'}</#outputFormat> ${.outputFormat}",
+                "undefined XML undefined");
+        assertOutput("${'foo ${xmlPlain}'}", "foo a &lt; {x&apos;}");
+        assertOutput("${'${xmlMarkup}'}", "<p>c</p>");
+        assertErrorContains("${'${\"x\"?esc}'}", "?esc", "undefined");
+        assertOutput("<#ftl outputFormat='XML'>${'${xmlMarkup?esc} ${\"<\"?esc} ${\">\"} ${\"&amp;\"?noEsc}'}",
+                "<p>c</p> &lt; &gt; &amp;");
     }
     
     @Test
@@ -875,11 +884,13 @@ public class OutputFormatTest extends TemplateTest {
                 assertOutput(commonFTL, "x");
                 assertErrorContains("<#ftl outputFormat='HTML'>" + commonFTL,
                         "?" + biName, "HTML", "double-escaping");
+                assertErrorContains("<#ftl outputFormat='HTML'>${'${\"x\"?" + biName + "}'}",
+                        "?" + biName, "HTML", "double-escaping");
                 assertOutput("<#ftl outputFormat='plainText'>" + commonFTL, "x");
                 assertOutput("<#ftl outputFormat='HTML' autoEsc=false>" + commonFTL, "x");
                 assertOutput("<#ftl outputFormat='HTML'><#noAutoEsc>" + commonFTL + "</#noAutoEsc>", "x");
-                assertOutput("<#ftl outputFormat='HTML'><#outputFormat 'plainText'>" + commonFTL + "</#outputFormat>", "x");
-                assertOutput("<#ftl outputFormat='HTML'>${'${\"x\"?" + biName + "}'}", "x");
+                assertOutput("<#ftl outputFormat='HTML'><#outputFormat 'plainText'>" + commonFTL + "</#outputFormat>",
+                        "x");
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
index fd6fb14..b7bfeee 100644
--- a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
+++ b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
@@ -19,6 +19,7 @@
 package freemarker.core;
 
 import java.io.IOException;
+import java.util.Collections;
 
 import org.junit.Test;
 
@@ -36,6 +37,7 @@ public class StringLiteralInterpolationTest extends TemplateTest {
         assertOutput("${'#{x}'}", "1");
         assertOutput("${'a${x}b${x*2}c'}", "a1b2c");
         assertOutput("${'a#{x}b#{x*2}c'}", "a1b2c");
+        assertOutput("${'a#{x; m2}'}", "a1.00");
         assertOutput("${'${x} ${x}'}", "1 1");
         assertOutput("${'$\\{x}'}", "${x}");
         assertOutput("${'$\\{x} $\\{x}'}", "${x} ${x}");
@@ -73,6 +75,13 @@ public class StringLiteralInterpolationTest extends TemplateTest {
         assertOutput("${'${1}'}", "1");
         assertErrorContains("${'${  '}", "");
     }
+    
+    @Test
+    public void testErrors() {
+        addToDataModel("x", 1);
+        assertErrorContains("${'${noSuchVar}'}", InvalidReferenceException.class, "missing", "noSuchVar");
+        assertErrorContains("${'${x/0}'}", ArithmeticException.class, "zero");
+    }
 
     @Test
     public void escaping() throws IOException, TemplateException {
@@ -90,4 +99,18 @@ public class StringLiteralInterpolationTest extends TemplateTest {
         assertOutput("${'&\\''?html} ${\"${'&\\\\\\''?html}\"}", "&amp;&#39; &amp;&#39;");
     }
     
+    @Test
+    public void markup() throws IOException, TemplateException {
+        Configuration cfg = getConfiguration();
+        cfg.setCustomNumberFormats(Collections.singletonMap("G", PrintfGTemplateNumberFormatFactory.INSTANCE));
+        cfg.setNumberFormat("@G 3");
+        
+        assertOutput("${\"${1000}\"}", "1.00*10<sup>3</sup>");
+        assertOutput("${\"&_${1000}\"}", "&amp;_1.00*10<sup>3</sup>");
+        assertOutput("${\"${1000}_&\"}", "1.00*10<sup>3</sup>_&amp;");
+        assertOutput("${\"${1000}, ${2000}\"}", "1.00*10<sup>3</sup>, 2.00*10<sup>3</sup>");
+        assertOutput("${\"& ${'x'}, ${2000}\"}", "&amp; x, 2.00*10<sup>3</sup>");
+        assertOutput("${\"& ${'x'}, #{2000}\"}", "& x, 2000");
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/java/freemarker/test/TemplateTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/test/TemplateTest.java b/src/test/java/freemarker/test/TemplateTest.java
index 0b1e03d..6047e2e 100644
--- a/src/test/java/freemarker/test/TemplateTest.java
+++ b/src/test/java/freemarker/test/TemplateTest.java
@@ -229,11 +229,13 @@ public abstract class TemplateTest {
             }
             assertContainsAll(e.getEditorMessage(), expectedSubstrings);
             return e;
-        } catch (IOException e) {
+        } catch (Exception e) {
             if (exceptionClass != null) {
                 assertThat(e, instanceOf(exceptionClass));
+                return e;
+            } else {
+                throw new RuntimeException("Unexpected exception class: " + e.getClass().getName(), e);
             }
-            throw new RuntimeException("Unexpected exception class: " + e.getClass().getName(), e);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/core/ast-1.ast
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/core/ast-1.ast b/src/test/resources/freemarker/core/ast-1.ast
index 6c5a753..9c3b8d1 100644
--- a/src/test/resources/freemarker/core/ast-1.ast
+++ b/src/test/resources/freemarker/core/ast-1.ast
@@ -64,19 +64,15 @@
             - AST-node subtype: "1"  // Integer
             ${...}  // f.c.DollarVariable
                 - content: "static"  // f.c.StringLiteral
-                    - embedded template: null  // Null
             ${...}  // f.c.DollarVariable
                 - content: dynamic "..."  // f.c.StringLiteral
-                    - embedded template: #mixed_content  // f.c.MixedContent
-                        #text  // f.c.TextBlock
-                            - content: "x"  // String
-                        ${...}  // f.c.DollarVariable
-                            - content: *  // f.c.ArithmeticExpression
-                                - left-hand operand: baaz  // f.c.Identifier
-                                - right-hand operand: 10  // f.c.NumberLiteral
-                                - AST-node subtype: "1"  // Integer
-                        #text  // f.c.TextBlock
-                            - content: "y"  // String
+                    - value part: "x"  // String
+                    - value part: ${...}  // f.c.DollarVariable
+                        - content: *  // f.c.ArithmeticExpression
+                            - left-hand operand: baaz  // f.c.Identifier
+                            - right-hand operand: 10  // f.c.NumberLiteral
+                            - AST-node subtype: "1"  // Integer
+                    - value part: "y"  // String
     #text  // f.c.TextBlock
         - content: "\n5 "  // String
     #switch  // f.c.SwitchBlock
@@ -163,7 +159,6 @@
         - content: "\n11 "  // String
     #outputformat  // f.c.OutputFormatBlock
         - value: "XML"  // f.c.StringLiteral
-            - embedded template: null  // Null
         #noautoesc  // f.c.NoAutoEscBlock
             ${...}  // f.c.DollarVariable
                 - content: a  // f.c.Identifier

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/core/ast-builtins.ast
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/core/ast-builtins.ast b/src/test/resources/freemarker/core/ast-builtins.ast
index 164c790..9278d8b 100644
--- a/src/test/resources/freemarker/core/ast-builtins.ast
+++ b/src/test/resources/freemarker/core/ast-builtins.ast
@@ -20,7 +20,6 @@
                 - right-hand operand: "left_pad"  // String
             - argument value: 5  // f.c.NumberLiteral
             - argument value: "-"  // f.c.StringLiteral
-                - embedded template: null  // Null
     #text  // f.c.TextBlock
         - content: "\n"  // String
     ${...}  // f.c.DollarVariable
@@ -28,9 +27,7 @@
             - left-hand operand: x  // f.c.Identifier
             - right-hand operand: "then"  // String
             - argument value: "y"  // f.c.StringLiteral
-                - embedded template: null  // Null
             - argument value: "n"  // f.c.StringLiteral
-                - embedded template: null  // Null
     #text  // f.c.TextBlock
         - content: "\n"  // String
     ${...}  // f.c.DollarVariable

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/core/ast-range.ast
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/core/ast-range.ast b/src/test/resources/freemarker/core/ast-range.ast
index eb862f4..3ddae45 100644
--- a/src/test/resources/freemarker/core/ast-range.ast
+++ b/src/test/resources/freemarker/core/ast-range.ast
@@ -102,13 +102,11 @@
                     - left-hand operand: n  // f.c.Identifier
                     - right-hand operand: "index_of"  // String
                 - argument value: "x"  // f.c.StringLiteral
-                    - embedded template: null  // Null
             - right-hand operand: ...(...)  // f.c.MethodCall
                 - callee: ?index_of  // f.c.BuiltInsForStringsBasic$index_ofBI
                     - left-hand operand: m  // f.c.Identifier
                     - right-hand operand: "index_of"  // String
                 - argument value: "y"  // f.c.StringLiteral
-                    - embedded template: null  // Null
         - variable scope: "1"  // Integer
         - namespace: null  // Null
     #assign  // f.c.Assignment

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/core/ast-strlitinterpolation.ast
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/core/ast-strlitinterpolation.ast b/src/test/resources/freemarker/core/ast-strlitinterpolation.ast
index f8f57bd..c55a320 100644
--- a/src/test/resources/freemarker/core/ast-strlitinterpolation.ast
+++ b/src/test/resources/freemarker/core/ast-strlitinterpolation.ast
@@ -1,10 +1,64 @@
-@  // f.c.UnifiedCall
-    - callee: m  // f.c.Identifier
-    - argument name: "x"  // String
-    - argument value: dynamic "..."  // f.c.StringLiteral
-        - embedded template: #mixed_content  // f.c.MixedContent
-            ${...}  // f.c.DollarVariable
+#mixed_content  // f.c.MixedContent
+    #text  // f.c.TextBlock
+        - content: "1. "  // String
+    @  // f.c.UnifiedCall
+        - callee: m  // f.c.Identifier
+        - argument name: "x"  // String
+        - argument value: dynamic "..."  // f.c.StringLiteral
+            - value part: ${...}  // f.c.DollarVariable
                 - content: e1  // f.c.Identifier
-    - argument name: "y"  // String
-    - argument value: "$\\{e2}"  // f.c.StringLiteral
-        - embedded template: null  // Null
\ No newline at end of file
+        - argument name: "y"  // String
+        - argument value: "$\\{e2}"  // f.c.StringLiteral
+    #text  // f.c.TextBlock
+        - content: "\n2. "  // String
+    ${...}  // f.c.DollarVariable
+        - content: dynamic "..."  // f.c.StringLiteral
+            - value part: "a"  // String
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+            - value part: "b"  // String
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+            - value part: "c"  // String
+    #text  // f.c.TextBlock
+        - content: "\n3. "  // String
+    ${...}  // f.c.DollarVariable
+        - content: dynamic "..."  // f.c.StringLiteral
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+            - value part: "b"  // String
+    #text  // f.c.TextBlock
+        - content: "\n4. "  // String
+    ${...}  // f.c.DollarVariable
+        - content: dynamic "..."  // f.c.StringLiteral
+            - value part: "a"  // String
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+    #text  // f.c.TextBlock
+        - content: "\n5. "  // String
+    ${...}  // f.c.DollarVariable
+        - content: dynamic "..."  // f.c.StringLiteral
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+            - value part: #{...}  // f.c.NumericalOutput
+                - content: y  // f.c.Identifier
+                - minimum decimals: "0"  // Integer
+                - maximum decimals: "0"  // Integer
+    #text  // f.c.TextBlock
+        - content: "\n6. "  // String
+    ${...}  // f.c.DollarVariable
+        - content: dynamic "..."  // f.c.StringLiteral
+            - value part: "a b "  // String
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+            - value part: " c d"  // String
+    #text  // f.c.TextBlock
+        - content: "\n7. "  // String
+    ${...}  // f.c.DollarVariable
+        - content: dynamic "..."  // f.c.StringLiteral
+            - value part: ${...}  // f.c.DollarVariable
+                - content: x  // f.c.Identifier
+            - value part: " a b "  // String
+            - value part: ${...}  // f.c.DollarVariable
+                - content: y  // f.c.Identifier
+            - value part: " c$d"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/core/ast-strlitinterpolation.ftl
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/core/ast-strlitinterpolation.ftl b/src/test/resources/freemarker/core/ast-strlitinterpolation.ftl
index efaced8..f67ba55 100644
--- a/src/test/resources/freemarker/core/ast-strlitinterpolation.ftl
+++ b/src/test/resources/freemarker/core/ast-strlitinterpolation.ftl
@@ -1 +1,7 @@
-<@m x='${e1}' y='$\\{e2}' />
\ No newline at end of file
+1. <@m x='${e1}' y='$\\{e2}' />
+2. ${'a${x}b${x}c'}
+3. ${'${x}b'}
+4. ${'a${x}'}
+5. ${'${x}#{y}'}
+6. ${'a b ${x} c d'}
+7. ${'${x} a b ${y} c$d'}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh b/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh
index 6d951a6..060b000 100644
--- a/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh
+++ b/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh
@@ -6,4 +6,4 @@
 <#assign mo2 = "<p>Foo"?no_esc>
 
 ${"${mo1} baz"}
-<#attempt>${"${mo2} baz"}<#recover>Failed</#attempt>
\ No newline at end of file
+${"${mo2} baz"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/fa6ac0ee/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh.out
----------------------------------------------------------------------
diff --git a/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh.out b/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh.out
index bc280c6..b8e929b 100644
--- a/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh.out
+++ b/src/test/resources/freemarker/manual/AutoEscapingExample-stringLiteral2.ftlh.out
@@ -1,3 +1,3 @@
 
 Foo &amp; bar baz
-Failed
\ No newline at end of file
+<p>Foo baz
\ No newline at end of file


[09/16] incubator-freemarker git commit: (Some Manual adjustments regarding string literal interpolations.)

Posted by dd...@apache.org.
(Some Manual adjustments regarding string literal interpolations.)


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

Branch: refs/heads/2.3
Commit: db94e0726416af827bdd8868f46dcfb75cbebd7b
Parents: 83a30d5
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 14:11:03 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 14:15:16 2015 +0200

----------------------------------------------------------------------
 src/manual/book.xml | 40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db94e072/src/manual/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/book.xml b/src/manual/book.xml
index 5685b35..75aa34d 100644
--- a/src/manual/book.xml
+++ b/src/manual/book.xml
@@ -2858,6 +2858,12 @@ ${s} &lt;#-- Just to see what the value of s is --&gt;
               something like <literal>"someUrl?id=1234"</literal>, regardless
               of locale and format settings.</para>
             </warning>
+
+            <para>As when <literal>${<replaceable>...</replaceable>}</literal>
+            is used inside string <emphasis>expressions</emphasis> it's just a
+            shorthand of using the <literal>+</literal> operator, <link
+            linkend="dgui_misc_autoescaping">auto-escaping</link> is not
+            applied on it.</para>
           </section>
 
           <section xml:id="dgui_template_exp_get_character">
@@ -5271,10 +5277,12 @@ jsmith@other.com, jsmith@other.com, jsmith@other.com</programlisting>
           <literal>freemarker.core.OutputFormat</literal> instance)</phrase>.
           The output format dictates the escaping rules, which is applied on
           all <literal>${<replaceable>...</replaceable>}</literal>-s (and
-          <literal>#{<replaceable>...</replaceable>}</literal>-s). It also
-          specifies a MIME type (e.g. <literal>"text/HTML"</literal>) and a
-          canonical name (e.g. <literal>"HTML"</literal>) that the embedding
-          application/framework can leverage for its own purposes.</para>
+          <literal>#{<replaceable>...</replaceable>}</literal>-s) that aren't
+          <link linkend="dgui_misc_autoescaping_stringliteral">inside a string
+          literal</link>. It also specifies a MIME type (e.g.
+          <literal>"text/HTML"</literal>) and a canonical name (e.g.
+          <literal>"HTML"</literal>) that the embedding application/framework
+          can leverage for its own purposes.</para>
 
           <para>It's the programmer's responsibility to <link
           linkend="pgui_config_outputformatsautoesc">associate output format
@@ -5702,13 +5710,15 @@ ${"&lt;h1&gt;"?no_esc + "Foo &amp; bar" + "&lt;/h1&gt;"?no_esc}</programlisting>
           </section>
 
           <section xml:id="dgui_misc_autoescaping_stringliteral">
-            <title>Auto-escaping and ${...} inside string literals</title>
+            <title>${...} inside string literals</title>
 
-            <para>A string <emphasis>expression</emphasis> like
-            <literal>"Hello ${name}!"</literal> is just a shorthand for
-            <literal>"Hello" + name + "!"</literal>, so that
-            <literal>${<replaceable>...</replaceable>}</literal> doesn't
-            auto-escape.</para>
+            <para>When <literal>${<replaceable>...</replaceable>}</literal> is
+            used inside string <emphasis>expressions</emphasis> (e.g., in
+            <literal>&lt;#assign s = "Hello ${name}!"&gt;</literal>), it's
+            just a shorthand of using the <literal>+</literal> operator
+            (<literal>&lt;#assign s = "Hello" + name + "!"&gt;</literal>).
+            Thus, <literal>${<replaceable>...</replaceable>}</literal> inside
+            string expressions isn't auto-escaped.</para>
 
             <programlisting role="template">&lt;#-- We assume that we have "HTML" output format by default. --&gt;
 &lt;#assign name = "Foo &amp; Bar"&gt;
@@ -5717,13 +5727,13 @@ ${"&lt;h1&gt;"?no_esc + "Foo &amp; bar" + "&lt;/h1&gt;"?no_esc}</programlisting>
 ${s}
 &lt;p&gt;Hello ${name}!
 
-To prove that s didn't contain the value escaped:
+To prove that s didn't contain the value in escaped form:
 ${s?replace('&amp;'), 'and'}</programlisting>
 
             <programlisting role="output">&amp;lt;p&amp;gt;Hello Foo &amp;amp; Bar!
 &lt;p&gt;Hello Foo &amp;amp; Bar!
 
-To prove that s didn't contain the value escaped:
+To prove that s didn't contain the value in escaped form:
 &amp;lt;p&amp;gt;Hello Foo and Bar!</programlisting>
           </section>
 
@@ -26270,6 +26280,12 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               <para>Added <literal>XHTMLOutputFormat</literal> and
               <literal>TemplateXHTMLOutputModel</literal>.</para>
             </listitem>
+
+            <listitem>
+              <para>Added new built-in: <literal>is_markup_output</literal>,
+              returns <literal>true</literal> if the value is of type
+              <quote>markup output</quote>.</para>
+            </listitem>
           </itemizedlist>
         </section>
       </section>


[07/16] incubator-freemarker git commit: Added new built-in: is_markup_output, returns true if the value is of type markup output.

Posted by dd...@apache.org.
Added new built-in: is_markup_output, returns true if the value is of type markup output.


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

Branch: refs/heads/2.3
Commit: 75fab1f789523ed8513a1aa6b938f6a89e9fe906
Parents: fa6ac0e
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 12:45:26 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 12:45:26 2015 +0200

----------------------------------------------------------------------
 src/main/java/freemarker/core/BuiltIn.java            |  3 ++-
 .../freemarker/core/BuiltInsForMultipleTypes.java     | 10 ++++++++++
 src/manual/book.xml                                   | 14 ++++++++++++++
 src/test/java/freemarker/core/OutputFormatTest.java   |  9 +++++++++
 4 files changed, 35 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/75fab1f7/src/main/java/freemarker/core/BuiltIn.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltIn.java b/src/main/java/freemarker/core/BuiltIn.java
index 11e9be4..144d70b 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -77,7 +77,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
     protected Expression target;
     protected String key;
 
-    static final int NUMBER_OF_BIS = 257;
+    static final int NUMBER_OF_BIS = 259;
     static final HashMap builtins = new HashMap(NUMBER_OF_BIS * 3 / 2 + 1, 1f);
     static {
         // Note that you must update NUMBER_OF_BIS if you add new items here!
@@ -140,6 +140,7 @@ abstract class BuiltIn extends Expression implements Cloneable {
         putBI("is_infinite", "isInfinite", new is_infiniteBI());
         putBI("is_indexable", "isIndexable", new BuiltInsForMultipleTypes.is_indexableBI());
         putBI("is_macro", "isMacro", new BuiltInsForMultipleTypes.is_macroBI());
+        putBI("is_markup_output", "isMarkupOutput", new BuiltInsForMultipleTypes.is_markup_outputBI());
         putBI("is_method", "isMethod", new BuiltInsForMultipleTypes.is_methodBI());
         putBI("is_nan", "isNan", new is_nanBI());
         putBI("is_node", "isNode", new BuiltInsForMultipleTypes.is_nodeBI());

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/75fab1f7/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
index 4b5d548..a15c3b6 100644
--- a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
+++ b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
@@ -391,6 +391,16 @@ class BuiltInsForMultipleTypes {
         }
     }
 
+    static class is_markup_outputBI extends BuiltIn {
+        @Override
+        TemplateModel _eval(Environment env) throws TemplateException {
+            TemplateModel tm = target.eval(env);
+            target.assertNonNull(tm, env);
+            return (tm instanceof TemplateMarkupOutputModel)  ?
+                TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
+        }
+    }
+    
     static class is_methodBI extends BuiltIn {
         @Override
         TemplateModel _eval(Environment env) throws TemplateException {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/75fab1f7/src/manual/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/book.xml b/src/manual/book.xml
index 3546923..5685b35 100644
--- a/src/manual/book.xml
+++ b/src/manual/book.xml
@@ -17168,6 +17168,13 @@ Sorted by name.last:
 
                 <td>node</td>
               </tr>
+
+              <tr>
+                <td><literal>is_markup_output</literal></td>
+
+                <td>markup output (a value that won't be <link
+                linkend="dgui_misc_autoescaping">auto-escaped</link>)</td>
+              </tr>
             </tbody>
           </informaltable>
         </section>
@@ -25673,6 +25680,13 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
                 </listitem>
 
                 <listitem>
+                  <para>Added new built-in:
+                  <literal>is_markup_output</literal>, returns
+                  <literal>true</literal> if the value is of type
+                  <quote>markup output</quote>.</para>
+                </listitem>
+
+                <listitem>
                   <para>New directive: <literal>outputformat</literal>, used
                   to change the output format for a section of a template,
                   like <literal>&lt;#outputformat

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/75fab1f7/src/test/java/freemarker/core/OutputFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/OutputFormatTest.java b/src/test/java/freemarker/core/OutputFormatTest.java
index b36761e..b596437 100644
--- a/src/test/java/freemarker/core/OutputFormatTest.java
+++ b/src/test/java/freemarker/core/OutputFormatTest.java
@@ -991,6 +991,15 @@ public class OutputFormatTest extends TemplateTest {
             assertErrorContains(ftl, InvalidReferenceException.class, "noSuchVar", "null or missing");
         }
     }
+
+    @Test
+    public void testIsMarkupOutputBI() throws Exception {
+        addToDataModel("m1", HTMLOutputFormat.INSTANCE.fromPlainTextByEscaping("x"));
+        addToDataModel("m2", HTMLOutputFormat.INSTANCE.fromMarkup("x"));
+        addToDataModel("s", "x");
+        assertOutput("${m1?isMarkupOutput?c} ${m2?isMarkupOutput?c} ${s?isMarkupOutput?c}", "true true false");
+        assertOutput("${m1?is_markup_output?c}", "true");
+    }
     
     @Override
     protected Configuration createConfiguration() throws TemplateModelException {


[10/16] incubator-freemarker git commit: (Added a date format test for a markup producing format.)

Posted by dd...@apache.org.
(Added a date format test for a markup producing format.)


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

Branch: refs/heads/2.3
Commit: dd54594617cd382b60c6113649c7717b20cd54b8
Parents: db94e07
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 16:31:21 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 16:31:21 2015 +0200

----------------------------------------------------------------------
 src/test/java/freemarker/core/DateFormatTest.java | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/dd545946/src/test/java/freemarker/core/DateFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/DateFormatTest.java b/src/test/java/freemarker/core/DateFormatTest.java
index b36a97f..6902b95 100644
--- a/src/test/java/freemarker/core/DateFormatTest.java
+++ b/src/test/java/freemarker/core/DateFormatTest.java
@@ -62,7 +62,8 @@ public class DateFormatTest extends TemplateTest {
                 "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
                 "loc", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE,
                 "div", EpochMillisDivTemplateDateFormatFactory.INSTANCE,
-                "appMeta", AppMetaTemplateDateFormatFactory.INSTANCE));
+                "appMeta", AppMetaTemplateDateFormatFactory.INSTANCE,
+                "htmlIso", HTMLISOTemplateDateFormatFactory.INSTANCE));
     }
 
     @Test
@@ -77,6 +78,14 @@ public class DateFormatTest extends TemplateTest {
                 "<#assign d = d?datetime>"
                 + "${d} ${d?string} <#setting locale='de_DE'>${d}",
                 "123456789 123456789 123456789");
+        
+        getConfiguration().setDateTimeFormat("@htmlIso");
+        assertOutput(
+                "<#assign d = d?datetime>"
+                + "${d} ${d?string} <#setting locale='de_DE'>${d}",
+                "1970-01-02<span class='T'>T</span>10:17:36Z "
+                + "1970-01-02T10:17:36Z "
+                + "1970-01-02<span class='T'>T</span>10:17:36Z");
     }
 
     @Test


[03/16] incubator-freemarker git commit: <@ and Posted by dd...@apache.org.
<@ and </@ is now allowed in String literals that contain ${exp}, and will be part of the literal as is. Earlier it was a syntactical error.


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

Branch: refs/heads/2.3
Commit: 6ac1b86a48ab9826e5061e497df22ea289b0c17b
Parents: a361243
Author: ddekany <dd...@apache.org>
Authored: Thu Oct 1 12:46:50 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Thu Oct 1 12:46:50 2015 +0200

----------------------------------------------------------------------
 src/main/javacc/FTL.jj                          | 33 +++++++++++++-------
 src/manual/book.xml                             |  8 +++++
 .../core/StringLiteralInterpolationTest.java    | 14 +++++++++
 3 files changed, 44 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6ac1b86a/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index e234e90..f65f4c5 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -731,6 +731,11 @@ TOKEN_MGR_DECLS:
     }
 
     private void unifiedCall(Token tok) {
+        if (onlyTextOutput) {
+            tok.kind = STATIC_TEXT_NON_WS;
+            return;
+        }
+    
         char firstChar = tok.image.charAt(0);
         if (autodetectTagSyntax && !directiveSyntaxEstablished) {
             squBracTagSyntax = (firstChar == '[');
@@ -748,6 +753,11 @@ TOKEN_MGR_DECLS:
     }
 
     private void unifiedCallEnd(Token tok) {
+        if (onlyTextOutput) {
+            tok.kind = STATIC_TEXT_NON_WS;
+            return;
+        }
+    
         char firstChar = tok.image.charAt(0);
         if (squBracTagSyntax && firstChar == '<') {
             tok.kind = STATIC_TEXT_NON_WS;
@@ -2225,19 +2235,20 @@ StringLiteral StringLiteral(boolean interpolate) :
         t = <RAW_STRING> { raw = true; }
     )
     {
-        String s = t.image;
+        String s;
         // Get rid of the quotes.
-        s = s.substring(1, s.length() -1);
         if (raw) {
-            s = s.substring(1);
-        } else try {
-            s = StringUtil.FTLStringLiteralDec(s);
-        } catch (ParseException pe) {
-            pe.lineNumber = t.beginLine;
-            pe.columnNumber = t.beginColumn;
-            pe.endLineNumber = t.endLine;
-            pe.endColumnNumber = t.endColumn;
-            throw pe;
+            s = t.image.substring(2, t.image.length() -1);
+        } else {
+	        try {
+	            s = StringUtil.FTLStringLiteralDec(t.image.substring(1, t.image.length() -1));
+	        } catch (ParseException pe) {
+	            pe.lineNumber = t.beginLine;
+	            pe.columnNumber = t.beginColumn;
+	            pe.endLineNumber = t.endLine;
+	            pe.endColumnNumber = t.endColumn;
+	            throw pe;
+	        }
         }
         StringLiteral result = new StringLiteral(s);
         result.setLocation(template, t, t);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6ac1b86a/src/manual/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/book.xml b/src/manual/book.xml
index b8bc656..6decbd9 100644
--- a/src/manual/book.xml
+++ b/src/manual/book.xml
@@ -25810,6 +25810,14 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               keeping the exact class can be important in some
               applications.</para>
             </listitem>
+
+            <listitem>
+              <para><literal>&lt;@</literal> and <literal>&lt;/@</literal> is
+              now allowed in String literals that contain
+              <literal>${<replaceable>exp</replaceable>}</literal>, and will
+              be part of the literal as is. Earlier it was a syntactical
+              error.</para>
+            </listitem>
           </itemizedlist>
         </section>
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6ac1b86a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
index 6abe579..e6d86e4 100644
--- a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
+++ b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
@@ -34,6 +34,20 @@ public class StringLiteralInterpolationTest extends TemplateTest {
         assertOutput("<#assign x = 1>${'${x} ${x}'}", "1 1");
         assertOutput("<#assign x = 1>${'$\\{x}'}", "${x}");
         assertOutput("<#assign x = 1>${'$\\{x} $\\{x}'}", "${x} ${x}");
+        assertOutput("<#assign x = 1>${'<#-- not a comment -->${x}'}", "<#-- not a comment -->1");
+        assertOutput("<#assign x = 1>${'<#-- not a comment -->$\\{x}'}", "<#-- not a comment -->${x}");
+        assertOutput("<#assign x = 1>${'<@x/>${x}'}", "<@x/>1");
+        assertOutput("<#assign x = 1>${'<@x/>$\\{x}'}", "<@x/>${x}");
+        assertOutput("<#assign x = 1>${'<@ ${x}<@'}", "<@ 1<@");
+        assertOutput("<#assign x = 1>${'<@ $\\{x}<@'}", "<@ ${x}<@");
+        assertOutput("<#assign x = 1>${'</...@x>${x}'}", "</...@x>1");
+        assertOutput("<#assign x = 1>${'</...@x>$\\{x}'}", "</...@x>${x}");
+        assertOutput("<#assign x = 1>${'</@ ${x}</@'}", "</@ 1</@");
+        assertOutput("<#assign x = 1>${'</@ $\\{x}</@'}", "</@ ${x}</@");
+        assertOutput("<#assign x = 1>${'[@ ${x}'}", "[@ 1");
+        assertOutput("<#assign x = 1>${'[@ $\\{x}'}", "[@ ${x}");
+        assertOutput("<#assign x = 1>${'<#assign x = 2> ${x}'}", "<#assign x = 2> 1");
+        assertOutput("<#assign x = 1>${'<#assign x = 2> $\\{x}'}", "<#assign x = 2> ${x}");
     }
 
     /**


[04/16] incubator-freemarker git commit: Simplified static text parsing

Posted by dd...@apache.org.
Simplified static text parsing


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

Branch: refs/heads/2.3
Commit: 6802cc7110d796c841f4d49d401dda1c3f78048a
Parents: 6ac1b86
Author: ddekany <dd...@apache.org>
Authored: Thu Oct 1 14:17:11 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Thu Oct 1 14:17:11 2015 +0200

----------------------------------------------------------------------
 src/main/javacc/FTL.jj | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6802cc71/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index f65f4c5..a3c5870 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -3893,9 +3893,7 @@ TextBlock PCData() :
 }
 {
     (
-        LOOKAHEAD(<STATIC_TEXT_WS>|<STATIC_TEXT_NON_WS>|<STATIC_TEXT_FALSE_ALARM>)
         (
-            { prevToken = t; }
             t = <STATIC_TEXT_WS>
             |
             t = <STATIC_TEXT_NON_WS>
@@ -3906,6 +3904,7 @@ TextBlock PCData() :
             buf.append(t.image);
             if (start == null) start = t;
             if (prevToken != null) prevToken.next = null;
+            prevToken = t;
         }
     )+
     {


[08/16] incubator-freemarker git commit: Some more markup string literal interpolation tests

Posted by dd...@apache.org.
Some more markup string literal interpolation tests


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

Branch: refs/heads/2.3
Commit: 83a30d5ae03b76ef637cda926ed13009e8fc0294
Parents: 75fab1f
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 13:58:20 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 13:58:20 2015 +0200

----------------------------------------------------------------------
 .../core/StringLiteralInterpolationTest.java           | 13 +++++++++++++
 1 file changed, 13 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/83a30d5a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
index b7bfeee..fc66013 100644
--- a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
+++ b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
@@ -111,6 +111,19 @@ public class StringLiteralInterpolationTest extends TemplateTest {
         assertOutput("${\"${1000}, ${2000}\"}", "1.00*10<sup>3</sup>, 2.00*10<sup>3</sup>");
         assertOutput("${\"& ${'x'}, ${2000}\"}", "&amp; x, 2.00*10<sup>3</sup>");
         assertOutput("${\"& ${'x'}, #{2000}\"}", "& x, 2000");
+        
+        assertOutput("${\"${2000}\"?isMarkupOutput?c}", "true");
+        assertOutput("${\"x ${2000}\"?isMarkupOutput?c}", "true");
+        assertOutput("${\"${2000} x\"?isMarkupOutput?c}", "true");
+        assertOutput("${\"#{2000}\"?isMarkupOutput?c}", "false");
+        assertOutput("${\"${'x'}\"?isMarkupOutput?c}", "false");
+        assertOutput("${\"x ${'x'}\"?isMarkupOutput?c}", "false");
+        assertOutput("${\"${'x'} x\"?isMarkupOutput?c}", "false");
+        
+        addToDataModel("rtf", RTFOutputFormat.INSTANCE.fromMarkup("\\p"));
+        assertOutput("${\"${rtf}\"?isMarkupOutput?c}", "true");
+        assertErrorContains("${\"${1000}${rtf}\"}", TemplateException.class, "HTML", "RTF", "onversion");
+        assertErrorContains("x${\"${1000}${rtf}\"}", TemplateException.class, "HTML", "RTF", "onversion");
     }
     
 }


[16/16] incubator-freemarker git commit: Merge remote-tracking branch 'origin/2.3-gae' into 2.3

Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3


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

Branch: refs/heads/2.3
Commit: d07ad04ceb1e735af3f216c101632ed7e37a0844
Parents: a8814b8 8adee32
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 21:16:07 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 21:16:07 2015 +0200

----------------------------------------------------------------------
 .../core/ExtendedDecimalFormatParser.java       |  44 +++---
 src/manual/book.xml                             | 150 +++++++++++--------
 .../core/ExtendedDecimalFormatTest.java         | 139 +++++++++--------
 3 files changed, 188 insertions(+), 145 deletions(-)
----------------------------------------------------------------------



[13/16] incubator-freemarker git commit: (Added unknown date-type test)

Posted by dd...@apache.org.
(Added unknown date-type test)


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

Branch: refs/heads/2.3
Commit: 1e905a47da788a9e0d5fa5b820e6250bc0980c1a
Parents: 43007bf
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 16:44:42 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 16:44:42 2015 +0200

----------------------------------------------------------------------
 src/test/java/freemarker/core/DateFormatTest.java | 8 ++++++++
 1 file changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/1e905a47/src/test/java/freemarker/core/DateFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/DateFormatTest.java b/src/test/java/freemarker/core/DateFormatTest.java
index 6902b95..20b2cc9 100644
--- a/src/test/java/freemarker/core/DateFormatTest.java
+++ b/src/test/java/freemarker/core/DateFormatTest.java
@@ -428,6 +428,14 @@ public class DateFormatTest extends TemplateTest {
                 T + " " + T + "/foo");
     }
     
+    @Test
+    public void testUnknownDateType() throws IOException, TemplateException {
+        addToDataModel("u", new Date(T));
+        assertErrorContains("${u?string}", "isn't known");
+        assertOutput("${u?string('yyyy')}", "2015");
+        assertOutput("<#assign s = u?string>${s('yyyy')}", "2015");
+    }
+    
     private static class MutableTemplateDateModel implements TemplateDateModel {
         
         private Date date;


[12/16] incubator-freemarker git commit: (Minor code cleanup)

Posted by dd...@apache.org.
(Minor code cleanup)


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

Branch: refs/heads/2.3
Commit: 43007bfed4b663e76d99aa77735a42e7a354acc1
Parents: 14fab44
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 16:44:24 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 16:44:24 2015 +0200

----------------------------------------------------------------------
 .../freemarker/core/BuiltInsForMultipleTypes.java     | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/43007bfe/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
index a15c3b6..861b370 100644
--- a/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
+++ b/src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
@@ -580,14 +580,14 @@ class BuiltInsForMultipleTypes {
             public String getAsString()
             throws TemplateModelException {
                 if (cachedValue == null) {
-                    try {
-                        if (defaultFormat == null) {
-                            if (dateModel.getDateType() == TemplateDateModel.UNKNOWN) {
-                                throw MessageUtil.newCantFormatUnknownTypeDateException(target, null);
-                            } else {
-                                throw new BugException();
-                            }
+                    if (defaultFormat == null) {
+                        if (dateModel.getDateType() == TemplateDateModel.UNKNOWN) {
+                            throw MessageUtil.newCantFormatUnknownTypeDateException(target, null);
+                        } else {
+                            throw new BugException();
                         }
+                    }
+                    try {
                         cachedValue = EvalUtil.assertFormatResultNotNull(defaultFormat.formatToPlainText(dateModel));
                     } catch (TemplateValueFormatException e) {
                         try {


[05/16] incubator-freemarker git commit: Reworked how ${...}-s are lexed a bit, to make the lexing of string literals (which may contain ${...}) more manageable.

Posted by dd...@apache.org.
Reworked how ${...}-s are lexed a bit, to make the lexing of string literals (which may contain ${...}) more manageable.


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

Branch: refs/heads/2.3
Commit: d8487ffee38a1fd3ab9291c9174d8f7e7ce15be8
Parents: 6802cc7
Author: ddekany <dd...@apache.org>
Authored: Thu Oct 1 16:20:45 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Fri Oct 2 00:07:17 2015 +0200

----------------------------------------------------------------------
 src/main/javacc/FTL.jj                          | 57 +++++++++++++-------
 .../core/ParsingErrorMessagesTest.java          |  7 +++
 .../core/StringLiteralInterpolationTest.java    | 55 ++++++++++++-------
 3 files changed, 79 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d8487ffe/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index a3c5870..9c6bae1 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -255,10 +255,11 @@ public class FMParser {
     }
     
     void setupStringLiteralMode(FMParserTokenManager parentTokenSource) {
-        token_source.onlyTextOutput = true;
         token_source.initialNamingConvention = parentTokenSource.initialNamingConvention;
         token_source.namingConvention = parentTokenSource.namingConvention;
         token_source.namingConventionEstabilisher = parentTokenSource.namingConventionEstabilisher;
+        token_source.SwitchTo(NODIRECTIVE);
+        
         outputFormat = PlainTextOutputFormat.INSTANCE;
         recalculateAutoEscapingField();                                
         if (incompatibleImprovements < _TemplateAPI.VERSION_INT_2_3_24) {
@@ -578,12 +579,12 @@ TOKEN_MGR_DECLS:
      * distinguish the } used to close a hash literal and the one used to close a ${
      */
     private FMParser parser;
+    private int postInterpolationLexState = -1;
     private int hashLiteralNesting;
     private int parenthesisNesting;
     private int bracketNesting;
     private boolean inFTLHeader;
     boolean strictEscapeSyntax,
-            onlyTextOutput,
             squBracTagSyntax,
             autodetectTagSyntax,
             directiveSyntaxEstablished,
@@ -602,11 +603,6 @@ TOKEN_MGR_DECLS:
     // tag syntax detection. If you update this logic, take a look
     // at the UNKNOWN_DIRECTIVE token too.
     private void strictSyntaxCheck(Token tok, int tokenNamingConvention, int newLexState) {
-        if (onlyTextOutput) {
-            tok.kind = STATIC_TEXT_NON_WS;
-            return;
-        }
-
         final String image = tok.image;
         
         // Non-strict syntax (deprecated) only supports legacy naming convention.
@@ -731,11 +727,6 @@ TOKEN_MGR_DECLS:
     }
 
     private void unifiedCall(Token tok) {
-        if (onlyTextOutput) {
-            tok.kind = STATIC_TEXT_NON_WS;
-            return;
-        }
-    
         char firstChar = tok.image.charAt(0);
         if (autodetectTagSyntax && !directiveSyntaxEstablished) {
             squBracTagSyntax = (firstChar == '[');
@@ -753,11 +744,6 @@ TOKEN_MGR_DECLS:
     }
 
     private void unifiedCallEnd(Token tok) {
-        if (onlyTextOutput) {
-            tok.kind = STATIC_TEXT_NON_WS;
-            return;
-        }
-    
         char firstChar = tok.image.charAt(0);
         if (squBracTagSyntax && firstChar == '<') {
             tok.kind = STATIC_TEXT_NON_WS;
@@ -781,6 +767,37 @@ TOKEN_MGR_DECLS:
             SwitchTo(DEFAULT);
         }
     }
+    
+    private void startInterpolation(Token tok) {
+        if (postInterpolationLexState != -1) {
+            char c = tok.image.charAt(0);
+            throw new TokenMgrError(
+                    "You can't start an interpolation (" + c + "{...}) here "
+                    + "as you are inside another interpolation.)",
+                    TokenMgrError.LEXICAL_ERROR,
+                    tok.beginLine, tok.beginColumn,
+                    tok.endLine, tok.endColumn);
+        }
+        postInterpolationLexState = curLexState;
+        SwitchTo(FM_EXPRESSION);
+    }
+
+    /**
+     * @param tok
+     *         Assumed to be an '}', or something that is the closing pair of another "mirror image" character.
+     */
+    private void endInterpolation(Token tok) {
+        if (postInterpolationLexState == -1) {
+            char c = tok.image.charAt(0);
+            throw new TokenMgrError(
+                    "You can't have an \"" + c + "\" here, as there's nothing open that it could close.",
+                    TokenMgrError.LEXICAL_ERROR,
+                    tok.beginLine, tok.beginColumn,
+                    tok.endLine, tok.endColumn);
+        }
+        SwitchTo(postInterpolationLexState);
+        postInterpolationLexState = -1;
+    }
 
     private void eatNewline() {
         int charsRead = 0;
@@ -1096,9 +1113,9 @@ TOKEN:
     |
     <STATIC_TEXT_FALSE_ALARM : "$" | "#" | "<" | "[" | "{"> // to handle a lone dollar sign or "<" or "# or <@ with whitespace after"
     |
-    <DOLLAR_INTERPOLATION_OPENING : "${"> : FM_EXPRESSION
+    <DOLLAR_INTERPOLATION_OPENING : "${"> { startInterpolation(matchedToken); }
     |
-    <HASH_INTERPOLATION_OPENING : "#{"> : FM_EXPRESSION
+    <HASH_INTERPOLATION_OPENING : "#{"> { startInterpolation(matchedToken); }
 }
 
 <FM_EXPRESSION, IN_PAREN, NAMED_PARAMETER_EXPRESSION> SKIP :
@@ -1259,7 +1276,7 @@ TOKEN:
     |
     <CLOSING_CURLY_BRACKET : "}">
     {
-        if (hashLiteralNesting == 0) SwitchTo(DEFAULT);
+        if (hashLiteralNesting == 0) endInterpolation(matchedToken);
         else --hashLiteralNesting;
     }
     |

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d8487ffe/src/test/java/freemarker/core/ParsingErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/ParsingErrorMessagesTest.java b/src/test/java/freemarker/core/ParsingErrorMessagesTest.java
index d528675..f34ddf2 100644
--- a/src/test/java/freemarker/core/ParsingErrorMessagesTest.java
+++ b/src/test/java/freemarker/core/ParsingErrorMessagesTest.java
@@ -74,6 +74,13 @@ public class ParsingErrorMessagesTest {
         assertErrorContains("${blah", "\"{\"", "unclosed");
     }
     
+    @Test
+    public void testInterpolatingClosingsErrors() {
+        assertErrorContains("${x", "unclosed");
+        assertErrorContains("<#assign x = x}>", "\"}\"", "open");
+        // TODO assertErrorContains("<#assign x = '${x'>", "unclosed");
+    }
+    
     private void assertErrorContains(String ftl, String... expectedSubstrings) {
         assertErrorContains(false, ftl, expectedSubstrings);
         assertErrorContains(true, ftl, expectedSubstrings);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d8487ffe/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
index e6d86e4..fd6fb14 100644
--- a/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
+++ b/src/test/java/freemarker/core/StringLiteralInterpolationTest.java
@@ -26,28 +26,33 @@ import freemarker.template.Configuration;
 import freemarker.template.TemplateException;
 import freemarker.test.TemplateTest;
 
+@SuppressWarnings("boxing")
 public class StringLiteralInterpolationTest extends TemplateTest {
 
     @Test
     public void basics() throws IOException, TemplateException {
-        assertOutput("<#assign x = 1>${'${x}'}", "1");
-        assertOutput("<#assign x = 1>${'${x} ${x}'}", "1 1");
-        assertOutput("<#assign x = 1>${'$\\{x}'}", "${x}");
-        assertOutput("<#assign x = 1>${'$\\{x} $\\{x}'}", "${x} ${x}");
-        assertOutput("<#assign x = 1>${'<#-- not a comment -->${x}'}", "<#-- not a comment -->1");
-        assertOutput("<#assign x = 1>${'<#-- not a comment -->$\\{x}'}", "<#-- not a comment -->${x}");
-        assertOutput("<#assign x = 1>${'<@x/>${x}'}", "<@x/>1");
-        assertOutput("<#assign x = 1>${'<@x/>$\\{x}'}", "<@x/>${x}");
-        assertOutput("<#assign x = 1>${'<@ ${x}<@'}", "<@ 1<@");
-        assertOutput("<#assign x = 1>${'<@ $\\{x}<@'}", "<@ ${x}<@");
-        assertOutput("<#assign x = 1>${'</...@x>${x}'}", "</...@x>1");
-        assertOutput("<#assign x = 1>${'</...@x>$\\{x}'}", "</...@x>${x}");
-        assertOutput("<#assign x = 1>${'</@ ${x}</@'}", "</@ 1</@");
-        assertOutput("<#assign x = 1>${'</@ $\\{x}</@'}", "</@ ${x}</@");
-        assertOutput("<#assign x = 1>${'[@ ${x}'}", "[@ 1");
-        assertOutput("<#assign x = 1>${'[@ $\\{x}'}", "[@ ${x}");
-        assertOutput("<#assign x = 1>${'<#assign x = 2> ${x}'}", "<#assign x = 2> 1");
-        assertOutput("<#assign x = 1>${'<#assign x = 2> $\\{x}'}", "<#assign x = 2> ${x}");
+        addToDataModel("x", 1);
+        assertOutput("${'${x}'}", "1");
+        assertOutput("${'#{x}'}", "1");
+        assertOutput("${'a${x}b${x*2}c'}", "a1b2c");
+        assertOutput("${'a#{x}b#{x*2}c'}", "a1b2c");
+        assertOutput("${'${x} ${x}'}", "1 1");
+        assertOutput("${'$\\{x}'}", "${x}");
+        assertOutput("${'$\\{x} $\\{x}'}", "${x} ${x}");
+        assertOutput("${'<#-- not a comment -->${x}'}", "<#-- not a comment -->1");
+        assertOutput("${'<#-- not a comment -->$\\{x}'}", "<#-- not a comment -->${x}");
+        assertOutput("${'<#assign x = 2> ${x} <#assign x = 2>'}", "<#assign x = 2> 1 <#assign x = 2>");
+        assertOutput("${'<#assign x = 2> $\\{x} <#assign x = 2>'}", "<#assign x = 2> ${x} <#assign x = 2>");
+        assertOutput("${'<@x/>${x}<@x/>'}", "<@x/>1<@x/>");
+        assertOutput("${'<@x/>$\\{x}<@x/>'}", "<@x/>${x}<@x/>");
+        assertOutput("${'<@ ${x}<@'}", "<@ 1<@");
+        assertOutput("${'<@ $\\{x}<@'}", "<@ ${x}<@");
+        assertOutput("${'</...@x>${x}'}", "</...@x>1");
+        assertOutput("${'</...@x>$\\{x}'}", "</...@x>${x}");
+        assertOutput("${'</@ ${x}</@'}", "</@ 1</@");
+        assertOutput("${'</@ $\\{x}</@'}", "</@ ${x}</@");
+        assertOutput("${'[@ ${x}'}", "[@ 1");
+        assertOutput("${'[@ $\\{x}'}", "[@ ${x}");
     }
 
     /**
@@ -55,8 +60,18 @@ public class StringLiteralInterpolationTest extends TemplateTest {
      */
     @Test
     public void legacyEscapingBugStillPresent() throws IOException, TemplateException {
-        assertOutput("<#assign x = 1>${'$\\{x} ${x}'}", "1 1");
-        assertOutput("<#assign x = 1>${'${x} $\\{x}'}", "1 1");
+        addToDataModel("x", 1);
+        assertOutput("${'$\\{x} ${x}'}", "1 1");
+        assertOutput("${'${x} $\\{x}'}", "1 1");
+    }
+    
+    @Test
+    public void legacyLengthGlitch() throws IOException, TemplateException {
+        assertOutput("${'${'}", "${");
+        assertOutput("${'${1'}", "${1");
+        assertOutput("${'${}'}", "${}");
+        assertOutput("${'${1}'}", "1");
+        assertErrorContains("${'${  '}", "");
     }
 
     @Test


[14/16] incubator-freemarker git commit: Merge remote-tracking branch 'origin/2.3-gae' into 2.3

Posted by dd...@apache.org.
Merge remote-tracking branch 'origin/2.3-gae' into 2.3


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

Branch: refs/heads/2.3
Commit: a8814b8803a4cafe857924419cda475bf5ad07ec
Parents: 4b1550e 1e905a4
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 16:45:42 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 16:45:42 2015 +0200

----------------------------------------------------------------------
 README.txt                                      |   4 +-
 .../freemarker/core/AddConcatExpression.java    |  32 +---
 src/main/java/freemarker/core/BuiltIn.java      |   3 +-
 .../core/BuiltInsForMultipleTypes.java          |  24 ++-
 .../java/freemarker/core/DollarVariable.java    |  10 +-
 src/main/java/freemarker/core/EvalUtil.java     |  28 +++-
 .../java/freemarker/core/Interpolation.java     |   9 ++
 .../java/freemarker/core/NumericalOutput.java   |  18 ++-
 .../java/freemarker/core/ParameterRole.java     |   1 +
 .../java/freemarker/core/StringLiteral.java     | 105 +++++++-----
 src/main/javacc/FTL.jj                          | 139 +++++++++++++---
 src/manual/book.xml                             | 158 +++++++++++--------
 .../freemarker/core/CoercionToTextualTest.java  | 119 ++++++++++++++
 .../freemarker/core/CorectionToTextualTest.java | 119 --------------
 .../java/freemarker/core/DateFormatTest.java    |  19 ++-
 .../java/freemarker/core/NumberFormatTest.java  |   4 +-
 .../java/freemarker/core/OutputFormatTest.java  |  32 +++-
 .../core/ParsingErrorMessagesTest.java          |   7 +
 .../core/StringLiteralInterpolationTest.java    |  77 ++++++++-
 src/test/java/freemarker/test/TemplateTest.java |   6 +-
 src/test/resources/freemarker/core/ast-1.ast    |  19 +--
 .../resources/freemarker/core/ast-builtins.ast  |   3 -
 .../resources/freemarker/core/ast-range.ast     |   2 -
 .../freemarker/core/ast-strlitinterpolation.ast |  72 +++++++--
 .../freemarker/core/ast-strlitinterpolation.ftl |   8 +-
 .../AutoEscapingExample-stringLiteral2.ftlh     |   2 +-
 .../AutoEscapingExample-stringLiteral2.ftlh.out |   2 +-
 27 files changed, 677 insertions(+), 345 deletions(-)
----------------------------------------------------------------------



[15/16] incubator-freemarker git commit: The extended decimal format options don't use abbreviations anymore. Like instead of rnd=hu, now there's roundingMode=halfUp.

Posted by dd...@apache.org.
The extended decimal format options don't use abbreviations anymore. Like instead of rnd=hu, now there's roundingMode=halfUp.


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

Branch: refs/heads/2.3
Commit: 8adee326161c928aaa02525bc84b7293d86262cd
Parents: 1e905a4
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 16:44:42 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 21:14:09 2015 +0200

----------------------------------------------------------------------
 .../core/ExtendedDecimalFormatParser.java       |  44 +++---
 src/manual/book.xml                             | 150 +++++++++++--------
 .../core/ExtendedDecimalFormatTest.java         | 139 +++++++++--------
 3 files changed, 188 insertions(+), 145 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8adee326/src/main/java/freemarker/core/ExtendedDecimalFormatParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ExtendedDecimalFormatParser.java b/src/main/java/freemarker/core/ExtendedDecimalFormatParser.java
index 76484cf..8824531 100644
--- a/src/main/java/freemarker/core/ExtendedDecimalFormatParser.java
+++ b/src/main/java/freemarker/core/ExtendedDecimalFormatParser.java
@@ -32,29 +32,29 @@ import freemarker.template.utility.StringUtil;
 
 class ExtendedDecimalFormatParser {
     
-    private static final String PARAM_ROUNDING_MODE = "rnd";
-    private static final String PARAM_MULTIPIER = "mul";
-    private static final String PARAM_DECIMAL_SEPARATOR = "dec";
-    private static final String PARAM_MONETARY_DECIMAL_SEPARATOR = "mdec";
-    private static final String PARAM_GROUP_SEPARATOR = "grp";
-    private static final String PARAM_EXPONENT_SEPARATOR = "exp";
-    private static final String PARAM_MINUS_SIGN = "min";
-    private static final String PARAM_INFINITY = "inf";
+    private static final String PARAM_ROUNDING_MODE = "roundingMode";
+    private static final String PARAM_MULTIPIER = "multipier";
+    private static final String PARAM_DECIMAL_SEPARATOR = "decimalSeparator";
+    private static final String PARAM_MONETARY_DECIMAL_SEPARATOR = "monetaryDecimalSeparator";
+    private static final String PARAM_GROUP_SEPARATOR = "groupingSeparator";
+    private static final String PARAM_EXPONENT_SEPARATOR = "exponentSeparator";
+    private static final String PARAM_MINUS_SIGN = "minusSign";
+    private static final String PARAM_INFINITY = "infinity";
     private static final String PARAM_NAN = "nan";
-    private static final String PARAM_PERCENT = "prc";
-    private static final String PARAM_PER_MILL = "prm";
-    private static final String PARAM_ZERO_DIGIT = "zero";
-    private static final String PARAM_CURRENCY_CODE = "curc";
-    private static final String PARAM_CURRENCY_SYMBOL = "curs";
-
-    private static final String PARAM_VALUE_RND_UP = "u";
-    private static final String PARAM_VALUE_RND_DOWN = "d";
-    private static final String PARAM_VALUE_RND_CEILING = "c";
-    private static final String PARAM_VALUE_RND_FLOOR = "f";
-    private static final String PARAM_VALUE_RND_HALF_DOWN = "hd";
-    private static final String PARAM_VALUE_RND_HALF_EVEN = "he";
-    private static final String PARAM_VALUE_RND_HALF_UP = "hu";
-    private static final String PARAM_VALUE_RND_UNNECESSARY = "un";
+    private static final String PARAM_PERCENT = "percent";
+    private static final String PARAM_PER_MILL = "perMill";
+    private static final String PARAM_ZERO_DIGIT = "zeroDigit";
+    private static final String PARAM_CURRENCY_CODE = "currencyCode";
+    private static final String PARAM_CURRENCY_SYMBOL = "currencySymbol";
+
+    private static final String PARAM_VALUE_RND_UP = "up";
+    private static final String PARAM_VALUE_RND_DOWN = "down";
+    private static final String PARAM_VALUE_RND_CEILING = "ceiling";
+    private static final String PARAM_VALUE_RND_FLOOR = "floor";
+    private static final String PARAM_VALUE_RND_HALF_DOWN = "halfDown";
+    private static final String PARAM_VALUE_RND_HALF_EVEN = "halfEven";
+    private static final String PARAM_VALUE_RND_HALF_UP = "halfUp";
+    private static final String PARAM_VALUE_RND_UNNECESSARY = "unnecessary";
     
     private static final HashMap<String, ? extends ParameterHandler> PARAM_HANDLERS;
     static {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8adee326/src/manual/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/book.xml b/src/manual/book.xml
index 75aa34d..da26c70 100644
--- a/src/manual/book.xml
+++ b/src/manual/book.xml
@@ -14550,15 +14550,17 @@ German people write: 12.345.678,00</programlisting>
             0.0"</literal>), the after only one semicolon. For example:</para>
 
             <programlisting role="template">Standard decimal format: ${10002.5?string[",000"]}
-Extended decimal format: ${10002.5?string[",000<emphasis>;; rnd=hu grp=_</emphasis>"]}</programlisting>
+Extended decimal format: ${10002.5?string[",000<emphasis>;; roundingMode=halfUp groupingSeparator=_</emphasis>"]}</programlisting>
 
             <programlisting role="output">Standard decimal format: 10,002
 Extended decimal format: 10<emphasis>_</emphasis>00<emphasis>3</emphasis></programlisting>
 
             <para>Above, in the extended decimal format, we have specified
-            half-up rounding mode (<literal>rnd=hu</literal>), and group
-            separator <literal>"_"</literal> (<literal>grp=_</literal>). The
-            table of all options:</para>
+            half-up rounding mode and group separator <literal>"_"</literal>.
+            The table of all options follows (note that these are defined by
+            <literal>java.text.DecimalFormat</literal> and
+            <literal>java.text.DecimalFormatSymbols</literal>, not by
+            FreeMarker):</para>
 
             <informaltable border="1">
               <thead>
@@ -14571,101 +14573,120 @@ Extended decimal format: 10<emphasis>_</emphasis>00<emphasis>3</emphasis></progr
 
               <tbody>
                 <tr>
-                  <td><literal>rnd</literal></td>
-
-                  <td>Rounding mode. The value is one of <literal>u</literal>
-                  for up, <literal>d</literal> for down, <literal>c</literal>
-                  for ceiling, <literal>f</literal> for floor,
-                  <literal>hu</literal> for half-up, <literal>hd</literal> for
-                  half-down, <literal>he</literal> for half-even, and
-                  <literal>un</literal> for unused. (See <link
+                  <td><literal>roundingMode</literal></td>
+
+                  <td>The value is one of <literal>up</literal>,
+                  <literal>down</literal>, <literal>ceiling</literal>,
+                  <literal>floor</literal>, <literal>halfUp</literal>,
+                  <literal>halfDown</literal>, <literal>halfEven</literal>,
+                  and <literal>unnecessary</literal>. The behavior that most
+                  people learns in school is <literal>halfUp</literal>, but
+                  the Java default is <literal>halfEven</literal> (also called
+                  bankers' rounding). (See <link
                   xlink:href="http://docs.oracle.com/javase/7/docs/api/java/math/RoundingMode.html">the
                   <literal>java.math.RoundingMode</literal> API</link> for
                   explanations.)</td>
                 </tr>
 
                 <tr>
-                  <td><literal>mul</literal></td>
+                  <td><literal>multipier</literal></td>
 
-                  <td>Multiplier. The number will be shown after multiplied
-                  with this integer number.</td>
+                  <td>The number will be shown after multiplied with this
+                  integer number.</td>
                 </tr>
 
                 <tr>
-                  <td><literal>dec</literal></td>
+                  <td><literal>decimalSeparator</literal></td>
 
-                  <td>Decimal separator character (like <literal>"."</literal>
-                  in <literal>3.14</literal>).</td>
+                  <td>The character separating the integer part from the
+                  fraction part (like <literal>"."</literal> in
+                  <literal>3.14</literal>).</td>
                 </tr>
 
                 <tr>
-                  <td><literal>mdec</literal></td>
+                  <td><literal>monetaryDecimalSeparator</literal></td>
 
-                  <td>Monetary decimal separator character. This is used
-                  instead of <literal>dec</literal> when the pattern contains
-                  parts that make it a monetary format. (See the <link
+                  <td>This is used instead of
+                  <literal>decimalSeparator</literal> when the pattern
+                  contains parts that make it a monetary format. (See the
+                  <link
                   xlink:href="http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html">Java
                   decimal number format documentation</link> for more.)</td>
                 </tr>
 
                 <tr>
-                  <td><literal>grp</literal></td>
-
-                  <td>Grouping separator character. Note that grouping is
-                  turned on by using <literal>","</literal> in the pattern, as
-                  shown in the earlier example. If it's not turned on, this
-                  option won't have visible effect.</td>
+                  <td><literal>groupingSeparator</literal></td>
+
+                  <td>The single character used for grouping the integer part
+                  (like <literal>","</literal> in
+                  <literal>1,000,000</literal>) Note that grouping is turned
+                  on by using <literal>","</literal> in the pattern, as shown
+                  in the earlier example. If it's not turned on, this option
+                  won't have visible effect.</td>
                 </tr>
 
                 <tr>
-                  <td><literal>exp</literal></td>
+                  <td><literal>exponentSeparator</literal></td>
 
-                  <td>Exponent separator string. Only has visible effect if
-                  the pattern specifies exponential form, like
+                  <td>This string (of arbitrary length) is used to separate
+                  the exponent from the part before it. (like
+                  <literal>"E"</literal> in <literal>1.23E6</literal>). Only
+                  has visible effect if the pattern specifies exponential
+                  (also known as scientific) format, like
                   <literal>"0.##E0"</literal>.</td>
                 </tr>
 
                 <tr>
-                  <td><literal>min</literal></td>
+                  <td><literal>minusSign</literal></td>
 
-                  <td>Minus sign character.</td>
+                  <td>The single character used as minus sign (like
+                  <literal>"-"</literal> in <literal>-1</literal>).</td>
                 </tr>
 
                 <tr>
-                  <td><literal>inf</literal></td>
+                  <td><literal>infinity</literal></td>
 
-                  <td>The string used to show infinity.</td>
+                  <td>The string (of arbitrary length) used to show
+                  infinity.</td>
                 </tr>
 
                 <tr>
                   <td><literal>nan</literal></td>
 
-                  <td>The string used to show not-a-number (NaN).</td>
+                  <td>The string (of arbitrary length) used to show
+                  not-a-number (NaN).</td>
                 </tr>
 
                 <tr>
-                  <td><literal>prc</literal></td>
+                  <td><literal>percent</literal></td>
 
-                  <td>Percent character.</td>
+                  <td>The single character used as the percent symbol (like
+                  <literal>"%"</literal> in <literal>50%</literal>). Only has
+                  visible effect if the pattern contains
+                  <literal>%</literal>.</td>
                 </tr>
 
                 <tr>
-                  <td><literal>prm</literal></td>
+                  <td><literal>perMill</literal></td>
 
-                  <td>Per-mill character.</td>
+                  <td>The single character used as the per-mill symbol (like
+                  <literal>"‰"</literal> in <literal>50021‰</literal>). Only
+                  has visible effect if the pattern contains
+                  <literal>‰</literal>.</td>
                 </tr>
 
                 <tr>
-                  <td><literal>zero</literal></td>
+                  <td><literal>zeroDigit</literal></td>
 
-                  <td>Zero character. This modifies the other digits too, for
-                  example, if zero is <literal>A</literal>, then 1 will
+                  <td>The first character in the 10 character range (of
+                  character codes) that contains the digits to be used. For
+                  example, if this is <literal>A</literal>, then 1 will
                   <literal>B</literal>, 2 will be <literal>C</literal>, and so
                   on.</td>
                 </tr>
 
                 <tr>
-                  <td><literal>curc</literal></td>
+                  <td><literal>currencyCode</literal></td>
 
                   <td>Currency ISO 4217 code. Only has effect when the pattern
                   contains parts that make it a monetary format. It's an error
@@ -14674,11 +14695,11 @@ Extended decimal format: 10<emphasis>_</emphasis>00<emphasis>3</emphasis></progr
                 </tr>
 
                 <tr>
-                  <td><literal>curs</literal></td>
+                  <td><literal>currencySymbol</literal></td>
 
                   <td>Currency symbol; shown where the localized currency name
                   is present in the pattern. Overrides the symbol determined
-                  from <literal>curc</literal>.</td>
+                  based on the <literal>currencyCode</literal>.</td>
                 </tr>
               </tbody>
             </informaltable>
@@ -14699,19 +14720,23 @@ Extended decimal format: 10<emphasis>_</emphasis>00<emphasis>3</emphasis></progr
               <listitem>
                 <para>The option value can be quoted with apostrophe
                 (<literal>'</literal>) or normal quotation mark
-                (<literal>"</literal>) , like <literal>exp='*10^'</literal> or
-                <literal>exp="*10^"</literal>. If the value itself has to
-                contain the character used for quotation, then it has to be
-                entered twice (like <literal>inf='It''s infinite'</literal>,
-                but you could also write <literal>inf="It's
-                infinite"</literal>). Backslash has no special meaning.</para>
+                (<literal>"</literal>) , like
+                <literal>exponentSeparator='*10^'</literal> or
+                <literal>exponentSeparator="*10^"</literal>. If the value
+                itself has to contain the character used for quotation, then
+                it has to be entered twice (like <literal>infinity='It''s
+                infinite'</literal>, but you could also write
+                <literal>infinity="It's infinite"</literal>). Backslash has no
+                special meaning.</para>
               </listitem>
 
               <listitem>
                 <para>Non-string values must not be quoted. Strings only has
                 to be quoted if they contain punctuation or whitespace, or any
                 other non-letter non-digit non-<literal>"_"</literal>
-                non-<literal>"$"</literal> characters.</para>
+                non-<literal>"$"</literal> characters. Thus, for example, both
+                <literal>roundingMode=down</literal> and
+                <literal>roundingMode="down"</literal> are legal.</para>
               </listitem>
             </itemizedlist>
           </simplesect>
@@ -25822,12 +25847,12 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
-              <para><emphasis>Attention!</emphasis> FreeMarker's JSP support
-              (if it's used) now requires at least JSP 2.0. Earlier it only
-              required JSP 1.1. (Reason: The <literal>jsp-api</literal>
-              dependency for JSP 1.x, which was needed for building, can't be
-              legally present in the Maven Central Repository, nor be provided
-              by freemarker.org.)</para>
+              <para><emphasis role="strong">Attention!</emphasis> FreeMarker's
+              JSP support (if it's used) now requires at least JSP 2.0.
+              Earlier it only required JSP 1.1. (Reason: The
+              <literal>jsp-api</literal> dependency for JSP 1.x, which was
+              needed for building, can't be legally present in the Maven
+              Central Repository, nor be provided by freemarker.org.)</para>
             </listitem>
 
             <listitem>
@@ -26277,6 +26302,13 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
             </listitem>
 
             <listitem>
+              <para>The extended decimal format options don't use
+              abbreviations anymore. Like instead of
+              <literal>rnd=hu</literal>, now there's
+              <literal>roundingMode=halfUp</literal>.</para>
+            </listitem>
+
+            <listitem>
               <para>Added <literal>XHTMLOutputFormat</literal> and
               <literal>TemplateXHTMLOutputModel</literal>.</para>
             </listitem>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8adee326/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java b/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
index d53fc84..264c1ea 100644
--- a/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
+++ b/src/test/java/freemarker/core/ExtendedDecimalFormatTest.java
@@ -107,84 +107,89 @@ public class ExtendedDecimalFormatTest extends TemplateTest {
     @Test
     public void testExtendedParamsParsing() throws ParseException {
         for (String fs : new String[] {
-                "00.##;; dec='D'", "00.##;;dec=D", "00.##;;  dec  =  D ", "00.##;; dec = 'D' " }) {
+                "00.##;; decimalSeparator='D'",
+                "00.##;;decimalSeparator=D",
+                "00.##;;  decimalSeparator  =  D ", "00.##;; decimalSeparator = 'D' " }) {
             assertFormatted(fs, 1.125, "01D12");
         }
         for (String fs : new String[] {
-                ",#0.0;; dec=D, grp=_", ",#0.0;;dec=D,grp=_", ",#0.0;; dec = D , grp = _ ", ",#0.0;; dec='D', grp='_'"
+                ",#0.0;; decimalSeparator=D, groupingSeparator=_",
+                ",#0.0;;decimalSeparator=D,groupingSeparator=_",
+                ",#0.0;; decimalSeparator = D , groupingSeparator = _ ",
+                ",#0.0;; decimalSeparator='D', groupingSeparator='_'"
                 }) {
             assertFormatted(fs, 12345, "1_23_45D0");
         }
         
-        assertFormatted("0.0;;inf=infinity", Double.POSITIVE_INFINITY, "infinity");
-        assertFormatted("0.0;;inf='infinity'", Double.POSITIVE_INFINITY, "infinity");
-        assertFormatted("0.0;;inf=\"infinity\"", Double.POSITIVE_INFINITY, "infinity");
-        assertFormatted("0.0;;inf=''", Double.POSITIVE_INFINITY, "");
-        assertFormatted("0.0;;inf=\"\"", Double.POSITIVE_INFINITY, "");
-        assertFormatted("0.0;;inf='x''y'", Double.POSITIVE_INFINITY, "x'y");
-        assertFormatted("0.0;;inf=\"x'y\"", Double.POSITIVE_INFINITY, "x'y");
-        assertFormatted("0.0;;inf='x\"\"y'", Double.POSITIVE_INFINITY, "x\"\"y");
-        assertFormatted("0.0;;inf=\"x''y\"", Double.POSITIVE_INFINITY, "x''y");
-        assertFormatted("0.0;;dec=''''", 1, "1'0");
-        assertFormatted("0.0;;dec=\"'\"", 1, "1'0");
-        assertFormatted("0.0;;dec='\"'", 1, "1\"0");
-        assertFormatted("0.0;;dec=\"\"\"\"", 1, "1\"0");
+        assertFormatted("0.0;;infinity=infinity", Double.POSITIVE_INFINITY, "infinity");
+        assertFormatted("0.0;;infinity='infinity'", Double.POSITIVE_INFINITY, "infinity");
+        assertFormatted("0.0;;infinity=\"infinity\"", Double.POSITIVE_INFINITY, "infinity");
+        assertFormatted("0.0;;infinity=''", Double.POSITIVE_INFINITY, "");
+        assertFormatted("0.0;;infinity=\"\"", Double.POSITIVE_INFINITY, "");
+        assertFormatted("0.0;;infinity='x''y'", Double.POSITIVE_INFINITY, "x'y");
+        assertFormatted("0.0;;infinity=\"x'y\"", Double.POSITIVE_INFINITY, "x'y");
+        assertFormatted("0.0;;infinity='x\"\"y'", Double.POSITIVE_INFINITY, "x\"\"y");
+        assertFormatted("0.0;;infinity=\"x''y\"", Double.POSITIVE_INFINITY, "x''y");
+        assertFormatted("0.0;;decimalSeparator=''''", 1, "1'0");
+        assertFormatted("0.0;;decimalSeparator=\"'\"", 1, "1'0");
+        assertFormatted("0.0;;decimalSeparator='\"'", 1, "1\"0");
+        assertFormatted("0.0;;decimalSeparator=\"\"\"\"", 1, "1\"0");
         
         try {
-            ExtendedDecimalFormatParser.parse(";;dec=D,", LOC);
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator=D,", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(),
                     allOf(containsStringIgnoringCase("expected a(n) name"), containsString(" end of ")));
         }
         try {
-            ExtendedDecimalFormatParser.parse(";;xdec=D,", LOC);
+            ExtendedDecimalFormatParser.parse(";;foo=D,", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(),
-                    allOf(containsString("\"xdec\""), containsString("name")));
+                    allOf(containsString("\"foo\""), containsString("name")));
         }
         try {
-            ExtendedDecimalFormatParser.parse(";;dec='D", LOC);
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator='D", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(),
                     allOf(containsString("quotation"), containsString("closed")));
         }
         try {
-            ExtendedDecimalFormatParser.parse(";;dec=\"D", LOC);
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator=\"D", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(),
                     allOf(containsString("quotation"), containsString("closed")));
         }
         try {
-            ExtendedDecimalFormatParser.parse(";;dec='D'grp=G", LOC);
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator='D'groupingSeparator=G", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(), allOf(
                     containsString("separator"), containsString("whitespace"), containsString("comma")));
         }
         try {
-            ExtendedDecimalFormatParser.parse(";;dec=., grp=G", LOC);
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator=., groupingSeparator=G", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(), allOf(
-                    containsStringIgnoringCase("expected a(n) value"), containsString("., grp")));
+                    containsStringIgnoringCase("expected a(n) value"), containsString("., gr[...]")));
         }
         try {
-            ExtendedDecimalFormatParser.parse("0.0;;dec=''", LOC);
+            ExtendedDecimalFormatParser.parse("0.0;;decimalSeparator=''", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(), allOf(
-                    containsStringIgnoringCase("\"dec\""), containsString("exactly 1 char")));
+                    containsStringIgnoringCase("\"decimalSeparator\""), containsString("exactly 1 char")));
         }
         try {
-            ExtendedDecimalFormatParser.parse("0.0;;mul=ten", LOC);
+            ExtendedDecimalFormatParser.parse("0.0;;multipier=ten", LOC);
             fail();
         } catch (java.text.ParseException e) {
             assertThat(e.getMessage(), allOf(
-                    containsString("\"mul\""), containsString("\"ten\""), containsString("integer")));
+                    containsString("\"multipier\""), containsString("\"ten\""), containsString("integer")));
         }
     }
     
@@ -193,71 +198,77 @@ public class ExtendedDecimalFormatTest extends TemplateTest {
     public void testExtendedParamsEffect() throws ParseException {
         assertFormatted("0",
                 1.5, "2", 2.5, "2", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-2", -1.6, "-2");
-        assertFormatted("0;; rnd=he",
+        assertFormatted("0;; roundingMode=halfEven",
                 1.5, "2", 2.5, "2", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-2", -1.6, "-2");
-        assertFormatted("0;; rnd=hu",
+        assertFormatted("0;; roundingMode=halfUp",
                 1.5, "2", 2.5, "3", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-3", -1.6, "-2");
-        assertFormatted("0;; rnd=hd",
+        assertFormatted("0;; roundingMode=halfDown",
                 1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-2");
-        assertFormatted("0;; rnd=f",
+        assertFormatted("0;; roundingMode=floor",
                 1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "1", -1.4, "-2", -1.5, "-2", -2.5, "-3", -1.6, "-2");
-        assertFormatted("0;; rnd=c",
+        assertFormatted("0;; roundingMode=ceiling",
                 1.5, "2", 2.5, "3", 3.5, "4", 1.4, "2", 1.6, "2", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-1");
-        assertFormatted("0;; rnd=un", 2, "2");
+        assertFormatted("0;; roundingMode=up",
+                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "2", 1.6, "2", -1.4, "-2", -1.5, "-2", -2.5, "-3", -1.6, "-2");
+        assertFormatted("0;; roundingMode=down",
+                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "1", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-1");
+        assertFormatted("0;; roundingMode=unnecessary", 2, "2");
         try {
-            assertFormatted("0;; rnd=un", 2.5, "2");
+            assertFormatted("0;; roundingMode=unnecessary", 2.5, "2");
             fail();
         } catch (ArithmeticException e) {
             // Expected
         }
 
-        assertFormatted("0.##;; mul=100", 12.345, "1234.5");
-        assertFormatted("0.##;; mul=1000", 12.345, "12345");
+        assertFormatted("0.##;; multipier=100", 12.345, "1234.5");
+        assertFormatted("0.##;; multipier=1000", 12.345, "12345");
         
-        assertFormatted(",##0.##;; grp=_ dec=D", 12345.1, "12_345D1", 1, "1");
+        assertFormatted(",##0.##;; groupingSeparator=_ decimalSeparator=D", 12345.1, "12_345D1", 1, "1");
         
-        assertFormatted("0.##E0;; exp='*10^'", 12345.1, "1.23*10^4");
+        assertFormatted("0.##E0;; exponentSeparator='*10^'", 12345.1, "1.23*10^4");
         
-        assertFormatted("0.##;; min=m", -1, "m1", 1, "1");
+        assertFormatted("0.##;; minusSign=m", -1, "m1", 1, "1");
         
-        assertFormatted("0.##;; inf=foo", Double.POSITIVE_INFINITY, "foo", Double.NEGATIVE_INFINITY, "-foo");
+        assertFormatted("0.##;; infinity=foo", Double.POSITIVE_INFINITY, "foo", Double.NEGATIVE_INFINITY, "-foo");
         
         assertFormatted("0.##;; nan=foo", Double.NaN, "foo");
         
-        assertFormatted("0%;; prc='c'", 0.75, "75c");
+        assertFormatted("0%;; percent='c'", 0.75, "75c");
         
-        assertFormatted("0\u2030;; prm='m'", 0.75, "750m");
+        assertFormatted("0\u2030;; perMill='m'", 0.75, "750m");
         
-        assertFormatted("0.00;; zero='@'", 10.5, "A@.E@");
+        assertFormatted("0.00;; zeroDigit='@'", 10.5, "A@.E@");
         
-        assertFormatted("0;; curc=USD", 10, "10");
-        assertFormatted("0 \u00A4;; curc=USD", 10, "10 $");
-        assertFormatted("0 \u00A4\u00A4;; curc=USD", 10, "10 USD");
-        assertFormatted(Locale.GERMANY, "0 \u00A4;; curc=EUR", 10, "10 \u20AC");
-        assertFormatted(Locale.GERMANY, "0 \u00A4\u00A4;; curc=EUR", 10, "10 EUR");
+        assertFormatted("0;; currencyCode=USD", 10, "10");
+        assertFormatted("0 \u00A4;; currencyCode=USD", 10, "10 $");
+        assertFormatted("0 \u00A4\u00A4;; currencyCode=USD", 10, "10 USD");
+        assertFormatted(Locale.GERMANY, "0 \u00A4;; currencyCode=EUR", 10, "10 \u20AC");
+        assertFormatted(Locale.GERMANY, "0 \u00A4\u00A4;; currencyCode=EUR", 10, "10 EUR");
         try {
-            assertFormatted("0;; curc=USDX", 10, "10");
+            assertFormatted("0;; currencyCode=USDX", 10, "10");
         } catch (ParseException e) {
             assertThat(e.getMessage(), containsString("ISO 4217"));
         }
-        assertFormatted("0 \u00A4;; curc=USD curs=bucks", 10, "10 bucks");
-        assertFormatted("0 \u00A4;; curs=bucks curc=USD", 10, "10 bucks"); // Order doesn't mater
-        assertFormatted("0 \u00A4\u00A4;; curc=USD curs=bucks", 10, "10 USD"); // International symbol isn't affected
+        assertFormatted("0 \u00A4;; currencyCode=USD currencySymbol=bucks", 10, "10 bucks");
+     // Order doesn't mater:
+        assertFormatted("0 \u00A4;; currencySymbol=bucks currencyCode=USD", 10, "10 bucks");
+        // International symbol isn't affected:
+        assertFormatted("0 \u00A4\u00A4;; currencyCode=USD currencySymbol=bucks", 10, "10 USD");
         
-        assertFormatted("0.0 \u00A4;; mdec=m", 10.5, "10m5 $");
-        assertFormatted("0.0 kg;; mdec=m", 10.5, "10.5 kg");
-        assertFormatted("0.0 \u00A4;; dec=d", 10.5, "10.5 $");
-        assertFormatted("0.0 kg;; dec=d", 10.5, "10d5 kg");
-        assertFormatted("0.0 \u00A4;; mdec=m dec=d", 10.5, "10m5 $");
-        assertFormatted("0.0 kg;; mdec=m dec=d", 10.5, "10d5 kg");
+        assertFormatted("0.0 \u00A4;; monetaryDecimalSeparator=m", 10.5, "10m5 $");
+        assertFormatted("0.0 kg;; monetaryDecimalSeparator=m", 10.5, "10.5 kg");
+        assertFormatted("0.0 \u00A4;; decimalSeparator=d", 10.5, "10.5 $");
+        assertFormatted("0.0 kg;; decimalSeparator=d", 10.5, "10d5 kg");
+        assertFormatted("0.0 \u00A4;; monetaryDecimalSeparator=m decimalSeparator=d", 10.5, "10m5 $");
+        assertFormatted("0.0 kg;; monetaryDecimalSeparator=m decimalSeparator=d", 10.5, "10d5 kg");
     }
     
     @Test
     public void testLocale() throws ParseException {
         assertEquals("1000.0", ExtendedDecimalFormatParser.parse("0.0", Locale.US).format(1000));
         assertEquals("1000,0", ExtendedDecimalFormatParser.parse("0.0", Locale.FRANCE).format(1000));
-        assertEquals("1_000.0", ExtendedDecimalFormatParser.parse(",000.0;;grp=_", Locale.US).format(1000));
-        assertEquals("1_000,0", ExtendedDecimalFormatParser.parse(",000.0;;grp=_", Locale.FRANCE).format(1000));
+        assertEquals("1_000.0", ExtendedDecimalFormatParser.parse(",000.0;;groupingSeparator=_", Locale.US).format(1000));
+        assertEquals("1_000,0", ExtendedDecimalFormatParser.parse(",000.0;;groupingSeparator=_", Locale.FRANCE).format(1000));
     }
     
     @Test
@@ -267,16 +278,16 @@ public class ExtendedDecimalFormatTest extends TemplateTest {
         
         cfg.setNumberFormat(",000.#");
         assertOutput("${1000.15} ${1000.25}", "1,000.2 1,000.2");
-        cfg.setNumberFormat(",000.#;; rnd=hu grp=_");
+        cfg.setNumberFormat(",000.#;; roundingMode=halfUp groupingSeparator=_");
         assertOutput("${1000.15} ${1000.25}", "1_000.2 1_000.3");
         cfg.setLocale(Locale.GERMANY);
         assertOutput("${1000.15} ${1000.25}", "1_000,2 1_000,3");
         cfg.setLocale(Locale.US);
         assertOutput(
                 "${1000.15}; "
-                + "${1000.15?string(',##.#;;grp=\" \"')}; "
+                + "${1000.15?string(',##.#;;groupingSeparator=\" \"')}; "
                 + "<#setting locale='de_DE'>${1000.15}; "
-                + "<#setting numberFormat='0.0;;rnd=d'>${1000.15}",
+                + "<#setting numberFormat='0.0;;roundingMode=down'>${1000.15}",
                 "1_000.2; 10 00.2; 1_000,2; 1000,1");
         assertErrorContains("${1?string('#E')}",
                 TemplateException.class, "\"#E\"", "format string", "exponential");
@@ -284,7 +295,7 @@ public class ExtendedDecimalFormatTest extends TemplateTest {
                 TemplateException.class, "\"#E\"", "format string", "exponential");
         assertErrorContains("<#setting numberFormat=';;foo=bar'>${1}",
                 TemplateException.class, "\"foo\"", "supported");
-        assertErrorContains("<#setting numberFormat='0;;rnd=un'>${1.5}",
+        assertErrorContains("<#setting numberFormat='0;;roundingMode=unnecessary'>${1.5}",
                 TemplateException.class, "can't format", "1.5", "UNNECESSARY");
     }
 


[11/16] incubator-freemarker git commit: Fixed accidental use of Java 6 API.

Posted by dd...@apache.org.
Fixed accidental use of Java 6 API.


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

Branch: refs/heads/2.3
Commit: 14fab44fe1a20bee814c086f110ec01e97bcbefc
Parents: dd54594
Author: ddekany <dd...@apache.org>
Authored: Sun Oct 4 16:32:06 2015 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sun Oct 4 16:32:06 2015 +0200

----------------------------------------------------------------------
 src/main/javacc/FTL.jj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/14fab44f/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index 34f737b..a10552f 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -4227,7 +4227,7 @@ List<Object> StaticTextAndInterpolations() :
 	    )
 	    {
 	       String s = t.image;
-	       if (!s.isEmpty()) {
+	       if (s.length() != 0) {
 	           if (staticTextCollector == null) {
 	               staticTextCollector = new StringBuilder(t.image);
 	           } else {