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