Repository: incubator-freemarker
Updated Branches:
  refs/heads/2.3-gae 4a5eec42d -> 7adecaee2


FREEMARKER-83: Modified how .macro_caller_template_name works... now it has no 
surprising restrictions, and is simpler.


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

Branch: refs/heads/2.3-gae
Commit: 7adecaee25f2c5dddc8c75ff2aeb54fbefbf8458
Parents: 4a5eec4
Author: ddekany <ddek...@apache.org>
Authored: Fri Mar 9 22:38:35 2018 +0100
Committer: ddekany <ddek...@apache.org>
Committed: Fri Mar 9 22:38:35 2018 +0100

----------------------------------------------------------------------
 .../java/freemarker/core/BuiltinVariable.java   | 15 ++++----
 src/main/java/freemarker/core/Environment.java  | 36 ++------------------
 src/main/java/freemarker/core/Macro.java        |  6 ++--
 src/main/java/freemarker/core/UnifiedCall.java  |  2 +-
 src/manual/en_US/book.xml                       | 17 +++------
 .../core/MacroCallerTemplateNameTest.java       | 36 +++++++++++---------
 6 files changed, 38 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7adecaee/src/main/java/freemarker/core/BuiltinVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BuiltinVariable.java 
b/src/main/java/freemarker/core/BuiltinVariable.java
index 9b9b135..13dd67d 100644
--- a/src/main/java/freemarker/core/BuiltinVariable.java
+++ b/src/main/java/freemarker/core/BuiltinVariable.java
@@ -22,6 +22,7 @@ package freemarker.core;
 import java.util.Arrays;
 import java.util.Date;
 
+import freemarker.core.Macro.Context;
 import freemarker.template.Configuration;
 import freemarker.template.SimpleDate;
 import freemarker.template.SimpleScalar;
@@ -30,6 +31,7 @@ import freemarker.template.TemplateException;
 import freemarker.template.TemplateHashModel;
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateScalarModel;
 import freemarker.template._TemplateAPI;
 import freemarker.template.utility.StringUtil;
 
@@ -253,14 +255,13 @@ final class BuiltinVariable extends Expression {
             return GetOptionalTemplateMethod.INSTANCE_CC;
         }
         if (name == MACRO_CALLER_TEMPLATE_NAME || name == 
MACRO_CALLER_TEMPLATE_NAME_CC) {
-            UnifiedCall caller;
-            try {
-                caller = env.getMacroCaller();
-            } catch (IllegalStateException e) {
-                throw new TemplateException("Failed to resolve ." + name + ": 
" + e.getMessage(), e, env);
+            Context ctx = env.getCurrentMacroContext();
+            if (ctx == null) {
+                throw new TemplateException(
+                        "Can't get ." + name + " here, as there's no macro 
call in context.", env);
             }
-            String name = caller.getTemplate().getName();
-            return name != null ? new SimpleScalar(name) : 
SimpleScalar.EMPTY_STRING;
+            String name = ctx.callPlace.getTemplate().getName();
+            return name != null ? new SimpleScalar(name) : 
TemplateScalarModel.EMPTY_STRING;
         }
         
         throw new _MiscTemplateException(this,

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7adecaee/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java 
b/src/main/java/freemarker/core/Environment.java
index 5f20c26..2d4b585 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -281,36 +281,6 @@ public final class Environment extends Configurable {
     }
 
     /**
-     * Gets the non-{@code null} {@link UnifiedCall} of the caller of the 
macro whose context we are in; note
-     * that you can't call this from everywhere. Specifically, the FTL call 
stack must not contain {@code #nested} or a
-     * call to user-defined-directive after the stack entry of the {@code 
#macro} directive. This practically means that
-     * this should be called on the top-level inside {@code #macro}, or inside 
some core directives like {@code #if}.
-     * 
-     * @throws IllegalStateException
-     *             If there's no macro caller or it can't be figured out at 
this point of the template execution.
-     */
-    UnifiedCall getMacroCaller() throws IllegalStateException {
-        for (int ln = instructionStackSize - 1; ln > 0; ln--) {
-            TemplateElement te = instructionStack[ln];
-            if (te instanceof Macro) {
-                TemplateElement macroCaller = instructionStack[ln - 1];
-                if (macroCaller instanceof UnifiedCall) {
-                    return (UnifiedCall) macroCaller;
-                }
-            }
-            // Avoid returning the caller of @nested in `<#macro 
called><@inner>${getMacroCallerHere()}</@></#macro>`;
-            // the #macro that defines "inner" would break our logic above.
-            if (te instanceof BodyInstruction) {
-                throw new IllegalStateException(
-                        "Can't get the location of the macro caller here, 
because you are inside an user-defined "
-                        + "directive call that's nested inside the #macro 
directive. (You may "
-                        + "need to get the caller location earlier, and store 
it in a local variable for later use.)");
-            }
-        }
-        throw new IllegalStateException("There's no macro caller at this 
point.");
-    }
-
-    /**
      * Deletes cached values that meant to be valid only during a single 
template execution.
      */
     private void clearCachedValues() {
@@ -624,7 +594,7 @@ public final class Environment extends Configurable {
     void invokeNestedContent(BodyInstruction.Context bodyCtx) throws 
TemplateException, IOException {
         Macro.Context invokingMacroContext = getCurrentMacroContext();
         LocalContextStack prevLocalContextStack = localContextStack;
-        TemplateElement[] nestedContentBuffer = 
invokingMacroContext.nestedContentBuffer;
+        TemplateElement[] nestedContentBuffer = 
invokingMacroContext.callPlace.getChildBuffer();
         if (nestedContentBuffer != null) {
             this.currentMacroContext = invokingMacroContext.prevMacroContext;
             currentNamespace = invokingMacroContext.nestedContentNamespace;
@@ -765,7 +735,7 @@ public final class Environment extends Configurable {
      */
     void invoke(Macro macro,
             Map namedArgs, List positionalArgs,
-            List bodyParameterNames, TemplateElement[] childBuffer) throws 
TemplateException, IOException {
+            List bodyParameterNames, TemplateElement callPlace) throws 
TemplateException, IOException {
         if (macro == Macro.DO_NOTHING_MACRO) {
             return;
         }
@@ -780,7 +750,7 @@ public final class Environment extends Configurable {
             elementPushed = false;
         }
         try {
-            final Macro.Context macroCtx = macro.new Context(this, 
childBuffer, bodyParameterNames);
+            final Macro.Context macroCtx = macro.new Context(this, callPlace, 
bodyParameterNames);
             // Causes the evaluation of argument expressions:
             setMacroContextLocalsFromArguments(macroCtx, macro, namedArgs, 
positionalArgs);
             

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7adecaee/src/main/java/freemarker/core/Macro.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Macro.java 
b/src/main/java/freemarker/core/Macro.java
index 2ea9c2c..9f743cb 100644
--- a/src/main/java/freemarker/core/Macro.java
+++ b/src/main/java/freemarker/core/Macro.java
@@ -154,17 +154,17 @@ public final class Macro extends TemplateElement 
implements TemplateModel {
 
     class Context implements LocalContext {
         final Environment.Namespace localVars; 
-        final TemplateElement[] nestedContentBuffer;
+        final TemplateElement callPlace;
         final Environment.Namespace nestedContentNamespace;
         final List nestedContentParameterNames;
         final LocalContextStack prevLocalContextStack;
         final Context prevMacroContext;
         
         Context(Environment env, 
-                TemplateElement[] nestedContentBuffer,
+                TemplateElement callPlace,
                 List nestedContentParameterNames) {
             this.localVars = env.new Namespace(); 
-            this.nestedContentBuffer = nestedContentBuffer;
+            this.callPlace = callPlace;
             this.nestedContentNamespace = env.getCurrentNamespace();
             this.nestedContentParameterNames = nestedContentParameterNames;
             this.prevLocalContextStack = env.getLocalContextStack();

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7adecaee/src/main/java/freemarker/core/UnifiedCall.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/UnifiedCall.java 
b/src/main/java/freemarker/core/UnifiedCall.java
index f445cd3..68777d3 100644
--- a/src/main/java/freemarker/core/UnifiedCall.java
+++ b/src/main/java/freemarker/core/UnifiedCall.java
@@ -80,7 +80,7 @@ final class UnifiedCall extends TemplateElement implements 
DirectiveCallPlace {
                         + "Functions can only be called from expressions, like 
in ${f()}, ${x + f()} or ",
                         "<@someDirective someParam=f() />", ".");
             }    
-            env.invoke(macro, namedArgs, positionalArgs, bodyParameterNames, 
getChildBuffer());
+            env.invoke(macro, namedArgs, positionalArgs, bodyParameterNames, 
this);
         } else {
             boolean isDirectiveModel = tm instanceof TemplateDirectiveModel; 
             if (isDirectiveModel || tm instanceof TemplateTransformModel) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7adecaee/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 6c9c8bb..f45a516 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -23316,19 +23316,10 @@ There was no specific handler for node y
             </indexterm><literal>macro_caller_template_name</literal>: Returns
           the name (path) of the template from which the current macro was
           called. It's mostly useful if you want to resolve paths relative to
-          the caller template. If the caller template is nameless, this will
-          be an empty string (not a missing value). Reading this variable will
-          cause error if you aren't inside a macro call, also if you are
-          inside an user-defined directive call
-          (<literal>&lt;@<replaceable>...</replaceable>&gt;</literal>) that's
-          nested inside the <literal>macro</literal> directive (as in
-          <literal>&lt;#macro
-          m&gt;&lt;@x&gt;${.macro_caller_template_name}&lt;#-- FAILS!
-          --&gt;&lt;/@&gt;&lt;/#macro&gt;</literal>). (Note that if <link
-          linkend="pgui_config_incompatible_improvements">incompatible
-          improvements</link> is set to less than 2.3.28, then when using this
-          variable in an argument to a macro, it will be incorrectly evaluated
-          to the caller of the called macro.)</para>
+          the caller template. To serve that purpose better, if the caller
+          template is nameless, this will be an empty string (not a missing
+          value). Reading this variable will cause error if you aren't inside
+          a macro call.</para>
         </listitem>
 
         <listitem>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7adecaee/src/test/java/freemarker/core/MacroCallerTemplateNameTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/core/MacroCallerTemplateNameTest.java 
b/src/test/java/freemarker/core/MacroCallerTemplateNameTest.java
index 32b1d4e..5a26b8f 100644
--- a/src/test/java/freemarker/core/MacroCallerTemplateNameTest.java
+++ b/src/test/java/freemarker/core/MacroCallerTemplateNameTest.java
@@ -35,28 +35,31 @@ public class MacroCallerTemplateNameTest extends 
TemplateTest {
 
     @Test
     public void testNoCaller() throws Exception {
-        assertErrorContains("${.macroCallerTemplateName}", "no macro caller", 
".macroCallerTemplateName");
-        assertErrorContains("${.macro_caller_template_name}", "no macro 
caller", ".macro_caller_template_name");
+        assertErrorContains("${.macroCallerTemplateName}", "no macro call", 
".macroCallerTemplateName");
+        assertErrorContains("${.macro_caller_template_name}", "no macro call", 
".macro_caller_template_name");
 
         assertErrorContains(""
                 + "<#macro m><#nested></#macro>"
                 + "<@m>${.macroCallerTemplateName}</@>",
-                "nested", ".macroCallerTemplateName");
+                "no macro call", ".macroCallerTemplateName");
 
-        assertErrorContains(""
+        addTemplate("main.ftl", "${.macroCallerTemplateName}");
+        assertErrorContainsForNamed("main.ftl", "no macro call");
+    }
+
+    @Test
+    public void testNested() throws Exception {
+        assertOutput(""
                 + "<#macro m><#nested></#macro>"
                 + "<#macro m2><@m>${.macroCallerTemplateName}</@></#macro>"
-                + "<@m2/>",
-                "nested", ".macroCallerTemplateName");
+                + "[<@m2/>]",
+                "[]");
         assertOutput(""
                 + "<#macro m2>${.macroCallerTemplateName}</#macro>"
                 + "[<@m2/>]",
                 "[]");
-
-        addTemplate("main.ftl", "${.macroCallerTemplateName}");
-        assertErrorContainsForNamed("main.ftl", "no macro caller");
     }
-
+    
     @Test
     public void testSameTemplateCaller() throws Exception {
         addTemplate("main.ftl", ""
@@ -127,13 +130,12 @@ public class MacroCallerTemplateNameTest extends 
TemplateTest {
                 + "</#macro>"
                 + "<#macro m2><@m .macroCallerTemplateName /></#macro>");
         
-        assertOutputForNamed("main.ftl", ""
-                + "x: main.ftl; y: main.ftl; caller: main.ftl;"
-                + "x: main.ftl; y: inc.ftl; caller: inc.ftl;");
-        
getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_27);
-        assertOutputForNamed("main.ftl", ""
-                + "x: main.ftl; y: main.ftl; caller: main.ftl;"
-                + "x: inc.ftl; y: inc.ftl; caller: inc.ftl;");
+        for (int i = 0; i < 2; i++) {
+            assertOutputForNamed("main.ftl", ""
+                    + "x: main.ftl; y: main.ftl; caller: main.ftl;"
+                    + "x: main.ftl; y: inc.ftl; caller: inc.ftl;");
+            
getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_27); 
// Has no effect
+        }
     }
     
     @Test

Reply via email to