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 2012/02/12 18:59:34 UTC

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

Author: henrib
Date: Sun Feb 12 17:59:34 2012
New Revision: 1243285

URL: http://svn.apache.org/viewvc?rev=1243285&view=rev
Log:
Closure implements JexlScript (execute, callable);

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java   (with props)
Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java?rev=1243285&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java Sun Feb 12 17:59:34 2012
@@ -0,0 +1,92 @@
+/*
+ * 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.commons.jexl3.internal;
+
+import java.util.concurrent.Callable;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.parser.ASTJexlLambda;
+import org.apache.commons.jexl3.parser.JexlNode;
+
+/**
+ * A Script closure.
+ */
+final class Closure extends Script {
+    /** The frame. */
+    private final Scope.Frame frame;
+    /** The caller, kept to copy options, flags and functors. */
+    private final Interpreter caller;
+
+    /**
+     * Creates a closure.
+     * @param theCaller the calling interpreter
+     * @param lambda the lambda
+     */
+    Closure(Interpreter theCaller, ASTJexlLambda lambda) {
+        super(theCaller.jexl, null, lambda);
+        caller = theCaller;
+        frame = lambda.createFrame(theCaller.frame);
+    }
+
+    @Override
+    public String getExpression() {
+        Debugger debug = new Debugger();
+        boolean d = debug.debug(script);
+        return debug.data();
+    }
+
+    @Override
+    public Object evaluate(JexlContext context) {
+        return execute(context, (Object[])null);
+    }
+
+    @Override
+    public Object execute(JexlContext context) {
+        return execute(context, (Object[])null);
+    }
+
+    @Override
+    public Object execute(JexlContext context, Object... args) {
+        if (frame != null) {
+            frame.assign(args);
+        }
+        Interpreter interpreter = new Interpreter(caller, context, frame);
+        JexlNode block = script.jjtGetChild(script.jjtGetNumChildren() - 1);
+        return interpreter.interpret(block);
+    }
+
+    @Override
+    public Callable<Object> callable(JexlContext context, Object... args) {
+        if (frame != null) {
+            frame.assign(args);
+        }
+        final Interpreter interpreter = new Interpreter(caller, context, frame);
+        return new Callable<Object>() {
+            /** Use interpreter as marker for not having run. */
+            private Object result = interpreter;
+
+            @Override
+            public Object call() throws Exception {
+                if (result == interpreter) {
+                    JexlNode block = script.jjtGetChild(script.jjtGetNumChildren() - 1);
+                    return interpreter.interpret(block);
+                }
+                return result;
+            }
+        };
+    }
+    
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java?rev=1243285&r1=1243284&r2=1243285&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java Sun Feb 12 17:59:34 2012
@@ -496,7 +496,7 @@ public final class Debugger extends Pars
                     builder.append(params[p]);
                 }
             }
-            builder.append(")");
+            builder.append(") ");
         }
         int num = node.jjtGetNumChildren();
         for (int i = 0; i < num; ++i) {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java?rev=1243285&r1=1243284&r2=1243285&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java Sun Feb 12 17:59:34 2012
@@ -21,12 +21,10 @@ import org.apache.commons.jexl3.JexlCont
 import org.apache.commons.jexl3.JexlEngine;
 import org.apache.commons.jexl3.JexlException;
 import org.apache.commons.jexl3.JexlScript;
-
 import org.apache.commons.jexl3.introspection.JexlMethod;
 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
 import org.apache.commons.jexl3.introspection.JexlPropertySet;
 import org.apache.commons.jexl3.introspection.JexlUberspect;
-
 import org.apache.commons.jexl3.parser.ASTAdditiveNode;
 import org.apache.commons.jexl3.parser.ASTAdditiveOperator;
 import org.apache.commons.jexl3.parser.ASTAndNode;
@@ -50,6 +48,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTGTNode;
 import org.apache.commons.jexl3.parser.ASTIdentifier;
 import org.apache.commons.jexl3.parser.ASTIfStatement;
+import org.apache.commons.jexl3.parser.ASTJexlLambda;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
 import org.apache.commons.jexl3.parser.ASTLENode;
 import org.apache.commons.jexl3.parser.ASTLTNode;
@@ -89,7 +88,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import org.apache.commons.jexl3.parser.ASTJexlLambda;
 
 /**
  * An interpreter of JEXL syntax.
@@ -155,17 +153,18 @@ public class Interpreter extends ParserV
         this.frame = eFrame;
         this.functors = null;
     }
-    
+
     /**
      * Creates a copy of an interpreter, used for function/lambda evaluation.
      * @param copy the interpreter to copy
+     * @param eContext the global variables context
      * @param eFrame the interpreter evaluation frame
      */
-    protected Interpreter(Interpreter copy, Scope.Frame eFrame) {
+    protected Interpreter(Interpreter copy, JexlContext eContext, Scope.Frame eFrame) {
         this.jexl = copy.jexl;
         this.logger = copy.logger;
         this.uberspect = copy.uberspect;
-        this.context = copy.context;
+        this.context = eContext;
         this.arithmetic = copy.arithmetic;
         this.silent = copy.silent;
         this.functions = copy.functions;
@@ -830,7 +829,7 @@ public class Interpreter extends ParserV
     @Override
     protected Object visit(ASTJexlScript node, Object data) {
         if (node instanceof ASTJexlLambda) {
-            return new Closure((ASTJexlLambda) node, frame);
+            return new Closure(this, (ASTJexlLambda) node);
         } else {
             final int numChildren = node.jjtGetNumChildren();
             Object result = null;
@@ -841,41 +840,6 @@ public class Interpreter extends ParserV
             return result;
         }
     }
-    
-    /**
-     * A function closure.
-     */
-    private static final class Closure {
-        /** The frame. */
-        private final Scope.Frame frame;
-        /** The actual lambda. */
-        private final ASTJexlLambda lambda;
-        /** Creates a closure.
-         * @param l the lambda
-         * @param f the interpreter frame
-         */
-        Closure(ASTJexlLambda l, Scope.Frame f) {
-            lambda = l;
-            frame = lambda.createFrame(f);
-        }
-    }
-    
-    /**
-     * Evaluates a closure.
-     * @param closure the closure
-     * @param argv the arguments
-     * @return the result of evaluation
-     */
-    private Object call(Closure closure, Object[] argv) {
-        Scope.Frame cframe = closure.frame;
-        if (cframe != null) {
-            cframe.assign(argv);
-        }
-        ASTJexlLambda lambda = closure.lambda;
-        JexlNode block = lambda.jjtGetChild(lambda.jjtGetNumChildren() - 1);
-        Interpreter interpreter = new Interpreter(this, cframe);
-        return interpreter.interpret(block);
-    }
 
     @Override
     protected Object visit(ASTLENode node, Object data) {
@@ -983,9 +947,6 @@ public class Interpreter extends ParserV
                     }
                 }
                 // lambda, script or jexl method will do
-                if (functor instanceof Closure) {
-                    return call((Closure) functor, argv);
-                }
                 if (functor instanceof JexlScript) {
                     return ((JexlScript) functor).execute(context, argv);
                 }
@@ -1274,8 +1235,8 @@ public class Interpreter extends ParserV
                     // variable unknow in context and not (from) a register
                     && !(context.has(variableName.toString())
                     || (numChildren == 1
-                        && node.jjtGetChild(0) instanceof ASTIdentifier
-                        && ((ASTIdentifier) node.jjtGetChild(0)).getRegister() >= 0))) {
+                    && node.jjtGetChild(0) instanceof ASTIdentifier
+                    && ((ASTIdentifier) node.jjtGetChild(0)).getRegister() >= 0))) {
                 JexlException xjexl = propertyName != null
                                       ? new JexlException.Property(node, variableName.toString())
                                       : new JexlException.Variable(node, variableName.toString());

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=1243285&r1=1243284&r2=1243285&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 Sun Feb 12 17:59:34 2012
@@ -30,12 +30,27 @@ public class LambdaTest extends JexlTest
     public void testScriptArguments() throws Exception {
         JexlEngine jexl = new Engine();
         JexlScript s = jexl.createScript("{ x + x }", "x");
-        String strs = "s(21)";
         JexlScript s42 = jexl.createScript("s(21)", "s");
         Object result = s42.execute(null, s);
         assertEquals(42, result);
     }
-
+    
+    public void testScriptContext() throws Exception {
+        JexlEngine jexl = new Engine();
+        JexlScript s = jexl.createScript("function(x) { x + x }");
+        JexlScript fs = (JexlScript) s.execute(null);
+        String fsstr = fs.getExpression();
+        assertEquals("function(x) { x + x; };", fsstr);
+        assertEquals(42, fs.execute(null, 21));
+        JexlScript s42 = jexl.createScript("s(21)");
+        JexlEvalContext ctxt = new JexlEvalContext();
+        ctxt.set("s", fs);
+        Object result = s42.execute(ctxt);
+        assertEquals(42, result);
+        result = s42.evaluate(ctxt);
+        assertEquals(42, result);
+    }
+    
     public void testLambda() throws Exception {
         JexlEngine jexl = new Engine();
         String strs = "var s = function(x) { x + x }; s(21)";

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java?rev=1243285&r1=1243284&r2=1243285&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java Sun Feb 12 17:59:34 2012
@@ -66,8 +66,26 @@ public class ScriptCallableTest extends 
         future.cancel(true);
         assertTrue(future.isCancelled());
     }
+    
+    public void testCallableClosure() throws Exception {
+        JexlScript e = JEXL.createScript("function(t) {while(t);}");
+        e = (JexlScript) e.execute(null);
+        Callable<Object> c = e.callable(null, Boolean.TRUE);
+
+        ExecutorService executor = Executors.newFixedThreadPool(1);
+        Future<?> future = executor.submit(c);
+        try {
+            future.get(100, TimeUnit.MILLISECONDS);
+            fail("should have timed out");
+        } catch (TimeoutException xtimeout) {
+            // ok, ignore
+        }
+        future.cancel(true);
+        assertTrue(future.isCancelled());
+    }
 
     public static class TestContext extends MapContext implements JexlContext.NamespaceResolver {
+        @Override
         public Object resolveNamespace(String name) {
             return name == null ? this : null;
         }