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 <ddek...@apache.org> Authored: Mon Aug 14 20:05:14 2017 +0200 Committer: ddekany <ddek...@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); } }