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 2017/10/26 23:35:31 UTC

incubator-freemarker git commit: Removed some operator aliases:

Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 1e1493549 -> b16e37ae2


Removed some operator aliases:

  - `\and`, `&&`. Use `and` instead. (HTML entity support will be re-added, but "globally")
  - `|` for logical "or". Use `||` instead.
  - `\lt`, `<`. Use "lt" instead.
  - `lte`, `\lte`, `<=`. Use "le" instead (syntax from XSTL).
  - `\gt`, `>`. Use "gt" instead.
  - `gte`, `\gte`, `>=`. Use "ge" instead (syntax from XSTL).


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

Branch: refs/heads/3
Commit: b16e37ae2463ec61ca66ee587230f5d8382d84ad
Parents: 1e14935
Author: ddekany <dd...@apache.org>
Authored: Fri Oct 27 01:35:19 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Fri Oct 27 01:35:19 2017 +0200

----------------------------------------------------------------------
 FM3-CHANGE-LOG.txt                              |  6 +++
 freemarker-converter/build.gradle               |  2 +-
 .../core/FM2ASTToFM3SourceConverter.java        | 45 +++++++++-------
 .../UnconvertableLegacyFeatureException.java    | 17 ++++++
 .../converter/FM2ToFM3ConverterTest.java        | 20 ++++---
 .../core/FM3EscapedOperatorsTest.java           | 57 ++++++++++++++++++++
 .../core/templatesuite/templates/boolean.ftl    |  8 +--
 .../org/apache/freemarker/core/ASTExpAnd.java   |  9 ++--
 .../freemarker/core/ASTExpComparison.java       | 10 ++--
 .../org/apache/freemarker/core/ASTExpOr.java    |  9 ++--
 freemarker-core/src/main/javacc/FTL.jj          | 22 ++++----
 11 files changed, 154 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index 3d61c35..bf4bdfd 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -83,7 +83,13 @@ Node: Changes already mentioned above aren't repeated here!
 - Removed the following operator aliases:
   - `=` for comparison (it can only be used for assignment now). Use `==` instead.
   - `&` for logical "and". Use `&&` instead.
+  - `\and`, `&amp;&amp;`. Use `and` instead. (HTML entity support will be re-added, but "globally")
   - `|` for logical "or". Use `||` instead.
+  - `\lt`, `&lt;`. Use "lt" instead.
+  - `lte`, `\lte`, `&lt;=`. Use "le" instead (syntax from XSTL).
+  - `\gt`, `&gt;`. Use "gt" instead.
+  - `gte`, `\gte`, `&gt;=`. Use "ge" instead (syntax from XSTL).
+- New keywords (can't be used as identifier): `and`, `or`, `le`, `ge`
 - Removed some long deprecated template language directives:
   - <#call ...> (deprecated by <@... />)
   - <#comment>...</#comment> (deprecated by <#-- ... -->)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-converter/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-converter/build.gradle b/freemarker-converter/build.gradle
index ee42afe..f8ee507 100644
--- a/freemarker-converter/build.gradle
+++ b/freemarker-converter/build.gradle
@@ -25,7 +25,7 @@ inAggregateJavadoc = false
 
 dependencies {
     compile project(":freemarker-core")
-    compile "org.freemarker:freemarker-gae:2.3.27-incubating-SNAPSHOT"
+    compile "org.freemarker:freemarker-gae:2.3.28-incubating-SNAPSHOT"
     compile libraries.commonsCli
     compile libraries.commonsLang
     compile libraries.commonsIo

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
----------------------------------------------------------------------
diff --git a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
index f883a80..d816a04 100644
--- a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
+++ b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
@@ -291,8 +291,7 @@ public class FM2ASTToFM3SourceConverter {
         print("#--");
         String content = getOnlyParam(node, ParameterRole.CONTENT, String.class);
         if (content.indexOf("-->") != -1) {
-            throw new UnconvertableLegacyFeatureException("You can't have a \"-->\" inside a comment.",
-                    node.getBeginLine(), node.getBeginColumn());
+            throw new UnconvertableLegacyFeatureException("You can't have a \"-->\" inside a comment.", node);
         }
         print(content);
         print("--");
@@ -566,7 +565,7 @@ public class FM2ASTToFM3SourceConverter {
                 } else if (pastDefault) {
                     throw new UnconvertableLegacyFeatureException("The \"case\" directive can't be after "
                             + "the \"default\" directive since FreeMarker 3. You need to rearrange this \"switch\".",
-                            child.getBeginLine(), child.getBeginColumn());
+                            child);
                 }
             }
         }
@@ -612,7 +611,7 @@ public class FM2ASTToFM3SourceConverter {
         if (converted.equals("classicCompatible")) {
             throw new UnconvertableLegacyFeatureException("There \"classicCompatible\" setting doesn't exist in "
                     + "FreeMarker 3. You have to remove it manually before conversion.",
-                    node.getBeginLine(), node.getBeginColumn());
+                    node);
         }
         if (converted.equals("datetimeFormat")) {
             converted = "dateTimeFormat";
@@ -1549,20 +1548,20 @@ public class FM2ASTToFM3SourceConverter {
         COMPARATOR_OP_MAP.put("!=", "!=");
         COMPARATOR_OP_MAP.put("<", "<");
         COMPARATOR_OP_MAP.put("lt", "lt");
-        COMPARATOR_OP_MAP.put("\\lt", "\\lt");
-        COMPARATOR_OP_MAP.put("&lt;", "&lt;");
+        COMPARATOR_OP_MAP.put("\\lt", "lt");
+        COMPARATOR_OP_MAP.put("&lt;", "lt");
         COMPARATOR_OP_MAP.put("<=", "<=");
-        COMPARATOR_OP_MAP.put("lte", "lte");
-        COMPARATOR_OP_MAP.put("\\lte", "\\lte");
-        COMPARATOR_OP_MAP.put("&lt;=", "&lt;=");
+        COMPARATOR_OP_MAP.put("lte", "le");
+        COMPARATOR_OP_MAP.put("\\lte", "le");
+        COMPARATOR_OP_MAP.put("&lt;=", "le");
         COMPARATOR_OP_MAP.put(">", ">");
         COMPARATOR_OP_MAP.put("gt", "gt");
-        COMPARATOR_OP_MAP.put("\\gt", "\\gt");
-        COMPARATOR_OP_MAP.put("&gt;", "&gt;");
+        COMPARATOR_OP_MAP.put("\\gt", "gt");
+        COMPARATOR_OP_MAP.put("&gt;", "gt");
         COMPARATOR_OP_MAP.put(">=", ">=");
-        COMPARATOR_OP_MAP.put("gte", "gte");
-        COMPARATOR_OP_MAP.put("\\gte", "\\gte");
-        COMPARATOR_OP_MAP.put("&gt;=", "&gt;=");
+        COMPARATOR_OP_MAP.put("gte", "ge");
+        COMPARATOR_OP_MAP.put("\\gte", "ge");
+        COMPARATOR_OP_MAP.put("&gt;=", "ge");
     }
 
     private void printExpComparison(ComparisonExpression node) throws ConverterException {
@@ -1575,8 +1574,8 @@ public class FM2ASTToFM3SourceConverter {
         AND_OP_MAP = new HashMap<String, String>();
         AND_OP_MAP.put("&&", "&&");
         AND_OP_MAP.put("&", "&&");
-        AND_OP_MAP.put("\\and", "\\and");
-        AND_OP_MAP.put("&amp;&amp;", "&amp;&amp;");
+        AND_OP_MAP.put("\\and", "and");
+        AND_OP_MAP.put("&amp;&amp;", "and");
     }
 
     private void printExpAnd(AndExpression node) throws ConverterException {
@@ -1820,8 +1819,16 @@ public class FM2ASTToFM3SourceConverter {
                 node.getEndColumn(), node.getEndLine()));
     }
 
-    private void printExpIdentifier(Identifier node) {
-        print(TemplateLanguageUtils.escapeIdentifier(node.getName()));
+    private void printExpIdentifier(Identifier node) throws UnconvertableLegacyFeatureException {
+        Identifier name = node;
+        if (name.equals("ge") || name.equals("le") || name.equals("or") || name.equals("and")) {
+            // TODO [FM3] The plan is to extend the identifier syntax so that any variable name can be specified.
+            // (Although with FM2 syntax we could convert to `.var.ge`, it's not supported on all places where an
+            // identifier can occur, so we can't convert to that in some cases, so we wait for the real solution.)
+            throw new UnconvertableLegacyFeatureException(
+                    _StringUtils.jQuote(name) + " is a keyword now, so you must rename this variable.", node);
+        }
+        print(TemplateLanguageUtils.escapeIdentifier(name.getName()));
     }
 
     private void printExpMethodCall(MethodCall node) throws ConverterException {
@@ -1902,7 +1909,7 @@ public class FM2ASTToFM3SourceConverter {
                 throw new UnconvertableLegacyFeatureException(
                         "?default must be followed by a paramter list, like in ?default(1), "
                         + "otherwise it has no equivalent in FreeMarker 3.",
-                        node.getBeginLine(), node.getBeginColumn());
+                        node);
             }
             MethodCall parentCall = (MethodCall) parentNodeRel.parentNode;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-converter/src/main/java/org/apache/freemarker/converter/UnconvertableLegacyFeatureException.java
----------------------------------------------------------------------
diff --git a/freemarker-converter/src/main/java/org/apache/freemarker/converter/UnconvertableLegacyFeatureException.java b/freemarker-converter/src/main/java/org/apache/freemarker/converter/UnconvertableLegacyFeatureException.java
index c3a4d6e..5c173c9 100644
--- a/freemarker-converter/src/main/java/org/apache/freemarker/converter/UnconvertableLegacyFeatureException.java
+++ b/freemarker-converter/src/main/java/org/apache/freemarker/converter/UnconvertableLegacyFeatureException.java
@@ -19,12 +19,29 @@
 
 package org.apache.freemarker.converter;
 
+import freemarker.core.TemplateObject;
+
 /**
  * The legacy feature has no equivalent in the target format.
  */
+@SuppressWarnings({ "deprecation", "serial" })
 public class UnconvertableLegacyFeatureException extends ConverterException {
 
     /**
+     * @param astNode The position of the error is extracted from this.
+     */
+    public UnconvertableLegacyFeatureException(String message, TemplateObject astNode) {
+        this(message, astNode.getBeginLine(), astNode.getBeginColumn(), null);
+    }
+
+    /**
+     * @param astNode The position of the error is extracted from this.
+     */
+    public UnconvertableLegacyFeatureException(String message, TemplateObject astNode, Throwable cause) {
+        this(message, astNode.getBeginLine(), astNode.getBeginColumn(), cause);
+    }
+    
+    /**
      * @param row 1-based
      * @param column 1-based
      */

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java
----------------------------------------------------------------------
diff --git a/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java b/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java
index 048d534..a8bdadc 100644
--- a/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java
+++ b/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java
@@ -133,16 +133,23 @@ public class FM2ToFM3ConverterTest extends ConverterTest {
                 + "${(a<#--7-->><#--8-->b)}${(a<#--9-->>=<#--A-->b)}"
                 + "${a<#--B-->==<#--C-->b}${a<#--D-->!=<#--E-->b}");
         assertConverted("${a == b}${a == b}", "${a = b}${a == b}");
-        assertConvertedSame("${a &lt; b}${a lt b}${a \\lt b}");
-        assertConvertedSame("${a &lt;= b}${a lte b}${a \\lte b}");
-        assertConvertedSame("${a &gt; b}${a gt b}${a \\gt b}");
-        assertConvertedSame("${a &gt;= b}${a gte b}${a \\gte b}");
+        assertConverted("${a lt b}${a lt b}${a lt b}${a lt b}", "${a &lt; b}${a lt b}${a \\lt b}${a &lt; b}");
+        assertConverted("${a le b}${a le b}${a le b}${a le b}", "${a &lt;= b}${a lte b}${a \\lte b}${a &lt;= b}");
+        assertConverted("${a gt b}${a gt b}${a gt b}${a gt b}", "${a &gt; b}${a gt b}${a \\gt b}${a &gt; b}");
+        assertConverted("${a ge b}${a ge b}${a ge b}${a ge b}", "${a &gt;= b}${a gte b}${a \\gte b}${a &gt;= b}");
 
-        assertConverted("${a && b}${a && b}${a || b}${a || b}", "${a && b}${a & b}${a || b}${a | b}");
+        assertConverted("${a && b}${a && b}${a and b}${a and b}", "${a && b}${a & b}${a &amp;&amp; b}${a \\and b}");
+        assertConverted("${a || b}${a || b}", "${a || b}${a | b}");
         assertConverted(
                 "${a<#--1-->&&<#--2-->b}${a<#--3-->&&<#--4-->b}${a<#--5-->||<#--6-->b}${a<#--7-->||<#--8-->b}",
                 "${a<#--1-->&&<#--2-->b}${a<#--3-->&<#--4-->b}${a<#--5-->||<#--6-->b}${a<#--7-->|<#--8-->b}");
-        assertConvertedSame("${a &amp;&amp; b}${a \\and b}");
+        for (String newKeyword : new String[] { "and", "or", "le", "ge" }) {
+            try {
+                convert("${" + newKeyword + "}");
+            } catch (UnconvertableLegacyFeatureException e) {
+                assertThat(e.getMessage(), containsString("keyword"));
+            }
+        }
 
         assertConvertedSame("${!a}${! foo}${! <#--1--> bar}${!!c}");
 
@@ -552,6 +559,7 @@ public class FM2ToFM3ConverterTest extends ConverterTest {
         assertConvertedSame("${v!(d + 1)}");
         assertConvertedSame("${v!?upperCase}");
         assertConvertedSame("${(v!) + 'x'}");
+        assertConvertedSame("<@foo x=v! y=2 />");
         assertConverted("${v!(+1)}", "${v!+1}"); 
         assertConverted("${v!(-1)}", "${v!-1}"); 
         assertConverted("${v!(d+1)}", "${v!d+1}");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-core-test/src/test/java/org/apache/freemarker/core/FM3EscapedOperatorsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/FM3EscapedOperatorsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/FM3EscapedOperatorsTest.java
new file mode 100644
index 0000000..4c3f270
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/FM3EscapedOperatorsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import static org.junit.Assert.*;
+
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class FM3EscapedOperatorsTest extends TemplateTest {
+    
+    @Test
+    public void testComparisonResults() throws Exception {
+        assertOutput("${(1 < 2)?c} ${(1 < 1)?c} ${(1 lt 2)?c} ${(1 lt 1)?c}", "true false true false");
+        assertOutput("${(1 <= 2)?c} ${(1 <= 1)?c} ${(1 le 2)?c} ${(1 le 1)?c}", "true true true true");
+        assertOutput("${(2 > 1)?c} ${(1 > 1)?c} ${(2 gt 1)?c} ${(1 gt 1)?c}", "true false true false");
+        assertOutput("${(2 >= 1)?c} ${(1 >= 1)?c} ${(2 ge 1)?c} ${(1 ge 1)?c}", "true true true true");
+    }
+
+    @Test
+    public void testLogicalAndResults() throws Exception {
+        assertOutput("${(true && true)?c} ${(true && false)?c} ${(true and true)?c} ${(true and false)?c}",
+                "true false true false");
+    }
+
+    @Test
+    public void testLogicalOrResults() throws Exception {
+        assertOutput("${(true || false)?c} ${(false || false)?c} ${(true or false)?c} ${(false or false)?c}",
+                "true false true false");
+    }
+    
+    @Test
+    public void testCanonicalForm() throws Exception {
+        assertEquals(
+                "${a && b and c || d or f} ${a < b}  ${a lt b}",
+                new Template(null, "${a && b and c || d or f} ${a < b}  ${a lt b}",
+                getConfiguration()).toString());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
index 9780377..8c36cbf 100644
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
@@ -71,10 +71,10 @@
 <#else>
     boolean4 && boolean5 failed.<br />
 </#if></p>
-<@assert true &amp;&amp; true />
-<@assert !(false &amp;&amp; true) />
-<@assert true \and true />
-<@assert !(false \and true) />
+<@assert true && true />
+<@assert !(false && true) />
+<@assert true and true />
+<@assert !(false and true) />
  
 <p>Now test list models:</p>
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
index 0d3d3b0..ec60b26 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
@@ -26,10 +26,12 @@ final class ASTExpAnd extends ASTExpBoolean {
 
     private final ASTExpression lho;
     private final ASTExpression rho;
+    private final String opString;
 
-    ASTExpAnd(ASTExpression lho, ASTExpression rho) {
+    ASTExpAnd(ASTExpression lho, ASTExpression rho, String opString) {
         this.lho = lho;
         this.rho = rho;
+        this.opString = opString.intern();
     }
 
     @Override
@@ -39,7 +41,7 @@ final class ASTExpAnd extends ASTExpBoolean {
 
     @Override
     public String getCanonicalForm() {
-        return lho.getCanonicalForm() + " && " + rho.getCanonicalForm();
+        return lho.getCanonicalForm() + " " + opString + " " + rho.getCanonicalForm();
     }
 
     @Override
@@ -57,7 +59,8 @@ final class ASTExpAnd extends ASTExpBoolean {
             String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
     	return new ASTExpAnd(
     	        lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
-    	        rho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState));
+    	        rho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
+    	        opString);
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
index 4f429ac..c7d92f0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
@@ -40,16 +40,16 @@ final class ASTExpComparison extends ASTExpBoolean {
             operation = _EvalUtils.CMP_OP_EQUALS;
         } else if (opString == "!=") {
             operation = _EvalUtils.CMP_OP_NOT_EQUALS;
-        } else if (opString == "gt" || opString == "\\gt" || opString == ">" || opString == "&gt;") {
+        } else if (opString == ">" || opString == "gt") {
             operation = _EvalUtils.CMP_OP_GREATER_THAN;
-        } else if (opString == "gte" || opString == "\\gte" || opString == ">=" || opString == "&gt;=") {
+        } else if (opString == ">=" || opString == "ge") {
             operation = _EvalUtils.CMP_OP_GREATER_THAN_EQUALS;
-        } else if (opString == "lt" || opString == "\\lt" || opString == "<" || opString == "&lt;") {
+        } else if (opString == "<" || opString == "lt") {
             operation = _EvalUtils.CMP_OP_LESS_THAN;
-        } else if (opString == "lte" || opString == "\\lte" || opString == "<=" || opString == "&lt;=") {
+        } else if (opString == "<=" || opString == "le") {
             operation = _EvalUtils.CMP_OP_LESS_THAN_EQUALS;
         } else {
-            throw new BugException("Unknown comparison operator " + opString);
+            throw new BugException("Unknown comparison operator: " + opString);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
index 26dab92..e9d64a0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
@@ -26,10 +26,12 @@ final class ASTExpOr extends ASTExpBoolean {
 
     private final ASTExpression lho;
     private final ASTExpression rho;
+    private final String opString;
 
-    ASTExpOr(ASTExpression lho, ASTExpression rho) {
+    ASTExpOr(ASTExpression lho, ASTExpression rho, String opString) {
         this.lho = lho;
         this.rho = rho;
+        this.opString = opString.intern();
     }
 
     @Override
@@ -39,7 +41,7 @@ final class ASTExpOr extends ASTExpBoolean {
 
     @Override
     public String getCanonicalForm() {
-        return lho.getCanonicalForm() + " || " + rho.getCanonicalForm();
+        return lho.getCanonicalForm() + " " + opString + " " + rho.getCanonicalForm();
     }
     
     @Override
@@ -57,7 +59,8 @@ final class ASTExpOr extends ASTExpBoolean {
             String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
     	return new ASTExpOr(
     	        lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
-    	        rho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState));
+    	        rho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
+    	        opString);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/b16e37ae/freemarker-core/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/javacc/FTL.jj b/freemarker-core/src/main/javacc/FTL.jj
index 0479dbc..33a86da 100644
--- a/freemarker-core/src/main/javacc/FTL.jj
+++ b/freemarker-core/src/main/javacc/FTL.jj
@@ -1045,13 +1045,13 @@ TOKEN:
     |
     <MINUS_MINUS : "--">
     |
-    <LESS_THAN : "lt" | "\\lt" | "<" | "&lt;">
+    <LESS_THAN : "lt" | "<">
     |
-    <LESS_THAN_EQUALS : "lte" | "\\lte" | "<=" | "&lt;=">
+    <LESS_THAN_EQUALS : "le" | "<=">
     |
-    <ESCAPED_GT: "gt" | "\\gt" |  "&gt;">
+    <ESCAPED_GT: "gt">
     |
-    <ESCAPED_GTE : "gte" | "\\gte" | "&gt;=">
+    <ESCAPED_GTE : "ge">
     |
     <PLUS : "+">
     |
@@ -1067,9 +1067,9 @@ TOKEN:
     |
     <PERCENT : "%">
     |
-    <AND : "&&" | "&amp;&amp;" | "\\and">
+    <AND : "&&" | "and">
     |
-    <OR : "||">
+    <OR : "||" | "or">
     |
     <EXCLAM : "!">
     |
@@ -1718,17 +1718,18 @@ ASTExpression RangeExpression() :
 ASTExpression ASTExpAnd() :
 {
     ASTExpression lhs, rhs, result;
+    Token tk;
 }
 {
     lhs = EqualityExpression() { result = lhs; }
     (
         LOOKAHEAD(<AND>)
-        <AND>
+        tk = <AND>
         rhs = EqualityExpression()
         {
             booleanLiteralOnly(lhs);
             booleanLiteralOnly(rhs);
-            result = new ASTExpAnd(lhs, rhs);
+            result = new ASTExpAnd(lhs, rhs, tk.image);
             result.setLocation(template, lhs, rhs);
             lhs = result;
         }
@@ -1741,17 +1742,18 @@ ASTExpression ASTExpAnd() :
 ASTExpression ASTExpOr() :
 {
     ASTExpression lhs, rhs, result;
+    Token tk;
 }
 {
     lhs = ASTExpAnd() { result = lhs; }
     (
         LOOKAHEAD(<OR>)
-        <OR>
+        tk = <OR>
         rhs = ASTExpAnd()
         {
             booleanLiteralOnly(lhs);
             booleanLiteralOnly(rhs);
-            result = new ASTExpOr(lhs, rhs);
+            result = new ASTExpOr(lhs, rhs, tk.image);
             result.setLocation(template, lhs, rhs);
             lhs = result;
         }