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/08/15 23:08:41 UTC

[2/2] incubator-freemarker git commit: FREEMARKER-65: Utilities for argument validation: work in progress... so far only some internal cleanup.

FREEMARKER-65: Utilities for argument validation: work in progress... so far only some internal cleanup.


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

Branch: refs/heads/3
Commit: e941aedc100de2f14401e355c6b70c207a8b3c7d
Parents: 7842821
Author: ddekany <dd...@apache.org>
Authored: Mon Aug 14 20:05:14 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Wed Aug 16 01:08:18 2017 +0200

----------------------------------------------------------------------
 .../core/TemplateCallableModelTest.java         |  18 +-
 .../CommonSupertypeForUnwrappingHintTest.java   |   2 +-
 .../impl/ParameterListPreferabilityTest.java    |   2 +-
 .../core/templatesuite/models/MultiModel2.java  |   2 +-
 .../core/userpkg/AllFeaturesDirective.java      |  24 +-
 .../core/userpkg/AllFeaturesFunction.java       |  24 +-
 .../core/templatesuite/templates/list-bis.ftl   |   2 +-
 .../freemarker/core/ASTDynamicTopLevelCall.java |   3 +-
 .../apache/freemarker/core/ASTExpBuiltIn.java   | 126 +----
 .../freemarker/core/ASTExpDynamicKeyName.java   |   2 +-
 .../freemarker/core/ASTExpFunctionCall.java     |   3 +-
 .../freemarker/core/BuiltInsForDates.java       |  21 +-
 .../core/BuiltInsForMultipleTypes.java          |  25 +-
 .../BuiltInsForNestedContentParameters.java     |   6 +-
 .../freemarker/core/BuiltInsForNodes.java       | 110 +++--
 .../freemarker/core/BuiltInsForSequences.java   |  14 +-
 .../core/BuiltInsForStringsBasic.java           | 175 +++----
 .../core/BuiltInsForStringsEncoding.java        |  21 +-
 .../core/BuiltInsForStringsRegexp.java          |  16 +-
 .../org/apache/freemarker/core/Environment.java |  54 ++-
 .../apache/freemarker/core/MessageUtils.java    | 105 ----
 .../freemarker/core/NonNumericalException.java  |   8 +-
 .../freemarker/core/NonStringException.java     |   8 +-
 .../core/UnexpectedTypeException.java           |  81 +++-
 .../apache/freemarker/core/_CallableUtils.java  | 482 ++++++++++++++++---
 .../org/apache/freemarker/core/_EvalUtils.java  |   9 +-
 .../core/model/TemplateHashModelEx2.java        |   2 +-
 .../core/model/TemplateModelWithOriginName.java |  39 ++
 .../core/model/impl/ArgumentTypes.java          |   2 +-
 .../core/model/impl/JavaMethodModel.java        |  20 +-
 .../model/impl/OverloadedJavaMethodModel.java   |  15 +
 .../core/model/impl/OverloadedMethods.java      |  29 +-
 .../model/impl/OverloadedMethodsSubset.java     |   4 +-
 .../core/model/impl/ResourceBundleModel.java    |   2 +-
 .../core/model/impl/SimpleJavaMethodModel.java  |  16 +-
 .../core/util/TemplateLanguageUtils.java        |  64 ++-
 .../freemarker/servlet/jsp/JspTagModelBase.java |  10 +-
 ...eDirectiveModelAndTemplateFunctionModel.java |  32 +-
 38 files changed, 993 insertions(+), 585 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 d6c9e66..cbe1c5c 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
@@ -222,7 +222,10 @@ public class TemplateCallableModelTest extends TemplateTest {
         assertErrorContains("<@p 9, 9, 9 />", "can only have 2", "3", "by position");
         assertErrorContains("<@n 9 />", "can't have arguments passed by position");
         assertErrorContains("<@n n3=9 />", "has no", "\"n3\"", "supported", "\"n1\", \"n2\"");
-        assertErrorContains("<@p n1=9 />", "directive", "can't have arguments that are passed by name", "\"n1\"");
+        assertErrorContains("<@p n1=9 />", "directive", "can't have arguments that are passed by name", "\"n1\"",
+                "<@example");
+        assertErrorContains("${fp(n1=9)}", "function", "can't have arguments that are passed by name", "\"n1\"",
+                "example(");
         assertErrorContains("<@uc n1=9 />", "directive", "doesn't support any parameters");
         assertErrorContains("<@uc 9 />", "directive", "doesn't support any parameters");
 
@@ -235,6 +238,19 @@ public class TemplateCallableModelTest extends TemplateTest {
         assertOutput("<@p...@p>",
                 "#p(p1=null, p2=null)");
         assertErrorContains("<@p> </...@p>", "Nested content", "not supported");
+
+        assertErrorContains("<@a n1='str' />", "directive", ".AllFeaturesDirective", "\"n1\"", "number", "string");
+        assertErrorContains("<#macro myM n1></#macro><@myM/>", "macro", "\"myM\"", "\"n1\"", "null");
+        assertErrorContains("${fa(n1='str')}", "function", ".AllFeaturesFunction", "\"n1\"", "number", "string");
+        assertErrorContains("<@a 1, 'str' />", "directive", ".AllFeaturesDirective", "2nd", "number", "string");
+        assertErrorContains("${fa(1, 'str')}", "function", ".AllFeaturesFunction", "2nd", "number", "string");
+        assertErrorContains("<#function myF(p1)></#function>${myF()}", "function", "\"myF\"", "1st", "null");
+        assertErrorContains("${'x'?leftPad(1, 2)}", "?leftPad", "2nd", "string", "number");
+        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\"");
+        addToDataModel("bean", new TestBean());
+        assertErrorContains("${bean.intMP()}", "method", "org.apache.freemarker.test.TemplateTest$TestBean.intMP");
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
index c4e42ab..fb9a065 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
@@ -52,7 +52,7 @@ public class CommonSupertypeForUnwrappingHintTest extends TestCase {
         testArrayAndOther(oms);
     }
     
-    /** These will be the same with oms and buggy: */
+    /** These will be the same with fixed and buggy: */
     private void testArrayAndOther(OverloadedMethodsSubset oms) {
         assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, String.class));
         assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, String.class));

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
index 54461d4..826a65f 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
@@ -395,7 +395,7 @@ public class ParameterListPreferabilityTest extends TestCase {
                 true);
         
         
-        // Different oms prefix length; in the case of ambiguity, the one with higher oms param count wins.
+        // Different fixed prefix length; in the case of ambiguity, the one with higher oms param count wins.
         testAllCmpPermutationsInc(
                 new Class[][] {
                     new Class[] { String.class, int.class, int.class, int[].class },

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 ad4cbe3..e56c0a2 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
@@ -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.castArgToString(args, i));
+            aResults.append(_CallableUtils.getStringArgument(args, i, this));
             aResults.append("<br />");
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 27a42d9..3931a67 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
@@ -59,30 +59,14 @@ public class AllFeaturesDirective extends TestTemplateCallableModel implements T
     private static final int P_VARARGS_ARG_IDX = ARGS_LAYOUT.getPositionalVarargsArgumentIndex();
     private static final int N_VARARGS_ARG_IDX = ARGS_LAYOUT.getNamedVarargsArgumentIndex();
 
-    private final boolean p1AllowNull;
-    private final boolean p2AllowNull;
-    private final boolean n1AllowNull;
-    private final boolean n2AllowNull;
-
-    public AllFeaturesDirective() {
-        this(true, true, true, true);
-    }
-
-    public AllFeaturesDirective(boolean p1AllowNull, boolean p2AllowNull, boolean n1AllowNull, boolean n2AllowNull) {
-        this.p1AllowNull = p1AllowNull;
-        this.p2AllowNull = p2AllowNull;
-        this.n1AllowNull = n1AllowNull;
-        this.n2AllowNull = n2AllowNull;
-    }
-
     @Override
     public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
             throws TemplateException, IOException {
-        execute(castArgToNumber(args, P1_ARG_IDX, p1AllowNull),
-                castArgToNumber(args, P2_ARG_IDX, p2AllowNull),
+        execute(getOptionalNumberArgument(args, P1_ARG_IDX, this),
+                getOptionalNumberArgument(args, P2_ARG_IDX, this),
                 (TemplateSequenceModel) args[P_VARARGS_ARG_IDX],
-                castArgToNumber(args[N1_ARG_IDX], N1_ARG_NAME, n1AllowNull),
-                castArgToNumber(args[N2_ARG_IDX], N2_ARG_NAME, n2AllowNull),
+                getOptionalNumberArgument(args, N1_ARG_IDX, this),
+                getOptionalNumberArgument(args, N2_ARG_IDX, this),
                 (TemplateHashModelEx2) args[N_VARARGS_ARG_IDX],
                 out, env, callPlace);
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 66817bb..261c369 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
@@ -56,30 +56,18 @@ public class AllFeaturesFunction extends TestTemplateCallableModel implements Te
     private static final int P_VARARGS_ARG_IDX = ARGS_LAYOUT.getPositionalVarargsArgumentIndex();
     private static final int N_VARARGS_ARG_IDX = ARGS_LAYOUT.getNamedVarargsArgumentIndex();
 
-    private final boolean p1AllowNull;
-    private final boolean p2AllowNull;
-    private final boolean n1AllowNull;
-    private final boolean n2AllowNull;
-
-    public AllFeaturesFunction() {
-        this(true, true, true, true);
-    }
-
-    public AllFeaturesFunction(boolean p1AllowNull, boolean p2AllowNull, boolean n1AllowNull, boolean n2AllowNull) {
-        this.p1AllowNull = p1AllowNull;
-        this.p2AllowNull = p2AllowNull;
-        this.n1AllowNull = n1AllowNull;
-        this.n2AllowNull = n2AllowNull;
+    private AllFeaturesFunction() {
+        //
     }
 
     @Override
     public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
         return execute(
-                castArgToNumber(args, P1_ARG_IDX, p1AllowNull),
-                castArgToNumber(args, P2_ARG_IDX, p2AllowNull),
+                getOptionalNumberArgument(args, P1_ARG_IDX, this),
+                getOptionalNumberArgument(args, P2_ARG_IDX, this),
                 (TemplateSequenceModel) args[P_VARARGS_ARG_IDX],
-                castArgToNumber(args[N1_ARG_IDX], N1_ARG_NAME, n1AllowNull),
-                castArgToNumber(args[N2_ARG_IDX], N2_ARG_NAME, n2AllowNull),
+                getOptionalNumberArgument(args, N1_ARG_IDX, this),
+                getOptionalNumberArgument(args, N2_ARG_IDX, this),
                 (TemplateHashModelEx2) args[N_VARARGS_ARG_IDX]);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/list-bis.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/list-bis.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/list-bis.ftl
index e52307f..e277d2d 100644
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/list-bis.ftl
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/list-bis.ftl
@@ -45,4 +45,4 @@
 <#list ['a', 'b', 'c', 'd', 'e', 'f', 'g'] as x>
     <td class="${x?itemCycle('R', 'G', 'B')}">${x}</td>
 </#list>
-<@assertFails message="expects 1"><#list 1..1 as x>${x?itemCycle()}</#list></@>
\ No newline at end of file
+<@assertFails message="1 or more"><#list 1..1 as x>${x?itemCycle()}</#list></@>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 35cd02d..e4b3c17 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
@@ -118,7 +118,8 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace  {
         }
 
         TemplateModel[] execArgs = _CallableUtils.getExecuteArgs(
-                positionalArgs, namedArgs, argsLayout, callableValue, env);
+                positionalArgs, namedArgs, argsLayout, callableValue,
+                false, env);
 
         if (directive != null) {
             directive.execute(execArgs, this, env.getOut(), env);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
index eb78ef5..8e542ba 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
@@ -61,10 +61,9 @@ import org.apache.freemarker.core.BuiltInsForSequences.seq_index_ofBI;
 import org.apache.freemarker.core.BuiltInsForSequences.sortBI;
 import org.apache.freemarker.core.BuiltInsForSequences.sort_byBI;
 import org.apache.freemarker.core.BuiltInsForStringsMisc.evalBI;
+import org.apache.freemarker.core.model.TemplateCallableModel;
 import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateModelWithOriginName;
 import org.apache.freemarker.core.util._DateUtils;
 import org.apache.freemarker.core.util._StringUtils;
 
@@ -383,105 +382,7 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable {
 
     @Override
     boolean isLiteral() {
-        return false; // be on the safe side.
-    }
-    
-    protected final void checkMethodArgCount(List args, int expectedCnt) throws TemplateException {
-        checkMethodArgCount(args.size(), expectedCnt);
-    }
-
-    protected final void checkMethodArgCount(TemplateModel[] args, int expectedCnt) throws TemplateException {
-        checkMethodArgCount(args.length, expectedCnt);
-    }
-
-    protected final void checkMethodArgCount(int argCnt, int expectedCnt) throws TemplateException {
-        if (argCnt != expectedCnt) {
-            throw MessageUtils.newArgCntError("?" + key, argCnt, expectedCnt);
-        }
-    }
-
-    protected final void checkMethodArgCount(List args, int minCnt, int maxCnt) throws TemplateException {
-        checkMethodArgCount(args.size(), minCnt, maxCnt);
-    }
-
-    protected final void checkMethodArgCount(TemplateModel[] args, int minCnt, int maxCnt) throws
-            TemplateException {
-        checkMethodArgCount(args.length, minCnt, maxCnt);
-    }
-
-    protected final void checkMethodArgCount(int argCnt, int minCnt, int maxCnt) throws TemplateException {
-        if (argCnt < minCnt || argCnt > maxCnt) {
-            throw MessageUtils.newArgCntError("?" + key, argCnt, minCnt, maxCnt);
-        }
-    }
-
-    protected final String getStringMethodArg(TemplateModel[] args, int argIdx) throws TemplateException {
-        return getStringMethodArg(args, argIdx, false);
-    }
-
-    /**
-     * Gets a method argument and checks if it's a string; it does NOT check if {@code args} is big enough.
-     */
-    protected final String getStringMethodArg(TemplateModel[] args, int argIdx, boolean optional)
-            throws TemplateException {
-        TemplateModel arg = args[argIdx];
-        return getStringMethodArg(arg, argIdx, optional);
-    }
-
-    protected String getStringMethodArg(TemplateModel arg, int argIdx)
-            throws TemplateException {
-        return getStringMethodArg(arg, argIdx, false);
-    }
-
-    protected String getStringMethodArg(TemplateModel arg, int argIdx, boolean optional)
-            throws TemplateException {
-        if (!(arg instanceof TemplateScalarModel)) {
-            if (optional && arg == null) {
-                return null;
-            }
-            throw MessageUtils.newMethodArgMustBeStringException("?" + key, argIdx, arg);
-        } else {
-            return _EvalUtils.modelToString((TemplateScalarModel) arg, null, null);
-        }
-    }
-
-    protected final Number getNumberMethodArg(TemplateModel[] args, int argIdx)
-            throws TemplateException {
-        return getNumberMethodArg(args, argIdx, false);
-    }
-
-    /**
-     * Gets a method argument and checks if it's a number; it does NOT check if {@code args} is big enough.
-     */
-    protected final Number getNumberMethodArg(TemplateModel[] args, int argIdx, boolean optional)
-            throws TemplateException {
-        TemplateModel arg = args[argIdx];
-        return getNumberMethodArg(arg, argIdx, optional);
-    }
-
-    protected Number getNumberMethodArg(TemplateModel arg, int argIdx)
-            throws TemplateException {
-        return getNumberMethodArg(arg, argIdx, false);
-    }
-
-    protected Number getNumberMethodArg(TemplateModel arg, int argIdx, boolean optional)
-            throws TemplateException {
-        if (!(arg instanceof TemplateNumberModel)) {
-            if (optional && arg == null) {
-                return null;
-            }
-            throw MessageUtils.newMethodArgMustBeNumberException("?" + key, argIdx, arg);
-        } else {
-            return _EvalUtils.modelToNumber((TemplateNumberModel) arg, null);
-        }
-    }
-
-    protected final TemplateException newMethodArgInvalidValueException(int argIdx, Object[] details) {
-        return MessageUtils.newMethodArgInvalidValueException("?" + key, argIdx, details);
-    }
-
-    protected final TemplateException newMethodArgsInvalidValueException(Object[] details) {
-        return MessageUtils.newMethodArgsInvalidValueException("?" + key, details);
+        return false;
     }
     
     @Override
@@ -519,4 +420,25 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable {
         }
     }
 
+    /** */
+    interface BuiltInCallable extends TemplateModelWithOriginName {
+        String getBuiltInName();
+    }
+
+    abstract class BuiltInCallableImpl implements TemplateCallableModel, BuiltInCallable {
+        @Override
+        public String getBuiltInName() {
+            return key;
+        }
+
+        @Override
+        public String getOriginName() {
+            return ASTExpBuiltIn.getOriginName(this);
+        }
+    }
+
+    static String getOriginName(BuiltInCallable lThis) {
+        return  "?" + lThis.getBuiltInName();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 d8041f7..7633ea9 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
@@ -52,7 +52,7 @@ final class ASTExpDynamicKeyName extends ASTExpression {
             return dealWithNumericalKey(targetModel, index, env);
         }
         if (keyModel instanceof TemplateScalarModel) {
-            String key = _EvalUtils.modelToString((TemplateScalarModel) keyModel, keyExpression, env);
+            String key = _EvalUtils.modelToString((TemplateScalarModel) keyModel, keyExpression);
             return dealWithStringKey(targetModel, key, env);
         }
         if (keyModel instanceof RangeModel) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 391e5a7..1d60af7 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
@@ -68,7 +68,8 @@ final class ASTExpFunctionCall extends ASTExpression implements CallPlace {
 
         return function.execute(
                 _CallableUtils.getExecuteArgs(
-                        positionalArgs, namedArgs, function.getFunctionArgumentArrayLayout(), function, env),
+                        positionalArgs, namedArgs, function.getFunctionArgumentArrayLayout(),
+                        function, true,env),
                 this,
                 env);
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 49bfbdb..c237613 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,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.*;
+
 import java.util.Date;
 import java.util.TimeZone;
 
@@ -27,7 +29,6 @@ import org.apache.freemarker.core.model.ArgumentArrayLayout;
 import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
 import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateScalarModel;
 import org.apache.freemarker.core.model.impl.SimpleDate;
 import org.apache.freemarker.core.model.impl.SimpleScalar;
@@ -70,7 +71,7 @@ class BuiltInsForDates {
      */
     static class iso_BI extends AbstractISOBI {
         
-        class Result implements TemplateFunctionModel {
+        class Result extends BuiltInCallableImpl implements TemplateFunctionModel {
             private final Date date;
             private final int dateType;
             private final Environment env;
@@ -81,7 +82,6 @@ class BuiltInsForDates {
                 this.env = env;
             }
 
-
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
@@ -95,18 +95,19 @@ class BuiltInsForDates {
                             instanceof TimeZone) {
                     tzArg = (TimeZone) adaptedObj;
                 } else if (tzArgTM instanceof TemplateScalarModel) {
-                    String tzName = _EvalUtils.modelToString((TemplateScalarModel) tzArgTM, null, null);
+                    String tzName = _EvalUtils.modelToString((TemplateScalarModel) tzArgTM, null);
                     try {
                         tzArg = _DateUtils.getTimeZone(tzName);
                     } catch (UnrecognizedTimeZoneException e) {
-                        throw new TemplateException(
-                                "The time zone string specified for ?", key,
-                                "(...) is not recognized as a valid time zone name: ",
-                                new _DelayedJQuote(tzName));
+                        throw newArgumentValueException(0,
+                                "not recognized as a valid time zone name: " + new _DelayedJQuote(tzName),
+                                this, true);
                     }
                 } else {
-                    throw MessageUtils.newMethodArgUnexpectedTypeException(
-                            "?" + key, 0, "string or java.util.TimeZone", tzArgTM);
+                    throw newArgumentValueTypeException(
+                            tzArgTM, 0,
+                            new Class[] { TemplateScalarModel.class }, "string or java.util.TimeZone",
+                            this, true);
                 }
 
                 return new SimpleScalar(_DateUtils.dateToISO8601String(

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 5d6dccc..6b70721 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,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.getOptionalStringArgument;
+
 import java.util.Date;
 
 import org.apache.freemarker.core.model.ArgumentArrayLayout;
@@ -107,7 +109,8 @@ class BuiltInsForMultipleTypes {
     }
 
     static class dateBI extends ASTExpBuiltIn {
-        private class DateParser implements TemplateDateModel, TemplateFunctionModel, TemplateHashModel {
+        private class DateParser extends BuiltInCallableImpl
+                implements TemplateDateModel, TemplateFunctionModel, TemplateHashModel {
             private final String text;
             private final Environment env;
             private final TemplateDateFormat defaultFormat;
@@ -122,8 +125,8 @@ class BuiltInsForMultipleTypes {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                TemplateModel arg1 = args[0];
-                return arg1 == null ? getAsDateModel() : get(_CallableUtils.castArgToString(arg1, 0));
+                String pattern = getOptionalStringArgument(args, 0, this);
+                return pattern == null ? getAsDateModel() : get(pattern);
             }
 
             @Override
@@ -459,7 +462,8 @@ class BuiltInsForMultipleTypes {
     
     static class stringBI extends ASTExpBuiltIn {
         
-        private class BooleanFormatter implements TemplateScalarModel, TemplateFunctionModel {
+        private class BooleanFormatter extends BuiltInCallableImpl
+                implements TemplateScalarModel, TemplateFunctionModel {
             private final TemplateBooleanModel bool;
             private final Environment env;
             
@@ -474,7 +478,8 @@ class BuiltInsForMultipleTypes {
                 int argIdx = bool.getAsBoolean() ? 0 : 1;
                 TemplateModel result = args[argIdx];
                 if (!(result instanceof TemplateScalarModel)) {
-                    throw new NonStringException(argIdx, result, null, null);
+                    // Cause usual type exception
+                    _CallableUtils.castArgumentValueToString(result, argIdx, this, true, false);
                 }
                 return result;
             }
@@ -499,7 +504,8 @@ class BuiltInsForMultipleTypes {
             }
         }
     
-        private class DateFormatter implements TemplateScalarModel, TemplateHashModel, TemplateFunctionModel {
+        private class DateFormatter extends BuiltInCallableImpl
+                implements TemplateScalarModel, TemplateHashModel, TemplateFunctionModel {
             private final TemplateDateModel dateModel;
             private final Environment env;
             private final TemplateDateFormat defaultFormat;
@@ -520,7 +526,7 @@ class BuiltInsForMultipleTypes {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                return formatWith(_CallableUtils.castArgToString(args, 0));
+                return formatWith(_CallableUtils.getStringArgument(args, 0, this));
             }
 
             @Override
@@ -575,7 +581,8 @@ class BuiltInsForMultipleTypes {
             }
         }
         
-        private class NumberFormatter implements TemplateScalarModel, TemplateHashModel, TemplateFunctionModel {
+        private class NumberFormatter extends BuiltInCallableImpl
+                implements TemplateScalarModel, TemplateHashModel, TemplateFunctionModel {
             private final TemplateNumberModel numberModel;
             private final Number number;
             private final Environment env;
@@ -599,7 +606,7 @@ class BuiltInsForMultipleTypes {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                return get(_CallableUtils.castArgToString(args, 0));
+                return get(_CallableUtils.getStringArgument(args, 0, this));
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 bc4b9dc..9b35b63 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,6 +18,8 @@
  */
 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;
@@ -129,7 +131,7 @@ class BuiltInsForNestedContentParameters {
 
     static class item_cycleBI extends BuiltInForNestedContentParameter {
 
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             
             private final IterationContext iterCtx;
     
@@ -140,7 +142,7 @@ class BuiltInsForNestedContentParameters {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                checkMethodArgCount(args, 1, Integer.MAX_VALUE);
+                _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/e941aedc/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 bd01e06..ae23e18 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,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.getStringArgument;
+
 import org.apache.freemarker.core.model.ArgumentArrayLayout;
 import org.apache.freemarker.core.model.TemplateFunctionModel;
 import org.apache.freemarker.core.model.TemplateModel;
@@ -44,6 +46,66 @@ class BuiltInsForNodes {
            }
            return result;
        }
+
+        class AncestorSequence extends NativeSequence implements TemplateFunctionModel,
+                BuiltInCallable {
+
+            private static final int INITIAL_CAPACITY = 12;
+
+            private Environment env;
+
+            AncestorSequence(Environment env) {
+                super(INITIAL_CAPACITY);
+                this.env = env;
+            }
+
+            @Override
+            public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
+                    throws TemplateException {
+                if (args.length == 0) {
+                    return this;
+                }
+                AncestorSequence result = new AncestorSequence(env);
+                for (int seqIdx = 0; seqIdx < size(); seqIdx++) {
+                    TemplateNodeModel tnm = (TemplateNodeModel) get(seqIdx);
+                    String nodeName = tnm.getNodeName();
+                    String nsURI = tnm.getNodeNamespace();
+                    if (nsURI == null) {
+                        for (int argIdx = 0; argIdx < args.length; argIdx++) {
+                            String name = getStringArgument(args, argIdx, this);
+                            if (name.equals(nodeName)) {
+                                result.add(tnm);
+                                break;
+                            }
+                        }
+                    } else {
+                        for (int argIdx = 0; argIdx < args.length; argIdx++) {
+                            if (_StringUtils.matchesQName(
+                                    getStringArgument(args, argIdx, this), nodeName, nsURI, env)) {
+                                result.add(tnm);
+                                break;
+                            }
+                        }
+                    }
+                }
+                return result;
+            }
+
+            @Override
+            public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+                return null;
+            }
+
+            @Override
+            public String getBuiltInName() {
+                return key;
+            }
+
+            @Override
+            public String getOriginName() {
+                return ASTExpBuiltIn.getOriginName(this);
+            }
+        }
     }
     
     static class childrenBI extends BuiltInForNode {
@@ -113,52 +175,4 @@ class BuiltInsForNodes {
     // Can't be instantiated
     private BuiltInsForNodes() { }
 
-    static class AncestorSequence extends NativeSequence implements TemplateFunctionModel {
-
-        private static final int INITIAL_CAPACITY = 12;
-
-        private Environment env;
-        
-        AncestorSequence(Environment env) {
-            super(INITIAL_CAPACITY);
-            this.env = env;
-        }
-
-        @Override
-        public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
-                throws TemplateException {
-            if (args.length == 0) {
-                return this;
-            }
-            AncestorSequence result = new AncestorSequence(env);
-            for (int seqIdx = 0; seqIdx < size(); seqIdx++) {
-                TemplateNodeModel tnm = (TemplateNodeModel) get(seqIdx);
-                String nodeName = tnm.getNodeName();
-                String nsURI = tnm.getNodeNamespace();
-                if (nsURI == null) {
-                    for (int argIdx = 0; argIdx < args.length; argIdx++) {
-                        String name = _CallableUtils.castArgToString(args, argIdx);
-                        if (name.equals(nodeName)) {
-                            result.add(tnm);
-                            break;
-                        }
-                    }
-                } else {
-                    for (int argIdx = 0; argIdx < args.length; argIdx++) {
-                        if (_StringUtils.matchesQName(
-                                _CallableUtils.castArgToString(args, argIdx), nodeName, nsURI, env)) {
-                            result.add(tnm);
-                            break;
-                        }
-                    }
-                }
-            }
-            return result;
-        }
-
-        @Override
-        public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
-            return null;
-        }
-    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/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 045432a..0e8dd2b 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,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.*;
+
 import java.io.Serializable;
 import java.text.Collator;
 import java.util.ArrayList;
@@ -64,7 +66,7 @@ class BuiltInsForSequences {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                int chunkSize = getNumberMethodArg(args, 0).intValue();
+                int chunkSize = getNumberArgument(args, 0, this).intValue();
 
                 return new ChunkedSequence(tsm, chunkSize, args[1]);
             }
@@ -183,7 +185,7 @@ class BuiltInsForSequences {
 
     static class joinBI extends ASTExpBuiltIn {
         
-        private class BIMethodForCollection implements TemplateFunctionModel {
+        private class BIMethodForCollection extends BuiltInCallableImpl implements TemplateFunctionModel {
             
             private final Environment env;
             private final TemplateCollectionModel coll;
@@ -196,9 +198,9 @@ class BuiltInsForSequences {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                final String separator = getStringMethodArg(args, 0);
-                final String whenEmpty = getStringMethodArg(args, 1, true);
-                final String afterLast = getStringMethodArg(args, 2, true);
+                final String separator = getStringArgument(args, 0, this);
+                final String whenEmpty = getOptionalStringArgument(args, 1, this);
+                final String afterLast = getOptionalStringArgument(args, 2, this);
 
                 StringBuilder sb = new StringBuilder();
 
@@ -411,7 +413,7 @@ class BuiltInsForSequences {
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
                 TemplateModel target = args[0];
-                Number startIndex = getNumberMethodArg(args, 1, true);
+                Number startIndex = getOptionalNumberArgument(args, 1, this);
                 int foundAtIdx;
                 if (startIndex != null) {
                     // TODO [FM3] Prefer Col?

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
index e6c9011..d31c885 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsBasic.java
@@ -19,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.*;
+
 import java.util.ArrayList;
 import java.util.StringTokenizer;
 import java.util.regex.Matcher;
@@ -80,7 +82,7 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                return s.contains(_CallableUtils.castArgToString(args, 0))
+                return s.contains(_CallableUtils.getStringArgument(args, 0, this))
                         ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
             }
 
@@ -99,7 +101,7 @@ class BuiltInsForStringsBasic {
 
     static class ends_withBI extends BuiltInForString {
     
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
     
             private BIMethod(String s) {
@@ -109,7 +111,7 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                return s.endsWith(getStringMethodArg(args, 0)) ?
+                return s.endsWith(getStringArgument(args, 0, this)) ?
                         TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
             }
 
@@ -127,7 +129,7 @@ class BuiltInsForStringsBasic {
 
     static class ensure_ends_withBI extends BuiltInForString {
         
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
     
             private BIMethod(String s) {
@@ -137,7 +139,7 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String suffix = getStringMethodArg(args, 0);
+                String suffix = getStringArgument(args, 0, this);
                 return new SimpleScalar(s.endsWith(suffix) ? s : s + suffix);
             }
 
@@ -155,7 +157,7 @@ class BuiltInsForStringsBasic {
 
     static class ensure_starts_withBI extends BuiltInForString {
         
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
     
             private BIMethod(String s) {
@@ -165,12 +167,12 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                final String checkedPrefix = getStringMethodArg(args, 0);
+                final String checkedPrefix = getStringArgument(args, 0, this);
 
                 final boolean startsWithPrefix;
                 final String addedPrefix;
-                String addedPrefixArg = getStringMethodArg(args, 1, true);
-                String flagsArg = getStringMethodArg(args, 2, true);
+                String addedPrefixArg = getOptionalStringArgument(args, 1, this);
+                String flagsArg = getOptionalStringArgument(args, 2, this);
                 if (addedPrefixArg != null) {
                     addedPrefix = addedPrefixArg;
                     long flags = flagsArg != null
@@ -214,7 +216,7 @@ class BuiltInsForStringsBasic {
 
     static class index_ofBI extends ASTExpBuiltIn {
         
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             
             private final String s;
             
@@ -225,8 +227,8 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String subStr = getStringMethodArg(args, 0);
-                Number indexModel = getNumberMethodArg(args, 1, true);
+                String subStr = getStringArgument(args, 0, this);
+                Number indexModel = getOptionalNumberArgument(args, 1, this);
                 if (indexModel != null) {
                     int startIdx = indexModel.intValue();
                     return new SimpleNumber(findLast ? s.lastIndexOf(subStr, startIdx) : s.indexOf(subStr, startIdx));
@@ -255,7 +257,7 @@ class BuiltInsForStringsBasic {
     }
     
     static class keep_afterBI extends BuiltInForString {
-        class KeepAfterMethod implements TemplateFunctionModel {
+        class KeepAfterMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
 
             KeepAfterMethod(String s) {
@@ -265,9 +267,9 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String separatorString = getStringMethodArg(args, 0);
+                String separatorString = getStringArgument(args, 0, this);
 
-                String flagsStr = getStringMethodArg(args, 1, true);
+                String flagsStr = getOptionalStringArgument(args, 1, this);
                 long flags = flagsStr != null ? RegexpHelper.parseFlagString(flagsStr) : 0;
 
                 int startIndex;
@@ -307,7 +309,7 @@ class BuiltInsForStringsBasic {
     }
     
     static class keep_after_lastBI extends BuiltInForString {
-        class KeepAfterMethod implements TemplateFunctionModel {
+        class KeepAfterMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
 
             KeepAfterMethod(String s) {
@@ -317,8 +319,8 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String separatorString = getStringMethodArg(args, 0);
-                String flagString = getStringMethodArg(args, 1, true);
+                String separatorString = getStringArgument(args, 0, this);
+                String flagString = getOptionalStringArgument(args, 1, this);
                 long flags = flagString != null ? RegexpHelper.parseFlagString(flagString) : 0;
 
                 int startIndex;
@@ -365,7 +367,7 @@ class BuiltInsForStringsBasic {
     }
     
     static class keep_beforeBI extends BuiltInForString {
-        class KeepUntilMethod implements TemplateFunctionModel {
+        class KeepUntilMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
 
             KeepUntilMethod(String s) {
@@ -375,8 +377,8 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String separatorString = getStringMethodArg(args, 0);
-                String flagString = getStringMethodArg(args, 1, true);
+                String separatorString = getStringArgument(args, 0, this);
+                String flagString = getOptionalStringArgument(args, 1, this);
                 long flags = flagString != null ? RegexpHelper.parseFlagString(flagString) : 0;
 
                 int stopIndex;
@@ -414,7 +416,7 @@ class BuiltInsForStringsBasic {
     
     // TODO
     static class keep_before_lastBI extends BuiltInForString {
-        class KeepUntilMethod implements TemplateFunctionModel {
+        class KeepUntilMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
 
             KeepUntilMethod(String s) {
@@ -424,8 +426,8 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String separatorString = getStringMethodArg(args, 0);
-                String flagString = getStringMethodArg(args, 1, true);
+                String separatorString = getStringArgument(args, 0, this);
+                String flagString = getOptionalStringArgument(args, 1, this);
                 long flags = flagString != null ? RegexpHelper.parseFlagString(flagString) : 0;
 
                 int stopIndex;
@@ -486,7 +488,7 @@ class BuiltInsForStringsBasic {
 
     static class padBI extends BuiltInForString {
         
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             
             private final String s;
     
@@ -497,9 +499,9 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                int width = getNumberMethodArg(args, 0).intValue();
+                int width = getNumberArgument(args, 0, this).intValue();
 
-                String filling = getStringMethodArg(args, 1, true);
+                String filling = getOptionalStringArgument(args, 1, this);
                 if (filling != null) {
                     try {
                         return new SimpleScalar(
@@ -540,7 +542,7 @@ class BuiltInsForStringsBasic {
     
     static class remove_beginningBI extends BuiltInForString {
         
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
     
             private BIMethod(String s) {
@@ -550,7 +552,7 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String prefix = getStringMethodArg(args, 0);
+                String prefix = getStringArgument(args, 0, this);
                 return new SimpleScalar(s.startsWith(prefix) ? s.substring(prefix.length()) : s);
             }
 
@@ -568,7 +570,7 @@ class BuiltInsForStringsBasic {
 
     static class remove_endingBI extends BuiltInForString {
     
-        private class BIMethod implements TemplateFunctionModel {
+        private class BIMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
     
             private BIMethod(String s) {
@@ -578,7 +580,7 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String suffix = getStringMethodArg(args, 0);
+                String suffix = getStringArgument(args, 0, this);
                 return new SimpleScalar(s.endsWith(suffix) ? s.substring(0, s.length() - suffix.length()) : s);
             }
 
@@ -595,7 +597,7 @@ class BuiltInsForStringsBasic {
     }
     
     static class split_BI extends BuiltInForString {
-        class SplitMethod implements TemplateFunctionModel {
+        class SplitMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
 
             SplitMethod(String s) {
@@ -605,11 +607,10 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                int argCnt = args.length;
-                String splitString = getStringMethodArg(args, 0);
+                String splitString = getStringArgument(args, 0, this);
                 TemplateModel arg2 = args[1];
                 long flags = arg2 != null
-                        ? RegexpHelper.parseFlagString(getStringMethodArg(args, 1))
+                        ? RegexpHelper.parseFlagString(getStringArgument(args, 1, this))
                         : 0;
                 String[] result;
                 if ((flags & RegexpHelper.RE_FLAG_REGEXP) == 0) {
@@ -648,7 +649,7 @@ class BuiltInsForStringsBasic {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                return s.startsWith(getStringMethodArg(args, 0)) ?
+                return s.startsWith(getStringArgument(args, 0, this)) ?
                         TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
             }
 
@@ -668,62 +669,68 @@ class BuiltInsForStringsBasic {
         
         @Override
         TemplateModel calculateResult(final String s, final Environment env) throws TemplateException {
-            return new TemplateFunctionModel() {
+            return new MyTemplateFunctionModel(s);
+        }
 
-                @Override
-                public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
-                        throws TemplateException {
-                    int beginIdx = getNumberMethodArg(args, 0).intValue();
+        private class MyTemplateFunctionModel extends BuiltInCallableImpl implements TemplateFunctionModel {
 
-                    final int len = s.length();
+            private final String s;
 
-                    if (beginIdx < 0) {
-                        throw newIndexLessThan0Exception(0, beginIdx);
-                    } else if (beginIdx > len) {
-                        throw newIndexGreaterThanLengthException(0, beginIdx, len);
-                    }
+            public MyTemplateFunctionModel(String s) {
+                this.s = s;
+            }
 
-                    Number endIdxNumber = getNumberMethodArg(args, 1, true);
-                    if (endIdxNumber != null) {
-                        int endIdx = endIdxNumber.intValue();
-                        if (endIdx < 0) {
-                            throw newIndexLessThan0Exception(1, endIdx);
-                        } else if (endIdx > len) {
-                            throw newIndexGreaterThanLengthException(1, endIdx, len);
-                        }
-                        if (beginIdx > endIdx) {
-                            throw MessageUtils.newMethodArgsInvalidValueException("?" + key,
-                                    "The begin index argument, ", beginIdx,
-                                    ", shouldn't be greater than the end index argument, ",
-                                    endIdx, ".");
-                        }
-                        return new SimpleScalar(s.substring(beginIdx, endIdx));
-                    } else {
-                        return new SimpleScalar(s.substring(beginIdx));
-                    }
-                }
+            @Override
+            public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
+                    throws TemplateException {
+                int beginIdx = getNumberArgument(args, 0, this).intValue();
 
-                @Override
-                public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
-                    return ArgumentArrayLayout.TWO_POSITIONAL_PARAMETERS;
-                }
+                final int len = s.length();
 
-                private TemplateException newIndexGreaterThanLengthException(
-                        int argIdx, int idx, final int len) throws TemplateModelException {
-                    return MessageUtils.newMethodArgInvalidValueException(
-                            "?" + key, argIdx,
-                            "The index mustn't be greater than the length of the string, ",
-                            len, ", but it was ", idx, ".");
+                if (beginIdx < 0) {
+                    throw newIndexLessThan0Exception(0, beginIdx);
+                } else if (beginIdx > len) {
+                    throw newIndexGreaterThanLengthException(0, beginIdx, len);
                 }
-    
-                private TemplateException newIndexLessThan0Exception(
-                        int argIdx, int idx) throws TemplateModelException {
-                    return MessageUtils.newMethodArgInvalidValueException(
-                            "?" + key, argIdx,
-                            "The index must be at least 0, but was ", idx, ".");
+
+                Number endIdxNumber = getOptionalNumberArgument(args, 1, this);
+                if (endIdxNumber != null) {
+                    int endIdx = endIdxNumber.intValue();
+                    if (endIdx < 0) {
+                        throw newIndexLessThan0Exception(1, endIdx);
+                    } else if (endIdx > len) {
+                        throw newIndexGreaterThanLengthException(1, endIdx, len);
+                    }
+                    if (beginIdx > endIdx) {
+                        throw newGenericExecuteException(this,
+                                "The begin index argument, " + beginIdx
+                                + ", shouldn't be greater than the end index argument, " + endIdx + ".");
+                    }
+                    return new SimpleScalar(s.substring(beginIdx, endIdx));
+                } else {
+                    return new SimpleScalar(s.substring(beginIdx));
                 }
-                
-            };
+            }
+
+            @Override
+            public ArgumentArrayLayout getFunctionArgumentArrayLayout() {
+                return ArgumentArrayLayout.TWO_POSITIONAL_PARAMETERS;
+            }
+
+            private TemplateException newIndexGreaterThanLengthException(
+                    int argIdx, int idx, final int len) throws TemplateModelException {
+                return newArgumentValueException(
+                        argIdx,
+                        "mustn't be greater than the length of the string, " + len + ", but it was " + idx + ".",
+                        this);
+            }
+
+            private TemplateException newIndexLessThan0Exception(
+                    int argIdx, int idx) throws TemplateModelException {
+                return newArgumentValueException(
+                        argIdx, "must be at least 0, but was " + idx + ".", this);
+            }
+
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsEncoding.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsEncoding.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsEncoding.java
index 5c6ad97..7a3fe12 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsEncoding.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsEncoding.java
@@ -19,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.getStringArgument;
+
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.UnsupportedCharsetException;
@@ -82,7 +84,7 @@ class BuiltInsForStringsEncoding {
             protected String encodeWithCharset(Charset charset) throws UnsupportedEncodingException {
                 return _StringUtils.URLEnc(targetAsString, charset);
             }
-            
+
         }
         
         @Override
@@ -131,8 +133,8 @@ class BuiltInsForStringsEncoding {
     // Can't be instantiated
     private BuiltInsForStringsEncoding() { }
 
-    static abstract class AbstractUrlBIResult implements
-    TemplateScalarModel, TemplateFunctionModel {
+    static abstract class AbstractUrlBIResult implements TemplateScalarModel, TemplateFunctionModel,
+            ASTExpBuiltIn.BuiltInCallable {
         
         protected final ASTExpBuiltIn parent;
         protected final String targetAsString;
@@ -151,7 +153,7 @@ class BuiltInsForStringsEncoding {
         public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                 throws TemplateException {
             try {
-                String charsetName = _CallableUtils.castArgToString(args,0);
+                String charsetName = getStringArgument(args,0, this);
                 Charset charset;
                 try {
                     charset = Charset.forName(charsetName);
@@ -194,7 +196,16 @@ class BuiltInsForStringsEncoding {
             }
             return cachedResult;
         }
-        
+
+        @Override
+        public String getBuiltInName() {
+            return parent.key;
+        }
+
+        @Override
+        public String getOriginName() {
+            return ASTExpBuiltIn.getOriginName(this);
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
index a0fa172..6879477 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
@@ -19,6 +19,8 @@
 
 package org.apache.freemarker.core;
 
+import static org.apache.freemarker.core._CallableUtils.*;
+
 import java.util.ArrayList;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -61,7 +63,7 @@ class BuiltInsForStringsRegexp {
     }
     
     static class matchesBI extends BuiltInForString {
-        class MatcherBuilder implements TemplateFunctionModel {
+        class MatcherBuilder extends BuiltInCallableImpl implements TemplateFunctionModel {
             
             String matchString;
             
@@ -73,8 +75,8 @@ class BuiltInsForStringsRegexp {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String patternString = getStringMethodArg(args, 0);
-                String flagString = getStringMethodArg(args, 1, true);
+                String patternString = getStringArgument(args, 0, this);
+                String flagString = getOptionalStringArgument(args, 1, this);
                 long flags = flagString != null
                         ? RegexpHelper.parseFlagString(flagString)
                         : 0;
@@ -101,7 +103,7 @@ class BuiltInsForStringsRegexp {
     
     static class replace_reBI extends BuiltInForString {
         
-        class ReplaceMethod implements TemplateFunctionModel {
+        class ReplaceMethod extends BuiltInCallableImpl implements TemplateFunctionModel {
             private String s;
 
             ReplaceMethod(String s) {
@@ -111,9 +113,9 @@ class BuiltInsForStringsRegexp {
             @Override
             public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
                     throws TemplateException {
-                String arg1 = getStringMethodArg(args, 0);
-                String arg2 = getStringMethodArg(args, 1);
-                String flagString = getStringMethodArg(args, 2, true);
+                String arg1 = getStringArgument(args, 0, this);
+                String arg2 = getStringArgument(args, 1, this);
+                String flagString = getOptionalStringArgument(args, 2, this);
                 long flags = flagString != null
                         ? RegexpHelper.parseFlagString(flagString)
                         : 0;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
index 59b390f..fcf9471 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
@@ -55,6 +55,7 @@ import org.apache.freemarker.core.model.TemplateHashModelEx;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.TemplateModelWithOriginName;
 import org.apache.freemarker.core.model.TemplateNodeModel;
 import org.apache.freemarker.core.model.TemplateNumberModel;
 import org.apache.freemarker.core.model.TemplateScalarModel;
@@ -2559,7 +2560,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
             lazyImport = false;
             // As we have an already normalized name, we use it. 2.3.x note: We should use the template.sourceName as
             // namespace key, but historically we use the looked up name (template.name); check what lazy import does if
-            // that will be oms, as that can't do the template lookup, yet the keys must be the same.
+            // that will be fixed, as that can't do the template lookup, yet the keys must be the same.
             templateName = loadedTemplate.getLookupName();
         } else {
             lazyImport = true;
@@ -2928,7 +2929,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
     /**
      * Superclass of {@link TemplateCallableModel}-s implemented in the template language.
      */
-    abstract class TemplateLanguageCallable implements TemplateCallableModel {
+    abstract class TemplateLanguageCallable implements TemplateCallableModel, TemplateModelWithOriginName {
         final ASTDirMacroOrFunction callableDefinition;
         private final Namespace namespace;
 
@@ -2937,6 +2938,13 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
             this.namespace = namespace;
         }
 
+        @Override
+        public String getOriginName() {
+            String sourceName = callableDefinition.getTemplate().getSourceName();
+            return sourceName != null ? sourceName + ":" + callableDefinition.getName()
+                    : callableDefinition.getName();
+        }
+
         protected void genericExecute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
                 throws TemplateException, IOException {
             pushElement(callableDefinition);
@@ -2972,6 +2980,8 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
             }
         }
 
+        abstract boolean isFunction();
+
         private void setLocalsFromArguments(ASTDirMacroOrFunction.Context macroCtx, TemplateModel[] args)
                 throws TemplateException {
             ASTDirMacroOrFunction.ParameterDefinition[] paramDefsByArgIdx =
@@ -2991,22 +3001,20 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
                         // it was null, but this will be fixed with the null related refactoring.
                         throw new TemplateException(Environment.this,
                                 new _ErrorDescriptionBuilder(
-                                        "When calling macro ", new _DelayedJQuote(callableDefinition.getName()),
-                                        ", required parameter ", new _DelayedJQuote(paramDef.getName()),
-                                        (argIdx < callableDefinition.getArgumentArrayLayout()
-                                                        .getPredefinedPositionalArgumentCount()
-                                                ? new Object[] { " (parameter #", (argIdx + 1), ")" }
-                                                : ""),
-                                        " was either not specified, or had null/missing value.")
-                                        .tip("If the parameter value expression on the caller side is known to "
-                                                + "be legally null/missing, you may want to specify a default "
-                                                + "value for it on the caller side with the \"!\" operator, like "
-                                                + "paramValue!defaultValue.")
-                                        .tip("If the parameter was omitted on the caller side, and the omission was "
-                                                + "deliberate, you may consider making the parameter optional in the macro "
-                                                + "by specifying a default value for it, like <#macro macroName "
-                                                + "paramName=defaultExpr>."
-                                        )
+                                        _CallableUtils.getMessageArgumentProblem(
+                                                this, argIdx,
+                                                " can't be null or omitted.",
+                                                isFunction())
+                                )
+                                .tip("If the parameter value expression on the caller side is known to "
+                                        + "be legally null/missing, you may want to specify a default "
+                                        + "value for it on the caller side with the \"!\" operator, like "
+                                        + "paramValue!defaultValue.")
+                                .tip("If the parameter was omitted on the caller side, and the omission was "
+                                        + "deliberate, you may consider making the parameter optional in the macro "
+                                        + "by specifying a default value for it, like <#macro macroName "
+                                        + "paramName=defaultExpr>."
+                                )
                         );
                     }
                 }
@@ -3029,7 +3037,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
      */
     final class TemplateLanguageDirective extends TemplateLanguageCallable implements TemplateDirectiveModel {
 
-        public TemplateLanguageDirective(ASTDirMacroOrFunction macroDef, Namespace namespace) {
+        TemplateLanguageDirective(ASTDirMacroOrFunction macroDef, Namespace namespace) {
             super(macroDef, namespace);
         }
 
@@ -3054,6 +3062,10 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
             return callableDefinition.getArgumentArrayLayout();
         }
 
+        boolean isFunction() {
+            return false;
+        }
+
     }
 
     /**
@@ -3084,6 +3096,10 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
             return callableDefinition.getArgumentArrayLayout();
         }
 
+        boolean isFunction() {
+            return true;
+        }
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
index b7fdf4c..0edbee6 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
@@ -19,9 +19,6 @@
 
 package org.apache.freemarker.core;
 
-import java.util.ArrayList;
-
-import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.util._StringUtils;
 import org.apache.freemarker.core.valueformat.TemplateDateFormat;
@@ -59,10 +56,6 @@ class MessageUtils {
     // Can't be instantiated
     private MessageUtils() { }
 
-    static String formatLocationForSimpleParsingError(Template template, int line, int column) {
-        return formatLocation("in", template, line, column);
-    }
-
     static String formatLocationForSimpleParsingError(String templateSourceOrLookupName, int line, int column) {
         return formatLocation("in", templateSourceOrLookupName, line, column);
     }
@@ -177,104 +170,6 @@ class MessageUtils {
         return sb;
     }
 
-    static TemplateException newArgCntError(String methodName, int argCnt, int expectedCnt) {
-        return newArgCntError(methodName, argCnt, expectedCnt, expectedCnt);
-    }
-    
-    static TemplateException newArgCntError(String methodName, int argCnt, int minCnt, int maxCnt) {
-        ArrayList/*<Object>*/ desc = new ArrayList(20);
-        
-        desc.add(methodName);
-        
-        desc.add("(");
-        if (maxCnt != 0) desc.add("...");
-        desc.add(") expects ");
-        
-        if (minCnt == maxCnt) {
-            if (maxCnt == 0) {
-                desc.add("no");
-            } else {
-                desc.add(Integer.valueOf(maxCnt));
-            }
-        } else if (maxCnt - minCnt == 1) {
-            desc.add(Integer.valueOf(minCnt));
-            desc.add(" or ");
-            desc.add(Integer.valueOf(maxCnt));
-        } else {
-            desc.add(Integer.valueOf(minCnt));
-            if (maxCnt != Integer.MAX_VALUE) {
-                desc.add(" to ");
-                desc.add(Integer.valueOf(maxCnt));
-            } else {
-                desc.add(" or more (unlimited)");
-            }
-        }
-        desc.add(" argument");
-        if (maxCnt > 1) desc.add("s");
-        
-        desc.add(" but has received ");
-        if (argCnt == 0) {
-            desc.add("none");
-        } else {
-            desc.add(Integer.valueOf(argCnt));
-        }
-        desc.add(".");
-        
-        return new TemplateException(desc.toArray());
-    }
-
-    static TemplateException newMethodArgMustBeStringException(String methodName, int argIdx, TemplateModel arg) {
-        return newMethodArgUnexpectedTypeException(methodName, argIdx, "string", arg);
-    }
-
-    static TemplateException newMethodArgMustBeNumberException(String methodName, int argIdx, TemplateModel arg) {
-        return newMethodArgUnexpectedTypeException(methodName, argIdx, "number", arg);
-    }
-    
-    static TemplateException newMethodArgMustBeBooleanException(String methodName, int argIdx, TemplateModel arg) {
-        return newMethodArgUnexpectedTypeException(methodName, argIdx, "boolean", arg);
-    }
-    
-    static TemplateException newMethodArgMustBeExtendedHashException(
-            String methodName, int argIdx, TemplateModel arg) {
-        return newMethodArgUnexpectedTypeException(methodName, argIdx, "extended hash", arg);
-    }
-    
-    static TemplateException newMethodArgMustBeSequenceException(
-            String methodName, int argIdx, TemplateModel arg) {
-        return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence", arg);
-    }
-    
-    static TemplateException newMethodArgMustBeSequenceOrCollectionException(
-            String methodName, int argIdx, TemplateModel arg) {
-        return newMethodArgUnexpectedTypeException(methodName, argIdx, "sequence or collection", arg);
-    }
-    
-    static TemplateException newMethodArgUnexpectedTypeException(
-            String methodName, int argIdx, String expectedType, TemplateModel arg) {
-        return new _TemplateModelException(
-                methodName, "(...) expects ", new _DelayedAOrAn(expectedType), " as argument #", Integer.valueOf(argIdx + 1),
-                ", but received ", new _DelayedAOrAn(new _DelayedTemplateLanguageTypeDescription(arg)), ".");
-    }
-    
-    /**
-     * The type of the argument was good, but it's value wasn't.
-     */
-    static TemplateException newMethodArgInvalidValueException(
-            String methodName, int argIdx, Object... details) {
-        return new _TemplateModelException(
-                methodName, "(...) argument #", Integer.valueOf(argIdx + 1),
-                " had invalid value: ", details);
-    }
-
-    /**
-     * The type of the argument was good, but the values of two or more arguments are inconsistent with each other.
-     */
-    static TemplateException newMethodArgsInvalidValueException(
-            String methodName, Object... details) {
-        return new _TemplateModelException(methodName, "(...) arguments have invalid value: ", details);
-    }
-    
     static TemplateException newInstantiatingClassNotAllowedException(String className, Environment env) {
         return new TemplateException(env,
                 "Instantiating ", className, " is not allowed in the template for security reasons.");

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/NonNumericalException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NonNumericalException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NonNumericalException.java
index 1b9b586..e943bad 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NonNumericalException.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NonNumericalException.java
@@ -19,8 +19,7 @@
 
 package org.apache.freemarker.core;
 
-import java.io.Serializable;
-
+import org.apache.freemarker.core.model.TemplateCallableModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateNumberModel;
 
@@ -69,9 +68,10 @@ public class NonNumericalException extends UnexpectedTypeException {
 
 
     NonNumericalException(
-            Serializable argumentNameOrIndex, TemplateModel model, String[] tips, Environment env)
+            TemplateCallableModel callableModel, int argArrayIndex,
+            TemplateModel model, String[] tips, Environment env)
             throws InvalidReferenceException {
-        super(argumentNameOrIndex, model, "number", EXPECTED_TYPES, tips, env);
+        super(callableModel, argArrayIndex, model, "number", EXPECTED_TYPES, tips, env);
     }
 
     static NonNumericalException newMalformedNumberException(ASTExpression blamed, String text, Environment env) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/e941aedc/freemarker-core/src/main/java/org/apache/freemarker/core/NonStringException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NonStringException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NonStringException.java
index 6cf29f4..ec02f73 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NonStringException.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NonStringException.java
@@ -19,9 +19,8 @@
 
 package org.apache.freemarker.core;
 
-import java.io.Serializable;
-
 import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateCallableModel;
 import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateNumberModel;
@@ -76,9 +75,10 @@ public class NonStringException extends UnexpectedTypeException {
     }
 
     NonStringException(
-            Serializable argumentNameOrIndex, TemplateModel model, String[] tips, Environment env)
+            TemplateCallableModel callableModel, int argArrayIndex,
+            TemplateModel model, String[] tips, Environment env)
             throws InvalidReferenceException {
-        super(argumentNameOrIndex, model, "string", EXPECTED_TYPES, tips, env);
+        super(callableModel, argArrayIndex, model, "string", EXPECTED_TYPES, tips, env);
     }
 
 }