You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2016/05/21 18:54:27 UTC
[07/23] jena git commit: Towards new walker/transformation code
Towards new walker/transformation code
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/c1fde992
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/c1fde992
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/c1fde992
Branch: refs/heads/master
Commit: c1fde992d024d1402639c9c2e98bfa486c324966
Parents: 86877d1
Author: Andy Seaborne <an...@apache.org>
Authored: Fri Apr 22 16:34:29 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat May 21 18:29:13 2016 +0100
----------------------------------------------------------------------
.../jena/sparql/algebra/TransformQuadGraph.java | 4 +
.../apache/jena/sparql/algebra/Transformer.java | 31 +-
.../algebra/walker/ApplyTransformVisitor.java | 419 +++++++++++++++++++
.../algebra/walker/ElementWalker_New.java | 196 +++++++++
.../algebra/walker/ExprVisitorFunction.java | 38 ++
.../algebra/walker/OpVisitorByTypeAndExpr.java | 229 ++++++++++
.../jena/sparql/algebra/walker/Walker.java | 190 +++++++++
.../sparql/algebra/walker/WalkerVisitor.java | 272 ++++++++++++
8 files changed, 1368 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/TransformQuadGraph.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/TransformQuadGraph.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/TransformQuadGraph.java
index fffb57e..27d44e5 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/TransformQuadGraph.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/TransformQuadGraph.java
@@ -46,6 +46,9 @@ public class TransformQuadGraph extends TransformCopy
@Override
public Op transform(OpGraph opGraph, Op op) {
+
+ //System.err.println("transform(OpGraph)\n"+opGraph+op) ;
+
// ?? Could just leave the (graph) in place always - just rewrite BGPs.
boolean noPattern = false ;
@@ -113,6 +116,7 @@ public class TransformQuadGraph extends TransformCopy
@Override
public Op transform(OpBGP opBGP) {
+ //System.err.println("transform(OpBGP) : "+getNode()+"\n"+opBGP) ;
return new OpQuadPattern(getNode(), opBGP.getPattern()) ;
}
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/Transformer.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/Transformer.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/Transformer.java
index ba3ee21..9f155d4 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/Transformer.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/Transformer.java
@@ -25,6 +25,7 @@ import org.apache.jena.query.SortCondition ;
import org.apache.jena.sparql.algebra.OpWalker.WalkerVisitor ;
import org.apache.jena.sparql.algebra.op.* ;
import org.apache.jena.sparql.algebra.optimize.ExprTransformApplyTransform ;
+import org.apache.jena.sparql.algebra.walker.Walker ;
import org.apache.jena.sparql.core.Var ;
import org.apache.jena.sparql.core.VarExprList ;
import org.apache.jena.sparql.expr.* ;
@@ -119,21 +120,30 @@ public class Transformer
// and theses protected methods.
protected Op transformation(Transform transform, Op op, OpVisitor beforeVisitor, OpVisitor afterVisitor)
{
+ // XXX
ExprTransform exprTransform = new ExprTransformApplyTransform(transform, beforeVisitor, afterVisitor) ;
return transformation(transform, exprTransform, op, beforeVisitor, afterVisitor) ;
- }
+ }
+
+ protected Op transformation(Transform transform, ExprTransform exprTransform, Op op, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ // XXX Switch on before/after via the Walker.
+ if ( true )
+ return Walker.transform(op, transform, exprTransform, beforeVisitor, afterVisitor) ;
- protected Op transformation(Transform transform, ExprTransform exprTransform, Op op, OpVisitor beforeVisitor, OpVisitor afterVisitor)
- {
+ if ( beforeVisitor == null && afterVisitor == null )
+ return Walker.transform(op, transform, exprTransform) ;
+// static Set<Class<?>> seen = new HashSet<>() ;
+// if ( ! seen.contains(beforeVisitor.getClass()) ) {
+// System.out.println("T:"+beforeVisitor.getClass().getName()) ;
+// seen.add(beforeVisitor.getClass()) ;
+// }
ApplyTransformVisitor v = new ApplyTransformVisitor(transform, exprTransform) ;
return transformation(v, op, beforeVisitor, afterVisitor) ;
}
- protected Op transformation(ApplyTransformVisitor transformApply,
- Op op, OpVisitor beforeVisitor, OpVisitor afterVisitor)
- {
- if ( op == null )
- {
+ protected Op transformation(ApplyTransformVisitor transformApply, Op op,
+ OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ if ( op == null ) {
Log.warn(this, "Attempt to transform a null Op - ignored") ;
return op ;
}
@@ -141,9 +151,8 @@ public class Transformer
}
/** The primitive operation to apply a transformation to an Op */
- protected Op applyTransformation(ApplyTransformVisitor transformApply,
- Op op, OpVisitor beforeVisitor, OpVisitor afterVisitor)
- {
+ private /*protected*/ Op applyTransformation(ApplyTransformVisitor transformApply, Op op,
+ OpVisitor beforeVisitor, OpVisitor afterVisitor) {
OpWalker.walk(op, transformApply, beforeVisitor, afterVisitor) ;
Op r = transformApply.result() ;
return r ;
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ApplyTransformVisitor.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ApplyTransformVisitor.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ApplyTransformVisitor.java
new file mode 100644
index 0000000..750f893
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ApplyTransformVisitor.java
@@ -0,0 +1,419 @@
+/*
+ * 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.jena.sparql.algebra.walker;
+
+import java.util.* ;
+
+import org.apache.jena.atlas.logging.Log ;
+import org.apache.jena.query.SortCondition ;
+import org.apache.jena.sparql.algebra.Op ;
+import org.apache.jena.sparql.algebra.OpVisitor ;
+import org.apache.jena.sparql.algebra.Transform ;
+import org.apache.jena.sparql.algebra.op.* ;
+import org.apache.jena.sparql.core.Var ;
+import org.apache.jena.sparql.core.VarExprList ;
+import org.apache.jena.sparql.expr.* ;
+import org.apache.jena.sparql.expr.aggregate.Aggregator ;
+
+public class ApplyTransformVisitor implements OpVisitorByTypeAndExpr, ExprVisitor {
+ private final Transform opTransform ;
+ private final ExprTransform exprTransform ;
+
+ protected boolean visitService = true ;
+
+ private final Deque<Op> opStack = new ArrayDeque<>() ;
+ private final Deque<Expr> exprStack = new ArrayDeque<>() ;
+
+ private final OpVisitor beforeVisitor ;
+ private final OpVisitor afterVisitor ;
+
+ public ApplyTransformVisitor(Transform opTransform, ExprTransform exprTransform, OpVisitor before, OpVisitor after) {
+ this.opTransform = opTransform ;
+ this.exprTransform = exprTransform ;
+ this.beforeVisitor = before ;
+ this.afterVisitor = after ;
+ }
+
+ /*package*/ final Op opResult() {
+ return pop(opStack) ;
+ }
+
+ /*package*/ final Expr exprResult() {
+ return pop(exprStack) ;
+ }
+
+ protected Op transform(Op op) {
+ // reuse this ApplyTransformVisitor? with stack checking?
+ return Walker.transform(op, this, beforeVisitor, afterVisitor) ;
+ }
+
+ protected Expr transform(Expr expr) {
+ // reuse this ApplyTransformVisitor? with stack checking?
+ return Walker.transform(expr, this, beforeVisitor, afterVisitor) ;
+ }
+
+ protected ExprList transform(ExprList exprList) {
+// if ( exprList == null || exprTransform == null )
+// return exprList ;
+ ExprList exprList2 = new ExprList() ;
+ exprList.forEach( e->exprList2.add(transform(e)) );
+ return exprList2 ;
+ }
+
+ @Override
+ public void visit(OpOrder opOrder) {
+ List<SortCondition> conditions = opOrder.getConditions() ;
+ List<SortCondition> conditions2 = new ArrayList<>() ;
+ boolean changed = false ;
+
+ for ( SortCondition sc : conditions ) {
+ Expr e = sc.getExpression() ;
+ Expr e2 = transform(e) ;
+ conditions2.add(new SortCondition(e2, sc.getDirection())) ;
+ if ( e != e2 )
+ changed = true ;
+ }
+ OpOrder x = opOrder ;
+ if ( changed )
+ x = new OpOrder(opOrder.getSubOp(), conditions2) ;
+ visit1(x) ;
+ }
+
+ @Override
+ public void visit(OpAssign opAssign) {
+ VarExprList varExpr = opAssign.getVarExprList() ;
+ VarExprList varExpr2 = process(varExpr) ;
+ OpAssign opAssign2 = opAssign ;
+ if ( varExpr != varExpr2 )
+ opAssign2 = OpAssign.create(opAssign.getSubOp(), varExpr2) ;
+ visit1(opAssign2) ;
+ }
+
+ @Override
+ public void visit(OpExtend opExtend) {
+ VarExprList varExpr = opExtend.getVarExprList() ;
+ VarExprList varExpr2 = process(varExpr) ;
+ OpExtend opExtend2 = opExtend ;
+ if ( varExpr != varExpr2 )
+ opExtend2 = OpExtend.create(opExtend.getSubOp(), varExpr2) ;
+ visit1(opExtend2) ;
+ }
+
+ private VarExprList process(VarExprList varExprList) {
+ if ( varExprList == null )
+ return varExprList ;
+ List<Var> vars = varExprList.getVars() ;
+ VarExprList varExpr2 = new VarExprList() ;
+ boolean changed = false ;
+ for ( Var v : vars ) {
+ Expr e = varExprList.getExpr(v) ;
+ Expr e2 = e ;
+ if ( e != null )
+ e2 = transform(e) ;
+ if ( e2 == null )
+ varExpr2.add(v) ;
+ else
+ varExpr2.add(v, e2) ;
+ if ( e != e2 )
+ changed = true ;
+ }
+ if ( !changed )
+ return varExprList ;
+ return varExpr2 ;
+ }
+
+ private ExprList process(ExprList exprList) {
+ if ( exprList == null )
+ return null ;
+ ExprList exprList2 = new ExprList() ;
+ boolean changed = false ;
+ for ( Expr e : exprList ) {
+ Expr e2 = process(e) ;
+ exprList2.add(e2) ;
+ if ( e != e2 )
+ changed = true ;
+ }
+ if ( !changed )
+ return exprList ;
+ return exprList2 ;
+ }
+
+ private Expr process(Expr expr) {
+ Expr e = expr ;
+ Expr e2 = e ;
+ if ( e != null )
+ e2 = transform(e) ;
+ if ( e == e2 )
+ return expr ;
+ return e2 ;
+ }
+
+ @Override
+ public void visit(OpGroup opGroup) {
+ boolean changed = false ;
+
+ VarExprList varExpr = opGroup.getGroupVars() ;
+ VarExprList varExpr2 = process(varExpr) ;
+ if ( varExpr != varExpr2 )
+ changed = true ;
+
+ List<ExprAggregator> aggs = opGroup.getAggregators() ;
+ List<ExprAggregator> aggs2 = aggs ;
+
+ // And the aggregators...
+ aggs2 = new ArrayList<>() ;
+ for ( ExprAggregator agg : aggs ) {
+ Aggregator aggregator = agg.getAggregator() ;
+ Var v = agg.getVar() ;
+
+ // Variable associated with the aggregate
+ Expr eVar = agg.getAggVar() ; // Not .getExprVar()
+ Expr eVar2 = transform(eVar) ;
+ if ( eVar != eVar2 )
+ changed = true ;
+
+ // The Aggregator expression
+ ExprList e = aggregator.getExprList() ;
+ ExprList e2 = e ;
+ if ( e != null )
+ // Null means "no relevant expression" e.g. COUNT(*)
+ e2 = transform(e) ;
+ if ( e != e2 )
+ changed = true ;
+ Aggregator a2 = aggregator.copy(e2) ;
+ aggs2.add(new ExprAggregator(eVar2.asVar(), a2)) ;
+ }
+
+ OpGroup opGroup2 = opGroup ;
+ if ( changed )
+ opGroup2 = new OpGroup(opGroup.getSubOp(), varExpr2, aggs2) ;
+ visit1(opGroup2) ;
+ }
+
+ @Override
+ public void visit0(Op0 op) {
+ push(opStack, op.apply(opTransform)) ;
+ }
+
+ @Override
+ public void visit1(Op1 op) {
+ Op subOp = null ;
+ if ( op.getSubOp() != null )
+ subOp = pop(opStack) ;
+ push(opStack, op.apply(opTransform, subOp)) ;
+ }
+
+ @Override
+ public void visit2(Op2 op) {
+ Op left = null ;
+ Op right = null ;
+
+ // Must do right-left because the pushes onto the stack were left-right.
+ if ( op.getRight() != null )
+ right = pop(opStack) ;
+ if ( op.getLeft() != null )
+ left = pop(opStack) ;
+ Op opX = op.apply(opTransform, left, right) ;
+ push(opStack, opX) ;
+ }
+
+ @Override
+ public void visitN(OpN op) {
+ List<Op> x = new ArrayList<>(op.size()) ;
+
+ for ( Iterator<Op> iter = op.iterator() ; iter.hasNext() ; ) {
+ Op sub = iter.next() ;
+ Op r = pop(opStack) ;
+ // Skip nulls.
+ if ( r != null )
+ // Add in reverse.
+ x.add(0, r) ;
+ }
+ Op opX = op.apply(opTransform, x) ;
+ push(opStack, opX) ;
+ }
+
+ @Override
+ public void visit(OpFilter opFilter) {
+ Op subOp = null ;
+ if ( opFilter.getSubOp() != null )
+ subOp = pop(opStack) ;
+ boolean changed = (opFilter.getSubOp() != subOp) ;
+
+ ExprList ex = opFilter.getExprs() ;
+ ExprList ex2 = process(ex) ;
+ OpFilter f = opFilter ;
+ if ( ex != ex2 )
+ f = (OpFilter)OpFilter.filter(ex2, subOp) ;
+ push(opStack, f.apply(opTransform, subOp)) ;
+ }
+
+ @Override
+ public void visit(OpLeftJoin op) {
+ Op left = null ;
+ Op right = null ;
+
+ // Must do right-left because the pushes onto the stack were left-right.
+ if ( op.getRight() != null )
+ right = pop(opStack) ;
+ if ( op.getLeft() != null )
+ left = pop(opStack) ;
+
+ ExprList exprs = op.getExprs() ;
+ ExprList exprs2 = process(exprs) ;
+ OpLeftJoin x = op ;
+ if ( exprs != exprs2 )
+ x = OpLeftJoin.createLeftJoin(left, right, exprs2) ;
+ Op opX = x.apply(opTransform, left, right) ;
+ push(opStack, opX) ;
+ }
+
+ @Override
+ public void visit(OpService op) {
+ if ( ! visitService ) {
+ // No visit - push input.
+ push(opStack, op) ;
+ return ;
+ }
+ // op.getService()
+ OpVisitorByTypeAndExpr.super.visit(op);
+ }
+
+ @Override
+ public void visitExt(OpExt op) {
+ push(opStack, opTransform.transform(op)) ;
+ }
+
+ @Override
+ public void visitExpr(ExprList exprs) {
+ System.err.println("visitExpr(ExprList)") ;
+ if ( exprs != null && exprTransform != null ) {
+
+ }
+ }
+
+ @Override
+ public void visitExpr(VarExprList exprVarExprList) {
+ System.err.println("visitExpr(ExprList)") ;
+ if ( exprVarExprList != null && exprTransform != null ) {
+
+ }
+ }
+
+ @Override
+ public void visit(ExprFunction0 func) {
+ Expr e = func.apply(exprTransform) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(ExprFunction1 func) {
+ Expr e1 = pop(exprStack) ;
+ Expr e = func.apply(exprTransform, e1) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(ExprFunction2 func) {
+ Expr e2 = pop(exprStack) ;
+ Expr e1 = pop(exprStack) ;
+ Expr e = func.apply(exprTransform, e1, e2) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(ExprFunction3 func) {
+ Expr e3 = pop(exprStack) ;
+ Expr e2 = pop(exprStack) ;
+ Expr e1 = pop(exprStack) ;
+ Expr e = func.apply(exprTransform, e1, e2, e3) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(ExprFunctionN func) {
+ ExprList x = process(func.getArgs()) ;
+ Expr e = func.apply(exprTransform, x) ;
+ push(exprStack, e) ;
+ }
+
+ private ExprList process(List<Expr> exprList) {
+ if ( exprList == null )
+ return null ;
+ int N = exprList.size() ;
+ List<Expr> x = new ArrayList<>(N) ;
+ for ( Expr anExprList : exprList ) {
+ Expr e2 = pop(exprStack) ;
+ // Add in reverse.
+ x.add(0, e2) ;
+ }
+ return new ExprList(x) ;
+ }
+
+ @Override
+ public void visit(ExprFunctionOp funcOp) {
+ ExprList x = null ;
+// Op op = transform(funcOp.getGraphPattern()) ;
+ if ( funcOp.getArgs() != null )
+ x = process(funcOp.getArgs()) ;
+ Expr e = funcOp.apply(exprTransform, x, funcOp.getGraphPattern()) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(NodeValue nv) {
+ Expr e = nv.apply(exprTransform) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(ExprVar var) {
+ Expr e = var.apply(exprTransform) ;
+ push(exprStack, e) ;
+ }
+
+ @Override
+ public void visit(ExprAggregator eAgg) {
+ Expr e = eAgg.apply(exprTransform) ;
+ push(exprStack, e) ;
+ }
+
+ private <T> void push(Deque<T> stack, T value) {
+ stack.push(value) ;
+ }
+
+ private <T> T pop(Deque<T> stack) {
+ try {
+ T v = stack.pop() ;
+ if ( v == null )
+ Log.warn(ApplyTransformVisitor.class, "Pop null from "+stackLabel(stack)+" stack") ;
+ return v ;
+ }
+ catch (EmptyStackException ex) {
+ Log.warn(ApplyTransformVisitor.class, "Empty "+stackLabel(stack)+" stack") ;
+ return null ;
+ }
+ }
+
+ private String stackLabel(Deque<?> stack) {
+ if ( stack == opStack ) return "Op" ;
+ if ( stack == exprStack ) return "Expr" ;
+ return "<other>" ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ElementWalker_New.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ElementWalker_New.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ElementWalker_New.java
new file mode 100644
index 0000000..7ca53b9
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ElementWalker_New.java
@@ -0,0 +1,196 @@
+/*
+ * 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.jena.sparql.algebra.walker;
+
+import org.apache.jena.sparql.expr.* ;
+import org.apache.jena.sparql.syntax.* ;
+
+/** An element visitor that walks the graph pattern tree for one query level.
+ * applying a visitor at each Element traversed.<br/>
+ * Does not process subqueries.<br/>
+ * Does not process (NOT)EXISTS in filters.<br/>
+ * These will need to call down themselves if it is meaningful for the visitor.
+ * Bottom-up walk - apply to subelements before applying to current element.
+ */
+
+public class ElementWalker_New {
+ public static void walk(Element el, ElementVisitor visitor) {
+ walk(el, visitor, null) ;
+ }
+
+ public static void walk(Element el, ElementVisitor elVisitor, ExprVisitor exprVisitor) {
+ EltWalker w = new EltWalker(elVisitor, exprVisitor) ;
+ el.visit(w) ;
+ }
+
+// protected static void walk$(Element el, Walker walker) {
+// el.visit(walker) ;
+// }
+
+ static public class EltWalker implements ElementVisitor, ExprVisitorFunction {
+ protected final ElementVisitor elementVisitor ;
+ protected final ExprVisitor exprVisitor ;
+
+ protected EltWalker(ElementVisitor visitor, ExprVisitor exprVisitor) {
+ this.elementVisitor = visitor ;
+ this.exprVisitor = exprVisitor ;
+ }
+
+ @Override
+ public void visit(ElementTriplesBlock el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementFilter el) {
+ el.getExpr().visit(this);
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementAssign el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementBind el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementData el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementUnion el) {
+ for ( Element e : el.getElements() )
+ e.visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementGroup el) {
+ for ( Element e : el.getElements() )
+ e.visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementOptional el) {
+ if ( el.getOptionalElement() != null )
+ el.getOptionalElement().visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementDataset el) {
+ if ( el.getElement() != null )
+ el.getElement().visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementNamedGraph el) {
+ if ( el.getElement() != null )
+ el.getElement().visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementService el) {
+ if ( el.getElement() != null )
+ el.getElement().visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ // EXISTs, NOT EXISTs also occur in FILTERs via expressions.
+
+ @Override
+ public void visit(ElementExists el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementNotExists el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementMinus el) {
+ if ( el.getMinusElement() != null )
+ el.getMinusElement().visit(this) ;
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementSubQuery el) {
+ // This does not automatically walk into the subquery.
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ElementPathBlock el) {
+ elementVisitor.visit(el) ;
+ }
+
+ @Override
+ public void visit(ExprFunction0 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunction1 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunction2 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunction3 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunctionN func) { visitExprFunction(func) ; }
+
+ @Override
+ public void visitExprFunction(ExprFunction func) {
+ for ( int i = 1 ; i <= func.numArgs() ; i++ )
+ {
+ Expr expr = func.getArg(i) ;
+ if ( expr == null )
+ // Put a dummy in, e.g. to keep the transform stack aligned.
+ NodeValue.nvNothing.visit(this) ;
+ else
+ expr.visit(this) ;
+ }
+ func.visit(exprVisitor) ;
+ }
+
+ @Override
+ public void visit(ExprFunctionOp funcOp) {
+ // Walk the op
+ funcOp.getElement().visit(this);
+ funcOp.visit(exprVisitor) ;
+ }
+
+ @Override
+ public void visit(NodeValue nv) { nv.visit(exprVisitor) ; }
+ @Override
+ public void visit(ExprVar v) { v.visit(exprVisitor) ; }
+ @Override
+ public void visit(ExprAggregator eAgg) {
+ //eAgg.getAggVar().visit(visitorExpr);
+ // XXX Hack for varsMentioned
+ eAgg.visit(exprVisitor) ;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ExprVisitorFunction.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ExprVisitorFunction.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ExprVisitorFunction.java
new file mode 100644
index 0000000..fa72d89
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/ExprVisitorFunction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.jena.sparql.algebra.walker;
+
+import org.apache.jena.sparql.expr.* ;
+
+/** Convert all visit calls on the expressions in a call to a generic visit operation for expression functions */
+public interface ExprVisitorFunction extends ExprVisitor
+{
+ @Override
+ public default void visit(ExprFunction0 func) { visitExprFunction(func) ; }
+ @Override
+ public default void visit(ExprFunction1 func) { visitExprFunction(func) ; }
+ @Override
+ public default void visit(ExprFunction2 func) { visitExprFunction(func) ; }
+ @Override
+ public default void visit(ExprFunction3 func) { visitExprFunction(func) ; }
+ @Override
+ public default void visit(ExprFunctionN func) { visitExprFunction(func) ; }
+
+ public void visitExprFunction(ExprFunction func) ;
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/OpVisitorByTypeAndExpr.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/OpVisitorByTypeAndExpr.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/OpVisitorByTypeAndExpr.java
new file mode 100644
index 0000000..7dfb65f
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/OpVisitorByTypeAndExpr.java
@@ -0,0 +1,229 @@
+/*
+ * 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.jena.sparql.algebra.walker;
+
+import org.apache.jena.sparql.algebra.OpVisitor ;
+import org.apache.jena.sparql.algebra.op.* ;
+import org.apache.jena.sparql.core.VarExprList ;
+import org.apache.jena.sparql.expr.ExprList ;
+
+/** A visitor helper that maps all visits to a few general ones */
+public interface OpVisitorByTypeAndExpr extends OpVisitor
+{
+ public void visitN(OpN op) ;
+
+ public void visit2(Op2 op) ;
+
+ public void visit1(Op1 op) ;
+
+ public void visit0(Op0 op) ;
+
+ public default void visitExt(OpExt op) {
+ op.effectiveOp().visit(this);
+ }
+
+ public void visitExpr(ExprList exprs) ;
+ public void visitExpr(VarExprList exprs) ;
+ //public void visitAssignVar(Var var) ;
+
+ public default void visitModifer(OpModifier opMod) {
+ visit1(opMod);
+ }
+
+ @Override
+ public default void visit(OpBGP opBGP) {
+ visit0(opBGP);
+ }
+
+ @Override
+ public default void visit(OpQuadPattern quadPattern) {
+ visit0(quadPattern);
+ }
+
+ @Override
+ public default void visit(OpQuadBlock quadBlock) {
+ visit0(quadBlock);
+ }
+
+ @Override
+ public default void visit(OpTriple opTriple) {
+ visit0(opTriple);
+ }
+
+ @Override
+ public default void visit(OpQuad opQuad) {
+ visit0(opQuad);
+ }
+
+ @Override
+ public default void visit(OpPath opPath) {
+ visit0(opPath);
+ }
+
+ @Override
+ public default void visit(OpProcedure opProcedure) {
+ visit1(opProcedure);
+ }
+
+ @Override
+ public default void visit(OpPropFunc opPropFunc) {
+ visit1(opPropFunc);
+ }
+
+ @Override
+ public default void visit(OpJoin opJoin) {
+ visit2(opJoin);
+ }
+
+ @Override
+ public default void visit(OpSequence opSequence) {
+ visitN(opSequence);
+ }
+
+ @Override
+ public default void visit(OpDisjunction opDisjunction) {
+ visitN(opDisjunction);
+ }
+
+ @Override
+ public default void visit(OpLeftJoin opLeftJoin) {
+ visitExpr(opLeftJoin.getExprs());
+ visit2(opLeftJoin);
+ }
+
+ @Override
+ public default void visit(OpDiff opDiff) {
+ visit2(opDiff);
+ }
+
+ @Override
+ public default void visit(OpMinus opMinus) {
+ visit2(opMinus);
+ }
+
+ @Override
+ public default void visit(OpUnion opUnion) {
+ visit2(opUnion);
+ }
+
+ @Override
+ public default void visit(OpConditional opCond) {
+ visit2(opCond);
+ }
+
+ @Override
+ public default void visit(OpFilter opFilter) {
+ visitExpr(opFilter.getExprs());
+ visit1(opFilter);
+ }
+
+ @Override
+ public default void visit(OpGraph opGraph) {
+ visit1(opGraph);
+ }
+
+ @Override
+ public default void visit(OpService opService) {
+ visit1(opService);
+ }
+
+ @Override
+ public default void visit(OpDatasetNames dsNames) {
+ visit0(dsNames);
+ }
+
+ @Override
+ public default void visit(OpTable opUnit) {
+ visit0(opUnit);
+ }
+
+ @Override
+ public default void visit(OpExt opExt) {
+ visitExt(opExt);
+ }
+
+ @Override
+ public default void visit(OpNull opNull) {
+ visit0(opNull);
+ }
+
+ @Override
+ public default void visit(OpLabel opLabel) {
+ visit1(opLabel);
+ }
+
+ @Override
+ public default void visit(OpOrder opOrder) {
+ // XXX
+ //opOrder.getConditions() ;
+ visitModifer(opOrder);
+ }
+
+ @Override
+ public default void visit(OpGroup opGroup) {
+ visitExpr(opGroup.getGroupVars()) ;
+ // XXX
+ //opGroup.getAggregators() ;
+ visit1(opGroup);
+ }
+
+ @Override
+ public default void visit(OpTopN opTop) {
+ // XXX
+ // opTop.getConditions() ;
+ visit1(opTop);
+ }
+
+ @Override
+ public default void visit(OpAssign opAssign) {
+ visitExpr(opAssign.getVarExprList()) ;
+ visit1(opAssign);
+ }
+
+ @Override
+ public default void visit(OpExtend opExtend) {
+ visitExpr(opExtend.getVarExprList()) ;
+ visit1(opExtend);
+ }
+
+ @Override
+ public default void visit(OpList opList) {
+ visitModifer(opList);
+ }
+
+ @Override
+ public default void visit(OpProject opProject) {
+ visitModifer(opProject);
+ }
+
+ @Override
+ public default void visit(OpReduced opReduced) {
+ visitModifer(opReduced);
+ }
+
+ @Override
+ public default void visit(OpDistinct opDistinct) {
+ visitModifer(opDistinct);
+ }
+
+ @Override
+ public default void visit(OpSlice opSlice) {
+ visitModifer(opSlice);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/Walker.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/Walker.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/Walker.java
new file mode 100644
index 0000000..6135416
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/Walker.java
@@ -0,0 +1,190 @@
+/*
+ * 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.jena.sparql.algebra.walker;
+
+import java.util.Objects ;
+
+import org.apache.jena.sparql.algebra.* ;
+import org.apache.jena.sparql.core.VarExprList ;
+import org.apache.jena.sparql.expr.* ;
+
+/** Walk algebra, {@link Op}s and {@link Expr}s. */
+public class Walker {
+
+ /** Walk visiting every {@link Op} with an {@link OpVisitor},
+ * including inside expressions.
+ */
+ public static void walk(Op op, OpVisitor opVisitor) {
+ Objects.requireNonNull(opVisitor) ;
+ walk(op, opVisitor, null);
+ }
+
+ /** Walk visiting every {@link Op} and every {@link Expr},
+ * starting from an {@link Op}.
+ */
+ public static void walk(Op op, OpVisitor opVisitor, ExprVisitor exprVisitor) {
+ walk(op, opVisitor, exprVisitor, null, null) ;
+ }
+
+ /** Walk visiting every {@link Op} and every {@link Expr},
+ * starting from an {@link Op}.
+ */
+ public static void walk(Op op, OpVisitor opVisitor, ExprVisitor exprVisitor, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ if ( op == null )
+ return ;
+ createWalker(opVisitor, exprVisitor, beforeVisitor, afterVisitor).walk(op);
+ }
+
+ /** Walk visiting every {@link Expr} with an {@link ExprVisitor},
+ * including inside any {@link Op} in expressions.
+ */
+ public static void walk(Expr expr, ExprVisitor exprVisitor) {
+ Objects.requireNonNull(exprVisitor) ;
+ walk(expr, null, exprVisitor);
+ }
+
+ /** Walk visiting every {@link Op} and every {@link Expr},
+ * starting from an {@link Expr}.
+ */
+ public static void walk(Expr expr, OpVisitor opVisitor, ExprVisitor exprVisitor) {
+ walk(expr, opVisitor, exprVisitor, null, null) ;
+ }
+
+ /** Walk visiting every {@link Op} and every {@link Expr},
+ * starting from an {@link Expr}.
+ */
+ public static void walk(Expr expr, OpVisitor opVisitor, ExprVisitor exprVisitor, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ if ( expr == null )
+ return ;
+ Objects.requireNonNull(expr) ;
+ createWalker(opVisitor, exprVisitor, beforeVisitor,afterVisitor).walk(expr);
+ }
+
+
+ /** Walk visiting every {@link Expr} with an {@link ExprVisitor},
+ * including inside any {@link Op} in expressions.
+ */
+ public static void walk(ExprList exprList, ExprVisitor exprVisitor) {
+ walk(exprList, null, exprVisitor);
+ }
+
+ /** Walk visiting every {@link Op} and every {@link Expr},
+ * starting from an {@link ExprList}.
+ */
+ public static void walk(ExprList exprList, OpVisitor opVisitor, ExprVisitor exprVisitor) {
+ if ( exprList == null )
+ return ;
+ Objects.requireNonNull(exprVisitor) ;
+ exprList.forEach(e->walk(e,opVisitor, exprVisitor)) ;
+ }
+
+ public static void walk(VarExprList varExprList, ExprVisitor exprVisitor) {
+ Objects.requireNonNull(exprVisitor) ;
+ walk(varExprList, null, exprVisitor);
+ }
+
+ public static void walk(VarExprList varExprList, OpVisitor opVisitor, ExprVisitor exprVisitor) {
+ if ( varExprList == null )
+ return ;
+ varExprList.forEach((v,e)->walk(e,opVisitor, exprVisitor)) ;
+ }
+
+ private static OpVisitor nullOpVisitor = new OpVisitorBase() ;
+ private static ExprVisitor nullExprVisitor = new ExprVisitorBase() ;
+
+ public static WalkerVisitor createWalker(OpVisitor opVisitor, ExprVisitor exprVisitor) {
+ return createWalker(opVisitor, exprVisitor, null, null) ;
+ }
+
+ public static WalkerVisitor createWalker(OpVisitor opVisitor, ExprVisitor exprVisitor, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+
+ if ( opVisitor == null )
+ opVisitor = nullOpVisitor ;
+ if ( exprVisitor == null )
+ exprVisitor = new ExprVisitorBase() ;
+ return new WalkerVisitor(opVisitor, exprVisitor, beforeVisitor, afterVisitor) ;
+ }
+
+ /** Transform an {@link Op}. */
+ public static Op transform(Op op, Transform opTransform, ExprTransform exprTransform) {
+ ApplyTransformVisitor v = createTransformer(opTransform, exprTransform) ;
+ return transform(op, v) ;
+ }
+
+ /** Transform an {@link Op}. */
+ public static Op transform(Op op, Transform opTransform, ExprTransform exprTransform, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ ApplyTransformVisitor v = createTransformer(opTransform, exprTransform) ;
+ return transform(op, v, beforeVisitor, afterVisitor) ;
+ }
+
+ /** Transform an {@link Expr}. */
+ public static Expr transform(Expr expr, Transform opTransform, ExprTransform exprTransform) {
+ ApplyTransformVisitor v = createTransformer(opTransform, exprTransform) ;
+ return transform(expr, v) ;
+ }
+
+ /** Transform an {@link Op}. */
+ public static Op transform(Op op, ApplyTransformVisitor v) {
+ return transform(op, v, null, null) ;
+ }
+
+ /** Transform an {@link Op}. */
+ public static Op transform(Op op, ApplyTransformVisitor v, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ walk(op, v, v, beforeVisitor, afterVisitor) ;
+ return v.opResult() ;
+ }
+
+ /** Transform an {@link Expr}. */
+ public static Expr transform(Expr expr, ApplyTransformVisitor v) {
+ walk(expr, v) ;
+ return v.exprResult() ;
+ }
+
+ /** Transform an {@link Expr}. */
+ public static Expr transform(Expr expr, ApplyTransformVisitor v, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ walk(expr, v, v, beforeVisitor, afterVisitor) ;
+ return v.exprResult() ;
+ }
+
+ /** Transform an algebra expression */
+ public static Op transform(Op op, Transform transform) {
+ return transform(op, transform, null) ;
+ }
+
+ /** Transform an expression */
+ public static Expr transform(Expr expr, ExprTransform exprTransform) {
+ return transform(expr, null, exprTransform) ;
+ }
+
+ private static Transform nullOpTransform = new TransformBase() ;
+ private static ExprTransform nullExprTransform = new ExprTransformBase() ;
+
+ public static ApplyTransformVisitor createTransformer(Transform opTransform, ExprTransform exprTransform) {
+ return createTransformer(opTransform, exprTransform, null, null) ;
+ }
+
+ public static ApplyTransformVisitor createTransformer(Transform opTransform, ExprTransform exprTransform, OpVisitor beforeVisitor, OpVisitor afterVisitor) {
+ if ( opTransform == null )
+ opTransform = nullOpTransform ;
+ if ( exprTransform == null )
+ exprTransform = nullExprTransform ;
+ return new ApplyTransformVisitor(opTransform, exprTransform, null, null) ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/c1fde992/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/WalkerVisitor.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/WalkerVisitor.java b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/WalkerVisitor.java
new file mode 100644
index 0000000..59fa8a0
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/walker/WalkerVisitor.java
@@ -0,0 +1,272 @@
+/*
+ * 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.jena.sparql.algebra.walker;
+
+import java.util.Iterator ;
+
+import org.apache.jena.sparql.algebra.Op ;
+import org.apache.jena.sparql.algebra.OpVisitor ;
+import org.apache.jena.sparql.algebra.OpVisitorBase ;
+import org.apache.jena.sparql.algebra.op.* ;
+import org.apache.jena.sparql.core.VarExprList ;
+import org.apache.jena.sparql.expr.* ;
+
+/** Walk algebra and expressions */
+public class WalkerVisitor implements OpVisitorByTypeAndExpr, ExprVisitorFunction {
+ protected final ExprVisitor exprVisitor ;
+ protected final OpVisitor opVisitor ;
+ protected boolean visitService = true ;
+ protected int opDepthLimit = Integer.MAX_VALUE ;
+ protected int exprDepthLimit = Integer.MAX_VALUE ;
+
+ protected int opDepth = 0 ;
+ protected int exprDepth = 0 ;
+
+ private final OpVisitor beforeVisitor ;
+ private final OpVisitor afterVisitor ;
+
+ /**
+ * A walker. If a visitor is null, then don't walk in. For
+ * "no action but keep walking inwards", use {@link OpVisitorBase} and
+ * {@link ExprVisitorBase}.
+ *
+ * @see OpVisitorBase
+ * @see ExprVisitorBase
+ */
+ public WalkerVisitor(OpVisitor opVisitor, ExprVisitor exprVisitor, OpVisitor before, OpVisitor after) {
+ this.opVisitor = opVisitor ;
+ this.exprVisitor = exprVisitor ;
+ if ( opDepthLimit < 0 )
+ opDepthLimit = Integer.MAX_VALUE ;
+ if ( exprDepth < 0 )
+ exprDepthLimit = Integer.MAX_VALUE ;
+ opDepth = 0 ;
+ exprDepth = 0 ;
+ beforeVisitor = before ;
+ afterVisitor = after ;
+ }
+
+ private void before(Op op) {
+ if ( beforeVisitor != null )
+ op.visit(beforeVisitor) ;
+ }
+
+ private void after(Op op) {
+ if ( afterVisitor != null )
+ op.visit(afterVisitor) ;
+ }
+
+ public void walk(Op op) {
+ if ( op == null )
+ return ;
+ if ( opDepth == opDepthLimit )
+ // No deeper.
+ return ;
+ opDepth++ ;
+ try { op.visit(this); }
+ finally { opDepth-- ; }
+ }
+
+ public void walk(Expr expr) {
+ if ( expr == null )
+ return ;
+ if ( exprDepth == exprDepthLimit )
+ return ;
+ exprDepth++ ;
+ try { expr.visit(this) ; }
+ finally { exprDepth-- ; }
+ }
+
+ public void walk(ExprList exprList) {
+ if ( exprList == null )
+ return ;
+ exprList.forEach(e->walk(e));
+ }
+
+ public void walk(VarExprList varExprList) {
+ if ( varExprList == null )
+ return ;
+ varExprList.forEach((v,e) -> walk(e));
+ }
+
+ // ---- Mode swapping between op and expr. visit=>?walk
+ // XXX
+ @Override
+ public void visitExpr(ExprList exprList) {
+ if ( exprVisitor != null )
+ walk(exprList) ;
+ }
+
+ @Override
+ public void visitExpr(VarExprList varExprList) {
+ if ( exprVisitor != null )
+ walk(varExprList);
+ }
+
+ // ----
+
+ public void visitOp(Op op) {
+ before(op) ;
+ if ( opVisitor != null )
+ op.visit(this);
+ after(op) ;
+ }
+
+ @Override
+ public void visit0(Op0 op) {
+ if ( opVisitor != null )
+ op.visit(opVisitor) ;
+ }
+
+ @Override
+ public void visit1(Op1 op) {
+ before(op) ;
+ if ( op.getSubOp() != null )
+ op.getSubOp().visit(this) ;
+ if ( opVisitor != null )
+ op.visit(opVisitor) ;
+ after(op) ;
+ }
+
+ @Override
+ public void visit2(Op2 op) {
+ before(op) ;
+ if ( op.getLeft() != null )
+ op.getLeft().visit(this) ;
+ if ( op.getRight() != null )
+ op.getRight().visit(this) ;
+ if ( opVisitor != null )
+ op.visit(opVisitor) ;
+ after(op) ;
+ }
+
+ @Override
+ public void visitN(OpN op) {
+ before(op) ;
+ for (Iterator<Op> iter = op.iterator(); iter.hasNext();) {
+ Op sub = iter.next() ;
+ sub.visit(this) ;
+ }
+ if ( opVisitor != null )
+ op.visit(opVisitor) ;
+ after(op) ;
+ }
+
+ @Override
+ public void visitExt(OpExt op) {
+ before(op) ;
+ if ( opVisitor != null )
+ op.visit(opVisitor) ;
+ after(op) ;
+ }
+
+ // Special case Ops.
+ // These should call super.visit to do full processing.
+
+ @Override
+ public void visit(OpService op) {
+ if ( ! visitService )
+ return ;
+ OpVisitorByTypeAndExpr.super.visit(op) ;
+ }
+
+ // Transforming to quads needs the graph node handled before doing the sub-algebra ops
+ // so it has to be done as before/after by the Walker. By the time visit(OpGraph) is called,
+ // the sub-tree has already been visited.
+
+
+// @Override
+// public void visit(OpGraph op) {
+// pushGraph(op.getNode()) ;
+// OpVisitorByTypeAndExpr.super.visit(op) ;
+// popGraph() ;
+// }
+//
+// private Deque<Node> stack = new ArrayDeque<>() ;
+//
+// public Node getCurrentGraph() { return stack.peek() ; }
+//
+// private void pushGraph(Node node) {
+// stack.push(node) ;
+// }
+//
+// private void popGraph() {
+// stack.pop() ;
+// }
+
+ // Shared with ElementWalker - mixin
+ @Override
+ public void visit(ExprFunction0 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunction1 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunction2 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunction3 func) { visitExprFunction(func) ; }
+ @Override
+ public void visit(ExprFunctionN func) { visitExprFunction(func) ; }
+
+ @Override
+ public void visitExprFunction(ExprFunction func) {
+ for ( int i = 1 ; i <= func.numArgs() ; i++ ) {
+ Expr expr = func.getArg(i) ;
+ if ( expr == null )
+ // Put a dummy in, e.g. to keep the transform stack aligned.
+ NodeValue.nvNothing.visit(this) ;
+ else
+ expr.visit(this) ;
+ }
+ if ( exprVisitor != null )
+ func.visit(exprVisitor) ;
+ }
+
+ @Override
+ public void visit(ExprFunctionOp funcOp) {
+ walk(funcOp.getGraphPattern());
+ if ( exprVisitor != null )
+ funcOp.visit(exprVisitor) ;
+ }
+
+ @Override
+ public void visit(NodeValue nv) {
+ if ( exprVisitor != null )
+ nv.visit(exprVisitor) ;
+ }
+
+ @Override
+ public void visit(ExprVar v) {
+ if ( exprVisitor != null )
+ v.visit(exprVisitor) ;
+ }
+
+ @Override
+ public void visit(ExprAggregator eAgg) {
+ // This is the assignment variable of the aggregation
+ // not a normal variable of an expression.
+
+ // visitAssignVar(eAgg.getAggVar().asVar()) ;
+
+ // XXX Hack for varsMentioned
+
+ if ( exprVisitor != null )
+ eAgg.visit(exprVisitor) ;
+ }
+}
+
+