You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2015/11/18 12:06:23 UTC

svn commit: r1714968 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/ main/java/org/apache/commons/jexl3/internal/ test/java/org/apache/commons/jexl3/

Author: henrib
Date: Wed Nov 18 11:06:23 2015
New Revision: 1714968

URL: http://svn.apache.org/viewvc?rev=1714968&view=rev
Log:
JEXL:
Added curry method on scripts

Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java?rev=1714968&r1=1714967&r2=1714968&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java Wed Nov 18 11:06:23 2015
@@ -123,4 +123,13 @@ public interface JexlScript {
      * @since 2.1
      */
     Callable<Object> callable(JexlContext context, Object... args);
+
+    /**
+     * Curries this script, returning a script with bound arguments.
+     * <p>If this script does not declare parameters or if all of them are already bound,
+     * no error is generated and this script is returned.</p>
+     * @param args the arguments to bind
+     * @return the curried script or this script if no binding can occur
+     */
+    JexlScript curry(Object... args);
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java?rev=1714968&r1=1714967&r2=1714968&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java Wed Nov 18 11:06:23 2015
@@ -193,7 +193,7 @@ public final class Scope {
                     arguments[target.intValue()] = arg;
                 }
             }
-            return new Frame(this, arguments);
+            return new Frame(this, arguments, 0);
         } else {
             return null;
         }
@@ -280,15 +280,19 @@ public final class Scope {
         private final Scope scope;
         /** The actual stack frame. */
         private final Object[] stack;
+        /** Number of curried parameters. */
+        private int curried = 0;
 
         /**
          * Creates a new frame.
          * @param s the scope
          * @param r the stack frame
+         * @param c the number of curried parameters
          */
-        public Frame(Scope s, Object[] r) {
+        public Frame(Scope s, Object[] r, int c) {
             scope = s;
             stack = r;
+            curried = c;
         }
 
         /**
@@ -342,8 +346,9 @@ public final class Scope {
         public Frame assign(Object... values) {
             if (stack != null && values != null && values.length > 0) {
                 Object[] copy = stack.clone();
-                System.arraycopy(values, 0, copy, 0, Math.min(copy.length, values.length));
-                return new Frame(scope, copy);
+                int ncopy = Math.min(copy.length - curried, values.length);
+                System.arraycopy(values, 0, copy, curried, ncopy);
+                return new Frame(scope, copy, curried + ncopy);
             }
             return this;
         }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java?rev=1714968&r1=1714967&r2=1714968&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java Wed Nov 18 11:06:23 2015
@@ -22,6 +22,7 @@ import org.apache.commons.jexl3.JexlScri
 import org.apache.commons.jexl3.JexlExpression;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
 
+import org.apache.commons.jexl3.parser.JexlNode;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -79,15 +80,23 @@ public class Script implements JexlScrip
         }
     }
 
-    @Override
-    public Object evaluate(JexlContext context) {
-        if (script.jjtGetNumChildren() < 1) {
-            return null;
-        }
-        checkCacheVersion();
-        Scope.Frame frame = script.createFrame((Object[]) null);
-        Interpreter interpreter = jexl.createInterpreter(context, frame);
-        return interpreter.interpret(script.jjtGetChild(0));
+    /**
+     * Creates this script frame for evaluation.
+     * @param args the arguments to bind to parameters
+     * @return the frame (may be null)
+     */
+    protected Scope.Frame createFrame(Object[] args) {
+        return script.createFrame(args);
+    }
+
+    /**
+     * Creates this script interpreter.
+     * @param context the context
+     * @param frame the calling frame
+     * @return  the interpreter
+     */
+    protected Interpreter createInterpreter(JexlContext context, Scope.Frame frame) {
+        return jexl.createInterpreter(context, frame);
     }
 
     /**
@@ -167,10 +176,24 @@ public class Script implements JexlScrip
      * {@inheritDoc}
      */
     @Override
+    public Object evaluate(JexlContext context) {
+        if (script.jjtGetNumChildren() < 1) {
+            return null;
+        }
+        checkCacheVersion();
+        Scope.Frame frame = createFrame((Object[]) null);
+        Interpreter interpreter = createInterpreter(context, frame);
+        return interpreter.interpret(script.jjtGetChild(0));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public Object execute(JexlContext context) {
         checkCacheVersion();
-        Scope.Frame frame = script.createFrame((Object[]) null);
-        Interpreter interpreter = jexl.createInterpreter(context, frame);
+        Scope.Frame frame = createFrame((Object[]) null);
+        Interpreter interpreter = createInterpreter(context, frame);
         return interpreter.interpret(script);
     }
 
@@ -180,12 +203,78 @@ public class Script implements JexlScrip
     @Override
     public Object execute(JexlContext context, Object... args) {
         checkCacheVersion();
-        Scope.Frame frame = script.createFrame(args != null && args.length > 0 ? args : null);
-        Interpreter interpreter = jexl.createInterpreter(context, frame);
+        Scope.Frame frame = createFrame(args != null && args.length > 0 ? args : null);
+        Interpreter interpreter = createInterpreter(context, frame);
         return interpreter.interpret(script);
     }
 
     /**
+     * A script whose parameters are (partially) bound.
+     */
+    public static class Curried extends Script {
+        /** The evaluation frame. */
+        private final Scope.Frame frame;
+
+        /**
+         * Creates a curried version of this script.
+         * @param base the base script
+         * @param args the arguments
+         */
+        protected Curried(Script base, Object[] args) {
+            super(base.jexl, base.source, base.script);
+            Scope.Frame sf = (base instanceof Curried) ? ((Curried) base).frame : null;
+            if (sf != null) {
+                frame = sf.assign(args);
+            } else {
+                frame = script.createFrame(args);
+            }
+        }
+
+        @Override
+        protected Scope.Frame createFrame(Object[] args) {
+            return frame != null? frame.assign(args) : super.createFrame(args);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return this == obj;
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(this);
+        }
+
+        @Override
+        public Object execute(JexlContext context) {
+            return execute(context, (Object[])null);
+        }
+
+        @Override
+        public Object execute(JexlContext context, Object... args) {
+            Scope.Frame callFrame = null;
+            if (frame != null) {
+                callFrame = frame.assign(args);
+            }
+            Interpreter interpreter = jexl.createInterpreter(context, callFrame);
+            JexlNode block = script.jjtGetChild(script.jjtGetNumChildren() - 1);
+            return interpreter.interpret(block);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public JexlScript curry(Object... args) {
+        String[] parms = script.getParameters();
+        if (parms == null || parms.length == 0) {
+            return this;
+        }
+        return new Curried(this, args);
+    }
+
+    /**
      * Gets this script parameters.
      * @return the parameters or null
      * @since 3.0

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java?rev=1714968&r1=1714967&r2=1714968&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java Wed Nov 18 11:06:23 2015
@@ -345,6 +345,10 @@ public class ArithmeticOperatorTest exte
         public Object arraySet(Date date, String identifier, Object value) throws Exception {
             return setDateValue(date, identifier, value);
         }
+
+        public Date now() {
+            return new Date(System.currentTimeMillis());
+        }
     }
 
     public static class DateContext extends MapContext {
@@ -413,6 +417,14 @@ public class ArithmeticOperatorTest exte
         jc.setLocale(Locale.FRANCE);
         s0 = expr1.execute(jc, x0, "EEE dd MMM yyyy");
         Assert.assertEquals("mer. 20 ao\u00fbt 1969", s0);
+
+        expr1 = jexl.createScript("format(now(), y)", "y");
+        Object n0 = expr1.execute(jc, y0);
+        Assert.assertNotNull(n0);
+        expr1 = jexl.createScript("now().format(y)", "y");
+        Object n1 = expr1.execute(jc, y0);
+        Assert.assertNotNull(n0);
+        Assert.assertEquals(n0, n1);
     }
 
     @Test
@@ -444,5 +456,11 @@ public class ArithmeticOperatorTest exte
         expr1.evaluate(jc, strw, expr0, 1, 3);
         strws = strw.toString();
         Assert.assertEquals("6", strws);
+
+        expr0 = jxlt.createTemplate("${now().format(y)}", "y");
+        strw = new StringWriter();
+        expr0.evaluate(jc, strw, y0);
+        strws = strw.toString();
+        Assert.assertNotNull(strws);
     }
 }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java?rev=1714968&r1=1714967&r2=1714968&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java Wed Nov 18 11:06:23 2015
@@ -239,4 +239,43 @@ public class LambdaTest extends JexlTest
         result = script.execute(null, 42);
         Assert.assertEquals(42, result);
     }
+
+    @Test
+    public void testCurry1() throws Exception {
+        JexlEngine jexl = new Engine();
+        JexlScript script;
+        Object result;
+
+        JexlScript base = jexl.createScript("(x, y, z)->{ x + y + z }");
+        script = base.curry(5);
+        script = script.curry(15);
+        script = script.curry(22);
+        result = script.execute(null);
+        Assert.assertEquals(42, result);
+    }
+
+    @Test
+    public void testCurry2() throws Exception {
+        JexlEngine jexl = new Engine();
+        JexlScript script;
+        Object result;
+
+        JexlScript base = jexl.createScript("(x, y, z)->{ x + y + z }");
+        script = base.curry(5, 15);
+        script = script.curry(22);
+        result = script.execute(null);
+        Assert.assertEquals(42, result);
+    }
+
+    @Test
+    public void testCurry3() throws Exception {
+        JexlEngine jexl = new Engine();
+        JexlScript script;
+        Object result;
+
+        JexlScript base = jexl.createScript("(x, y, z)->{ x + y + z }");
+        script = base.curry(5, 15);
+        result = script.execute(null, 22);
+        Assert.assertEquals(42, result);
+    }
 }