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/07 22:32:22 UTC
[20/21] incubator-freemarker git commit: FREEMARKER-63: Lot of
refinement in the API-s and implementation. #macro now creates a
`TemplateDirectiveModel`,
and #function now creates `TemplateFunctionModel` (though the function/method
call syntax doesn't ye
FREEMARKER-63: Lot of refinement in the API-s and implementation. #macro now creates a `TemplateDirectiveModel`, and #function now creates `TemplateFunctionModel` (though the function/method call syntax doesn't yet allow named parameters). Test suite passes.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/3cacd9ed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/3cacd9ed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/3cacd9ed
Branch: refs/heads/3
Commit: 3cacd9ed04a231af67e3964525fd592b97da1665
Parents: da4c332
Author: ddekany <dd...@apache.org>
Authored: Thu Aug 3 23:11:57 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Thu Aug 3 23:11:57 2017 +0200
----------------------------------------------------------------------
FM3-CHANGE-LOG.txt | 48 ++-
.../freemarker/core/CanonicalFormTest.java | 4 +-
.../freemarker/core/DirectiveCallPlaceTest.java | 1 -
.../EnvironmentGetTemplateVariantsTest.java | 1 -
.../core/MistakenlyPublicMacroAPIsTest.java | 21 +-
.../core/ParsingErrorMessagesTest.java | 65 +++-
.../core/TemplateCallableModelTest.java | 140 +++++--
.../core/TheadInterruptingSupportTest.java | 1 -
.../core/userpkg/AllFeaturesDirective.java | 9 +-
.../core/userpkg/AllFeaturesFunction.java | 114 ++++++
.../core/userpkg/NamedVarargsOnlyDirective.java | 5 +-
.../userpkg/PositionalVarargsOnlyDirective.java | 13 +-
.../userpkg/PositionalVarargsOnlyFunction.java | 62 +++
.../core/userpkg/TestTemplateCallableModel.java | 88 +++++
.../userpkg/TestTemplateDirectiveModel.java | 88 -----
.../core/userpkg/TwoNamedParamsDirective.java | 5 +-
.../TwoNestedContentParamsDirective.java | 5 +-
.../userpkg/TwoPositionalParamsDirective.java | 5 +-
.../userpkg/TwoPositionalParamsFunction.java | 63 +++
.../core/userpkg/UpperCaseDirective.java | 2 +-
.../core/util/StringToIndexMapTest.java | 5 +
.../core/valueformat/NumberFormatTest.java | 2 +-
.../org/apache/freemarker/core/ast-1.ast | 24 +-
.../apache/freemarker/core/ast-assignments.ast | 3 +-
.../freemarker/core/cano-macro-and-function.ftl | 43 +++
.../core/cano-macro-and-function.ftl.out | 42 ++
.../org/apache/freemarker/core/cano-macros.ftl | 29 --
.../apache/freemarker/core/cano-macros.ftl.out | 28 --
.../core/templatesuite/expected/macros2.txt | 22 --
.../templatesuite/templates/api-builtins.ftl | 20 +-
.../core/templatesuite/templates/boolean.ftl | 8 +-
.../templatesuite/templates/comparisons.ftl | 216 +++++------
.../templates/date-type-builtins.ftl | 32 +-
.../templatesuite/templates/dateparsing.ftl | 4 +-
.../templates/existence-operators.ftl | 34 +-
.../core/templatesuite/templates/hashconcat.ftl | 2 +-
.../templates/identifier-non-ascii.ftl | 2 +-
.../core/templatesuite/templates/list.ftl | 2 +-
.../core/templatesuite/templates/list2.ftl | 2 +-
.../core/templatesuite/templates/list3.ftl | 8 +-
.../core/templatesuite/templates/listhash.ftl | 2 +-
.../core/templatesuite/templates/macros.ftl | 17 +-
.../core/templatesuite/templates/macros2.ftl | 35 --
.../templates/number-math-builtins.ftl | 68 ++--
.../core/templatesuite/templates/recover.ftl | 8 +-
.../core/templatesuite/templates/root.ftl | 2 +-
.../templates/sequence-builtins.ftl | 18 +-
.../templates/string-builtin-coercion.ftl | 24 +-
.../templates/string-builtins-regexps.ftl | 6 +-
.../core/templatesuite/templates/var-layers.ftl | 2 +-
.../freemarker/core/templatesuite/testcases.xml | 1 -
.../org/apache/freemarker/core/ASTDirMacro.java | 325 ----------------
.../freemarker/core/ASTDirMacroOrFunction.java | 369 ++++++++++++++++++
.../apache/freemarker/core/ASTDirNested.java | 91 ++---
.../apache/freemarker/core/ASTDirReturn.java | 2 +-
.../freemarker/core/ASTDynamicTopLevelCall.java | 164 ++++----
.../org/apache/freemarker/core/ASTElement.java | 4 +-
.../freemarker/core/ASTExpBuiltInVariable.java | 4 +-
.../freemarker/core/ASTExpListLiteral.java | 8 +-
.../freemarker/core/ASTExpMethodCall.java | 117 +++++-
.../apache/freemarker/core/ASTStaticText.java | 2 +-
.../core/BuiltInsForMultipleTypes.java | 14 +-
.../freemarker/core/BuiltInsForStringsMisc.java | 1 -
.../org/apache/freemarker/core/CallPlace.java | 195 ++++++++++
...lPlaceCustomDataInitializationException.java | 3 +-
.../org/apache/freemarker/core/Environment.java | 379 +++++++++++--------
.../apache/freemarker/core/LocalContext.java | 2 +-
.../org/apache/freemarker/core/MessageUtil.java | 2 +-
.../freemarker/core/NonDirectiveException.java | 63 +++
.../freemarker/core/NonTemplateCallPlace.java | 166 ++++++++
.../NonUserDefinedDirectiveLikeException.java | 65 ----
.../apache/freemarker/core/ParameterRole.java | 6 +-
.../org/apache/freemarker/core/Template.java | 2 +-
.../core/TemplateCallableModelUtils.java | 46 ---
...nterruptionSupportTemplatePostProcessor.java | 1 -
.../org/apache/freemarker/core/_CoreAPI.java | 10 +-
.../core/_ErrorDescriptionBuilder.java | 5 +-
.../core/_TemplateCallableModelUtils.java | 112 ++++++
.../core/model/ArgumentArrayLayout.java | 101 +++--
.../apache/freemarker/core/model/CallPlace.java | 179 ---------
.../apache/freemarker/core/model/Constants.java | 2 +
.../core/model/TemplateCallableModel.java | 6 +-
.../core/model/TemplateDirectiveModel.java | 43 ++-
.../core/model/TemplateFunctionModel.java | 41 +-
.../core/util/DuplicateStringKeyException.java | 38 ++
.../apache/freemarker/core/util/FTLUtil.java | 40 +-
.../freemarker/core/util/StringToIndexMap.java | 29 +-
freemarker-core/src/main/javacc/FTL.jj | 328 ++++++++++------
.../examples/AutoEscapingExample-infoBox.ftlh | 2 +-
.../apache/freemarker/servlet/IncludePage.java | 2 +-
.../jsp/CustomTagAndELFunctionCombiner.java | 2 +-
.../servlet/jsp/SimpleTagDirectiveModel.java | 2 +-
.../servlet/jsp/TagDirectiveModel.java | 2 +-
.../test/templateutil/AssertDirective.java | 16 +-
.../templateutil/AssertEqualsDirective.java | 2 +-
.../test/templateutil/AssertFailsDirective.java | 2 +-
.../test/templateutil/NoOutputDirective.java | 2 +-
97 files changed, 2709 insertions(+), 1739 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index 21ce533..aab66b7 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -48,7 +48,21 @@ Major changes / features
Examples:
`<@x x + 1 2 3 />` now must be written as `<@x x + 1, 2, 3 />`
`<#nested x y>` now must be written as `<#nested x, y>`
-- TemplateDirectiveModel was redesigned to be more universal.
+- #macro-s and #function
+ - Both #macro-s and #function-s can now define parameters that are passed by position, and that are passed by name.
+ Function parameters are by default positional, which can be changed by adding `{named}` after the parameter name.
+ Macro parameters are by default named, which can be changed by adding `{positional}` after the parameter name.
+ Positional parameters always precede the named ones. There can be both a positional and a named varargs parameter;
+ the first is always a sequnce, the later is always a hash.
+ Examples:
+ - All named: `<#macro heading title icon>...</#macro>` `<@heading title="Test" icon="foo.jpg" />`
+ - Mixed: `<#macro heading title{positional} icon>...</#macro>` `<@heading "Test" icon="foo.jpg" />`
+ - All positional: `<#function f(x, y, r=0)>...</#function>` `${f(1, 2)} ${f(1, 2, 10)}`
+ - Mixed: `<#function f(x, y, r{named}=0)>...</#function>` `${f(1, 2)} ${f(1, 2, r=10)}`
+ - Positional varargs: `<#function sum(xs... abs{named}=false)>...</#function>` `${sum(1, 2, 3, abs=true)}
+ - Positional and named varargs: `<#function f(xs..., props{named}...)>...</#function>` `${f(1, 2, 3, x=1, y=2)}`
+ - In FM2, the same macro could be called with specifying all parameters by position, or by specifying all parameters
+ by name. In FM3 that won't work anymore, as now a parameter is either strictly positional or strictly named.
Smaller changes
---------------
@@ -104,13 +118,25 @@ Node: Changes already mentioned above aren't repeated here!
- TemplateDirectiveModel was redesigend (see in the major changes section)
- Removed `TemplateTransformModel`; `TemplateDirectiveModel` can do the same things, and more.
- Renamed `DirectiveCallPlace` to `CallPlace`
- - Removed Environment.getDirectiveCallPlace(), as TemplateDirectiveModel-s now get the CallPlace as the parameter
- of the `execute` method.
+ - Removed Environment.getDirectiveCallPlace(), as TemplateDirectiveModel-s now get the CallPlace as the
+ parameter of the `execute` method.
- ?isTransform was removed (as there are no transforms anymore).
Converter note: The template converter tool replaces it with ?isDirective
- The directive returned by `?interpret` doesn't allow nested content anymore. (It wasn't useful earlier either;
the nested content was simply executed after the interpreted string.)
-
+- Changes in #macro/#functions
+ - See major changes first, in the earlier chapter
+ - It's not tolerated anymore if the caller of a macro has declared more nested content parameters than
+ what `#nested` passes to it (like in `<#macro m><#nested 1, 2></#macro> <@m ; i, j, k>...</@>`, where `k` has
+ no corresponding value in `#nested`).
+ - In `#macro` (and `function`) named parameters with default values need not be at the end of the parameter list
+ anymore. (Positional parameters with default values need to be at the end of the list of positional parameters
+ only.)
+ - When parameter default expressions are evaluated, only the parameters defined earlier are already set.
+ So `<#macro m a b=a>` works, but `<#macro m a=b b>` won't work anymore (unless there's `b` outside the
+ parameter list), as `b` is not yet set when the default of `a` is calculated.
+
+
Java API changes
================
@@ -165,7 +191,18 @@ Major changes / features
- Configuration is now immutable. You should use Configuration.Builder to set up the setting values, then create
the Configuration with the builder's build() method.
- Configuration defaults were changed to follow the current best practices (like default charset is UTF-8 everywhere)
-- Removed freemarker.ext.log, our log abstraction layer from the old times when there was no clear winner on this field.
+- Reworked callable `TemplateModel`-s (i.e., models that can be called like `foo(...)` or as `<@foo .../>`)
+ - Earlier there were several callable `TemplateModel` internfaces (`TemplateMethodModel`, `TemplateMethodModelEx`,
+ `TemplateDirectiveModel`, `TemplateTransformModel`). FM3 replaces them with only two new interfaces,
+ `TemplateDirectiveModel` (differs from the interface with identical name in FM2) and `TemplateFunctionModel`.
+ (These are both the subinterfaces of another new interface `TemplateCallableModel`.)
+ [TODO: TemplateMethodModel[Ex] wasn't yet replaced by TemplateFunctionModel.]
+ - All callable TempalteModel-s support passing parameters by position and by name, even in the same call
+ (e.g., `<@heading "Some title" icon="foo.jpg" />`, `sum(1, 2, 3, abs=true)`)
+ - `#macro` now produces a `TemplateDirectiveModel` and `#function` produces a `TemplateFunctionModel`. (Earlier, the
+ product was just a generic `TemplateModel` that could only be invoked using internal API-s, and had capabilities
+ that the callable TemplateModel-s coulnd't have.)
+- Removed freemarker.ext.log, our log abstraction layer from the times when there was no clear winner on this field.
Added org.slf4j:slf4j-api as required dependency instead.
- Added Spring support to the FreeMarker project (freemarker-spring module), instead of relying Spring developers
[Note: This is in very early stage, as of 2017-07-06.]
@@ -426,6 +463,7 @@ Core / Miscellaneous
"compress"
- Removed `NestedContentNotSupportedException`, as `TemplateDirectiveModel.isNestedContentSupported()` now takes care
of that problem.
+- CallPlaceCustomDataInitializationException is not a checked exception anymore (now it extends RuntimeException)
Build / development process changes
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
index fd1a5a5..1bf4888 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
@@ -33,8 +33,8 @@ public class CanonicalFormTest extends FileTestCase {
super(name);
}
- public void testMacrosCanonicalForm() throws Exception {
- assertCanonicalFormOf("cano-macros.ftl");
+ public void testCallableDefinitionCanonicalForm() throws Exception {
+ assertCanonicalFormOf("cano-macro-and-function.ftl");
}
public void testIdentifierEscapingCanonicalForm() throws Exception {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
index f959b1d..7ee42c2 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
@@ -27,7 +27,6 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModel;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
index 10205e9..a094ec6 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
@@ -26,7 +26,6 @@ import java.io.Writer;
import java.util.Collections;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.impl.SimpleScalar;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
index 9c87e61..ad27627 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
@@ -19,15 +19,12 @@
package org.apache.freemarker.core;
-import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util._NullWriter;
import org.apache.freemarker.test.TestConfigurationBuilder;
import org.junit.Test;
@@ -44,7 +41,7 @@ public class MistakenlyPublicMacroAPIsTest {
@Test
public void testMacroCopyingExploit() throws IOException, TemplateException {
Template tMacros = new Template(null, "<#macro m1>1</#macro><#macro m2>2</#macro>", cfg);
- Map<String, ASTDirMacro> macros = tMacros.getMacros();
+ Map<String, ASTDirMacroOrFunction> macros = tMacros.getMacros();
Template t = new Template(null,
"<@m1/><@m2/><@m3/>"
@@ -60,25 +57,11 @@ public class MistakenlyPublicMacroAPIsTest {
public void testMacroCopyingExploitAndNamespaces() throws IOException, TemplateException {
Template tMacros = new Template(null, "<#assign x = 0><#macro m1>${x}</#macro>", cfg);
Template t = new Template(null, "<#assign x = 1><@m1/>", cfg);
- t.addMacro((ASTDirMacro) tMacros.getMacros().get("m1"));
+ t.addMacro((ASTDirMacroOrFunction) tMacros.getMacros().get("m1"));
assertEquals("1", getTemplateOutput(t));
}
- @Test
- public void testMacroCopyingFromFTLVariable() throws IOException, TemplateException {
- Template tMacros = new Template(null, "<#assign x = 0><#macro m1>${x}</#macro>", cfg);
- Environment env = tMacros.createProcessingEnvironment(null, _NullWriter.INSTANCE);
- env.process();
- TemplateModel m1 = env.getVariable("m1");
- assertThat(m1, instanceOf(ASTDirMacro.class));
-
- Template t = new Template(null, "<#assign x = 1><@m1/>", cfg);
- t.addMacro((ASTDirMacro) m1);
-
- assertEquals("1", getTemplateOutput(t));
- }
-
private String getTemplateOutput(Template t) throws TemplateException, IOException {
StringWriter sw = new StringWriter();
t.process(null, sw);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
index 77dbe0a..3189615 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
@@ -62,7 +62,9 @@ public class ParsingErrorMessagesTest {
@Test
public void testUnclosedDirectives() {
assertErrorContains("<#macro x>", "#macro", "unclosed");
+ assertErrorContains("<#macro x></#function>", "macro end tag");
assertErrorContains("<#function x()>", "#macro", "unclosed");
+ assertErrorContains("<#function x()></#macro>", "function end tag");
assertErrorContains("<#assign x>", "#assign", "unclosed");
assertErrorContains("<#macro m><#local x>", "#local", "unclosed");
assertErrorContains("<#global x>", "#global", "unclosed");
@@ -122,15 +124,62 @@ public class ParsingErrorMessagesTest {
assertErrorContains("<#assign x = x}>", "\"}\"", "open");
// TODO assertErrorContains("<#assign x = '${x'>", "unclosed");
}
-
+
+ @Test
+ public void testUnknownHeaderParameter() {
+ assertErrorContains("<#ftl foo=1>", "Unknown", "foo");
+ assertErrorContains("<#ftl attributes={}>", "Unknown", "attributes", "customSettings");
+ }
+
+ @Test
+ public void testDynamicTopCalls() throws IOException, TemplateException {
+ assertErrorContains("<@a, n1=1 />", "Remove comma", "between", "by position");
+ assertErrorContains("<@a n1=1, n2=1 />", "Remove comma", "between", "by position");
+ assertErrorContains("<@a n1=1, 2 />", "Remove comma", "between", "by position");
+ assertErrorContains("<@a, 1 />", "Remove comma", "between", "by position");
+ assertErrorContains("<@a 1, , 2 />", "Two commas");
+ assertErrorContains("<@a 1 2 />", "Missing comma");
+ assertErrorContains("<@a n1=1 2 />", "must be earlier than arguments passed by name");
+ }
+
+ @Test
+ public void testMacroAndFunctionDefinitions() {
+ assertErrorContains("<#macro m><#macro n></#macro></#macro>", "nested into each other");
+ assertErrorContains("<#macro m(a)></#macro>", "can't use \"(\"");
+ assertErrorContains("<#function f a></#function>", "must use \"(\"");
+ assertErrorContains("<#macro m a{badOption})></#macro>", "\"badOption\"",
+ "\"" + ASTDirMacroOrFunction.POSITIONAL_PARAMETER_OPTION_NAME + "\"",
+ "\"" + ASTDirMacroOrFunction.NAMED_PARAMETER_OPTION_NAME + "\"");
+ assertErrorContains("<#function f(a{named}, b)></#function>", "Positional", "must precede named");
+ assertErrorContains("<#function f(a..., b)></#function>", "another", "after", "positional varargs");
+ assertErrorContains("<#function f(a..., b...)></#function>", "another", "after", "positional varargs");
+ assertErrorContains("<#macro m a... b></#macro>", "another", "after", "named varargs");
+ assertErrorContains("<#macro m a... b...></#macro>", "another", "after", "named varargs");
+ assertErrorContains("<#function f(a b)></#function>", "Function", "must have comma");
+ assertErrorContains("<#function f(a{named} b{named})></#function>", "Function", "must have comma");
+ assertErrorContains("<#macro m a, b></#macro>", "Named param", "macro", "need no comma");
+ assertErrorContains("<#macro m a{positional} b{positional}></#macro>",
+ "Positional param", "must have comma");
+ assertErrorContains("<#macro m a...=[]></#macro>", "Varargs", "default");
+ assertErrorContains("<#function f(a=0, b)></#function>", "with default", "without a default");
+ assertErrorContains("<#function f(a,)></#function>", "Comma without");
+ assertErrorContains("<#macro m a{positional}, b{positional},></#macro>", "Comma without");
+ assertErrorContains(false, "<#function f(a, b></#function>");
+ assertErrorContains(false, "<#function f(></#function>");
+ assertErrorContains(false, "[#ftl][#function f(a, b][/#function]", "Missing closing \")\"");
+ assertErrorContains(false, "[#ftl][#function f(][/#function]", "Missing closing \")\"");
+ assertErrorContains("<#macro m a b)></#macro>", "\")\" without", "opening");
+ assertErrorContains("<#macro m a b a></#macro>", "\"a\"", "multiple");
+ }
+
private void assertErrorContains(String ftl, String... expectedSubstrings) {
assertErrorContains(false, ftl, expectedSubstrings);
assertErrorContains(true, ftl, expectedSubstrings);
}
- private void assertErrorContains(boolean squareTags, String ftl, String... expectedSubstrings) {
+ private void assertErrorContains(boolean convertToSquare, String ftl, String... expectedSubstrings) {
try {
- if (squareTags) {
+ if (convertToSquare) {
ftl = ftl.replace('<', '[').replace('>', ']');
}
new Template("adhoc", ftl, cfg);
@@ -139,7 +188,7 @@ public class ParsingErrorMessagesTest {
String msg = e.getMessage();
for (String needle: expectedSubstrings) {
if (needle.startsWith("\\!")) {
- String netNeedle = needle.substring(2);
+ String netNeedle = needle.substring(2);
if (msg.contains(netNeedle)) {
fail("The message shouldn't contain substring " + _StringUtil.jQuote(netNeedle) + ":\n" + msg);
}
@@ -153,15 +202,9 @@ public class ParsingErrorMessagesTest {
throw new RuntimeException(e);
}
}
-
+
private void showError(Throwable e) {
//System.out.println(e);
}
- @Test
- public void testUnknownHeaderParameter() {
- assertErrorContains("<#ftl foo=1>", "Unknown", "foo");
- assertErrorContains("<#ftl attributes={}>", "Unknown", "attributes", "customSettings");
- }
-
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/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 b7d55f5..3459aea 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
@@ -22,11 +22,14 @@ package org.apache.freemarker.core;
import java.io.IOException;
import org.apache.freemarker.core.userpkg.AllFeaturesDirective;
+import org.apache.freemarker.core.userpkg.AllFeaturesFunction;
import org.apache.freemarker.core.userpkg.NamedVarargsOnlyDirective;
import org.apache.freemarker.core.userpkg.PositionalVarargsOnlyDirective;
+import org.apache.freemarker.core.userpkg.PositionalVarargsOnlyFunction;
import org.apache.freemarker.core.userpkg.TwoNamedParamsDirective;
import org.apache.freemarker.core.userpkg.TwoNestedContentParamsDirective;
import org.apache.freemarker.core.userpkg.TwoPositionalParamsDirective;
+import org.apache.freemarker.core.userpkg.TwoPositionalParamsFunction;
import org.apache.freemarker.core.userpkg.UpperCaseDirective;
import org.apache.freemarker.test.TemplateTest;
import org.junit.Before;
@@ -36,15 +39,20 @@ public class TemplateCallableModelTest extends TemplateTest {
@Before
public void addCommonData() {
- addToDataModel("a", new AllFeaturesDirective());
+ addToDataModel("a", AllFeaturesDirective.INSTANCE);
addToDataModel("p", TwoPositionalParamsDirective.INSTANCE);
addToDataModel("n", TwoNamedParamsDirective.INSTANCE);
addToDataModel("pvo", PositionalVarargsOnlyDirective.INSTANCE);
addToDataModel("nvo", NamedVarargsOnlyDirective.INSTANCE);
+ addToDataModel("uc", UpperCaseDirective.INSTANCE);
+
+ addToDataModel("fa", AllFeaturesFunction.INSTANCE);
+ addToDataModel("fp", TwoPositionalParamsFunction.INSTANCE);
+ addToDataModel("fpvo", PositionalVarargsOnlyFunction.INSTANCE);
}
@Test
- public void testArguments() throws IOException, TemplateException {
+ public void testDirectiveArguments() throws IOException, TemplateException {
assertOutput("<@p />",
"#p(p1=null, p2=null)");
assertOutput("<@p 1 />",
@@ -103,6 +111,34 @@ public class TemplateCallableModelTest extends TemplateTest {
}
@Test
+ public void testFunctionArguments() throws IOException, TemplateException {
+ // TODO [FM3] Add more tests as named parameters become supported
+
+ assertOutput("${fp()}",
+ "fp(p1=null, p2=null)");
+ assertOutput("${fp(1)}",
+ "fp(p1=1, p2=null)");
+ assertOutput("${fp(1, 2)}",
+ "fp(p1=1, p2=2)");
+
+ assertOutput("${fpvo()}",
+ "fpvo(pVarargs=[])");
+ assertOutput("${fpvo(1)}",
+ "fpvo(pVarargs=[1])");
+ assertOutput("${fpvo(1, 2)}",
+ "fpvo(pVarargs=[1, 2])");
+
+ assertOutput("${fa()}",
+ "fa(p1=null, p2=null, pVarargs=[], n1=null, n2=null, nVarargs={})");
+ assertOutput("${fa(1, 2)}",
+ "fa(p1=1, p2=2, pVarargs=[], n1=null, n2=null, nVarargs={})");
+ assertOutput("${fa(1, 2, 3)}",
+ "fa(p1=1, p2=2, pVarargs=[3], n1=null, n2=null, nVarargs={})");
+ assertOutput("${fa(1, 2, 3, 4)}",
+ "fa(p1=1, p2=2, pVarargs=[3, 4], n1=null, n2=null, nVarargs={})");
+ }
+
+ @Test
public void testNestedContent() throws IOException, TemplateException {
assertOutput("<@a />",
"#a(p1=null, p2=null, pVarargs=[], n1=null, n2=null, nVarargs={})");
@@ -140,18 +176,16 @@ public class TemplateCallableModelTest extends TemplateTest {
assertOutput("<@a + 1 />",
"#a(p1=1, p2=null, pVarargs=[], n1=null, n2=null, nVarargs={})");
- }
- @Test
- @SuppressWarnings("ThrowableNotThrown")
- public void testParsingErrors() throws IOException, TemplateException {
- assertErrorContains("<@a, n1=1 />", "Remove comma", "between", "by position");
- assertErrorContains("<@a n1=1, n2=1 />", "Remove comma", "between", "by position");
- assertErrorContains("<@a n1=1, 2 />", "Remove comma", "between", "by position");
- assertErrorContains("<@a, 1 />", "Remove comma", "between", "by position");
- assertErrorContains("<@a 1, , 2 />", "Two commas");
- assertErrorContains("<@a 1 2 />", "Missing comma");
- assertErrorContains("<@a n1=1 2 />", "must be earlier than arguments passed by name");
+ assertOutput("<@nvo a=x! 1 b=2 />",
+ "#nvo(nVarargs={\"a\": 1, \"b\": 2})");
+ assertOutput("<@nvo a=x! b=2 />",
+ "#nvo(nVarargs={\"a\": \"\", \"b\": 2})");
+ assertOutput("<@nvo a=x!b=2 />",
+ "#nvo(nVarargs={\"a\": \"\", \"b\": 2})");
+
+ assertOutput("<@nvo a=(1)b=2 />",
+ "#nvo(nVarargs={\"a\": 1, \"b\": 2})");
}
@Test
@@ -160,7 +194,9 @@ 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 />", "doesn't have any by-name-passed");
+ assertErrorContains("<@p n1=9 />", "directive", "can't have arguments that are passed by name", "\"n1\"");
+ assertErrorContains("<@uc n1=9 />", "directive", "doesn't support any parameters");
+ assertErrorContains("<@uc 9 />", "directive", "doesn't support any parameters");
addToDataModel("tncp", TwoNestedContentParamsDirective.INSTANCE);
assertErrorContains("<@tncp />", " no ", " 2 ");
@@ -175,18 +211,76 @@ public class TemplateCallableModelTest extends TemplateTest {
@Test
public void testMacros() throws IOException, TemplateException {
+ assertOutput("<#macro m>text</#macro><@m /> <@m />",
+ "text text");
+ assertOutput("<#macro m a>text ${a}</#macro><@m a=1 /> <@m a=2 />",
+ "text 1 text 2");
+ assertOutput("<#macro m a b=2>text ${a} ${b}</#macro><@m a=1 /> <@m a=11 b=22 />",
+ "text 1 2 text 11 22");
+ assertOutput("<#macro m a{positional}>text ${a}</#macro><@m 1 /> <@m 2 />",
+ "text 1 text 2");
+ assertOutput("<#macro m a{positional}, b{positional}=2>text ${a} ${b}</#macro><@m 1 /> <@m 11, 22 />",
+ "text 1 2 text 11 22");
+ assertOutput("<#macro m a{positional}, b{positional}=2 c d=4>text ${a} ${b} ${c} ${d}</#macro>"
+ + "<@m 1 c=3 /> <@m 11, 22 c=33 d=44 />",
+ "text 1 2 3 4 text 11 22 33 44");
+
+ assertOutput("<#macro m>[<#n...@m>",
+ "[text]");
+ assertOutput("<#macro m>[<#nested 1>, <#nested 2>]</#macro><@m ; i>text ${i}</...@m>",
+ "[text 1, text 2]");
+ assertOutput("<#macro m>[<#nested 1, 2>]</#macro><@m ; i, j>${i} ${j}</...@m>",
+ "[1 2]");
assertOutput("<#macro m a b=22><#list 1..2 as n>[<#nested a * n, b * n>]</#list></#macro>"
- + "<@m 11; i, j>${i} ${j}</...@m> <@m a=1 b=2; i, j>${i} ${j}</...@m>",
+ + "<@m a=11; i, j>${i} ${j}</...@m> <@m a=1 b=2; i, j>${i} ${j}</...@m>",
"[11 22][22 44] [1 2][2 4]");
- assertOutput("<#macro m a b others...>[a=${a}, b=${b}<#if others?hasContent>, </#if>"
- + "<#if others?isSequence>"
- + "<#list others as v>${v}<#sep>, </#list>"
- + "<#else>"
- + "<#list others as k, v>${k}=${v}<#sep>, </#list>"
- + "</#if>]"
+ assertOutput("<#macro m1><#local x = 1>${x}{<@m2>${x}<<#list [3] as x>${x}</#...@m2>}${x}</#macro>"
+ + "<#macro m2><#local x = 2>${x}[<#nested>]${x}</#macro>"
+ + "<#assign x = 0>${x}(<@m1 />)${x}",
+ "0(1{2[1<3>1]2}1)0");
+ assertOutput("<#macro m1>"
+ + "<#local x = 0>${x} <#list [1, 2] as x>${x}{<@m...@m2>}${x}<#sep> </#list> ${x}"
+ "</#macro>"
- + "<@m 1, 2 /> <@m 1, 2, 3, 4 /> <@m a=1 b=2 /> <@m a=1 b=2 c=3 d=4 />",
- "[a=1, b=2] [a=1, b=2, 3, 4] [a=1, b=2] [a=1, b=2, c=3, d=4]");
+ + "<#macro m2><#list [3, 4] as x>${x}[<#nested>]${x}<#sep> </#list></#macro>"
+ + "<@m1 />",
+ "0 1{3[1]3 4[1]4}1 2{3[2]3 4[2]4}2 0");
+
+ assertOutput("<#macro m a b=0 others...>["
+ + "a=${a}, b=${b}"
+ + "<#list others>, <#items as k, v>${k}=${v}<#sep>, </#items></#list>"
+ + "]</#macro>"
+ + "<@m a=1 /> <@m a=1 b=2 /> <@m a=1 b=2 c=3 d=4 />",
+ "[a=1, b=0] [a=1, b=2] [a=1, b=2, c=3, d=4]");
+ assertOutput("<#macro m a{positional}, b{positional}=0, others{positional}...>["
+ + "a=${a}, b=${b}"
+ + "<#list others>, <#items as v>${v}<#sep>, </#items></#list>"
+ + "]</#macro>"
+ + "<@m 1 /> <@m 1, 2 /> <@m 1, 2, 3, 4 />",
+ "[a=1, b=0] [a=1, b=2] [a=1, b=2, 3, 4]");
+ assertOutput("<#macro m pVarargs{positional}... nVarargs...>"
+ + "[<#list pVarargs as v>${v}<#sep>, </#list>]"
+ + "{<#list nVarargs as k, v>${k}=${v}<#sep>, </#list>}"
+ + "</#macro>"
+ + "<@m 1, 2 a=1 b=2 /> <@m 1, 2 /> <@m a=1 b=2 />",
+ "[1, 2]{a=1, b=2} [1, 2]{} []{a=1, b=2}");
+
+ assertOutput("<#macro m x{positional}, y{positional}><#local y++><#local z = x + y>${x} + ${y} = ${z}</#macro>"
+ + "<@m 1, 2 />",
+ "1 + 3 = 4");
+
+ // Default expression sees previous argument:
+ assertOutput("<#macro m a{positional} b=a>${a}${b}</#macro><@m 1/> <@m 2 b=3/>", "11 23");
+
+ addTemplate("lib.ftl", ""
+ + "<#assign defaultA=1>"
+ + "<#assign b=2>"
+ + "<#macro m a=defaultA>${a} ${b}[<#nested>]${b} ${a}</#macro>");
+ assertOutput("<#import 'lib.ftl' as lib>"
+ + "<#assign a='a'>"
+ + "<#assign b='b'>"
+ + "<@lib.m>${a}${b}</@> "
+ + "<@lib.m a=3>${a}${b}</@>"
+ + "", "1 2[ab]2 1 3 2[ab]2 3");
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
index a6b01ac..61c5823 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
@@ -26,7 +26,6 @@ import java.io.Writer;
import org.apache.freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.util._NullWriter;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/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 24a3a4e..3509b78 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesDirective.java
@@ -19,7 +19,7 @@
package org.apache.freemarker.core.userpkg;
-import static org.apache.freemarker.core.TemplateCallableModelUtils.*;
+import static org.apache.freemarker.core._TemplateCallableModelUtils.*;
import java.io.IOException;
import java.io.Writer;
@@ -27,7 +27,8 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateHashModelEx2;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateNumberModel;
@@ -35,7 +36,9 @@ import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.impl.SimpleNumber;
import org.apache.freemarker.core.util.StringToIndexMap;
-public class AllFeaturesDirective extends TestTemplateDirectiveModel {
+public class AllFeaturesDirective extends TestTemplateCallableModel implements TemplateDirectiveModel {
+
+ public static final AllFeaturesDirective INSTANCE = new AllFeaturesDirective();
private static final int P1_ARG_IDX = 0;
private static final int P2_ARG_IDX = 1;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/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
new file mode 100644
index 0000000..7f1f6c1
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AllFeaturesFunction.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.userpkg;
+
+import static org.apache.freemarker.core._TemplateCallableModelUtils.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx2;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.util.StringToIndexMap;
+
+public class AllFeaturesFunction extends TestTemplateCallableModel implements TemplateFunctionModel {
+
+ public static final AllFeaturesFunction INSTANCE = new AllFeaturesFunction();
+
+ private static final int P1_ARG_IDX = 0;
+ private static final int P2_ARG_IDX = 1;
+ private static final int N1_ARG_IDX = 2;
+ private static final int N2_ARG_IDX = 3;
+
+ private static final String N1_ARG_NAME = "n1";
+ private static final String N2_ARG_NAME = "n2";
+
+ private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(
+ 2,
+ true,
+ StringToIndexMap.of(
+ N1_ARG_NAME, N1_ARG_IDX,
+ N2_ARG_NAME, N2_ARG_IDX),
+ true
+ );
+
+ 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;
+ }
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
+ return execute(castArgumentToNumber(args, P1_ARG_IDX, p1AllowNull, env),
+ castArgumentToNumber(args, P2_ARG_IDX, p2AllowNull, env),
+ (TemplateSequenceModel) args[P_VARARGS_ARG_IDX],
+ castArgumentToNumber(args[N1_ARG_IDX], N1_ARG_NAME, n1AllowNull, env),
+ castArgumentToNumber(args[N2_ARG_IDX], N2_ARG_NAME, n2AllowNull, env),
+ (TemplateHashModelEx2) args[N_VARARGS_ARG_IDX],
+ env);
+ }
+
+ private TemplateModel execute(TemplateNumberModel p1, TemplateNumberModel p2, TemplateSequenceModel pOthers,
+ TemplateNumberModel n1, TemplateNumberModel n2, TemplateHashModelEx2 nOthers,
+ Environment env) throws TemplateException {
+ StringWriter out = new StringWriter();
+ try {
+ out.write("fa(");
+ printParam("p1", p1, out, true);
+ printParam("p2", p2, out);
+ printParam("pVarargs", pOthers, out);
+ printParam(N1_ARG_NAME, n1, out);
+ printParam(N2_ARG_NAME, n2, out);
+ printParam("nVarargs", nOthers, out);
+ out.write(")");
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ return new SimpleScalar(out.toString());
+ }
+
+ @Override
+ public ArgumentArrayLayout getArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java
index fed4bc7..a087188 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/NamedVarargsOnlyDirective.java
@@ -25,10 +25,11 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
-public class NamedVarargsOnlyDirective extends TestTemplateDirectiveModel {
+public class NamedVarargsOnlyDirective extends TestTemplateCallableModel implements TemplateDirectiveModel {
public static final NamedVarargsOnlyDirective INSTANCE = new NamedVarargsOnlyDirective();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java
index 540a641..2f9532e 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyDirective.java
@@ -25,17 +25,14 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
-public class PositionalVarargsOnlyDirective extends TestTemplateDirectiveModel {
+public class PositionalVarargsOnlyDirective extends TestTemplateCallableModel implements TemplateDirectiveModel {
public static final PositionalVarargsOnlyDirective INSTANCE = new PositionalVarargsOnlyDirective();
- private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(
- 0, true,
- null, false);
-
private PositionalVarargsOnlyDirective() {
//
}
@@ -44,13 +41,13 @@ public class PositionalVarargsOnlyDirective extends TestTemplateDirectiveModel {
public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
throws TemplateException, IOException {
out.write("#pvo(");
- printParam("pVarargs", args[ARGS_LAYOUT.getPositionalVarargsArgumentIndex()], out, true);
+ printParam("pVarargs", args[0], out, true);
out.write(")");
}
@Override
public ArgumentArrayLayout getArgumentArrayLayout() {
- return ARGS_LAYOUT;
+ return ArgumentArrayLayout.POSITIONAL_VARARGS_PARAMETER_ONLY;
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyFunction.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyFunction.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyFunction.java
new file mode 100644
index 0000000..eb8a3eb
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PositionalVarargsOnlyFunction.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.userpkg;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+public class PositionalVarargsOnlyFunction extends TestTemplateCallableModel implements TemplateFunctionModel {
+
+ public static final PositionalVarargsOnlyFunction INSTANCE = new PositionalVarargsOnlyFunction();
+
+ private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(
+ 0, true,
+ null, false);
+
+ private PositionalVarargsOnlyFunction() {
+ //
+ }
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
+ try {
+ StringWriter out = new StringWriter();
+ out.write("fpvo(");
+ printParam("pVarargs", args[ARGS_LAYOUT.getPositionalVarargsArgumentIndex()], out, true);
+ out.write(")");
+ return new SimpleScalar(out.toString());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public ArgumentArrayLayout getArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
new file mode 100644
index 0000000..9dd34ba
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.userpkg;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateCallableModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx2;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.util.FTLUtil;
+
+public abstract class TestTemplateCallableModel implements TemplateCallableModel {
+
+ protected void printParam(String name, TemplateModel value, Writer out) throws IOException, TemplateModelException {
+ printParam(name, value, out, false);
+ }
+
+ protected void printParam(String name, TemplateModel value, Writer out, boolean first)
+ throws IOException, TemplateModelException {
+ if (!first) {
+ out.write(", ");
+ }
+ out.write(name);
+ out.write("=");
+ printValue(value, out);
+ }
+
+ private void printValue(TemplateModel value, Writer out) throws IOException, TemplateModelException {
+ if (value == null) {
+ out.write("null");
+ } else if (value instanceof TemplateNumberModel) {
+ out.write(((TemplateNumberModel) value).getAsNumber().toString());
+ } else if (value instanceof TemplateScalarModel) {
+ out.write(FTLUtil.toStringLiteral(((TemplateScalarModel) value).getAsString()));
+ } else if (value instanceof TemplateSequenceModel) {
+ int len = ((TemplateSequenceModel) value).size();
+ out.write('[');
+ for (int i = 0; i < len; i++) {
+ if (i != 0) {
+ out.write(", ");
+ }
+ printValue(((TemplateSequenceModel) value).get(i), out);
+ }
+ out.write(']');
+ } else if (value instanceof TemplateHashModelEx2) {
+ TemplateHashModelEx2.KeyValuePairIterator it = ((TemplateHashModelEx2) value).keyValuePairIterator();
+ out.write('{');
+ while (it.hasNext()) {
+ TemplateHashModelEx2.KeyValuePair kvp = it.next();
+
+ printValue(kvp.getKey(), out);
+ out.write(": ");
+ printValue(kvp.getValue(), out);
+
+ if (it.hasNext()) {
+ out.write(", ");
+ }
+ }
+ out.write('}');
+ } else {
+ throw new IllegalArgumentException("Unsupported value class: " + value.getClass().getName());
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateDirectiveModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateDirectiveModel.java
deleted file mode 100644
index 49bb049..0000000
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateDirectiveModel.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.freemarker.core.userpkg;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx2;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.util.FTLUtil;
-
-public abstract class TestTemplateDirectiveModel implements TemplateDirectiveModel {
-
- protected void printParam(String name, TemplateModel value, Writer out) throws IOException, TemplateModelException {
- printParam(name, value, out, false);
- }
-
- protected void printParam(String name, TemplateModel value, Writer out, boolean first)
- throws IOException, TemplateModelException {
- if (!first) {
- out.write(", ");
- }
- out.write(name);
- out.write("=");
- printValue(value, out);
- }
-
- private void printValue(TemplateModel value, Writer out) throws IOException, TemplateModelException {
- if (value == null) {
- out.write("null");
- } else if (value instanceof TemplateNumberModel) {
- out.write(((TemplateNumberModel) value).getAsNumber().toString());
- } else if (value instanceof TemplateScalarModel) {
- out.write(FTLUtil.toStringLiteral(((TemplateScalarModel) value).getAsString()));
- } else if (value instanceof TemplateSequenceModel) {
- int len = ((TemplateSequenceModel) value).size();
- out.write('[');
- for (int i = 0; i < len; i++) {
- if (i != 0) {
- out.write(", ");
- }
- printValue(((TemplateSequenceModel) value).get(i), out);
- }
- out.write(']');
- } else if (value instanceof TemplateHashModelEx2) {
- TemplateHashModelEx2.KeyValuePairIterator it = ((TemplateHashModelEx2) value).keyValuePairIterator();
- out.write('{');
- while (it.hasNext()) {
- TemplateHashModelEx2.KeyValuePair kvp = it.next();
-
- printValue(kvp.getKey(), out);
- out.write(": ");
- printValue(kvp.getValue(), out);
-
- if (it.hasNext()) {
- out.write(", ");
- }
- }
- out.write('}');
- } else {
- throw new IllegalArgumentException("Unsupported value class: " + value.getClass().getName());
- }
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java
index b4b85d3..83b5435 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNamedParamsDirective.java
@@ -25,11 +25,12 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.util.StringToIndexMap;
-public class TwoNamedParamsDirective extends TestTemplateDirectiveModel {
+public class TwoNamedParamsDirective extends TestTemplateCallableModel implements TemplateDirectiveModel {
public static final TwoNamedParamsDirective INSTANCE = new TwoNamedParamsDirective();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java
index ff47315..6f768f4 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java
@@ -25,12 +25,13 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
import org.apache.freemarker.core.model.Constants;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.impl.SimpleNumber;
-public class TwoNestedContentParamsDirective extends TestTemplateDirectiveModel {
+public class TwoNestedContentParamsDirective extends TestTemplateCallableModel implements TemplateDirectiveModel {
public static final TwoNestedContentParamsDirective INSTANCE = new TwoNestedContentParamsDirective();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java
index 4bd671e..008d8c8 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsDirective.java
@@ -25,10 +25,11 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
-public class TwoPositionalParamsDirective extends TestTemplateDirectiveModel {
+public class TwoPositionalParamsDirective extends TestTemplateCallableModel implements TemplateDirectiveModel {
public static final TwoPositionalParamsDirective INSTANCE = new TwoPositionalParamsDirective();
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsFunction.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsFunction.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsFunction.java
new file mode 100644
index 0000000..58e292b
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoPositionalParamsFunction.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core.userpkg;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+public class TwoPositionalParamsFunction extends TestTemplateCallableModel implements TemplateFunctionModel {
+
+ public static TwoPositionalParamsFunction INSTANCE = new TwoPositionalParamsFunction();
+
+ private TwoPositionalParamsFunction() {
+ //
+ }
+
+ private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(
+ 2, false,
+ null, false);
+
+ @Override
+ public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env) throws TemplateException {
+ try {
+ StringWriter out = new StringWriter();
+ out.write("fp(");
+ printParam("p1", args[0], out, true);
+ printParam("p2", args[1], out);
+ out.write(")");
+ return new SimpleScalar(out.toString());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public ArgumentArrayLayout getArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java
index 220aeef..05e5d6d 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/UpperCaseDirective.java
@@ -26,7 +26,7 @@ import java.io.Writer;
import org.apache.freemarker.core.Environment;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringToIndexMapTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringToIndexMapTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringToIndexMapTest.java
index 769325f..3be5783 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringToIndexMapTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringToIndexMapTest.java
@@ -47,6 +47,8 @@ public class StringToIndexMapTest {
assertEquals(-1, m.get("a"));
assertEquals(0, m.get("i"));
assertEquals(ImmutableList.of("i"), m.getKeys());
+ assertEquals("i", m.getKeyOfValue(0));
+ assertNull(m.getKeyOfValue(1));
}
@Test
@@ -57,6 +59,9 @@ public class StringToIndexMapTest {
assertEquals(0, m.get("i"));
assertEquals(1, m.get("j"));
assertEquals(ImmutableList.of("i", "j"), m.getKeys());
+ assertEquals("i", m.getKeyOfValue(0));
+ assertEquals("j", m.getKeyOfValue(1));
+ assertNull(m.getKeyOfValue(2));
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
index 318e7ae..9bdea77 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
@@ -35,7 +35,7 @@ import org.apache.freemarker.core.Template;
import org.apache.freemarker.core.TemplateConfiguration;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.core.model.ArgumentArrayLayout;
-import org.apache.freemarker.core.model.CallPlace;
+import org.apache.freemarker.core.CallPlace;
import org.apache.freemarker.core.model.TemplateDirectiveModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
index 18e46e9..81f83dc 100644
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
@@ -112,30 +112,22 @@
- content: "more" // String
#text // o.a.f.c.ASTStaticText
- content: "\n6 " // String
- #macro // o.a.f.c.ASTDirMacro
+ #macro // o.a.f.c.ASTDirMacroOrFunction
- assignment target: "foo" // String
- - parameter name: "x" // String
- - parameter default: null // Null
- - parameter name: "y" // String
- - parameter default: 2 // o.a.f.c.ASTExpNumberLiteral
- - parameter name: "z" // String
- - parameter default: + // o.a.f.c.ASTExpAddOrConcat
- - left-hand operand: y // o.a.f.c.ASTExpVariable
- - right-hand operand: 1 // o.a.f.c.ASTExpNumberLiteral
- - catch-all parameter name: "q" // String
+ - parameter definition: "ParameterDefinition(name=\"x\")" // o.a.f.c.ASTDirMacroOrFunction$ParameterDefinition
+ - parameter definition: "ParameterDefinition(name=\"y\", default=2)" // o.a.f.c.ASTDirMacroOrFunction$ParameterDefinition
+ - parameter definition: "ParameterDefinition(name=\"z\", default=y + 1)" // o.a.f.c.ASTDirMacroOrFunction$ParameterDefinition
+ - parameter definition: "ParameterDefinition(name=\"q\")" // o.a.f.c.ASTDirMacroOrFunction$ParameterDefinition
- AST-node subtype: "0" // Integer
#nested // o.a.f.c.ASTDirNested
- passed value: x // o.a.f.c.ASTExpVariable
- passed value: y // o.a.f.c.ASTExpVariable
#text // o.a.f.c.ASTStaticText
- content: "\n7 " // String
- #function // o.a.f.c.ASTDirMacro
+ #function // o.a.f.c.ASTDirMacroOrFunction
- assignment target: "foo" // String
- - parameter name: "x" // String
- - parameter default: null // Null
- - parameter name: "y" // String
- - parameter default: null // Null
- - catch-all parameter name: null // Null
+ - parameter definition: "ParameterDefinition(name=\"x\")" // o.a.f.c.ASTDirMacroOrFunction$ParameterDefinition
+ - parameter definition: "ParameterDefinition(name=\"y\")" // o.a.f.c.ASTDirMacroOrFunction$ParameterDefinition
- AST-node subtype: "1" // Integer
#local // o.a.f.c.ASTDirAssignment
- assignment target: "x" // String
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
index 479f868..847caab 100644
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
@@ -92,9 +92,8 @@
- assignment source: 2 // o.a.f.c.ASTExpNumberLiteral
- variable scope: "3" // Integer
- namespace: null // Null
- #macro // o.a.f.c.ASTDirMacro
+ #macro // o.a.f.c.ASTDirMacroOrFunction
- assignment target: "m" // String
- - catch-all parameter name: null // Null
- AST-node subtype: "0" // Integer
#text // o.a.f.c.ASTStaticText
- content: " 7 " // String
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl
new file mode 100644
index 0000000..56e816f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl
@@ -0,0 +1,43 @@
+<#ftl stripWhitespace=false>
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<#macro m></#macro>
+<#macro m a></#macro>
+<#macro m a b></#macro>
+<#macro m a b c...></#macro>
+<#macro m a...></#macro>
+<#macro m p1{positional}, p2{positional}, pva{positional}... n1 n2 nva...></#macro>
+<#macro m p1{positional}, p2{positional}=2, pva{positional}... n1=3 n2 nva...></#macro>
+<#macro m a{positional}></#macro>
+<#macro m a{positional}=1></#macro>
+<#macro m a{positional}...></#macro>
+<#macro m nva{positional}... pva...></#macro>
+<#function f()></#function>
+<#function f(a)></#function>
+<#function f(a, b)></#function>
+<#function f(a, b, c...)></#function>
+<#function f(a...)></#function>
+<#function f(p1, p2, pva..., n1{named}, n2{named}, nva{named}...)></#function>
+<#function f(p1, p2=2, pva..., n1{named}, n2{named}=3, nva{named}...)></#function>
+<#function f(a{named})></#function>
+<#function f(a{named}=1)></#function>
+<#function f(a{named}...)></#function>
+<#function f(nva..., pva{named}...)></#function>
+
+<#macro m p1 { positional } , p2 { positional } = 2 , pva { positional } ... n1 = 3 n2 nva ... ></#macro >
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl.out
new file mode 100644
index 0000000..c15b35d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macro-and-function.ftl.out
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+<#macro m></#macro>
+<#macro m a></#macro>
+<#macro m a b></#macro>
+<#macro m a b c...></#macro>
+<#macro m a...></#macro>
+<#macro m p1{positional}, p2{positional}, pva{positional}... n1 n2 nva...></#macro>
+<#macro m p1{positional}, p2{positional}=2, pva{positional}... n1=3 n2 nva...></#macro>
+<#macro m a{positional}></#macro>
+<#macro m a{positional}=1></#macro>
+<#macro m a{positional}...></#macro>
+<#macro m nva{positional}... pva...></#macro>
+<#function f()></#function>
+<#function f(a)></#function>
+<#function f(a, b)></#function>
+<#function f(a, b, c...)></#function>
+<#function f(a...)></#function>
+<#function f(p1, p2, pva..., n1{named}, n2{named}, nva{named}...)></#function>
+<#function f(p1, p2=2, pva..., n1{named}, n2{named}=3, nva{named}...)></#function>
+<#function f(a{named})></#function>
+<#function f(a{named}=1)></#function>
+<#function f(a{named}...)></#function>
+<#function f(nva..., pva{named}...)></#function>
+
+<#macro m p1{positional}, p2{positional}=2, pva{positional}... n1=3 n2 nva...></#macro>
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
deleted file mode 100644
index 9288e63..0000000
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
+++ /dev/null
@@ -1,29 +0,0 @@
-<#ftl stripWhitespace=false>
-<#--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<#macro m></#macro>
-<#macro m a></#macro>
-<#macro m a b></#macro>
-<#macro m a b c...></#macro>
-<#macro m a...></#macro>
-<#function f()></#function>
-<#function f(a)></#function>
-<#function f(a, b)></#function>
-<#function f(a, b, c...)></#function>
-<#function f(a...)></#function>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
deleted file mode 100644
index ad49cae..0000000
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-<#macro m></#macro>
-<#macro m a></#macro>
-<#macro m a b></#macro>
-<#macro m a b c...></#macro>
-<#macro m a...></#macro>
-<#function f()></#function>
-<#function f(a)></#function>
-<#function f(a, b)></#function>
-<#function f(a, b, c...)></#function>
-<#function f(a...)></#function>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/macros2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/macros2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/macros2.txt
deleted file mode 100644
index 1b4e007..0000000
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/expected/macros2.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-1 1
-2 2
-4
-m3 with d="4" Failed!
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/api-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/api-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/api-builtins.ftl
index c7d1915..5377f38 100644
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/api-builtins.ftl
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/api-builtins.ftl
@@ -18,8 +18,8 @@
-->
<@assertEquals expected="b" actual=map?api.get(2?int) />
<@assertEquals expected=2 actual=list?api.indexOf(3?int) />
-<@assert test=set?api.contains("b") />
-<@assert test=!set?api.contains("d") />
+<@assert set?api.contains("b") />
+<@assert !set?api.contains("d") />
<#assign dump = "">
<#list map?api.entrySet() as entry>
@@ -30,11 +30,11 @@
</#list>
<@assertEquals expected="1: a, 2: b, 3: c" actual=dump />
-<@assert test=map?hasApi />
-<@assert test=list?hasApi />
-<@assert test=set?hasApi />
-<@assert test=!s?hasApi />
-<@assert test=!1?hasApi />
-<@assert test=!""?hasApi />
-<@assert test=!{}?hasApi />
-<@assert test=!true?hasApi />
+<@assert map?hasApi />
+<@assert list?hasApi />
+<@assert set?hasApi />
+<@assert !s?hasApi />
+<@assert !1?hasApi />
+<@assert !""?hasApi />
+<@assert !{}?hasApi />
+<@assert !true?hasApi />
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3cacd9ed/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
index 49816ee..3d70cc5 100644
--- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templatesuite/templates/boolean.ftl
@@ -71,10 +71,10 @@
<#else>
boolean4 && boolean5 failed.<br />
</#if></p>
-<@assert test=true && true />
-<@assert test=!(false && true) />
-<@assert test=true \and true />
-<@assert test=!(false \and true) />
+<@assert true && true />
+<@assert !(false && true) />
+<@assert true \and true />
+<@assert !(false \and true) />
<p>Now test list models:</p>