This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git

commit 44e30e0ae281d400e9e4975884b15d751b464256
Author: ddekany <ddek...@apache.org>
AuthorDate: Sat Jul 20 17:38:23 2019 +0200

    (Moved IntermediateStreamOperationLikeBuiltIn out of BuiltInsForSequences, 
as it should be usable for FTL hash targets as well.)
---
 src/main/java/freemarker/core/BuiltIn.java         |   2 +-
 .../java/freemarker/core/BuiltInsForSequences.java | 191 ------------------
 .../IntermediateStreamOperationLikeBuiltIn.java    | 221 +++++++++++++++++++++
 3 files changed, 222 insertions(+), 192 deletions(-)

diff --git a/src/main/java/freemarker/core/BuiltIn.java 
b/src/main/java/freemarker/core/BuiltIn.java
index 4e26f50..5322eed 100644
--- a/src/main/java/freemarker/core/BuiltIn.java
+++ b/src/main/java/freemarker/core/BuiltIn.java
@@ -397,7 +397,7 @@ abstract class BuiltIn extends Expression implements 
Cloneable {
      * If the built-in supports a lazily generated value as its left operand 
(the target).
      * Don't confuse this with what's allowed for result of the built-in 
itself; that's influenced by
      * {@link Expression#enableLazilyGeneratedResult()} (and so
-     * {@link 
BuiltInsForSequences.IntermediateStreamOperationLikeBuiltIn#isLazilyGeneratedTargetResultSupported()}).
+     * {@link 
IntermediateStreamOperationLikeBuiltIn#isLazilyGeneratedTargetResultSupported()}).
      */
     protected boolean isLazilyGeneratedTargetResultSupported() {
         return false;
diff --git a/src/main/java/freemarker/core/BuiltInsForSequences.java 
b/src/main/java/freemarker/core/BuiltInsForSequences.java
index b0cc82e..7c8afc5 100644
--- a/src/main/java/freemarker/core/BuiltInsForSequences.java
+++ b/src/main/java/freemarker/core/BuiltInsForSequences.java
@@ -37,7 +37,6 @@ import freemarker.template.TemplateCollectionModelEx;
 import freemarker.template.TemplateDateModel;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateHashModel;
-import freemarker.template.TemplateMethodModel;
 import freemarker.template.TemplateMethodModelEx;
 import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
@@ -1001,196 +1000,6 @@ class BuiltInsForSequences {
         
     }
 
-    /**
-     * Built-in that's similar to a Java 8 Stream intermediate operation. To 
be on the safe side, by default these
-     * are eager, and just produce a {@link TemplateSequenceModel}. But when 
circumstances allow, they become lazy,
-     * similarly to Java 8 Stream intermediate operations. Another 
characteristic of these built-ins is that they
-     * usually accept lambda expressions as parameters.
-     */
-    static abstract class IntermediateStreamOperationLikeBuiltIn extends 
BuiltInWithParseTimeParameters {
-
-        private Expression elementTransformerExp;
-        private ElementTransformer precreatedElementTransformer;
-        private boolean lazilyGeneratedResultEnabled;
-
-        @Override
-        void bindToParameters(List<Expression> parameters, Token openParen, 
Token closeParen) throws ParseException {
-            // At the moment all built-ins of this kind requires 1 parameter.
-            if (parameters.size() != 1) {
-                throw newArgumentCountException("requires exactly 1", 
openParen, closeParen);
-            }
-            this.elementTransformerExp = parameters.get(0);
-            if (elementTransformerExp instanceof LocalLambdaExpression) {
-                LocalLambdaExpression localLambdaExp = (LocalLambdaExpression) 
elementTransformerExp;
-                checkLocalLambdaParamCount(localLambdaExp, 1);
-                // We can't do this with other kind of expressions, like a 
function or method reference, as they
-                // need to be evaluated on runtime:
-                precreatedElementTransformer = new 
LocalLambdaElementTransformer(localLambdaExp);
-            }
-        }
-
-        @Override
-        protected final boolean isLocalLambdaParameterSupported() {
-            return true;
-        }
-
-        @Override
-        final void enableLazilyGeneratedResult() {
-            this.lazilyGeneratedResultEnabled = true;
-        }
-
-        /** Tells if {@link #enableLazilyGeneratedResult()} was called. */
-        protected final boolean isLazilyGeneratedResultEnabled() {
-            return lazilyGeneratedResultEnabled;
-        }
-
-        @Override
-        protected final boolean isLazilyGeneratedTargetResultSupported() {
-            return true;
-        }
-
-        protected List<Expression> getArgumentsAsList() {
-            return Collections.singletonList(elementTransformerExp);
-        }
-
-        protected int getArgumentsCount() {
-            return 1;
-        }
-
-        protected Expression getArgumentParameterValue(int argIdx) {
-            if (argIdx != 0) {
-                throw new IndexOutOfBoundsException();
-            }
-            return elementTransformerExp;
-        }
-
-        protected Expression getElementTransformerExp() {
-            return elementTransformerExp;
-        }
-
-        protected void cloneArguments(
-                Expression clone, String replacedIdentifier, Expression 
replacement, ReplacemenetState replacementState) {
-            ((IntermediateStreamOperationLikeBuiltIn) 
clone).elementTransformerExp
-                    = elementTransformerExp.deepCloneWithIdentifierReplaced(
-                            replacedIdentifier, replacement, replacementState);
-        }
-
-        TemplateModel _eval(Environment env) throws TemplateException {
-            TemplateModel targetValue = target.eval(env);
-
-            final TemplateModelIterator targetIterator;
-            final boolean targetIsSequence;
-            {
-                if (targetValue instanceof TemplateCollectionModel) {
-                    targetIterator = isLazilyGeneratedResultEnabled()
-                            ? new 
LazyCollectionTemplateModelIterator((TemplateCollectionModel) targetValue)
-                            : ((TemplateCollectionModel) 
targetValue).iterator();
-                    targetIsSequence = targetValue instanceof 
LazilyGeneratedCollectionModel
-                            ? ((LazilyGeneratedCollectionModel) 
targetValue).isSequence()
-                            : targetValue instanceof TemplateSequenceModel;
-                } else if (targetValue instanceof TemplateSequenceModel) {
-                    targetIterator = new 
LazySequenceIterator((TemplateSequenceModel) targetValue);
-                    targetIsSequence = true;
-                } else {
-                    throw new NonSequenceOrCollectionException(target, 
targetValue, env);
-                }
-            }
-
-            return calculateResult(
-                    targetIterator, targetValue, targetIsSequence,
-                    evalElementTransformerExp(env),
-                    env);
-        }
-
-        private ElementTransformer evalElementTransformerExp(Environment env) 
throws TemplateException {
-            if (precreatedElementTransformer != null) {
-                return precreatedElementTransformer;
-            }
-
-            TemplateModel elementTransformerModel = 
elementTransformerExp.eval(env);
-            if (elementTransformerModel instanceof TemplateMethodModel) {
-                return new MethodElementTransformer((TemplateMethodModel) 
elementTransformerModel);
-            } else if (elementTransformerModel instanceof Macro) {
-                return new FunctionElementTransformer((Macro) 
elementTransformerModel, elementTransformerExp);
-            } else {
-                throw new NonMethodException(elementTransformerExp, 
elementTransformerModel, true, true, null, env);
-            }
-        }
-
-        /**
-         * @param lhoIterator Use this to read the elements of the left hand 
operand
-         * @param lho Maybe needed for operations specific to the built-in, 
like getting the size, otherwise use the
-         *           {@code lhoIterator} only.
-         * @param lhoIsSequence See {@link 
LazilyGeneratedCollectionModel#isSequence}
-         * @param elementTransformer The argument to the built-in (typically a 
lambda expression)
-         *
-         * @return {@link TemplateSequenceModel} or {@link 
TemplateCollectionModel} or {@link TemplateModelIterator}.
-         */
-        protected abstract TemplateModel calculateResult(
-                TemplateModelIterator lhoIterator, TemplateModel lho, boolean 
lhoIsSequence,
-                ElementTransformer elementTransformer,
-                Environment env) throws TemplateException;
-
-        /**
-         * Wraps the built-in argument that specifies how to transform the 
elements of the sequence, to hide the
-         * complexity of doing that.
-         */
-        interface ElementTransformer {
-            TemplateModel transformElement(TemplateModel element, Environment 
env) throws TemplateException;
-        }
-
-        /** {@link ElementTransformer} that wraps a local lambda expression. */
-        private static class LocalLambdaElementTransformer implements 
ElementTransformer {
-            private final LocalLambdaExpression elementTransformerExp;
-
-            public LocalLambdaElementTransformer(LocalLambdaExpression 
elementTransformerExp) {
-                this.elementTransformerExp = elementTransformerExp;
-            }
-
-            public TemplateModel transformElement(TemplateModel element, 
Environment env) throws TemplateException {
-                return 
elementTransformerExp.invokeLambdaDefinedFunction(element, env);
-            }
-        }
-
-        /** {@link ElementTransformer} that wraps a (Java) method call. */
-        private static class MethodElementTransformer implements 
ElementTransformer {
-            private final TemplateMethodModel elementTransformer;
-
-            public MethodElementTransformer(TemplateMethodModel 
elementTransformer) {
-                this.elementTransformer = elementTransformer;
-            }
-
-            public TemplateModel transformElement(TemplateModel element, 
Environment env)
-                    throws TemplateModelException {
-                Object result = 
elementTransformer.exec(Collections.singletonList(element));
-                return result instanceof TemplateModel ? (TemplateModel) 
result : env.getObjectWrapper().wrap(result);
-            }
-        }
-
-        /** {@link ElementTransformer} that wraps a call to an FTL function 
(things defined with {@code #function}). */
-        private static class FunctionElementTransformer implements 
ElementTransformer {
-            private final Macro templateTransformer;
-            private final Expression elementTransformerExp;
-
-            public FunctionElementTransformer(Macro templateTransformer, 
Expression elementTransformerExp) {
-                this.templateTransformer = templateTransformer;
-                this.elementTransformerExp = elementTransformerExp;
-            }
-
-            public TemplateModel transformElement(TemplateModel element, 
Environment env) throws
-                    TemplateException {
-                // #function-s were originally designed to be called from 
templates directly, so they expect an
-                // Expression as argument. So we have to create a fake one.
-                ExpressionWithFixedResult functionArgExp = new 
ExpressionWithFixedResult(
-                        element, elementTransformerExp);
-                return env.invokeFunction(env, templateTransformer,
-                        Collections.singletonList(functionArgExp),
-                        elementTransformerExp);
-            }
-        }
-
-    }
-
     static class filterBI extends IntermediateStreamOperationLikeBuiltIn {
 
         protected TemplateModel calculateResult(
diff --git 
a/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java 
b/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java
new file mode 100644
index 0000000..a270276
--- /dev/null
+++ b/src/main/java/freemarker/core/IntermediateStreamOperationLikeBuiltIn.java
@@ -0,0 +1,221 @@
+/*
+ * 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 freemarker.core;
+
+import java.util.Collections;
+import java.util.List;
+
+import freemarker.template.TemplateCollectionModel;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateMethodModel;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateModelIterator;
+import freemarker.template.TemplateSequenceModel;
+
+/**
+ * Built-in that's similar to a Java 8 Stream intermediate operation. To be on 
the safe side, by default these
+ * are eager, and just produce a {@link TemplateSequenceModel}. But when 
circumstances allow, they become lazy,
+ * similarly to Java 8 Stream intermediate operations. Another characteristic 
of these built-ins is that they
+ * usually accept lambda expressions as parameters.
+ */
+abstract class IntermediateStreamOperationLikeBuiltIn extends 
BuiltInWithParseTimeParameters {
+
+    private Expression elementTransformerExp;
+    private ElementTransformer precreatedElementTransformer;
+    private boolean lazilyGeneratedResultEnabled;
+
+    @Override
+    void bindToParameters(List<Expression> parameters, Token openParen, Token 
closeParen) throws ParseException {
+        // At the moment all built-ins of this kind requires 1 parameter.
+        if (parameters.size() != 1) {
+            throw newArgumentCountException("requires exactly 1", openParen, 
closeParen);
+        }
+        this.elementTransformerExp = parameters.get(0);
+        if (elementTransformerExp instanceof LocalLambdaExpression) {
+            LocalLambdaExpression localLambdaExp = (LocalLambdaExpression) 
elementTransformerExp;
+            checkLocalLambdaParamCount(localLambdaExp, 1);
+            // We can't do this with other kind of expressions, like a 
function or method reference, as they
+            // need to be evaluated on runtime:
+            precreatedElementTransformer = new 
LocalLambdaElementTransformer(localLambdaExp);
+        }
+    }
+
+    @Override
+    protected final boolean isLocalLambdaParameterSupported() {
+        return true;
+    }
+
+    @Override
+    final void enableLazilyGeneratedResult() {
+        this.lazilyGeneratedResultEnabled = true;
+    }
+
+    /** Tells if {@link #enableLazilyGeneratedResult()} was called. */
+    protected final boolean isLazilyGeneratedResultEnabled() {
+        return lazilyGeneratedResultEnabled;
+    }
+
+    @Override
+    protected final boolean isLazilyGeneratedTargetResultSupported() {
+        return true;
+    }
+
+    protected List<Expression> getArgumentsAsList() {
+        return Collections.singletonList(elementTransformerExp);
+    }
+
+    protected int getArgumentsCount() {
+        return 1;
+    }
+
+    protected Expression getArgumentParameterValue(int argIdx) {
+        if (argIdx != 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        return elementTransformerExp;
+    }
+
+    protected Expression getElementTransformerExp() {
+        return elementTransformerExp;
+    }
+
+    protected void cloneArguments(
+            Expression clone, String replacedIdentifier, Expression 
replacement, ReplacemenetState replacementState) {
+        ((IntermediateStreamOperationLikeBuiltIn) clone).elementTransformerExp
+                = elementTransformerExp.deepCloneWithIdentifierReplaced(
+                        replacedIdentifier, replacement, replacementState);
+    }
+
+    TemplateModel _eval(Environment env) throws TemplateException {
+        TemplateModel targetValue = target.eval(env);
+
+        final TemplateModelIterator targetIterator;
+        final boolean targetIsSequence;
+        {
+            if (targetValue instanceof TemplateCollectionModel) {
+                targetIterator = isLazilyGeneratedResultEnabled()
+                        ? new 
LazyCollectionTemplateModelIterator((TemplateCollectionModel) targetValue)
+                        : ((TemplateCollectionModel) targetValue).iterator();
+                targetIsSequence = targetValue instanceof 
LazilyGeneratedCollectionModel
+                        ? ((LazilyGeneratedCollectionModel) 
targetValue).isSequence()
+                        : targetValue instanceof TemplateSequenceModel;
+            } else if (targetValue instanceof TemplateSequenceModel) {
+                targetIterator = new 
LazySequenceIterator((TemplateSequenceModel) targetValue);
+                targetIsSequence = true;
+            } else {
+                throw new NonSequenceOrCollectionException(target, 
targetValue, env);
+            }
+        }
+
+        return calculateResult(
+                targetIterator, targetValue, targetIsSequence,
+                evalElementTransformerExp(env),
+                env);
+    }
+
+    private ElementTransformer evalElementTransformerExp(Environment env) 
throws TemplateException {
+        if (precreatedElementTransformer != null) {
+            return precreatedElementTransformer;
+        }
+
+        TemplateModel elementTransformerModel = 
elementTransformerExp.eval(env);
+        if (elementTransformerModel instanceof TemplateMethodModel) {
+            return new MethodElementTransformer((TemplateMethodModel) 
elementTransformerModel);
+        } else if (elementTransformerModel instanceof Macro) {
+            return new FunctionElementTransformer((Macro) 
elementTransformerModel, elementTransformerExp);
+        } else {
+            throw new NonMethodException(elementTransformerExp, 
elementTransformerModel, true, true, null, env);
+        }
+    }
+
+    /**
+     * @param lhoIterator Use this to read the elements of the left hand 
operand
+     * @param lho Maybe needed for operations specific to the built-in, like 
getting the size, otherwise use the
+     *           {@code lhoIterator} only.
+     * @param lhoIsSequence See {@link 
LazilyGeneratedCollectionModel#isSequence}
+     * @param elementTransformer The argument to the built-in (typically a 
lambda expression)
+     *
+     * @return {@link TemplateSequenceModel} or {@link 
TemplateCollectionModel} or {@link TemplateModelIterator}.
+     */
+    protected abstract TemplateModel calculateResult(
+            TemplateModelIterator lhoIterator, TemplateModel lho, boolean 
lhoIsSequence,
+            ElementTransformer elementTransformer,
+            Environment env) throws TemplateException;
+
+    /**
+     * Wraps the built-in argument that specifies how to transform the 
elements of the sequence, to hide the
+     * complexity of doing that.
+     */
+    interface ElementTransformer {
+        TemplateModel transformElement(TemplateModel element, Environment env) 
throws TemplateException;
+    }
+
+    /** {@link ElementTransformer} that wraps a local lambda expression. */
+    private static class LocalLambdaElementTransformer implements 
ElementTransformer {
+        private final LocalLambdaExpression elementTransformerExp;
+
+        public LocalLambdaElementTransformer(LocalLambdaExpression 
elementTransformerExp) {
+            this.elementTransformerExp = elementTransformerExp;
+        }
+
+        public TemplateModel transformElement(TemplateModel element, 
Environment env) throws TemplateException {
+            return elementTransformerExp.invokeLambdaDefinedFunction(element, 
env);
+        }
+    }
+
+    /** {@link ElementTransformer} that wraps a (Java) method call. */
+    private static class MethodElementTransformer implements 
ElementTransformer {
+        private final TemplateMethodModel elementTransformer;
+
+        public MethodElementTransformer(TemplateMethodModel 
elementTransformer) {
+            this.elementTransformer = elementTransformer;
+        }
+
+        public TemplateModel transformElement(TemplateModel element, 
Environment env)
+                throws TemplateModelException {
+            Object result = 
elementTransformer.exec(Collections.singletonList(element));
+            return result instanceof TemplateModel ? (TemplateModel) result : 
env.getObjectWrapper().wrap(result);
+        }
+    }
+
+    /** {@link ElementTransformer} that wraps a call to an FTL function 
(things defined with {@code #function}). */
+    private static class FunctionElementTransformer implements 
ElementTransformer {
+        private final Macro templateTransformer;
+        private final Expression elementTransformerExp;
+
+        public FunctionElementTransformer(Macro templateTransformer, 
Expression elementTransformerExp) {
+            this.templateTransformer = templateTransformer;
+            this.elementTransformerExp = elementTransformerExp;
+        }
+
+        public TemplateModel transformElement(TemplateModel element, 
Environment env) throws
+                TemplateException {
+            // #function-s were originally designed to be called from 
templates directly, so they expect an
+            // Expression as argument. So we have to create a fake one.
+            ExpressionWithFixedResult functionArgExp = new 
ExpressionWithFixedResult(
+                    element, elementTransformerExp);
+            return env.invokeFunction(env, templateTransformer,
+                    Collections.singletonList(functionArgExp),
+                    elementTransformerExp);
+        }
+    }
+
+}

Reply via email to