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

andy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/master by this push:
     new 9c59120  JENA-1672: Proper function implementation
     new e9d28c4  Merge pull request #532 from afs/eval-refactor
9c59120 is described below

commit 9c591200873573455135709456fbea0fb46b6999
Author: Andy Seaborne <[email protected]>
AuthorDate: Fri Feb 15 15:21:30 2019 +0000

    JENA-1672: Proper function implementation
---
 .../apache/jena/sparql/function/FunctionBase.java  | 42 ++++++++++------------
 .../jena/sparql/function/library/FN_Apply.java     | 16 +++++----
 .../jena/sparql/function/library/SystemVar.java    | 12 +++++--
 .../apache/jena/sparql/function/library/nowtz.java | 14 ++++++--
 4 files changed, 49 insertions(+), 35 deletions(-)

diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
index 4139f53..4672f9a 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
@@ -35,13 +35,6 @@ public abstract class FunctionBase implements Function {
         // Rename for legacy reasons.
         checkBuild(uri, args) ;
     }
-
-    // Valid during execution.
-    // Only specialised uses need these values 
-    // e.g. fn:apply which is a meta-function - it looks up a URI to get a 
function to call.
-    protected FunctionEnv functionEnv = null;
-    // Not needed so hide but keep for debugging.
-    private Binding binding = null;
     
     @Override
     public NodeValue exec(Binding binding, ExprList args, String uri, 
FunctionEnv env) {
@@ -49,24 +42,25 @@ public abstract class FunctionBase implements Function {
             // The contract on the function interface is that this should not 
happen.
             throw new ARQInternalErrorException("FunctionBase: Null args 
list") ;
         
-        List<NodeValue> evalArgs = new ArrayList<>() ;
-        for ( Expr e : args )
-        {
-            NodeValue x = e.eval( binding, env );
-            evalArgs.add( x );
-        }
-        
-        // Cature
-        try {
-            this.functionEnv = env ;
-            this.binding = binding;
-            NodeValue nv = exec(evalArgs) ;
-            return nv ;
-        } finally {
-            this.functionEnv = null ;
-            this.binding = null;
+        List<NodeValue> evalArgs = evalArgs(binding, args, env);
+        return exec(evalArgs, env) ;
+    }
+
+    public static List<NodeValue> evalArgs(Binding binding, ExprList args, 
FunctionEnv env) {
+        List<NodeValue> evalArgs = new ArrayList<>();
+        for ( Expr e : args ) {
+            NodeValue x = e.eval(binding, env);
+            evalArgs.add(x);
         }
-        
+        return evalArgs;
+    }
+
+    /** Evaluation with access to the environment. 
+     * Special and careful use only! 
+     * Arity will have been checked if using a fixed-count FunctionBase 
subclass.
+     */ 
+    protected NodeValue exec(List<NodeValue> args, FunctionEnv env) {
+        return exec(args);
     }
     
     /** Function call to a list of evaluated argument values */ 
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java
index 6539416..f758891 100644
--- 
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java
+++ 
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java
@@ -22,15 +22,13 @@ import java.util.List ;
 
 import org.apache.jena.atlas.lib.Cache ;
 import org.apache.jena.atlas.lib.CacheFactory ;
+import org.apache.jena.atlas.lib.InternalErrorException;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.sparql.expr.ExprEvalException ;
 import org.apache.jena.sparql.expr.ExprException ;
 import org.apache.jena.sparql.expr.ExprList ;
 import org.apache.jena.sparql.expr.NodeValue ;
-import org.apache.jena.sparql.function.Function ;
-import org.apache.jena.sparql.function.FunctionBase ;
-import org.apache.jena.sparql.function.FunctionFactory ;
-import org.apache.jena.sparql.function.FunctionRegistry ;
+import org.apache.jena.sparql.function.*;
 import org.apache.jena.sparql.util.Context ;
 
 /** XPath and XQuery Functions and Operators 3.1
@@ -46,8 +44,14 @@ public class FN_Apply extends FunctionBase {
         if ( args.isEmpty() )
             throw new ExprException("fn:apply: no function to call (minimum 
number of args is one)");
     }
+    
     @Override
     public NodeValue exec(List<NodeValue> args) {
+        throw new InternalErrorException("fn:apply: exec(args) Should not have 
been called");
+    }
+
+    @Override
+    public NodeValue exec(List<NodeValue> args, FunctionEnv env) {
         if ( args.isEmpty() )
             throw new ExprException("fn:apply: no function to call (minimum 
number of args is one)");
         NodeValue functionId = args.get(0);
@@ -65,7 +69,7 @@ public class FN_Apply extends FunctionBase {
             throw new ExprEvalException("fn:apply: function id is an unbound 
variable (must be a URI)");
         if ( fnNode.isURI() ) {
             String functionIRI = fnNode.getURI();
-            Function function = cache1.getOrFill(functionIRI, 
()->buildFunction(functionIRI));
+            Function function = cache1.getOrFill(functionIRI, 
()->buildFunction(functionIRI, env));
             if ( function == null )
                 throw new ExprEvalException("fn:apply: Unknown function: 
<"+functionId+">");
             if ( function instanceof FunctionBase ) {
@@ -80,7 +84,7 @@ public class FN_Apply extends FunctionBase {
         throw new ExprEvalException("fn:apply: Weird function argument (arg 
1): "+functionId);
     }
     
-    private Function buildFunction(String functionIRI) {
+    private Function buildFunction(String functionIRI, FunctionEnv 
functionEnv) {
         FunctionRegistry registry = chooseRegistry(functionEnv.getContext()) ;
         FunctionFactory ff = registry.get(functionIRI) ;
         if ( ff == null )
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/SystemVar.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/SystemVar.java
index 98af66f..103ea57 100644
--- 
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/SystemVar.java
+++ 
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/SystemVar.java
@@ -18,6 +18,9 @@
 
 package org.apache.jena.sparql.function.library;
 
+import java.util.List;
+
+import org.apache.jena.atlas.lib.InternalErrorException;
 import org.apache.jena.atlas.lib.Lib;
 import org.apache.jena.graph.Node;
 import org.apache.jena.sparql.expr.ExprEvalException;
@@ -39,10 +42,15 @@ public class SystemVar extends FunctionBase0 {
         this.systemSymbol = systemSymbol;
     }
 
-    // Need to intercept exec so we can get to the FunctionEnv
     @Override
     public NodeValue exec() {
-        return get(systemSymbol, super.functionEnv);
+        throw new InternalErrorException("SystemVar.exec shoudl not have been 
called");
+    }
+
+    // Need to intercept exec so we can get to the FunctionEnv
+    @Override
+    protected NodeValue exec(List<NodeValue> args, FunctionEnv env) {
+        return get(systemSymbol, env);
     }
 
     public static NodeValue get(Symbol symbol, FunctionEnv env) {
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/nowtz.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/nowtz.java
index ba6d387..5def9ff 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/nowtz.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/nowtz.java
@@ -22,8 +22,10 @@ import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
+import java.util.List;
 
 import org.apache.jena.atlas.lib.DateTimeUtils;
+import org.apache.jena.atlas.lib.InternalErrorException;
 import org.apache.jena.graph.Node;
 
 //import org.apache.commons.logging.*;
@@ -33,6 +35,7 @@ import org.apache.jena.sparql.SystemARQ;
 import org.apache.jena.sparql.expr.NodeValue;
 import org.apache.jena.sparql.expr.nodevalue.XSDFuncOp;
 import org.apache.jena.sparql.function.FunctionBase0;
+import org.apache.jena.sparql.function.FunctionEnv;
 import org.apache.jena.sparql.util.Context;
 import org.apache.jena.sparql.util.Symbol;
 
@@ -46,19 +49,24 @@ public class nowtz extends FunctionBase0
 
     @Override
     public NodeValue exec() {
+        throw new InternalErrorException("nowtz: exec() Should not have been 
called");
+    }
+
+    @Override
+    public NodeValue exec(List<NodeValue> args, FunctionEnv functionEnv) {
         Context cxt = functionEnv.getContext();
         if ( cxt.isDefined(symNowTz) ) {
             NodeValue nvx = cxt.get(symNowTz);
             return nvx; 
         }
-        NodeValue nvx = execAdjust();
+        NodeValue nvx = execAdjust(functionEnv);
 //        String formattedDate = fromQueryTime(cxt);
 //        NodeValue nvx = NodeValue.makeNode(formattedDate, null, 
XSD.dateTime.getURI());
         cxt.set(symNowTz, nvx);
         return nvx;
     }
     
-    private NodeValue execAdjust() {
+    private NodeValue execAdjust(FunctionEnv functionEnv) {
         // NOW is UTC in Jena to make the same whoever is looking.
         // For presentation reasons, you may want it in the (server) local 
timezone. 
         // Calculate:
@@ -66,7 +74,7 @@ public class nowtz extends FunctionBase0
         //   fn:adjust-dateTime-to-timezone(NOW(), afn:timezone())
         
         // Query time, in UTC. 
-        NodeValue nv = SystemVar.get(ARQConstants.sysCurrentTime, 
super.functionEnv);
+        NodeValue nv = SystemVar.get(ARQConstants.sysCurrentTime, functionEnv);
         // Timezone as xsd:dayTimeDuration.
         NodeValue nvTz = XSDFuncOp.localTimezone();
         // Comes out as "Z", not "+00:00" because of cal.toXMLFormat() in 
NodeValue.makeDateTime

Reply via email to