FREEMARKER-65: Utilities for argument validation: Work in progress. Changes in 
this commit:

- Added org.apache.freemarker.core.util.CallableUtils (published API), to help 
in implementing (and invoking) TemplateCallableModel-s.
- Removed UnexpectedTypeException (a `TemplateException subclass) and its 
subclasses (NonStringException, etc.),
  using simple TemplateException instead. Catching these exceptions 
specifically wasn't very useful, while they
  have bloated the public API (and the code).


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

Branch: refs/heads/3
Commit: f231e64fe8e4e9a2786966506aeef79d0dd36fcd
Parents: e941aed
Author: ddekany <ddek...@apache.org>
Authored: Wed Aug 16 17:21:41 2017 +0200
Committer: ddekany <ddek...@apache.org>
Committed: Thu Aug 17 01:24:25 2017 +0200

----------------------------------------------------------------------
 FM3-CHANGE-LOG.txt                              |   5 +-
 ...a8DefaultObjectWrapperBridgeMethodsTest.java |   6 +-
 .../impl/Java8DefaultObjectWrapperTest.java     |  10 +-
 .../freemarker/core/OutputFormatTest.java       |   2 +-
 .../core/TemplateCallableModelTest.java         |   1 +
 .../impl/AbstractParallelIntrospectionTest.java |   4 +-
 .../model/impl/DefaultObjectWrapperTest.java    |  10 +-
 .../core/model/impl/EnumModelsTest.java         |   4 +-
 .../core/model/impl/StaticModelsTest.java       |   4 +-
 .../core/templatesuite/models/MultiModel2.java  |   4 +-
 .../core/userpkg/AllFeaturesDirective.java      |   2 +-
 .../core/userpkg/AllFeaturesFunction.java       |   2 +-
 .../templates/boolean-formatting.ftl            |   2 +-
 .../freemarker/core/ASTDirAssignment.java       |   9 +-
 .../apache/freemarker/core/ASTDirInclude.java   |  14 +-
 .../org/apache/freemarker/core/ASTDirList.java  |  23 +-
 .../apache/freemarker/core/ASTDirRecurse.java   |   6 +-
 .../org/apache/freemarker/core/ASTDirVisit.java |   5 +-
 .../freemarker/core/ASTDynamicTopLevelCall.java |   5 +-
 .../freemarker/core/ASTExpAddOrConcat.java      |  78 ++-
 .../org/apache/freemarker/core/ASTExpDot.java   |   2 +-
 .../freemarker/core/ASTExpDynamicKeyName.java   |  69 +--
 .../freemarker/core/ASTExpFunctionCall.java     |   3 +-
 .../freemarker/core/ASTExpHashLiteral.java      |   6 +-
 .../freemarker/core/ASTExpNegateOrPlus.java     |   2 +-
 .../org/apache/freemarker/core/ASTExpRange.java |   6 -
 .../apache/freemarker/core/ASTExpression.java   |   4 +-
 .../apache/freemarker/core/BuiltInForDate.java  |  17 +-
 .../freemarker/core/BuiltInForHashEx.java       |   2 +-
 .../core/BuiltInForLegacyEscaping.java          |   3 +-
 .../freemarker/core/BuiltInForMarkupOutput.java |   2 +-
 .../apache/freemarker/core/BuiltInForNode.java  |   8 +-
 .../freemarker/core/BuiltInForNodeEx.java       |   2 +-
 .../freemarker/core/BuiltInForSequence.java     |   3 +-
 .../freemarker/core/BuiltInsForDates.java       |   4 +-
 .../core/BuiltInsForExistenceHandling.java      |   3 +-
 .../core/BuiltInsForMultipleTypes.java          |  30 +-
 .../BuiltInsForNestedContentParameters.java     |   5 +-
 .../freemarker/core/BuiltInsForNodes.java       |   5 +-
 .../freemarker/core/BuiltInsForSequences.java   |  36 +-
 .../core/BuiltInsForStringsBasic.java           |  14 +-
 .../core/BuiltInsForStringsEncoding.java        |   2 +-
 .../freemarker/core/BuiltInsForStringsMisc.java |  11 +-
 .../core/BuiltInsForStringsRegexp.java          |   6 +-
 .../org/apache/freemarker/core/Environment.java |  36 +-
 .../apache/freemarker/core/MessageUtils.java    | 117 ++++-
 .../freemarker/core/NonBooleanException.java    |  62 ---
 .../freemarker/core/NonDateException.java       |  58 ---
 .../freemarker/core/NonDirectiveException.java  |  63 ---
 .../core/NonExtendedHashException.java          |  62 ---
 .../core/NonExtendedNodeException.java          |  62 ---
 .../freemarker/core/NonFunctionException.java   |  62 ---
 .../freemarker/core/NonHashException.java       |  62 ---
 .../core/NonMarkupOutputException.java          |  62 ---
 .../freemarker/core/NonNamespaceException.java  |  61 ---
 .../freemarker/core/NonNodeException.java       |  62 ---
 .../freemarker/core/NonNumericalException.java  |  84 ----
 .../freemarker/core/NonSequenceException.java   |  62 ---
 .../core/NonSequenceOrCollectionException.java  |  90 ----
 .../freemarker/core/NonStringException.java     |  84 ----
 .../NonStringOrTemplateOutputException.java     |  78 ---
 .../freemarker/core/TemplateException.java      |   1 +
 .../core/UnexpectedTypeException.java           | 171 -------
 .../apache/freemarker/core/_CallableUtils.java  | 490 +-----------------
 .../org/apache/freemarker/core/_CoreAPI.java    |   4 +
 .../org/apache/freemarker/core/_EvalUtils.java  |  42 +-
 .../core/model/GeneralPurposeNothing.java       |  10 +-
 .../model/impl/OverloadedFixArgsMethods.java    |   4 +-
 .../model/impl/OverloadedVarArgsMethods.java    |   4 +-
 .../core/model/impl/ResourceBundleModel.java    |   4 +-
 .../core/model/impl/SimpleMethod.java           |   4 +-
 .../freemarker/core/util/CallableUtils.java     | 496 +++++++++++++++++++
 .../core/util/TemplateLanguageUtils.java        |   6 +
 freemarker-core/src/main/javacc/FTL.jj          |   4 +-
 74 files changed, 927 insertions(+), 1921 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index 0d6a14b..0c69572 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -471,7 +471,10 @@ Core / Miscellaneous
 - CallPlaceCustomDataInitializationException is not a checked exception 
anymore (now it extends RuntimeException)
 - Renamed `FTLUtil` to `TemplateLanguageUtils` (as the FTL name will be 
abandoned in FM3, and supporting multiple
   languages are planned in the future)
-
+- Removed `UnexpectedTypeException` (a `TemplateException` subclass) and its 
subclasses (`NonStringException`, etc.),
+  using simple `TemplateException` instead. Catching these exceptions 
specifically wasn't very useful, while they
+  have bloated the public API (and the code).
+- Added `org.apache.freemarker.core.util.CallableUtils`, to help in 
implementing (and invoking) `TemplateCallableModel`-s.
 
 Build / development process changes
 -----------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
 
b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
index 62bb7af..9c87b53 100644
--- 
a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
+++ 
b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.*;
 import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.NonTemplateCallPlace;
 import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.junit.Test;
 
@@ -56,10 +56,10 @@ public class Java8DefaultObjectWrapperBridgeMethodsTest {
         JavaMethodModel m1 = (JavaMethodModel) wrapped.get("m1");
         assertEquals(
                 BridgeMethodsBean.M1_RETURN_VALUE,
-                "" + m1.execute(_CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE));
+                "" + m1.execute(CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE));
 
         JavaMethodModel m2 = (JavaMethodModel) wrapped.get("m2");
-        assertNull(m2.execute(_CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE));
+        assertNull(m2.execute(CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE));
     }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
 
b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
index cf628ad..fcd8f23 100644
--- 
a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
+++ 
b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.*;
 import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.NonTemplateCallPlace;
 import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateNumberModel;
@@ -129,7 +129,7 @@ public class Java8DefaultObjectWrapperTest {
             assertEquals(
                     Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
                     ((TemplateScalarModel) action.execute(
-                            _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
+                            CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
                             .getAsString());
         }
         
@@ -140,7 +140,7 @@ public class Java8DefaultObjectWrapperTest {
             assertEquals(
                     Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
                     ((TemplateScalarModel) action.execute(
-                            _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
+                            CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
                             .getAsString());
         }
         {
@@ -150,7 +150,7 @@ public class Java8DefaultObjectWrapperTest {
             assertEquals(
                     Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE,
                     ((TemplateScalarModel) action.execute(
-                            _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
+                            CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
                             .getAsString());
         }
         {
@@ -160,7 +160,7 @@ public class Java8DefaultObjectWrapperTest {
             assertEquals(
                     
Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
                     ((TemplateScalarModel) action.execute(
-                            _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
+                            CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
                             .getAsString());
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
index 2bda427..51a0070 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
@@ -598,7 +598,7 @@ public class OutputFormatTest extends TemplateTest {
                 "noSuchVar", "null or missing");
         assertErrorContains(
                 "${'x'?markupString}",
-                "xpected", "markup output", "string");
+                "xpected", "markupOutput", "string");
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
index cbe1c5c..ec7b225 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
@@ -249,6 +249,7 @@ public class TemplateCallableModelTest extends TemplateTest 
{
         assertErrorContains("${'x'?leftPad(null)}", "?leftPad", "1st", "null");
         addTemplate("foo.ftl", "<#macro m n1></#macro>");
         assertErrorContains("<#import 'foo.ftl' as f><@f.m/>", "macro", 
"\"foo.ftl:m\"");
+        assertErrorContains("<#function myF(p1)></#function><#assign f2 = 
myF>${f2()}", "\"myF\"");
         addToDataModel("bean", new TestBean());
         assertErrorContains("${bean.intMP()}", "method", 
"org.apache.freemarker.test.TemplateTest$TestBean.intMP");
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
index cbccd66..49d4009 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
@@ -22,7 +22,7 @@ package org.apache.freemarker.core.model.impl;
 import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.NonTemplateCallPlace;
 import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateNumberModel;
@@ -117,7 +117,7 @@ public abstract class AbstractParallelIntrospectionTest 
extends TestCase {
             JavaMethodModel pv = (JavaMethodModel) h.get("m" + mIdx);
             final int expected = objIdx * 1000 + mIdx;
             final int got = ((TemplateNumberModel) pv.execute(
-                    _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
+                    CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
                     .getAsNumber().intValue();
             if (got != expected) {
                 throw new AssertionError("Method assertion failed; " +

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
index a1dfba6..0f9722e 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
@@ -45,7 +45,7 @@ import org.apache.freemarker.core.NonTemplateCallPlace;
 import org.apache.freemarker.core.Template;
 import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core._CoreAPI;
 import org.apache.freemarker.core.model.AdapterTemplateModel;
 import org.apache.freemarker.core.model.ObjectWrapper;
@@ -193,7 +193,7 @@ public class DefaultObjectWrapperTest {
         {
             // Check method calls, and also if the return value is wrapped 
with the overidden "wrap".
             final TemplateModel mr = ((JavaMethodModel) bean.get("m")).execute(
-                    _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE);
+                    CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE);
             assertEquals(Collections.singletonList(1), ow.unwrap(mr));
             assertTrue(DefaultListAdapter.class.isInstance(mr));
         }
@@ -586,7 +586,7 @@ public class DefaultObjectWrapperTest {
 
         TemplateHashModel api = (TemplateHashModel) iteratorAdapter.getAPI();
         assertFalse(((TemplateBooleanModel) ((JavaMethodModel)
-                
api.get("hasNext")).execute(_CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
+                
api.get("hasNext")).execute(CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE))
                 .getAsBoolean());
     }
 
@@ -677,7 +677,7 @@ public class DefaultObjectWrapperTest {
 
         TemplateHashModel api = (TemplateHashModel) enumAdapter.getAPI();
         assertFalse(((TemplateBooleanModel) ((JavaMethodModel) 
api.get("hasMoreElements"))
-                .execute(_CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE)).getAsBoolean());
+                .execute(CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE)).getAsBoolean());
     }
 
     @Test
@@ -734,7 +734,7 @@ public class DefaultObjectWrapperTest {
         TemplateHashModel apiModel = (TemplateHashModel) 
((TemplateModelWithAPISupport) normalModel).getAPI();
         JavaMethodModel sizeMethod = (JavaMethodModel) apiModel.get("size");
         TemplateNumberModel r = (TemplateNumberModel) sizeMethod.execute(
-                _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE);
+                CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE);
         assertEquals(expectedSize, r.getAsNumber().intValue());
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
index 7dc7879..89b6ec5 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.*;
 
 import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.NonTemplateCallPlace;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
@@ -59,7 +59,7 @@ public class EnumModelsTest {
         assertEquals(((TemplateScalarModel) a).getAsString(), "ts:A");
         JavaMethodModel nameMethod = (JavaMethodModel) ((TemplateHashModel) 
a).get("name");
         assertEquals(((TemplateScalarModel) nameMethod.execute(
-                _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE)).getAsString(),
+                CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE)).getAsString(),
                 "A");
         
         assertSame(e, enums.get(E.class.getName()));

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
index 2487105..241b349 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
@@ -24,7 +24,7 @@ import static org.junit.Assert.*;
 
 import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.NonTemplateCallPlace;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
@@ -66,7 +66,7 @@ public class StaticModelsTest {
         TemplateModel m = s.get("m");
         assertTrue(m instanceof JavaMethodModel);
         assertEquals(((TemplateScalarModel) ((JavaMethodModel) m).execute(
-                _CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE)).getAsString(),
+                CallableUtils.EMPTY_TEMPLATE_MODEL_ARRAY, 
NonTemplateCallPlace.INSTANCE)).getAsString(),
                 "m OK");
         
         assertSame(s, statics.get(S.class.getName()));

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/MultiModel2.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/MultiModel2.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/MultiModel2.java
index e56c0a2..96e4a7a 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/MultiModel2.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/MultiModel2.java
@@ -22,7 +22,7 @@ package org.apache.freemarker.core.templatesuite.models;
 import org.apache.freemarker.core.CallPlace;
 import org.apache.freemarker.core.Environment;
 import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core._CallableUtils;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.model.ArgumentArrayLayout;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
 import org.apache.freemarker.core.model.TemplateModel;
@@ -43,7 +43,7 @@ public class MultiModel2 implements TemplateScalarModel, 
TemplateFunctionModel {
     public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, 
Environment env) throws TemplateException {
         StringBuilder  aResults = new StringBuilder( "Arguments are:<br />" );
         for (int i = 0; i < args.length; i++) {
-            aResults.append(_CallableUtils.getStringArgument(args, i, this));
+            aResults.append(CallableUtils.getStringArgument(args, i, this));
             aResults.append("<br />");
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
index 3931a67..9302345 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core.userpkg;
 
-import static org.apache.freemarker.core._CallableUtils.*;
+import static org.apache.freemarker.core.util.CallableUtils.*;
 
 import java.io.IOException;
 import java.io.Writer;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesFunction.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesFunction.java
 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesFunction.java
index 261c369..e6ad111 100644
--- 
a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesFunction.java
+++ 
b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesFunction.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core.userpkg;
 
-import static org.apache.freemarker.core._CallableUtils.*;
+import static org.apache.freemarker.core.util.CallableUtils.*;
 
 import org.apache.freemarker.core.CallPlace;
 import org.apache.freemarker.core.Environment;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean-formatting.ftl
----------------------------------------------------------------------
diff --git 
a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean-formatting.ftl
 
b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean-formatting.ftl
index 72dc253..95bee38 100644
--- 
a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean-formatting.ftl
+++ 
b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean-formatting.ftl
@@ -47,7 +47,7 @@
 <#setting booleanFormat = 'y,n'>
 <#assign x = false>
 <#assign n = 123><#assign m = { x: 'foo', n: 'bar' }><@assertEquals 
actual=m['n'] + m['123'] expected='foobar' />
-<@assertFails exception="UnexpectedTypeException">${m[false]}</@>
+<@assertFails message="boolean">${m[false]}</@>
 <@assertFails message="can't compare">${x == 'false'}</@>
 <@assertFails message="can't compare">${x != 'false'}</@>
 <@assertFails message="can't 
convert">${booleanVsStringMethods.expectsString(x)}</@>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
index 09bf4ea..7efa95c 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
@@ -123,7 +123,11 @@ final class ASTDirAssignment extends ASTDirective {
             try {
                 namespace = (Environment.Namespace) namespaceTM;
             } catch (ClassCastException e) {
-                throw new NonNamespaceException(namespaceExp, namespaceTM, 
env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        namespaceExp, namespaceTM,
+                        "namespace",
+                        new Class[] { Environment.Namespace.class },
+                        null, env);
             }
             if (namespace == null) {
                 throw InvalidReferenceException.getInstance(namespaceExp, env);
@@ -158,7 +162,8 @@ final class ASTDirAssignment extends ASTDirective {
                 } else if (lhoValue == null) {
                     throw InvalidReferenceException.getInstance(variableName, 
getOperatorTypeAsString(), env);
                 } else {
-                    throw new NonNumericalException(variableName, lhoValue, 
null, env);
+                    throw 
MessageUtils.newUnexpectedAssignmentTargetTypeException(
+                            variableName, lhoValue, TemplateNumberModel.class, 
env);
                 }
 
                 if (operatorType == OPERATOR_TYPE_PLUS_PLUS) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
index 37cc017..76ce1f6 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
@@ -22,7 +22,6 @@ package org.apache.freemarker.core;
 import java.io.IOException;
 
 import 
org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
-import org.apache.freemarker.core.util.BugException;
 import org.apache.freemarker.core.util._StringUtils;
 
 /**
@@ -45,16 +44,11 @@ final class ASTDirInclude extends ASTDirective {
         this.ignoreMissingExp = ignoreMissingExp;
         if (ignoreMissingExp != null && ignoreMissingExp.isLiteral()) {
             try {
-                try {
-                    ignoreMissingExpPrecalcedValue = Boolean.valueOf(
-                            
ignoreMissingExp.evalToBoolean(template.getConfiguration()));
-                } catch (NonBooleanException e) {
-                    throw new ParseException("Expected a boolean as the value 
of the \"ignore_missing\" attribute",
-                            ignoreMissingExp, e);
-                }
+                ignoreMissingExpPrecalcedValue = Boolean.valueOf(
+                        
ignoreMissingExp.evalToBoolean(template.getConfiguration()));
             } catch (TemplateException e) {
-                // evaluation of literals must not throw a TemplateException
-                throw new BugException(e);
+                throw new ParseException("Expected a boolean as the value of 
the \"ignore_missing\" attribute",
+                        ignoreMissingExp, e);
             }
         } else {
             ignoreMissingExpPrecalcedValue = null;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
index 7878e97..2182a5c 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
@@ -304,17 +304,19 @@ final class ASTDirList extends ASTDirective {
                         env.visit(childBuffer);
                     }
                 }
-            } else if (listedValue instanceof TemplateHashModelEx
-                    && 
!NonSequenceOrCollectionException.isWrappedIterable(listedValue)) {
-                throw new NonSequenceOrCollectionException(env,
+            } else if (listedValue instanceof TemplateHashModelEx) {
+                throw new TemplateException(env,
                         new _ErrorDescriptionBuilder("The value you try to 
list is ",
                                 new _DelayedAOrAn(new 
_DelayedTemplateLanguageTypeDescription(listedValue)),
                                 ", thus you must declare two nested content 
parameters after the \"as\"; one for the "
                                 + "key, and another for the value, like ", 
"<#... as k, v>", ")."
                                 ));
             } else {
-                throw new NonSequenceOrCollectionException(
-                        listedExp, listedValue, env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        listedExp, listedValue,
+                        MessageUtils.SEQUENCE_OR_COLLECTION,
+                        MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
+                        null, env);
             }
             return listNotEmpty;
         }
@@ -359,13 +361,14 @@ final class ASTDirList extends ASTDirective {
                                 do {
                                     nestedContentParam = keysIter.next();
                                     if (!(nestedContentParam instanceof 
TemplateScalarModel)) {
-                                        throw new NonStringException(env,
+                                        throw new TemplateException(env,
                                                 new _ErrorDescriptionBuilder(
                                                         "When listing 
key-value pairs of traditional hash "
                                                         + "implementations, 
all keys must be strings, but one of them "
                                                         + "was ",
                                                         new _DelayedAOrAn(
-                                                                new 
_DelayedTemplateLanguageTypeDescription(nestedContentParam)),
+                                                                new 
_DelayedTemplateLanguageTypeDescription(
+                                                                        
nestedContentParam)),
                                                         "."
                                                         ).tip("The listed 
value's TemplateModel class was ",
                                                                 new 
_DelayedShortClassName(listedValue.getClass()),
@@ -389,15 +392,15 @@ final class ASTDirList extends ASTDirective {
                 }
             } else if (listedValue instanceof TemplateCollectionModel
                     || listedValue instanceof TemplateSequenceModel) {
-                throw new NonSequenceOrCollectionException(env,
+                throw new TemplateException(env,
                         new _ErrorDescriptionBuilder("The value you try to 
list is ",
                                 new _DelayedAOrAn(new 
_DelayedTemplateLanguageTypeDescription(listedValue)),
                                 ", thus you must declare only one nested 
content parameter after the \"as\" (there's "
                                 + "no separate key and value)."
                                 ));
             } else {
-                throw new NonExtendedHashException(
-                        listedExp, listedValue, env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        listedExp, listedValue, TemplateHashModelEx.class, 
env);
             }
             return hashNotEmpty;
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
index 17842ec..7fe528b 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
@@ -44,7 +44,8 @@ final class ASTDirRecurse extends ASTDirective {
     ASTElement[] accept(Environment env) throws IOException, TemplateException 
{
         TemplateModel node = targetNode == null ? null : targetNode.eval(env);
         if (node != null && !(node instanceof TemplateNodeModel)) {
-            throw new NonNodeException(targetNode, node, "node", env);
+            throw MessageUtils.newUnexpectedOperandTypeException(
+                    targetNode, node, TemplateNodeModel.class, env);
         }
         
         TemplateModel nss = namespaces == null ? null : namespaces.eval(env);
@@ -60,7 +61,8 @@ final class ASTDirRecurse extends ASTDirective {
                 nss = ss;
             } else if (!(nss instanceof TemplateSequenceModel)) {
                 if (namespaces != null) {
-                    throw new NonSequenceException(namespaces, nss, env);
+                    throw MessageUtils.newUnexpectedOperandTypeException(
+                            namespaces, nss, TemplateSequenceModel.class, env);
                 } else {
                     // Should not occur
                     throw new TemplateException(env, "Expecting a sequence of 
namespaces after \"using\"");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
index fd49371..b7438a0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
@@ -43,7 +43,7 @@ final class ASTDirVisit extends ASTDirective {
     ASTElement[] accept(Environment env) throws IOException, TemplateException 
{
         TemplateModel node = targetNode.eval(env);
         if (!(node instanceof TemplateNodeModel)) {
-            throw new NonNodeException(targetNode, node, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(targetNode, 
node, TemplateNodeModel.class, env);
         }
         
         TemplateModel nss = namespaces == null ? null : namespaces.eval(env);
@@ -59,7 +59,8 @@ final class ASTDirVisit extends ASTDirective {
                 nss = ss;
             } else if (!(nss instanceof TemplateSequenceModel)) {
                 if (namespaces != null) {
-                    throw new NonSequenceException(namespaces, nss, env);
+                    throw MessageUtils.newUnexpectedOperandTypeException(
+                            namespaces, nss, TemplateSequenceModel.class, env);
                 } else {
                     // Should not occur
                     throw new TemplateException(env, "Expecting a sequence of 
namespaces after \"using\"");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
index e4b3c17..7e713bd 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
@@ -98,7 +98,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements 
CallPlace  {
                 nestedContentSupported = directive.isNestedContentSupported();
             } else if (callableValueTM instanceof TemplateFunctionModel) {
                 if (!allowCallingFunctions) {
-                    throw new NonDirectiveException(
+                    throw new TemplateException(
                             "Calling functions is not allowed. You can only 
call directives (like macros) here.", env);
                 }
                 callableValue = (TemplateCallableModel) callableValueTM;
@@ -109,7 +109,8 @@ class ASTDynamicTopLevelCall extends ASTDirective 
implements CallPlace  {
             } else if (callableValueTM == null) {
                 throw InvalidReferenceException.getInstance(callableValueExp, 
env);
             } else {
-                throw new NonDirectiveException(callableValueExp, 
callableValueTM, env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        callableValueExp, callableValueTM, 
TemplateDirectiveModel.class, env);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
index 4385dac..79081e8 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
@@ -76,53 +76,43 @@ final class ASTExpAddOrConcat extends ASTExpression {
         } else {
             boolean hashConcatPossible
                     = leftModel instanceof TemplateHashModel && rightModel 
instanceof TemplateHashModel;
-            try {
-                // We try string addition first. If hash addition is possible, 
then instead of throwing exception
-                // we return null and do hash addition instead. (We can't 
simply give hash addition a priority, like
-                // with sequence addition above, as FTL strings are often also 
FTL hashes.)
-                Object leftOMOrStr = _EvalUtils.coerceModelToStringOrMarkup(
-                        leftModel, leftExp, /* returnNullOnNonCoercableType = 
*/ hashConcatPossible, null,
-                        env);
-                if (leftOMOrStr == null) {
-                    return _eval_concatenateHashes(leftModel, rightModel);
-                }
+            // We try string addition first. If hash addition is possible, 
then instead of throwing exception
+            // we return null and do hash addition instead. (We can't simply 
give hash addition a priority, like
+            // with sequence addition above, as FTL strings are often also FTL 
hashes.)
+            Object leftOMOrStr = _EvalUtils.coerceModelToStringOrMarkup(
+                    leftModel, leftExp, /* returnNullOnNonCoercableType = */ 
hashConcatPossible, null,
+                    env);
+            if (leftOMOrStr == null) {
+                return _eval_concatenateHashes(leftModel, rightModel);
+            }
 
-                // Same trick with null return as above.
-                Object rightOMOrStr = _EvalUtils.coerceModelToStringOrMarkup(
-                        rightModel, rightExp, /* returnNullOnNonCoercableType 
= */ hashConcatPossible, null,
-                        env);
-                if (rightOMOrStr == null) {
-                    return _eval_concatenateHashes(leftModel, rightModel);
-                }
+            // Same trick with null return as above.
+            Object rightOMOrStr = _EvalUtils.coerceModelToStringOrMarkup(
+                    rightModel, rightExp, /* returnNullOnNonCoercableType = */ 
hashConcatPossible, null,
+                    env);
+            if (rightOMOrStr == null) {
+                return _eval_concatenateHashes(leftModel, rightModel);
+            }
 
-                if (leftOMOrStr instanceof String) {
-                    if (rightOMOrStr instanceof String) {
-                        return new SimpleScalar(((String) 
leftOMOrStr).concat((String) rightOMOrStr));
-                    } else { // rightOMOrStr instanceof 
TemplateMarkupOutputModel
-                        TemplateMarkupOutputModel<?> rightMO = 
(TemplateMarkupOutputModel<?>) rightOMOrStr; 
-                        return _EvalUtils.concatMarkupOutputs(parent,
-                                
rightMO.getOutputFormat().fromPlainTextByEscaping((String) leftOMOrStr),
-                                rightMO);
-                    }                    
-                } else { // leftOMOrStr instanceof TemplateMarkupOutputModel 
-                    TemplateMarkupOutputModel<?> leftMO = 
(TemplateMarkupOutputModel<?>) leftOMOrStr; 
-                    if (rightOMOrStr instanceof String) {  // markup output
-                        return _EvalUtils.concatMarkupOutputs(parent,
-                                leftMO,
-                                
leftMO.getOutputFormat().fromPlainTextByEscaping((String) rightOMOrStr));
-                    } else { // rightOMOrStr instanceof 
TemplateMarkupOutputModel
-                        return _EvalUtils.concatMarkupOutputs(parent,
-                                leftMO,
-                                (TemplateMarkupOutputModel<?>) rightOMOrStr);
-                    }
+            if (leftOMOrStr instanceof String) {
+                if (rightOMOrStr instanceof String) {
+                    return new SimpleScalar(((String) 
leftOMOrStr).concat((String) rightOMOrStr));
+                } else { // rightOMOrStr instanceof TemplateMarkupOutputModel
+                    TemplateMarkupOutputModel<?> rightMO = 
(TemplateMarkupOutputModel<?>) rightOMOrStr;
+                    return _EvalUtils.concatMarkupOutputs(parent,
+                            
rightMO.getOutputFormat().fromPlainTextByEscaping((String) leftOMOrStr),
+                            rightMO);
                 }
-            } catch (NonStringOrTemplateOutputException e) {
-                // 2.4: Remove this catch; it's for BC, after reworking hash 
addition so it doesn't rely on this. But
-                // user code might throws this (very unlikely), and then in 
2.3.x we did catch that too, incorrectly.
-                if (hashConcatPossible) {
-                    return _eval_concatenateHashes(leftModel, rightModel);
-                } else {
-                    throw e;
+            } else { // leftOMOrStr instanceof TemplateMarkupOutputModel
+                TemplateMarkupOutputModel<?> leftMO = 
(TemplateMarkupOutputModel<?>) leftOMOrStr;
+                if (rightOMOrStr instanceof String) {  // markup output
+                    return _EvalUtils.concatMarkupOutputs(parent,
+                            leftMO,
+                            
leftMO.getOutputFormat().fromPlainTextByEscaping((String) rightOMOrStr));
+                } else { // rightOMOrStr instanceof TemplateMarkupOutputModel
+                    return _EvalUtils.concatMarkupOutputs(parent,
+                            leftMO,
+                            (TemplateMarkupOutputModel<?>) rightOMOrStr);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
index c1da34e..1e67fad 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
@@ -41,7 +41,7 @@ final class ASTExpDot extends ASTExpression {
         if (leftModel instanceof TemplateHashModel) {
             return ((TemplateHashModel) leftModel).get(key);
         }
-        throw new NonHashException(target, leftModel, env);
+        throw MessageUtils.newUnexpectedOperandTypeException(target, 
leftModel, TemplateHashModel.class, env);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
index 7633ea9..658be00 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
@@ -58,16 +58,18 @@ final class ASTExpDynamicKeyName extends ASTExpression {
         if (keyModel instanceof RangeModel) {
             return dealWithRangeKey(targetModel, (RangeModel) keyModel, env);
         }
-        throw new UnexpectedTypeException(keyExpression, keyModel, "number, 
range, or string",
-                new Class[] { TemplateNumberModel.class, 
TemplateScalarModel.class, ASTExpRange.class }, env);
+        throw MessageUtils.newUnexpectedOperandTypeException(keyExpression, 
keyModel,
+                "number, range, or string",
+                new Class[] { TemplateNumberModel.class, 
TemplateScalarModel.class, ASTExpRange.class },
+                null, env);
     }
 
     static private Class[] NUMERICAL_KEY_LHO_EXPECTED_TYPES;
     static {
-        NUMERICAL_KEY_LHO_EXPECTED_TYPES = new Class[1 + 
NonStringException.STRING_COERCABLE_TYPES.length];
+        NUMERICAL_KEY_LHO_EXPECTED_TYPES = new Class[1 + 
MessageUtils.EXPECTED_TYPES_STRING_COERCABLE.length];
         NUMERICAL_KEY_LHO_EXPECTED_TYPES[0] = TemplateSequenceModel.class;
-        for (int i = 0; i < NonStringException.STRING_COERCABLE_TYPES.length; 
i++) {
-            NUMERICAL_KEY_LHO_EXPECTED_TYPES[i + 1] = 
NonStringException.STRING_COERCABLE_TYPES[i];
+        for (int i = 0; i < 
MessageUtils.EXPECTED_TYPES_STRING_COERCABLE.length; i++) {
+            NUMERICAL_KEY_LHO_EXPECTED_TYPES[i + 1] = 
MessageUtils.EXPECTED_TYPES_STRING_COERCABLE[i];
         }
     }
     
@@ -84,35 +86,37 @@ final class ASTExpDynamicKeyName extends ASTExpression {
                 size = Integer.MAX_VALUE;
             }
             return index < size ? tsm.get(index) : null;
-        } 
-        
+        }
+
+        String s;
         try {
-            String s = target.evalAndCoerceToPlainText(env);
-            try {
-                return new SimpleScalar(s.substring(index, index + 1));
-            } catch (IndexOutOfBoundsException e) {
-                if (index < 0) {
-                    throw new TemplateException("Negative index not allowed: 
", Integer.valueOf(index));
-                }
-                if (index >= s.length()) {
-                    throw new TemplateException(
-                            "String index out of range: The index was ", 
Integer.valueOf(index),
-                            " (0-based), but the length of the string is only 
", Integer.valueOf(s.length()) , ".");
-                }
-                throw new RuntimeException("Can't explain exception", e);
-            }
-        } catch (NonStringException e) {
-            throw new UnexpectedTypeException(
+            s = target.evalAndCoerceToPlainText(env);
+        } catch (TemplateException e) {
+            // TODO [FM3] Wrong, as we don't know why this was thrown. I think 
we just shouldn't coerce.
+            throw MessageUtils.newUnexpectedOperandTypeException(
                     target, targetModel,
-                    "sequence or " + 
NonStringException.STRING_COERCABLE_TYPES_DESC,
+                    "sequence or " + MessageUtils.STRING_COERCABLE_TYPES_DESC,
                     NUMERICAL_KEY_LHO_EXPECTED_TYPES,
                     (targetModel instanceof TemplateHashModel
-                            ? "You had a numberical value inside the []. 
Currently that's only supported for "
-                                    + "sequences (lists) and strings. To get a 
Map item with a non-string key, "
-                                    + "use myMap?api.get(myKey)."
+                            ? new Object[] { "You had a numberical value 
inside the []. Currently that's only "
+                                    + "supported for sequences (lists) and 
strings. To get a Map item with a "
+                                    + "non-string key, use 
myMap?api.get(myKey)." }
                             : null),
                     env);
         }
+        try {
+            return new SimpleScalar(s.substring(index, index + 1));
+        } catch (IndexOutOfBoundsException e) {
+            if (index < 0) {
+                throw new TemplateException("Negative index not allowed: ", 
Integer.valueOf(index));
+            }
+            if (index >= s.length()) {
+                throw new TemplateException(
+                        "String index out of range: The index was ", 
Integer.valueOf(index),
+                        " (0-based), but the length of the string is only ", 
Integer.valueOf(s.length()) , ".");
+            }
+            throw new RuntimeException("Can't explain exception", e);
+        }
     }
 
     private TemplateModel dealWithStringKey(TemplateModel targetModel, String 
key, Environment env)
@@ -120,7 +124,7 @@ final class ASTExpDynamicKeyName extends ASTExpression {
         if (targetModel instanceof TemplateHashModel) {
             return((TemplateHashModel) targetModel).get(key);
         }
-        throw new NonHashException(target, targetModel, env);
+        throw MessageUtils.newUnexpectedOperandTypeException(target, 
targetModel, TemplateHashModel.class, env);
     }
 
     private TemplateModel dealWithRangeKey(TemplateModel targetModel, 
RangeModel range, Environment env)
@@ -134,11 +138,12 @@ final class ASTExpDynamicKeyName extends ASTExpression {
             targetSeq = null;
             try {
                 targetStr = target.evalAndCoerceToPlainText(env);
-            } catch (NonStringException e) {
-                throw new UnexpectedTypeException(
+            } catch (TemplateException e) {
+                // TODO [FM3] Wrong, as we don't know why this was thrown. I 
think we just shouldn't coerce.
+                throw MessageUtils.newUnexpectedOperandTypeException(
                         target, target.eval(env),
-                        "sequence or " + 
NonStringException.STRING_COERCABLE_TYPES_DESC,
-                        NUMERICAL_KEY_LHO_EXPECTED_TYPES, env);
+                        "sequence or " + 
MessageUtils.STRING_COERCABLE_TYPES_DESC,
+                        NUMERICAL_KEY_LHO_EXPECTED_TYPES, null, env);
             }
         }
         

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
index 1d60af7..07985c8 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
@@ -61,7 +61,8 @@ final class ASTExpFunctionCall extends ASTExpression 
implements CallPlace {
         {
             TemplateModel functionUncasted = functionExp.eval(env);
             if (!(functionUncasted instanceof TemplateFunctionModel)) {
-                throw new NonFunctionException(functionExp, functionUncasted, 
env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        functionExp, functionUncasted, 
TemplateFunctionModel.class, env);
             }
             function = (TemplateFunctionModel) functionUncasted;
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
index 32af9bb..463110e 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
@@ -49,7 +49,7 @@ final class ASTExpHashLiteral extends ASTExpression {
 
     @Override
     TemplateModel _eval(Environment env) throws TemplateException {
-        return new SequenceHash(env);
+        return new LinkedHash(env);
     }
 
     @Override
@@ -106,12 +106,12 @@ final class ASTExpHashLiteral extends ASTExpression {
        return new ASTExpHashLiteral(clonedKeys, clonedValues);
     }
 
-    private class SequenceHash implements TemplateHashModelEx2 {
+    private class LinkedHash implements TemplateHashModelEx2 {
 
         private HashMap<String, TemplateModel> map;
         private TemplateCollectionModel keyCollection, valueCollection; // 
ordered lists of keys and values
 
-        SequenceHash(Environment env) throws TemplateException {
+        LinkedHash(Environment env) throws TemplateException {
             map = new LinkedHashMap<>();
             for (int i = 0; i < size; i++) {
                 ASTExpression keyExp = (ASTExpression) keys.get(i);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
index dc41129..820e2e7 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
@@ -48,7 +48,7 @@ final class ASTExpNegateOrPlus extends ASTExpression {
         try {
             targetModel = (TemplateNumberModel) tm;
         } catch (ClassCastException cce) {
-            throw new NonNumericalException(target, tm, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, tm, 
TemplateNumberModel.class, env);
         }
         if (!isMinus) {
             return targetModel;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
index 6932827..7b86e3e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
@@ -58,12 +58,6 @@ final class ASTExpRange extends ASTExpression {
             return new ListableRightUnboundedRangeModel(begin);
         }
     }
-    
-    // Surely this way we can tell that it won't be a boolean without 
evaluating the range, but why was this important?
-    @Override
-    boolean evalToBoolean(Environment env) throws TemplateException {
-        throw new NonBooleanException(this, new BoundedRangeModel(0, 0, false, 
false), env);
-    }
 
     @Override
     public String getCanonicalForm() {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
index 97f82a5..0994685 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
@@ -113,7 +113,7 @@ abstract class ASTExpression extends ASTNode {
         if (model instanceof TemplateNumberModel) {
             return _EvalUtils.modelToNumber((TemplateNumberModel) model, this);
         } else {
-            throw new NonNumericalException(this, model, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(this, model, 
TemplateNumberModel.class, env);
         }
     }
     
@@ -148,7 +148,7 @@ abstract class ASTExpression extends ASTNode {
         if (model instanceof TemplateBooleanModel) {
             return ((TemplateBooleanModel) model).getAsBoolean();
         } else {
-            throw new NonBooleanException(this, model, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(this, model, 
TemplateBooleanModel.class, env);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForDate.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForDate.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForDate.java
index 44fda23..b47ff1a 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForDate.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForDate.java
@@ -33,24 +33,11 @@ abstract class BuiltInForDate extends ASTExpBuiltIn {
             TemplateDateModel tdm = (TemplateDateModel) model;
             return calculateResult(_EvalUtils.modelToDate(tdm, target), 
tdm.getDateType(), env);
         } else {
-            throw newNonDateException(env, model, target);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, 
model, TemplateDateModel.class, env);
         }
     }
 
     /** Override this to implement the built-in. */
-    protected abstract TemplateModel calculateResult(
-            Date date, int dateType, Environment env)
-    throws TemplateException;
-    
-    static TemplateException newNonDateException(Environment env, 
TemplateModel model, ASTExpression target)
-            throws InvalidReferenceException {
-        TemplateException e;
-        if (model == null) {
-            e = InvalidReferenceException.getInstance(target, env);
-        } else {
-            e = new NonDateException(target, model, "date", env);
-        }
-        return e;
-    }
+    protected abstract TemplateModel calculateResult(Date date, int dateType, 
Environment env) throws TemplateException;
     
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForHashEx.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForHashEx.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForHashEx.java
index ec21061..1988f5e 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForHashEx.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForHashEx.java
@@ -31,7 +31,7 @@ abstract class BuiltInForHashEx extends ASTExpBuiltIn {
         if (model instanceof TemplateHashModelEx) {
             return calculateResult((TemplateHashModelEx) model, env);
         }
-        throw new NonExtendedHashException(target, model, env);
+        throw MessageUtils.newUnexpectedOperandTypeException(target, model, 
TemplateHashModelEx.class, env);
     }
     
     abstract TemplateModel calculateResult(TemplateHashModelEx hashExModel, 
Environment env)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLegacyEscaping.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLegacyEscaping.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLegacyEscaping.java
index e1f46d1..6082a3d 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLegacyEscaping.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLegacyEscaping.java
@@ -20,6 +20,7 @@ package org.apache.freemarker.core;
 
 import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
 import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
 
 /**
  * A string built-in whose usage is banned when auto-escaping with a 
markup-output format is active.
@@ -39,7 +40,7 @@ abstract class BuiltInForLegacyEscaping extends 
BuiltInBannedWhenAutoEscaping {
             if (mo.getOutputFormat().isLegacyBuiltInBypassed(key)) {
                 return mo;
             }
-            throw new NonStringException(target, tm, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, tm, 
TemplateScalarModel.class, env);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForMarkupOutput.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForMarkupOutput.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForMarkupOutput.java
index fa617c2..384e491 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForMarkupOutput.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForMarkupOutput.java
@@ -30,7 +30,7 @@ abstract class BuiltInForMarkupOutput extends ASTExpBuiltIn {
             throws TemplateException {
         TemplateModel model = target.eval(env);
         if (!(model instanceof TemplateMarkupOutputModel)) {
-            throw new NonMarkupOutputException(target, model, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, 
model, TemplateMarkupOutputModel.class, env);
         }
         return calculateResult((TemplateMarkupOutputModel) model);
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNode.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNode.java 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNode.java
index ca0cd61..afe7111 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNode.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNode.java
@@ -24,6 +24,7 @@ import 
org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateNodeModel;
 
 abstract class BuiltInForNode extends ASTExpBuiltIn {
+
     @Override
     TemplateModel _eval(Environment env)
             throws TemplateException {
@@ -31,9 +32,10 @@ abstract class BuiltInForNode extends ASTExpBuiltIn {
         if (model instanceof TemplateNodeModel) {
             return calculateResult((TemplateNodeModel) model, env);
         } else {
-            throw new NonNodeException(target, model, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, 
model, TemplateNodeModel.class, env);
         }
     }
-    abstract TemplateModel calculateResult(TemplateNodeModel nodeModel, 
Environment env)
-            throws TemplateModelException;
+
+    abstract TemplateModel calculateResult(TemplateNodeModel nodeModel, 
Environment env) throws TemplateModelException;
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNodeEx.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNodeEx.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNodeEx.java
index 8360cbd..67d0383 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNodeEx.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNodeEx.java
@@ -29,7 +29,7 @@ abstract class BuiltInForNodeEx extends ASTExpBuiltIn {
         if (model instanceof TemplateNodeModelEx) {
             return calculateResult((TemplateNodeModelEx) model, env);
         } else {
-            throw new NonExtendedNodeException(target, model, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, 
model, TemplateNodeModelEx.class, env);
         }
     }
     abstract TemplateModel calculateResult(TemplateNodeModelEx nodeModel, 
Environment env)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForSequence.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForSequence.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForSequence.java
index 4aca088..bac6c7f 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForSequence.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForSequence.java
@@ -20,7 +20,6 @@
 package org.apache.freemarker.core;
 
 import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateSequenceModel;
 
 abstract class BuiltInForSequence extends ASTExpBuiltIn {
@@ -29,7 +28,7 @@ abstract class BuiltInForSequence extends ASTExpBuiltIn {
             throws TemplateException {
         TemplateModel model = target.eval(env);
         if (!(model instanceof TemplateSequenceModel)) {
-            throw new NonSequenceException(target, model, env);
+            throw MessageUtils.newUnexpectedOperandTypeException(target, 
model, TemplateSequenceModel.class, env);
         }
         return calculateResult((TemplateSequenceModel) model);
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForDates.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForDates.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForDates.java
index c237613..f69cfe9 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForDates.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForDates.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core;
 
-import static org.apache.freemarker.core._CallableUtils.*;
+import static org.apache.freemarker.core.util.CallableUtils.*;
 
 import java.util.Date;
 import java.util.TimeZone;
@@ -60,7 +60,7 @@ class BuiltInsForDates {
                 }
                 return new SimpleDate(_EvalUtils.modelToDate(tdm, target), 
dateType);
             } else {
-                throw BuiltInForDate.newNonDateException(env, model, target);
+                throw MessageUtils.newUnexpectedOperandTypeException(target, 
model, TemplateDateModel.class, env);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForExistenceHandling.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForExistenceHandling.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForExistenceHandling.java
index dfa7c46..f7c5258 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForExistenceHandling.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForExistenceHandling.java
@@ -69,8 +69,7 @@ class BuiltInsForExistenceHandling {
             }
 
             @Override
-            public TemplateModel execute(TemplateModel[] args, CallPlace 
callPlace, Environment env)
-                    throws TemplateException {
+            public TemplateModel execute(TemplateModel[] args, CallPlace 
callPlace, Environment env) {
                 return constant;
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java
index 6b70721..048d633 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForMultipleTypes.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core;
 
-import static 
org.apache.freemarker.core._CallableUtils.getOptionalStringArgument;
+import static 
org.apache.freemarker.core.util.CallableUtils.getOptionalStringArgument;
 
 import java.util.Date;
 
@@ -44,6 +44,7 @@ import org.apache.freemarker.core.model.impl.SimpleDate;
 import org.apache.freemarker.core.model.impl.SimpleNumber;
 import org.apache.freemarker.core.model.impl.SimpleScalar;
 import org.apache.freemarker.core.util.BugException;
+import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.core.valueformat.TemplateDateFormat;
 import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
 import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
@@ -64,10 +65,10 @@ class BuiltInsForMultipleTypes {
                 return new SimpleScalar(((TemplateBooleanModel) 
model).getAsBoolean()
                         ? TemplateBooleanFormat.C_TRUE : 
TemplateBooleanFormat.C_FALSE);
             } else {
-                throw new UnexpectedTypeException(
+                throw MessageUtils.newUnexpectedOperandTypeException(
                         target, model,
                         "number or boolean", new Class[] { 
TemplateNumberModel.class, TemplateBooleanModel.class },
-                        env);
+                        null, env);
             }
         }
 
@@ -424,9 +425,9 @@ class BuiltInsForMultipleTypes {
         TemplateModel _eval(Environment env) throws TemplateException {
             TemplateModel tm = target.eval(env);
             if (!(tm instanceof Environment.TemplateLanguageCallable)) {
-                throw new UnexpectedTypeException(
+                throw MessageUtils.newUnexpectedOperandTypeException(
                         target, tm,
-                        "macro or function", new Class[] { 
Environment.TemplateLanguageCallable.class },
+                        Environment.TemplateLanguageCallable.class,
                         env);
             }
             return ((Environment.TemplateLanguageCallable) tm).getNamespace();
@@ -446,7 +447,7 @@ class BuiltInsForMultipleTypes {
             } else if (model instanceof TemplateHashModelEx) {
                 size = ((TemplateHashModelEx) model).size();
             } else {
-                throw new UnexpectedTypeException(
+                throw MessageUtils.newUnexpectedOperandTypeException(
                         target, model,
                         "extended-hash or sequence or extended collection",
                         new Class[] {
@@ -454,6 +455,7 @@ class BuiltInsForMultipleTypes {
                                 TemplateSequenceModel.class,
                                 TemplateCollectionModelEx.class
                         },
+                        null,
                         env);
             }
             return new SimpleNumber(size);
@@ -479,7 +481,7 @@ class BuiltInsForMultipleTypes {
                 TemplateModel result = args[argIdx];
                 if (!(result instanceof TemplateScalarModel)) {
                     // Cause usual type exception
-                    _CallableUtils.castArgumentValueToString(result, argIdx, 
this, true, false);
+                    CallableUtils.castArgumentValueToString(result, argIdx, 
this, true, false);
                 }
                 return result;
             }
@@ -526,7 +528,7 @@ class BuiltInsForMultipleTypes {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace 
callPlace, Environment env)
                     throws TemplateException {
-                return formatWith(_CallableUtils.getStringArgument(args, 0, 
this));
+                return formatWith(CallableUtils.getStringArgument(args, 0, 
this));
             }
 
             @Override
@@ -606,7 +608,7 @@ class BuiltInsForMultipleTypes {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace 
callPlace, Environment env)
                     throws TemplateException {
-                return get(_CallableUtils.getStringArgument(args, 0, this));
+                return get(CallableUtils.getStringArgument(args, 0, this));
             }
 
             @Override
@@ -670,15 +672,15 @@ class BuiltInsForMultipleTypes {
                 return new BooleanFormatter((TemplateBooleanModel) model, env);
             } else if (model instanceof TemplateScalarModel) {
                 return new SimpleScalar(((TemplateScalarModel) 
model).getAsString());
-            } else {            
-                throw new UnexpectedTypeException(
+            } else {
+                throw MessageUtils.newUnexpectedOperandTypeException(
                         target, model,
                         "number, date, boolean or string",
                         new Class[] {
                             TemplateNumberModel.class, 
TemplateDateModel.class, TemplateBooleanModel.class,
                             TemplateScalarModel.class
                         },
-                        env);
+                        null, env);
             }
         }
     }
@@ -697,10 +699,10 @@ class BuiltInsForMultipleTypes {
                 return new SimpleScalar(((TemplateBooleanModel) 
model).getAsBoolean()
                         ? TemplateBooleanFormat.C_TRUE : 
TemplateBooleanFormat.C_FALSE);
             } else {
-                throw new UnexpectedTypeException(
+                throw MessageUtils.newUnexpectedOperandTypeException(
                         target, model,
                         "number or boolean", new Class[] { 
TemplateNumberModel.class, TemplateBooleanModel.class },
-                        env);
+                        null, env);
             }
         }
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNestedContentParameters.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNestedContentParameters.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNestedContentParameters.java
index 9b35b63..3767523 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNestedContentParameters.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNestedContentParameters.java
@@ -18,8 +18,6 @@
  */
 package org.apache.freemarker.core;
 
-import static org.apache.freemarker.core._CallableUtils.checkArgumentCount;
-
 import org.apache.freemarker.core.ASTDirList.IterationContext;
 import org.apache.freemarker.core.model.ArgumentArrayLayout;
 import org.apache.freemarker.core.model.TemplateBooleanModel;
@@ -27,6 +25,7 @@ import org.apache.freemarker.core.model.TemplateFunctionModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.impl.SimpleNumber;
 import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.util.CallableUtils;
 
 
 class BuiltInsForNestedContentParameters {
@@ -142,7 +141,7 @@ class BuiltInsForNestedContentParameters {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace 
callPlace, Environment env)
                     throws TemplateException {
-                _CallableUtils.checkArgumentCount(args.length, 1, 
Integer.MAX_VALUE, this);
+                CallableUtils.checkArgumentCount(args.length, 1, 
Integer.MAX_VALUE, this);
                 return args[iterCtx.getIndex() % args.length];
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNodes.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNodes.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNodes.java
index ae23e18..5174c3e 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNodes.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNodes.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core;
 
-import static org.apache.freemarker.core._CallableUtils.getStringArgument;
+import static org.apache.freemarker.core.util.CallableUtils.getStringArgument;
 
 import org.apache.freemarker.core.model.ArgumentArrayLayout;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
@@ -47,8 +47,7 @@ class BuiltInsForNodes {
            return result;
        }
 
-        class AncestorSequence extends NativeSequence implements 
TemplateFunctionModel,
-                BuiltInCallable {
+        class AncestorSequence extends NativeSequence implements 
TemplateFunctionModel, BuiltInCallable {
 
             private static final int INITIAL_CAPACITY = 12;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/f231e64f/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
----------------------------------------------------------------------
diff --git 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
index 0e8dd2b..857e7e3 100644
--- 
a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
+++ 
b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForSequences.java
@@ -19,7 +19,7 @@
 
 package org.apache.freemarker.core;
 
-import static org.apache.freemarker.core._CallableUtils.*;
+import static org.apache.freemarker.core.util.CallableUtils.*;
 
 import java.io.Serializable;
 import java.text.Collator;
@@ -55,7 +55,7 @@ class BuiltInsForSequences {
     
     static class chunkBI extends BuiltInForSequence {
 
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements 
TemplateFunctionModel {
             
             private final TemplateSequenceModel tsm;
 
@@ -160,7 +160,11 @@ class BuiltInsForSequences {
             } else if (model instanceof TemplateCollectionModel) {
                 return calculateResultForColletion((TemplateCollectionModel) 
model);
             } else {
-                throw new NonSequenceOrCollectionException(target, model, env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        target, model,
+                        MessageUtils.SEQUENCE_OR_COLLECTION,
+                        MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
+                        null, env);
             }
         }        
         
@@ -255,7 +259,11 @@ class BuiltInsForSequences {
             } else if (model instanceof TemplateSequenceModel) {
                 return new BIMethodForCollection(env, new 
CollectionAndSequence((TemplateSequenceModel) model));
             } else {
-                throw new NonSequenceOrCollectionException(target, model, env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        target, model,
+                        MessageUtils.SEQUENCE_OR_COLLECTION,
+                        MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
+                        null, env);
             }
         }
    
@@ -302,7 +310,7 @@ class BuiltInsForSequences {
     }
 
     static class seq_containsBI extends ASTExpBuiltIn {
-        private class BIMethodForCollection implements TemplateFunctionModel {
+        private class BIMethodForCollection extends BuiltInCallableImpl 
implements TemplateFunctionModel {
             private TemplateCollectionModel m_coll;
             private Environment m_env;
 
@@ -332,7 +340,7 @@ class BuiltInsForSequences {
 
         }
 
-        private class BIMethodForSequence implements TemplateFunctionModel {
+        private class BIMethodForSequence extends BuiltInCallableImpl 
implements TemplateFunctionModel {
             private TemplateSequenceModel m_seq;
             private Environment m_env;
 
@@ -371,7 +379,11 @@ class BuiltInsForSequences {
             } else if (model instanceof TemplateCollectionModel) {
                 return new BIMethodForCollection((TemplateCollectionModel) 
model, env);
             } else {
-                throw new NonSequenceOrCollectionException(target, model, env);
+                throw MessageUtils.newUnexpectedOperandTypeException(
+                        target, model,
+                        MessageUtils.SEQUENCE_OR_COLLECTION,
+                        MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
+                        null, env);
             }
         }
     
@@ -379,7 +391,7 @@ class BuiltInsForSequences {
     
     static class seq_index_ofBI extends ASTExpBuiltIn {
         
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements 
TemplateFunctionModel {
             
             final TemplateSequenceModel m_seq;
             final TemplateCollectionModel m_col;
@@ -403,7 +415,11 @@ class BuiltInsForSequences {
                         ? (TemplateCollectionModel) model
                         : null;
                 if (m_seq == null && m_col == null) {
-                    throw new NonSequenceOrCollectionException(target, model, 
env);
+                    throw MessageUtils.newUnexpectedOperandTypeException(
+                            target, model,
+                            MessageUtils.SEQUENCE_OR_COLLECTION,
+                            MessageUtils.EXPECTED_TYPES_SEQUENCE_OR_COLLECTION,
+                            null, env);
                 }
                 
                 m_env = env;
@@ -544,7 +560,7 @@ class BuiltInsForSequences {
     }
 
     static class sort_byBI extends sortBI {
-        class BIMethod implements TemplateFunctionModel {
+        class BIMethod extends BuiltInCallableImpl implements 
TemplateFunctionModel {
             TemplateSequenceModel seq;
             
             BIMethod(TemplateSequenceModel seq) {


Reply via email to