FREEMARKER-63: Change 1: Replaced the "loop variable" term with the more generic "nested content parameter" term. (In FM2, loop variables were introduced earlier than nested content parameter, so the two term coulnd't be unified. So it's just one less term in FM3.)
Change 2: CallPlace.executeNestedContent now requires the nested content paramter value array to have exactly the same length as the number of parameters declared by the caller. Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/589d9b80 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/589d9b80 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/589d9b80 Branch: refs/heads/3 Commit: 589d9b80e218a39d2ac128b1108952992868cc40 Parents: 126c506 Author: ddekany <ddek...@apache.org> Authored: Sun Jul 30 20:38:01 2017 +0200 Committer: ddekany <ddek...@apache.org> Committed: Sun Jul 30 20:38:01 2017 +0200 ---------------------------------------------------------------------- .../core/FM2ASTToFM3SourceConverter.java | 26 +-- .../apache/freemarker/core/ListErrorsTest.java | 20 +-- .../core/TemplateCallableModelTest.java | 8 +- .../core/userpkg/AllFeaturesDirective.java | 17 +- .../TwoNestedContentParamsDirective.java | 53 ++++++ .../org/apache/freemarker/core/ast-1.ast | 12 +- .../apache/freemarker/core/ast-locations.ast | 12 +- .../freemarker/core/ast-whitespacestripping.ast | 2 +- .../org/apache/freemarker/core/ASTDirItems.java | 42 ++--- .../org/apache/freemarker/core/ASTDirList.java | 162 ++++++++++--------- .../freemarker/core/ASTDynamicTopLevelCall.java | 59 +++---- .../apache/freemarker/core/ASTExpBuiltIn.java | 20 +-- .../freemarker/core/BuiltInForLoopVariable.java | 48 ------ .../core/BuiltInForNestedContentParameter.java | 49 ++++++ .../core/BuiltInsForLoopVariables.java | 156 ------------------ .../BuiltInsForNestedContentParameters.java | 156 ++++++++++++++++++ .../org/apache/freemarker/core/Environment.java | 29 ++-- .../apache/freemarker/core/ParameterRole.java | 2 +- .../apache/freemarker/core/model/CallPlace.java | 32 ++-- freemarker-core/src/main/javacc/FTL.jj | 142 ++++++++-------- 20 files changed, 561 insertions(+), 486 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java ---------------------------------------------------------------------- diff --git a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java index ed86057..57a912f 100644 --- a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java +++ b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java @@ -671,14 +671,16 @@ public class FM2ASTToFM3SourceConverter { int paramCnt = node.getParameterCount(); assertNodeContent(paramCnt <= 2, node, "Expected at most 2 parameters"); - String loopVar1 = getParam(node, 0, ParameterRole.TARGET_LOOP_VARIABLE, String.class); - String loopVar2 = paramCnt >= 2 ? getParam(node, 1, ParameterRole.TARGET_LOOP_VARIABLE, String.class) : null; + String nestedContParamName1 = getParam(node, 0, ParameterRole.TARGET_LOOP_VARIABLE, String.class); + String nestedContParamName2 = + paramCnt >= 2 ? getParam(node, 1, ParameterRole.TARGET_LOOP_VARIABLE, String.class) + : null; - print(FTLUtil.escapeIdentifier(loopVar1)); + print(FTLUtil.escapeIdentifier(nestedContParamName1)); pos = getPositionAfterIdentifier(pos); - if (loopVar2 != null) { + if (nestedContParamName2 != null) { pos = printSeparatorAndWSAndExpComments(pos, ","); - print(FTLUtil.escapeIdentifier(loopVar2)); + print(FTLUtil.escapeIdentifier(nestedContParamName2)); pos = getPositionAfterIdentifier(pos); } @@ -1318,20 +1320,20 @@ public class FM2ASTToFM3SourceConverter { paramIdx += 2; } - // Print loop variables: + // Print nested content parameters (aka. loop variables): int pos = lastParamEnd; - boolean beforeFirstLoopVar = true; + boolean beforeFirstNestedContParam = true; while (paramIdx < paramCount) { - pos = printSeparatorAndWSAndExpComments(pos, beforeFirstLoopVar ? ";" : ","); + pos = printSeparatorAndWSAndExpComments(pos, beforeFirstNestedContParam ? ";" : ","); - String loopVarName = getParam(node, paramIdx, ParameterRole.TARGET_LOOP_VARIABLE, String.class); - print(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); + String nestedContParamName = getParam(node, paramIdx, ParameterRole.TARGET_LOOP_VARIABLE, String.class); + print(_StringUtil.toFTLTopLevelIdentifierReference(nestedContParamName)); String identifierInSrc = readIdentifier(pos); assertNodeContent(identifierInSrc.length() != 0, node, - "Can't find loop variable identifier in source"); + "Can't find nested content parameter name in the source"); pos += identifierInSrc.length(); // skip loop var name - beforeFirstLoopVar = false; + beforeFirstNestedContParam = false; paramIdx++; } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java index 8986efe..8944dd1 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java @@ -53,11 +53,11 @@ public class ListErrorsTest extends TemplateTest { assertErrorContains("<#list xs><#macro m><#items as x></#items></#macro></#list>", "#items", "must be inside", "#list"); assertErrorContains("<#list xs as x><#items as x>${x}</#items></#list>", - "#list", "must not have", "#items", "as loopVar"); + "#list", "must not have", "#items", "as someItem"); assertErrorContains("<#list xs><#list xs as x><#items as x>${x}</#items></#list></#list>", - "#list", "must not have", "#items", "as loopVar"); + "#list", "must not have", "#items", "as someItem"); assertErrorContains("<#list xs></#list>", - "#list", "must have", "#items", "as loopVar"); + "#list", "must have", "#items", "as someItem"); } @Test @@ -81,17 +81,17 @@ public class ListErrorsTest extends TemplateTest { } @Test - public void testInvalidLoopVarBuiltinLHO() { + public void testInvalidNestedContentParameterBuiltinLHO() { assertErrorContains("<#list foos>${foo?index}</#list>", - "?index", "foo", "no loop variable"); + "?index", "foo", "nested content parameter", "none in scope"); assertErrorContains("<#list foos as foo></#list>${foo?index}", - "?index", "foo" , "no loop variable"); + "?index", "foo" , "nested content parameter", "none in scope"); assertErrorContains("<#list foos as foo><#macro m>${foo?index}</#macro></#list>", - "?index", "foo" , "no loop variable"); + "?index", "foo" , "nested content parameter", "none in scope"); assertErrorContains("<#list foos as foo><#function f()>${foo?index}</#function></#list>", - "?index", "foo" , "no loop variable"); + "?index", "foo" , "nested content parameter", "none in scope"); assertErrorContains("<#list xs as x>${foo?index}</#list>", - "?index", "foo" , "no loop variable"); + "?index", "foo" , "nested content parameter", "none in scope"); assertErrorContains("<#list foos as foo><@m; foo>${foo?index}</@></#list>", "?index", "foo" , "user defined directive"); assertErrorContains( @@ -115,7 +115,7 @@ public class ListErrorsTest extends TemplateTest { assertErrorContains("<#list {} as i></#list>", "as k, v"); assertErrorContains("<#list [] as k, v></#list>", - "only one loop variable"); + "only one nested content parameter"); } @Test http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 74edbaf..a51c657 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 @@ -25,6 +25,7 @@ import org.apache.freemarker.core.userpkg.AllFeaturesDirective; import org.apache.freemarker.core.userpkg.NamedVarargsOnlyDirective; import org.apache.freemarker.core.userpkg.PositionalVarargsOnlyDirective; 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.UpperCaseDirective; import org.apache.freemarker.test.TemplateTest; @@ -160,7 +161,12 @@ public class TemplateCallableModelTest extends TemplateTest { 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("<@a 1; i, j, k, l>x</@a>", "(4: \"i\", \"j\", \"k\", \"l\")", "(3)"); + + addToDataModel("tncp", TwoNestedContentParamsDirective.INSTANCE); + assertErrorContains("<@tncp />", " no ", " 2 "); + assertErrorContains("<@tncp ; i>${i}</@>", " 1 ", "\"i\"", " 2 "); + assertOutput("<@tncp ; i, j>${i} ${j}</@>", "1 2"); + assertErrorContains("<@tncp ; i, j, k>${i}</@>", " 3 ", "\"i\", \"j\", \"k\"", " 2 "); } @Test http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 c8d7329..e3be217 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 @@ -95,9 +95,9 @@ public class AllFeaturesDirective extends TestTemplateDirectiveModel { printParam(N1_ARG_NAME, n1, out); printParam(N2_ARG_NAME, n2, out); printParam("nVarargs", nOthers, out); - int loopVariableCount = callPlace.getLoopVariableCount(); - if (loopVariableCount != 0) { - out.write("; " + loopVariableCount); + int nestedContParamCnt = callPlace.getNestedContentParameterCount(); + if (nestedContParamCnt != 0) { + out.write("; " + nestedContParamCnt); } out.write(")"); @@ -106,12 +106,13 @@ public class AllFeaturesDirective extends TestTemplateDirectiveModel { if (p1 != null) { int intP1 = p1.getAsNumber().intValue(); for (int i = 0; i < intP1; i++) { - // We limit the number of loop variables passed to 3, so that related errors can be tested. - TemplateModel[] loopVariableValues = new TemplateModel[Math.min(loopVariableCount, 3)]; - for (int loopVarIdx = 0; loopVarIdx < loopVariableValues.length; loopVarIdx++) { - loopVariableValues[loopVarIdx] = new SimpleNumber((i + 1) * (loopVarIdx + 1)); + // We dynamically set as many nested content parameters as many the caller has declared; this is + // unusual, and is for testing purposes only. + TemplateModel[] nestedContParamValues = new TemplateModel[nestedContParamCnt]; + for (int paramIdx = 0; paramIdx < nestedContParamValues.length; paramIdx++) { + nestedContParamValues[paramIdx] = new SimpleNumber((i + 1) * (paramIdx + 1)); } - callPlace.executeNestedContent(loopVariableValues, out, env); + callPlace.executeNestedContent(nestedContParamValues, out, env); } } out.write("}"); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 new file mode 100644 index 0000000..eee1978 --- /dev/null +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TwoNestedContentParamsDirective.java @@ -0,0 +1,53 @@ +/* + * 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.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.model.Constants; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.model.impl.SimpleNumber; + +public class TwoNestedContentParamsDirective extends TestTemplateDirectiveModel { + + public static final TwoNestedContentParamsDirective INSTANCE = new TwoNestedContentParamsDirective(); + + private TwoNestedContentParamsDirective() { + // + } + + @Override + public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env) + throws TemplateException, IOException { + callPlace.executeNestedContent( + new TemplateModel[] { Constants.ONE, new SimpleNumber(2) }, + out, env); + } + + @Override + public ArgumentArrayLayout getArgumentArrayLayout() { + return ArgumentArrayLayout.PARAMETERLESS; + } +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 b7cf57f..18e46e9 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 @@ -25,8 +25,8 @@ - argument value: 1 // o.a.f.c.ASTExpNumberLiteral - argument name: "y" // String - argument value: 2 // o.a.f.c.ASTExpNumberLiteral - - target loop variable: "b1" // String - - target loop variable: "b2" // String + - nested content parameter: "b1" // String + - nested content parameter: "b2" // String #text // o.a.f.c.ASTStaticText - content: "x" // String #text // o.a.f.c.ASTStaticText @@ -37,8 +37,8 @@ - right-hand operand: "bar" // String - argument value: 1 // o.a.f.c.ASTExpNumberLiteral - argument value: 2 // o.a.f.c.ASTExpNumberLiteral - - target loop variable: "b1" // String - - target loop variable: "b2" // String + - nested content parameter: "b1" // String + - nested content parameter: "b2" // String #text // o.a.f.c.ASTStaticText - content: "y" // String #text // o.a.f.c.ASTStaticText @@ -149,7 +149,7 @@ - content: "\n8 " // String #list // o.a.f.c.ASTDirList - list source: xs // o.a.f.c.ASTExpVariable - - target loop variable: "x" // String + - nested content parameter: "x" // String #text // o.a.f.c.ASTStaticText - content: "\n9 " // String #list-#else-container // o.a.f.c.ASTDirListElseContainer @@ -158,7 +158,7 @@ #text // o.a.f.c.ASTStaticText - content: "[" // String #items // o.a.f.c.ASTDirItems - - target loop variable: "x" // String + - nested content parameter: "x" // String ${...} // o.a.f.c.ASTDollarInterpolation - content: x // o.a.f.c.ASTExpVariable #sep // o.a.f.c.ASTDirSep http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast index 2466cfd..5bdaded 100644 --- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast +++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast @@ -107,21 +107,21 @@ - content: "\n" // String #list // o.a.f.c.ASTDirList; Location 11:1-11:22 - list source: s // o.a.f.c.ASTExpVariable; Location 11:8-11:8 - - target loop variable: "i" // String + - nested content parameter: "i" // String #list // o.a.f.c.ASTDirList; Location 12:1-12:23 - list source: s // o.a.f.c.ASTExpVariable; Location 12:8-12:8 - - target loop variable: "i" // String + - nested content parameter: "i" // String #text // o.a.f.c.ASTStaticText; Location 12:15-12:15 - content: "1" // String #text // o.a.f.c.ASTStaticText; Location 12:24-12:24 - content: "\n" // String #list // o.a.f.c.ASTDirList; Location 13:1-13:28 - list source: s // o.a.f.c.ASTExpVariable; Location 13:8-13:8 - - target loop variable: "i" // String + - nested content parameter: "i" // String #sep // o.a.f.c.ASTDirSep; Location 13:15-13:20 #list // o.a.f.c.ASTDirList; Location 14:1-14:30 - list source: s // o.a.f.c.ASTExpVariable; Location 14:8-14:8 - - target loop variable: "i" // String + - nested content parameter: "i" // String #text // o.a.f.c.ASTStaticText; Location 14:15-14:15 - content: "1" // String #sep // o.a.f.c.ASTDirSep; Location 14:16-14:22 @@ -132,14 +132,14 @@ #list // o.a.f.c.ASTDirList; Location 15:1-15:45 - list source: s // o.a.f.c.ASTExpVariable; Location 15:8-15:8 #items // o.a.f.c.ASTDirItems; Location 15:10-15:37 - - target loop variable: "i" // String + - nested content parameter: "i" // String #sep // o.a.f.c.ASTDirSep; Location 15:23-15:28 #list // o.a.f.c.ASTDirList; Location 16:1-16:49 - list source: s // o.a.f.c.ASTExpVariable; Location 16:8-16:8 #text // o.a.f.c.ASTStaticText; Location 16:10-16:10 - content: "1" // String #items // o.a.f.c.ASTDirItems; Location 16:11-16:40 - - target loop variable: "i" // String + - nested content parameter: "i" // String #text // o.a.f.c.ASTStaticText; Location 16:24-16:24 - content: "1" // String #sep // o.a.f.c.ASTDirSep; Location 16:25-16:31 http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast index dd87f1f..ba69aa5 100644 --- a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast +++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast @@ -27,7 +27,7 @@ - content: "\n" // String #list // o.a.f.c.ASTDirList - list source: x // o.a.f.c.ASTExpVariable - - target loop variable: "xs" // String + - nested content parameter: "xs" // String #text // o.a.f.c.ASTStaticText - content: " " // String ${...} // o.a.f.c.ASTDollarInterpolation http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java index f2c62cd..7290153 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java @@ -28,17 +28,17 @@ import org.apache.freemarker.core.util._StringUtil; */ class ASTDirItems extends ASTDirective { - private final String loopVarName; - private final String loopVar2Name; + private final String nestedContentParamName; + private final String nestedContentParam2Name; /** - * @param loopVar2Name - * For non-hash listings always {@code null}, for hash listings {@code loopVarName} and - * {@code loopVarName2} holds the key- and value loop variable names. + * @param nestedContentParam2Name + * For non-hash listings always {@code null}, for hash listings {@code nestedContentParamName} and + * {@code nestedContentParamName2} holds the key- and value nested content parameter names. */ - ASTDirItems(String loopVarName, String loopVar2Name, TemplateElements children) { - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; + ASTDirItems(String nestedContentParamName, String nestedContentParam2Name, TemplateElements children) { + this.nestedContentParamName = nestedContentParamName; + this.nestedContentParam2Name = nestedContentParam2Name; setChildren(children); } @@ -51,7 +51,7 @@ class ASTDirItems extends ASTDirective { getASTNodeDescriptor(), " without iteration in context"); } - iterCtx.loopForItemsElement(env, getChildBuffer(), loopVarName, loopVar2Name); + iterCtx.loopForItemsElement(env, getChildBuffer(), nestedContentParamName, nestedContentParam2Name); return null; } @@ -66,10 +66,10 @@ class ASTDirItems extends ASTDirective { if (canonical) sb.append('<'); sb.append(getASTNodeDescriptor()); sb.append(" as "); - sb.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); - if (loopVar2Name != null) { + sb.append(_StringUtil.toFTLTopLevelIdentifierReference(nestedContentParamName)); + if (nestedContentParam2Name != null) { sb.append(", "); - sb.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVar2Name)); + sb.append(_StringUtil.toFTLTopLevelIdentifierReference(nestedContentParam2Name)); } if (canonical) { sb.append('>'); @@ -88,18 +88,18 @@ class ASTDirItems extends ASTDirective { @Override int getParameterCount() { - return loopVar2Name != null ? 2 : 1; + return nestedContentParam2Name != null ? 2 : 1; } @Override Object getParameterValue(int idx) { switch (idx) { case 0: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return loopVarName; + if (nestedContentParamName == null) throw new IndexOutOfBoundsException(); + return nestedContentParamName; case 1: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return loopVar2Name; + if (nestedContentParam2Name == null) throw new IndexOutOfBoundsException(); + return nestedContentParam2Name; default: throw new IndexOutOfBoundsException(); } } @@ -108,11 +108,11 @@ class ASTDirItems extends ASTDirective { ParameterRole getParameterRole(int idx) { switch (idx) { case 0: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; + if (nestedContentParamName == null) throw new IndexOutOfBoundsException(); + return ParameterRole.NESTED_CONTENT_PARAMETER; case 1: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; + if (nestedContentParam2Name == null) throw new IndexOutOfBoundsException(); + return ParameterRole.NESTED_CONTENT_PARAMETER; default: throw new IndexOutOfBoundsException(); } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java index c11ecef..14c7189 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java @@ -44,36 +44,36 @@ import org.apache.freemarker.core.util._StringUtil; final class ASTDirList extends ASTDirective { private final ASTExpression listedExp; - private final String loopVarName; - private final String loopVar2Name; + private final String nestedContentParamName; + private final String nestedContentParam2Name; private final boolean hashListing; /** * @param listedExp * a variable referring to a sequence or collection or extended hash to list - * @param loopVarName + * @param nestedContentParamName * The name of the variable that will hold the value of the current item when looping through listed value, * or {@code null} if we have a nested {@code #items}. If this is a hash listing then this variable will holds the value * of the hash key. - * @param loopVar2Name + * @param nestedContentParam2Name * The name of the variable that will hold the value of the current item when looping through the list, * or {@code null} if we have a nested {@code #items}. If this is a hash listing then it variable will hold the value * from the key-value pair. * @param childrenBeforeElse - * The nested content to execute if the listed value wasn't empty; can't be {@code null}. If the loop variable - * was specified in the start tag, this is also what we will iterate over. + * The nested content to execute if the listed value wasn't empty; can't be {@code null}. If the + * nested content parameter is specified in the start tag, this is also what we will iterate over. * @param hashListing * Whether this is a key-value pair listing, or a usual listing. This is properly set even if we have * a nested {@code #items}. */ ASTDirList(ASTExpression listedExp, - String loopVarName, - String loopVar2Name, + String nestedContentParamName, + String nestedContentParam2Name, TemplateElements childrenBeforeElse, boolean hashListing) { this.listedExp = listedExp; - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; + this.nestedContentParamName = nestedContentParamName; + this.nestedContentParam2Name = nestedContentParam2Name; setChildren(childrenBeforeElse); this.hashListing = hashListing; } @@ -94,25 +94,25 @@ final class ASTDirList extends ASTDirective { listedExp.assertNonNull(null, env); } - return env.visitIteratorBlock(new IterationContext(listedValue, loopVarName, loopVar2Name)); + return env.visitIteratorBlock(new IterationContext(listedValue, nestedContentParamName, nestedContentParam2Name)); } /** - * @param loopVariableName - * Then name of the loop variable whose context we are looking for, or {@code null} if we simply look for - * the innermost context. + * @param nestedContentParamName + * Then name of the nested content parameter whose context we are looking for, or {@code null} if we + * simply look for the innermost context. * @return The matching context or {@code null} if no such context exists. */ - static IterationContext findEnclosingIterationContext(Environment env, String loopVariableName) + static IterationContext findEnclosingIterationContext(Environment env, String nestedContentParamName) throws _MiscTemplateException { LocalContextStack ctxStack = env.getLocalContextStack(); if (ctxStack != null) { for (int i = ctxStack.size() - 1; i >= 0; i--) { Object ctx = ctxStack.get(i); if (ctx instanceof IterationContext - && (loopVariableName == null - || loopVariableName.equals(((IterationContext) ctx).getLoopVariableName()) - || loopVariableName.equals(((IterationContext) ctx).getLoopVariable2Name()) + && (nestedContentParamName == null + || nestedContentParamName.equals(((IterationContext) ctx).getNestedContentParameter1Name()) + || nestedContentParamName.equals(((IterationContext) ctx).getNestedContentParameter2Name()) )) { return (IterationContext) ctx; } @@ -128,12 +128,12 @@ final class ASTDirList extends ASTDirective { buf.append(getASTNodeDescriptor()); buf.append(' '); buf.append(listedExp.getCanonicalForm()); - if (loopVarName != null) { + if (nestedContentParamName != null) { buf.append(" as "); - buf.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); - if (loopVar2Name != null) { + buf.append(_StringUtil.toFTLTopLevelIdentifierReference(nestedContentParamName)); + if (nestedContentParam2Name != null) { buf.append(", "); - buf.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVar2Name)); + buf.append(_StringUtil.toFTLTopLevelIdentifierReference(nestedContentParam2Name)); } } if (canonical) { @@ -150,7 +150,7 @@ final class ASTDirList extends ASTDirective { @Override int getParameterCount() { - return 1 + (loopVarName != null ? 1 : 0) + (loopVar2Name != null ? 1 : 0); + return 1 + (nestedContentParamName != null ? 1 : 0) + (nestedContentParam2Name != null ? 1 : 0); } @Override @@ -159,11 +159,11 @@ final class ASTDirList extends ASTDirective { case 0: return listedExp; case 1: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return loopVarName; + if (nestedContentParamName == null) throw new IndexOutOfBoundsException(); + return nestedContentParamName; case 2: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return loopVar2Name; + if (nestedContentParam2Name == null) throw new IndexOutOfBoundsException(); + return nestedContentParam2Name; default: throw new IndexOutOfBoundsException(); } } @@ -174,11 +174,11 @@ final class ASTDirList extends ASTDirective { case 0: return ParameterRole.LIST_SOURCE; case 1: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; + if (nestedContentParamName == null) throw new IndexOutOfBoundsException(); + return ParameterRole.NESTED_CONTENT_PARAMETER; case 2: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; + if (nestedContentParam2Name == null) throw new IndexOutOfBoundsException(); + return ParameterRole.NESTED_CONTENT_PARAMETER; default: throw new IndexOutOfBoundsException(); } } @@ -190,7 +190,7 @@ final class ASTDirList extends ASTDirective { @Override boolean isNestedBlockRepeater() { - return loopVarName != null; + return nestedContentParamName != null; } /** @@ -203,50 +203,51 @@ final class ASTDirList extends ASTDirective { private Object openedIterator; private boolean hasNext; - private TemplateModel loopVar; - private TemplateModel loopVar2; + private TemplateModel nestedContentParam; + private TemplateModel nestedContentParam2; private int index; private boolean alreadyEntered; private Collection localVarNames = null; /** If the {@code #list} has nested {@code #items}, it's {@code null} outside the {@code #items}. */ - private String loopVarName; + private String nestedContentParam1Name; /** Used if we list key-value pairs */ - private String loopVar2Name; + private String nestedContentParam2Name; private final TemplateModel listedValue; - public IterationContext(TemplateModel listedValue, String loopVarName, String loopVar2Name) { + public IterationContext(TemplateModel listedValue, + String nestedContentParamName, String nestedContentParam2Name) { this.listedValue = listedValue; - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; + this.nestedContentParam1Name = nestedContentParamName; + this.nestedContentParam2Name = nestedContentParam2Name; } boolean accept(Environment env) throws TemplateException, IOException { return executeNestedContent(env, getChildBuffer()); } - void loopForItemsElement(Environment env, ASTElement[] childBuffer, String loopVarName, String loopVar2Name) - throws - TemplateException, IOException { + void loopForItemsElement(Environment env, ASTElement[] childBuffer, + String nestedContentParamName, String nestedContentParam2Name) + throws TemplateException, IOException { try { if (alreadyEntered) { throw new _MiscTemplateException(env, "The #items directive was already entered earlier for this listing."); } alreadyEntered = true; - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; + this.nestedContentParam1Name = nestedContentParamName; + this.nestedContentParam2Name = nestedContentParam2Name; executeNestedContent(env, childBuffer); } finally { - this.loopVarName = null; - this.loopVar2Name = null; + this.nestedContentParam1Name = null; + this.nestedContentParam2Name = null; } } /** - * Executes the given block for the {@link #listedValue}: if {@link #loopVarName} is non-{@code null}, then for - * each list item once, otherwise once if {@link #listedValue} isn't empty. + * Executes the given block for the {@link #listedValue}: if {@link #nestedContentParam1Name} is non-{@code + * null}, then for each list item once, otherwise once if {@link #listedValue} isn't empty. */ private boolean executeNestedContent(Environment env, ASTElement[] childBuffer) throws TemplateException, IOException { @@ -265,10 +266,10 @@ final class ASTDirList extends ASTDirective { : ((TemplateModelIterator) openedIterator); listNotEmpty = iterModel.hasNext(); if (listNotEmpty) { - if (loopVarName != null) { + if (nestedContentParam1Name != null) { try { do { - loopVar = iterModel.next(); + nestedContentParam = iterModel.next(); hasNext = iterModel.hasNext(); env.visit(childBuffer); index++; @@ -289,10 +290,10 @@ final class ASTDirList extends ASTDirective { final int size = seqModel.size(); listNotEmpty = size != 0; if (listNotEmpty) { - if (loopVarName != null) { + if (nestedContentParam1Name != null) { try { for (index = 0; index < size; index++) { - loopVar = seqModel.get(index); + nestedContentParam = seqModel.get(index); hasNext = (size > index + 1); env.visit(childBuffer); } @@ -308,8 +309,8 @@ final class ASTDirList extends ASTDirective { throw new NonSequenceOrCollectionException(env, new _ErrorDescriptionBuilder("The value you try to list is ", new _DelayedAOrAn(new _DelayedFTLTypeDescription(listedValue)), - ", thus you must specify two loop variables after the \"as\"; one for the key, and " - + "another for the value, like ", "<#... as k, v>", ")." + ", thus you must declare two nested content parameters after the \"as\"; one for the " + + "key, and another for the value, like ", "<#... as k, v>", ")." )); } else { throw new NonSequenceOrCollectionException( @@ -329,12 +330,12 @@ final class ASTDirList extends ASTDirective { : (KeyValuePairIterator) openedIterator; hashNotEmpty = kvpIter.hasNext(); if (hashNotEmpty) { - if (loopVarName != null) { + if (nestedContentParam1Name != null) { try { do { KeyValuePair kvp = kvpIter.next(); - loopVar = kvp.getKey(); - loopVar2 = kvp.getValue(); + nestedContentParam = kvp.getKey(); + nestedContentParam2 = kvp.getValue(); hasNext = kvpIter.hasNext(); env.visit(childBuffer); index++; @@ -353,24 +354,27 @@ final class ASTDirList extends ASTDirective { TemplateModelIterator keysIter = listedHash.keys().iterator(); hashNotEmpty = keysIter.hasNext(); if (hashNotEmpty) { - if (loopVarName != null) { + if (nestedContentParam1Name != null) { try { do { - loopVar = keysIter.next(); - if (!(loopVar instanceof TemplateScalarModel)) { + nestedContentParam = keysIter.next(); + if (!(nestedContentParam instanceof TemplateScalarModel)) { throw new NonStringException(env, new _ErrorDescriptionBuilder( "When listing key-value pairs of traditional hash " + "implementations, all keys must be strings, but one of them " + "was ", - new _DelayedAOrAn(new _DelayedFTLTypeDescription(loopVar)), "." + new _DelayedAOrAn( + new _DelayedFTLTypeDescription(nestedContentParam)), + "." ).tip("The listed value's TemplateModel class was ", new _DelayedShortClassName(listedValue.getClass()), ", which doesn't implement ", new _DelayedShortClassName(TemplateHashModelEx2.class), ", which leads to this restriction.")); } - loopVar2 = listedHash.get(((TemplateScalarModel) loopVar).getAsString()); + nestedContentParam2 = listedHash.get(((TemplateScalarModel) nestedContentParam) + .getAsString()); hasNext = keysIter.hasNext(); env.visit(childBuffer); index++; @@ -388,8 +392,8 @@ final class ASTDirList extends ASTDirective { throw new NonSequenceOrCollectionException(env, new _ErrorDescriptionBuilder("The value you try to list is ", new _DelayedAOrAn(new _DelayedFTLTypeDescription(listedValue)), - ", thus you must specify only one loop variable after the \"as\" (there's no separate " - + "key and value)." + ", thus you must declare only one nested content parameter after the \"as\" (there's " + + "no separate key and value)." )); } else { throw new NonExtendedHashException( @@ -398,21 +402,21 @@ final class ASTDirList extends ASTDirective { return hashNotEmpty; } - String getLoopVariableName() { - return loopVarName; + String getNestedContentParameter1Name() { + return nestedContentParam1Name; } - String getLoopVariable2Name() { - return loopVar2Name; + String getNestedContentParameter2Name() { + return nestedContentParam2Name; } @Override public TemplateModel getLocalVariable(String name) { - String loopVarName = this.loopVarName; - if (loopVarName != null && name.startsWith(loopVarName)) { - switch(name.length() - loopVarName.length()) { + String nestedContentParamName = this.nestedContentParam1Name; + if (nestedContentParamName != null && name.startsWith(nestedContentParamName)) { + switch(name.length() - nestedContentParamName.length()) { case 0: - return loopVar; + return nestedContentParam; case 6: if (name.endsWith(LOOP_STATE_INDEX)) { return new SimpleNumber(index); @@ -426,8 +430,8 @@ final class ASTDirList extends ASTDirective { } } - if (name.equals(loopVar2Name)) { - return loopVar2; + if (name.equals(nestedContentParam2Name)) { + return nestedContentParam2; } return null; @@ -435,13 +439,13 @@ final class ASTDirList extends ASTDirective { @Override public Collection<String> getLocalVariableNames() { - String loopVarName = this.loopVarName; - if (loopVarName != null) { + String nestedContentParamName = this.nestedContentParam1Name; + if (nestedContentParamName != null) { if (localVarNames == null) { localVarNames = new ArrayList(3); - localVarNames.add(loopVarName); - localVarNames.add(loopVarName + LOOP_STATE_INDEX); - localVarNames.add(loopVarName + LOOP_STATE_HAS_NEXT); + localVarNames.add(nestedContentParamName); + localVarNames.add(nestedContentParamName + LOOP_STATE_INDEX); + localVarNames.add(nestedContentParamName + LOOP_STATE_HAS_NEXT); } return localVarNames; } else { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 b178547..eb06e23 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 @@ -66,7 +66,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { private final ASTExpression callableValueExp; private final ASTExpression[] positionalArgs; private final NamedArgument[] namedArgs; - private final StringToIndexMap loopVarNames; + private final StringToIndexMap nestedContentParamNames; private final boolean allowCallingFunctions; private CustomDataHolder customDataHolder; @@ -77,19 +77,19 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { */ ASTDynamicTopLevelCall( ASTExpression callableValueExp, boolean allowCallingFunctions, - ASTExpression[] positionalArgs, NamedArgument[] namedArgs, StringToIndexMap loopVarNames, + ASTExpression[] positionalArgs, NamedArgument[] namedArgs, StringToIndexMap nestedContentParamNames, TemplateElements children) { this.callableValueExp = callableValueExp; this.allowCallingFunctions = allowCallingFunctions; if (positionalArgs != null && positionalArgs.length == 0 || namedArgs != null && namedArgs.length == 0 - || loopVarNames != null && loopVarNames.size() == 0) { + || nestedContentParamNames != null && nestedContentParamNames.size() == 0) { throw new IllegalArgumentException("Use null instead of empty collections"); } this.positionalArgs = positionalArgs; this.namedArgs = namedArgs; - this.loopVarNames = loopVarNames; + this.nestedContentParamNames = nestedContentParamNames; setChildren(children); } @@ -137,7 +137,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { env.invoke(macro, macroNamedArgs, _ArrayAdapterList.adapt(positionalArgs), - loopVarNames != null ? loopVarNames.getKeys() : null, + nestedContentParamNames != null ? nestedContentParamNames.getKeys() : null, getChildBuffer()); return null; } else if (callableValueTM == null) { @@ -269,16 +269,16 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { MessageUtil.appendExpressionAsUntearable(sb, namedArg.value); } } - if (loopVarNames != null) { + if (nestedContentParamNames != null) { sb.append("; "); boolean first = true; - for (String loopVarName : loopVarNames.getKeys()) { + for (String nestedContentParamName : nestedContentParamNames.getKeys()) { if (!first) { sb.append(", "); } else { first = false; } - sb.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); + sb.append(_StringUtil.toFTLTopLevelIdentifierReference(nestedContentParamName)); } } if (canonical) { @@ -309,7 +309,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { return 1/*nameExp*/ + (positionalArgs != null ? positionalArgs.length : 0) + (namedArgs != null ? namedArgs.length * 2 : 0) - + (loopVarNames != null ? loopVarNames.size() : 0); + + (nestedContentParamNames != null ? nestedContentParamNames.size() : 0); } @Override @@ -329,9 +329,10 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { return (idx - base) % 2 == 0 ? namedArg.name : namedArg.value; } else { base += namedArgsSize * 2; - final int bodyParameterNamesSize = loopVarNames != null ? loopVarNames.size() : 0; + final int bodyParameterNamesSize = nestedContentParamNames != null + ? nestedContentParamNames.size() : 0; if (idx - base < bodyParameterNamesSize) { - return loopVarNames.getKeys().get(idx - base); + return nestedContentParamNames.getKeys().get(idx - base); } else { throw new IndexOutOfBoundsException(); } @@ -356,9 +357,10 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { return (idx - base) % 2 == 0 ? ParameterRole.ARGUMENT_NAME : ParameterRole.ARGUMENT_VALUE; } else { base += namedArgsSize * 2; - final int bodyParameterNamesSize = loopVarNames != null ? loopVarNames.size() : 0; + final int bodyParameterNamesSize = nestedContentParamNames != null + ? nestedContentParamNames.size() : 0; if (idx - base < bodyParameterNamesSize) { - return ParameterRole.TARGET_LOOP_VARIABLE; + return ParameterRole.NESTED_CONTENT_PARAMETER; } else { throw new IndexOutOfBoundsException(); } @@ -377,26 +379,27 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace { } @Override - public int getLoopVariableCount() { - return loopVarNames != null ? loopVarNames.size() : 0; + public int getNestedContentParameterCount() { + return nestedContentParamNames != null ? nestedContentParamNames.size() : 0; } @Override - public void executeNestedContent(TemplateModel[] loopVarValues, Writer out, Environment env) + public void executeNestedContent(TemplateModel[] nestedContentParamValues, Writer out, Environment env) throws TemplateException, IOException { - if (loopVarNames != null) { - int loopVarNamesSize = loopVarNames.size(); - int loopVarValuesSize = loopVarValues != null ? loopVarValues.length : 0; - if (loopVarValuesSize < loopVarNamesSize) { - throw new _MiscTemplateException(this, - "The invocation declares more nested content parameters (", - loopVarNamesSize, ": ", new _DelayedJQuotedListing(loopVarNames.getKeys()), - ") than what the called object intends to pass (", - loopVarValuesSize, "). Declare no more than ", loopVarValuesSize, - " nested content parameters."); - } + int nestedContentParamNamesSize = nestedContentParamNames != null ? nestedContentParamNames.size() : 0; + int nestedContentParamValuesSize = nestedContentParamValues != null ? nestedContentParamValues.length : 0; + if (nestedContentParamValuesSize != nestedContentParamNamesSize) { + throw new _MiscTemplateException(this, + "The invocation declares ", (nestedContentParamNamesSize != 0 ? nestedContentParamNamesSize : "no"), + " nested content parameter(s)", + (nestedContentParamNamesSize != 0 + ? new Object[] { " (", new _DelayedJQuotedListing(nestedContentParamNames.getKeys()), ")", } + : ""), + ", but the called object intends to pass ", + nestedContentParamValuesSize, " parameters. You need to declare ", nestedContentParamValuesSize, + " nested content parameters."); } - env.visit(getChildBuffer(), loopVarNames, loopVarValues, out); + env.visit(getChildBuffer(), nestedContentParamNames, nestedContentParamValues, out); } @Override http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 4101b29..a74f83f 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 @@ -111,14 +111,14 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable { putBI("float", new floatBI()); putBI("floor", new floorBI()); putBI("chunk", new chunkBI()); - putBI("counter", new BuiltInsForLoopVariables.counterBI()); - putBI("itemCycle", new BuiltInsForLoopVariables.item_cycleBI()); + putBI("counter", new BuiltInsForNestedContentParameters.counterBI()); + putBI("itemCycle", new BuiltInsForNestedContentParameters.item_cycleBI()); putBI("hasApi", new BuiltInsForMultipleTypes.has_apiBI()); putBI("hasContent", new BuiltInsForExistenceHandling.has_contentBI()); - putBI("hasNext", new BuiltInsForLoopVariables.has_nextBI()); + putBI("hasNext", new BuiltInsForNestedContentParameters.has_nextBI()); putBI("html", new BuiltInsForStringsEncoding.htmlBI()); putBI("ifExists", new BuiltInsForExistenceHandling.if_existsBI()); - putBI("index", new BuiltInsForLoopVariables.indexBI()); + putBI("index", new BuiltInsForNestedContentParameters.indexBI()); putBI("indexOf", new BuiltInsForStringsBasic.index_ofBI(false)); putBI("int", new intBI()); putBI("interpret", new BuiltInsForStringsMisc.interpretBI()); @@ -129,9 +129,9 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable { putBI("isDate", bi); // misnomer putBI("isDateLike", bi); putBI("isDateOnly", new BuiltInsForMultipleTypes.is_dateOfTypeBI(TemplateDateModel.DATE)); - putBI("isEvenItem", new BuiltInsForLoopVariables.is_even_itemBI()); - putBI("isFirst", new BuiltInsForLoopVariables.is_firstBI()); - putBI("isLast", new BuiltInsForLoopVariables.is_lastBI()); + putBI("isEvenItem", new BuiltInsForNestedContentParameters.is_even_itemBI()); + putBI("isFirst", new BuiltInsForNestedContentParameters.is_firstBI()); + putBI("isLast", new BuiltInsForNestedContentParameters.is_lastBI()); putBI("isUnknownDateLike", new BuiltInsForMultipleTypes.is_dateOfTypeBI(TemplateDateModel.UNKNOWN)); putBI("isDatetime", new BuiltInsForMultipleTypes.is_dateOfTypeBI(TemplateDateModel.DATE_TIME)); putBI("isDirective", new BuiltInsForMultipleTypes.is_directiveBI()); @@ -146,7 +146,7 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable { putBI("isNan", new is_nanBI()); putBI("isNode", new BuiltInsForMultipleTypes.is_nodeBI()); putBI("isNumber", new BuiltInsForMultipleTypes.is_numberBI()); - putBI("isOddItem", new BuiltInsForLoopVariables.is_odd_itemBI()); + putBI("isOddItem", new BuiltInsForNestedContentParameters.is_odd_itemBI()); putBI("isSequence", new BuiltInsForMultipleTypes.is_sequenceBI()); putBI("isString", new BuiltInsForMultipleTypes.is_stringBI()); putBI("isTime", new BuiltInsForMultipleTypes.is_dateOfTypeBI(TemplateDateModel.TIME)); @@ -243,8 +243,8 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable { putBI("parent", new parentBI()); putBI("previousSibling", new previousSiblingBI()); putBI("nextSibling", new nextSiblingBI()); - putBI("itemParity", new BuiltInsForLoopVariables.item_parityBI()); - putBI("itemParityCap", new BuiltInsForLoopVariables.item_parity_capBI()); + putBI("itemParity", new BuiltInsForNestedContentParameters.item_parityBI()); + putBI("itemParityCap", new BuiltInsForNestedContentParameters.item_parity_capBI()); putBI("reverse", new reverseBI()); putBI("rightPad", new BuiltInsForStringsBasic.padBI(false)); putBI("root", new rootBI()); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLoopVariable.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLoopVariable.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLoopVariable.java deleted file mode 100644 index 5b7d9c3..0000000 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForLoopVariable.java +++ /dev/null @@ -1,48 +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; - -import org.apache.freemarker.core.ASTDirList.IterationContext; -import org.apache.freemarker.core.model.TemplateModel; - -abstract class BuiltInForLoopVariable extends SpecialBuiltIn { - - private String loopVarName; - - void bindToLoopVariable(String loopVarName) { - this.loopVarName = loopVarName; - } - - @Override - TemplateModel _eval(Environment env) throws TemplateException { - IterationContext iterCtx = ASTDirList.findEnclosingIterationContext(env, loopVarName); - if (iterCtx == null) { - // The parser should prevent this situation - throw new _MiscTemplateException( - this, env, - "There's no iteration in context that uses loop variable ", new _DelayedJQuote(loopVarName), "."); - } - - return calculateResult(iterCtx, env); - } - - abstract TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException; - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNestedContentParameter.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNestedContentParameter.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNestedContentParameter.java new file mode 100644 index 0000000..9847352 --- /dev/null +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInForNestedContentParameter.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.freemarker.core; + +import org.apache.freemarker.core.ASTDirList.IterationContext; +import org.apache.freemarker.core.model.TemplateModel; + +abstract class BuiltInForNestedContentParameter extends SpecialBuiltIn { + + private String nestedContentParamName; + + void bindToNestedContentParameter(String nestedContentParamName) { + this.nestedContentParamName = nestedContentParamName; + } + + @Override + TemplateModel _eval(Environment env) throws TemplateException { + IterationContext iterCtx = ASTDirList.findEnclosingIterationContext(env, nestedContentParamName); + if (iterCtx == null) { + // The parser should prevent this situation + throw new _MiscTemplateException( + this, env, + "There's no iteration in context that uses the nested content parameter ", + new _DelayedJQuote( nestedContentParamName), "."); + } + + return calculateResult(iterCtx, env); + } + + abstract TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException; + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForLoopVariables.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForLoopVariables.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForLoopVariables.java deleted file mode 100644 index 8d55e0e..0000000 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForLoopVariables.java +++ /dev/null @@ -1,156 +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; - -import java.util.List; - -import org.apache.freemarker.core.ASTDirList.IterationContext; -import org.apache.freemarker.core.model.TemplateBooleanModel; -import org.apache.freemarker.core.model.TemplateMethodModelEx; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.model.impl.SimpleNumber; -import org.apache.freemarker.core.model.impl.SimpleScalar; - - -class BuiltInsForLoopVariables { - - static class indexBI extends BuiltInForLoopVariable { - - @Override - TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { - return new SimpleNumber(iterCtx.getIndex()); - } - - } - - static class counterBI extends BuiltInForLoopVariable { - - @Override - TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { - return new SimpleNumber(iterCtx.getIndex() + 1); - } - - } - - static abstract class BooleanBuiltInForLoopVariable extends BuiltInForLoopVariable { - - @Override - final TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { - return calculateBooleanResult(iterCtx, env) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; - } - - protected abstract boolean calculateBooleanResult(IterationContext iterCtx, Environment env); - - } - - static class has_nextBI extends BooleanBuiltInForLoopVariable { - - @Override - protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { - return iterCtx.hasNext(); - } - - } - - static class is_lastBI extends BooleanBuiltInForLoopVariable { - - @Override - protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { - return !iterCtx.hasNext(); - } - - } - - static class is_firstBI extends BooleanBuiltInForLoopVariable { - - @Override - protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { - return iterCtx.getIndex() == 0; - } - - } - - static class is_odd_itemBI extends BooleanBuiltInForLoopVariable { - - @Override - protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { - return iterCtx.getIndex() % 2 == 0; - } - - } - - static class is_even_itemBI extends BooleanBuiltInForLoopVariable { - - @Override - protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { - return iterCtx.getIndex() % 2 != 0; - } - - } - - static class item_parityBI extends BuiltInForLoopVariable { - - private static final SimpleScalar ODD = new SimpleScalar("odd"); - private static final SimpleScalar EVEN = new SimpleScalar("even"); - - @Override - TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { - return iterCtx.getIndex() % 2 == 0 ? ODD: EVEN; - } - - } - - static class item_parity_capBI extends BuiltInForLoopVariable { - - private static final SimpleScalar ODD = new SimpleScalar("Odd"); - private static final SimpleScalar EVEN = new SimpleScalar("Even"); - - @Override - TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { - return iterCtx.getIndex() % 2 == 0 ? ODD: EVEN; - } - - } - - static class item_cycleBI extends BuiltInForLoopVariable { - - private class BIMethod implements TemplateMethodModelEx { - - private final IterationContext iterCtx; - - private BIMethod(IterationContext iterCtx) { - this.iterCtx = iterCtx; - } - - @Override - public Object exec(List args) throws TemplateModelException { - checkMethodArgCount(args, 1, Integer.MAX_VALUE); - return args.get(iterCtx.getIndex() % args.size()); - } - } - - @Override - TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { - return new BIMethod(iterCtx); - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 new file mode 100644 index 0000000..a4c4d8f --- /dev/null +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForNestedContentParameters.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.freemarker.core; + +import java.util.List; + +import org.apache.freemarker.core.ASTDirList.IterationContext; +import org.apache.freemarker.core.model.TemplateBooleanModel; +import org.apache.freemarker.core.model.TemplateMethodModelEx; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.model.TemplateModelException; +import org.apache.freemarker.core.model.impl.SimpleNumber; +import org.apache.freemarker.core.model.impl.SimpleScalar; + + +class BuiltInsForNestedContentParameters { + + static class indexBI extends BuiltInForNestedContentParameter { + + @Override + TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { + return new SimpleNumber(iterCtx.getIndex()); + } + + } + + static class counterBI extends BuiltInForNestedContentParameter { + + @Override + TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { + return new SimpleNumber(iterCtx.getIndex() + 1); + } + + } + + static abstract class BooleanBuiltInForNestedContentParameter extends BuiltInForNestedContentParameter { + + @Override + final TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { + return calculateBooleanResult(iterCtx, env) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; + } + + protected abstract boolean calculateBooleanResult(IterationContext iterCtx, Environment env); + + } + + static class has_nextBI extends BooleanBuiltInForNestedContentParameter { + + @Override + protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { + return iterCtx.hasNext(); + } + + } + + static class is_lastBI extends BooleanBuiltInForNestedContentParameter { + + @Override + protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { + return !iterCtx.hasNext(); + } + + } + + static class is_firstBI extends BooleanBuiltInForNestedContentParameter { + + @Override + protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { + return iterCtx.getIndex() == 0; + } + + } + + static class is_odd_itemBI extends BooleanBuiltInForNestedContentParameter { + + @Override + protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { + return iterCtx.getIndex() % 2 == 0; + } + + } + + static class is_even_itemBI extends BooleanBuiltInForNestedContentParameter { + + @Override + protected boolean calculateBooleanResult(IterationContext iterCtx, Environment env) { + return iterCtx.getIndex() % 2 != 0; + } + + } + + static class item_parityBI extends BuiltInForNestedContentParameter { + + private static final SimpleScalar ODD = new SimpleScalar("odd"); + private static final SimpleScalar EVEN = new SimpleScalar("even"); + + @Override + TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { + return iterCtx.getIndex() % 2 == 0 ? ODD: EVEN; + } + + } + + static class item_parity_capBI extends BuiltInForNestedContentParameter { + + private static final SimpleScalar ODD = new SimpleScalar("Odd"); + private static final SimpleScalar EVEN = new SimpleScalar("Even"); + + @Override + TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { + return iterCtx.getIndex() % 2 == 0 ? ODD: EVEN; + } + + } + + static class item_cycleBI extends BuiltInForNestedContentParameter { + + private class BIMethod implements TemplateMethodModelEx { + + private final IterationContext iterCtx; + + private BIMethod(IterationContext iterCtx) { + this.iterCtx = iterCtx; + } + + @Override + public Object exec(List args) throws TemplateModelException { + checkMethodArgCount(args, 1, Integer.MAX_VALUE); + return args.get(iterCtx.getIndex() % args.size()); + } + } + + @Override + TemplateModel calculateResult(IterationContext iterCtx, Environment env) throws TemplateException { + return new BIMethod(iterCtx); + } + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/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 ad6538d..af798b4 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 @@ -429,22 +429,22 @@ public final class Environment extends MutableProcessingConfiguration<Environmen void visit( ASTElement[] childBuffer, - final StringToIndexMap loopVarNames, final TemplateModel[] loopVarValues, + final StringToIndexMap nestedContentParamNames, final TemplateModel[] nestedContentParamValues, Writer out) throws IOException, TemplateException { - if (loopVarNames == null) { // This is by far the most frequent case + if (nestedContentParamNames == null) { // This is by far the most frequent case visit(childBuffer, out); } else { pushLocalContext(new LocalContext() { @Override public TemplateModel getLocalVariable(String name) throws TemplateModelException { - int index = loopVarNames.get(name); - return index != -1 ? loopVarValues[index] : null; + int index = nestedContentParamNames.get(name); + return index != -1 ? nestedContentParamValues[index] : null; } @Override public Collection<String> getLocalVariableNames() throws TemplateModelException { - return loopVarNames.getKeys(); + return nestedContentParamNames.getKeys(); } }); try { @@ -1955,10 +1955,11 @@ public final class Environment extends MutableProcessingConfiguration<Environmen } /** - * Returns the loop or macro local variable corresponding to this variable name. Possibly null. (Note that the - * misnomer is kept for backward compatibility: loop variables are not local variables according to our - * terminology.) + * Returns the loop or macro nested content parameter variables corresponding to this variable name. Possibly null. + * (Note that the misnomer is kept for backward compatibility: nested content parameters are not local variables + * according to our terminology.) */ + // TODO [FM3] Don't return nested content params anymore (see JavaDoc)? But, LocalContext does return them... public TemplateModel getLocalVariable(String name) throws TemplateModelException { if (localContextStack != null) { for (int i = localContextStack.size() - 1; i >= 0; i--) { @@ -1977,7 +1978,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen * correspondent to an FTL top-level variable reading expression. That is, it tries to find the the variable in this * order: * <ol> - * <li>An loop variable (if we're in a loop or user defined directive body) such as foo_has_next + * <li>A nested content parameter such as {@code x} in {@code <#list xs as x>} * <li>A local variable (if we're in a macro) * <li>A variable defined in the current namespace (say, via <#assign ...>) * <li>A variable defined globally (say, via <#global ....>) @@ -2055,11 +2056,11 @@ public final class Environment extends MutableProcessingConfiguration<Environmen /** * Returns a set of variable names that are known at the time of call. This includes names of all shared variables * in the {@link Configuration}, names of all global variables that were assigned during the template processing, - * names of all variables in the current name-space, names of all local variables and loop variables. If the passed - * root data model implements the {@link TemplateHashModelEx} interface, then all names it retrieves through a call - * to {@link TemplateHashModelEx#keys()} method are returned as well. The method returns a new Set object on each - * call that is completely disconnected from the Environment. That is, modifying the set will have no effect on the - * Environment object. + * names of all variables in the current name-space, names of all local variables and nested content parameters. If + * the passed root data model implements the {@link TemplateHashModelEx} interface, then all names it retrieves + * through a call to {@link TemplateHashModelEx#keys()} method are returned as well. The method returns a new Set + * object on each call that is completely disconnected from the Environment. That is, modifying the set will have no + * effect on the Environment object. */ public Set getKnownVariableNames() throws TemplateModelException { // shared vars. http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/ParameterRole.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ParameterRole.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ParameterRole.java index 146f0b8..ccae7b7 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/ParameterRole.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ParameterRole.java @@ -50,7 +50,7 @@ final class ParameterRole { static final ParameterRole PLACEHOLDER_VARIABLE = new ParameterRole("placeholder variable"); static final ParameterRole EXPRESSION_TEMPLATE = new ParameterRole("expression template"); static final ParameterRole LIST_SOURCE = new ParameterRole("list source"); - static final ParameterRole TARGET_LOOP_VARIABLE = new ParameterRole("target loop variable"); + static final ParameterRole NESTED_CONTENT_PARAMETER = new ParameterRole("nested content parameter"); static final ParameterRole TEMPLATE_NAME = new ParameterRole("template name"); static final ParameterRole IGNORE_MISSING_PARAMETER = new ParameterRole("\"ignore_missing\" parameter"); static final ParameterRole PARAMETER_NAME = new ParameterRole("parameter name"); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/589d9b80/freemarker-core/src/main/java/org/apache/freemarker/core/model/CallPlace.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/CallPlace.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/CallPlace.java index 7761eeb..749c313 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/CallPlace.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/CallPlace.java @@ -47,29 +47,27 @@ public interface CallPlace { boolean hasNestedContent(); /** - * The number of loop variables specified for this call. Note that users are generally allowed to omit loop - * variables when calling a directive. So this can be useful to avoid calculating the values of loop variables that - * the caller will not receive anyway. While it's an error if the user specifies too many loop variables, the - * implementor of the {@link TemplateDirectiveModel} shouldn't check for that condition, as far as they will call - * {@link #executeNestedContent(TemplateModel[], Writer, Environment)}, which will the should throw a {@link - * TemplateException} with a descriptive error message then. + * The number of nested content parameters in this call (like 2 in {@code <@foo xs; k, v>...</@>}). If you want the + * caller to specify a predefined number of nested content parameters, then this is not interesting for you, and + * just pass an array of that length to {@link #executeNestedContent(TemplateModel[], Writer, Environment)}. If, + * however, you want to allow the caller to declare less parameters, then this is how you know how much + * parameters you should omit when calling {@link #executeNestedContent(TemplateModel[], Writer, Environment)}. */ - int getLoopVariableCount(); + int getNestedContentParameterCount(); /** * Executed the nested content; it there's none, it just does nothing. * - * @param loopVarValues - * The loop variable values to pass to the nested content, or {@code null} if there's none. It's not a - * problem if this array is longer than the number of loop variables than the caller of the directive has - * declared (as in {@code <@foo bar; i, j />} there are 2 loop variables declared); the directive - * caller simply won't receive the excess variables. If the caller declares more loop variables than the - * length of this array though, then a {@link TemplateException} will thrown by FreeMarker with a - * descriptive error message. Thus, the caller of this method need not be concerned about the - * number of loop variables declared by the caller (unless to avoid calculating loop variable values - * unnecessarily, in which case use {@link #getLoopVariableCount()}). + * @param nestedContentParamValues + * The nested content parameter values to pass to the nested content (as in {@code <@foo bar; i, j>${i}, + * ${j}</@foo>} there are 2 such parameters, whose value you set here), or {@code null} if there's none. + * This array must be {@link #getNestedContentParameterCount()} long, or else {@link TemplateException} will thrown by + * FreeMarker with a descriptive error message that tells to user the they need to declare that many nested + * content parameters as the length of this array. If you want to allow the the caller to not declare some + * of nested content parameters, then you have to make this array shorter according to {@link + * #getNestedContentParameterCount()}. */ - void executeNestedContent(TemplateModel[] loopVarValues, Writer out, Environment env) + void executeNestedContent(TemplateModel[] nestedContentParamValues, Writer out, Environment env) throws TemplateException, IOException; // -------------------------------------------------------------------------------------------------------------