calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [2/3] calcite git commit: [CALCITE-1530] Create a visitor to traverse linq4j expressions without mutating them, and rename Visitor to Shuttle
Date Thu, 08 Dec 2016 06:05:01 GMT
[CALCITE-1530] Create a visitor to traverse linq4j expressions without mutating them, and rename Visitor to Shuttle


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/267e2f3e
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/267e2f3e
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/267e2f3e

Branch: refs/heads/master
Commit: 267e2f3e1db71e678f80bb69015164c0d45bcfe4
Parents: 02752fe
Author: Julian Hyde <jhyde@apache.org>
Authored: Mon Dec 5 19:53:41 2016 -0800
Committer: Julian Hyde <jhyde@apache.org>
Committed: Wed Dec 7 11:17:40 2016 -0800

----------------------------------------------------------------------
 .../enumerable/EnumerableRelImplementor.java    |  19 +-
 .../calcite/adapter/enumerable/RexImpTable.java |   4 +-
 .../calcite/linq4j/tree/AbstractNode.java       |   2 +-
 .../calcite/linq4j/tree/BinaryExpression.java   |   6 +-
 .../calcite/linq4j/tree/BlockBuilder.java       |  67 +--
 .../calcite/linq4j/tree/BlockStatement.java     |  12 +-
 .../calcite/linq4j/tree/ClassDeclaration.java   |  12 +-
 .../linq4j/tree/ClassDeclarationFinder.java     |   8 +-
 .../linq4j/tree/ConditionalExpression.java      |   6 +-
 .../linq4j/tree/ConditionalStatement.java       |  12 +-
 .../calcite/linq4j/tree/ConstantExpression.java |   6 +-
 .../linq4j/tree/ConstructorDeclaration.java     |  12 +-
 .../linq4j/tree/DeclarationStatement.java       |  12 +-
 .../calcite/linq4j/tree/DefaultExpression.java  |   7 +-
 .../calcite/linq4j/tree/DynamicExpression.java  |   7 +-
 .../apache/calcite/linq4j/tree/Expression.java  |   2 +-
 .../apache/calcite/linq4j/tree/Expressions.java |  44 +-
 .../calcite/linq4j/tree/FieldDeclaration.java   |  12 +-
 .../calcite/linq4j/tree/ForStatement.java       |  18 +-
 .../calcite/linq4j/tree/FunctionExpression.java |  12 +-
 .../calcite/linq4j/tree/GotoStatement.java      |  12 +-
 .../calcite/linq4j/tree/IndexExpression.java    |  13 +-
 .../linq4j/tree/InvocationExpression.java       |   7 +-
 .../calcite/linq4j/tree/LabelStatement.java     |   6 +-
 .../calcite/linq4j/tree/LambdaExpression.java   |   7 +-
 .../calcite/linq4j/tree/ListInitExpression.java |   7 +-
 .../calcite/linq4j/tree/MemberDeclaration.java  |   2 +-
 .../calcite/linq4j/tree/MemberExpression.java   |  12 +-
 .../linq4j/tree/MemberInitExpression.java       |   7 +-
 .../linq4j/tree/MethodCallExpression.java       |  14 +-
 .../calcite/linq4j/tree/MethodDeclaration.java  |  12 +-
 .../calcite/linq4j/tree/NewArrayExpression.java |  14 +-
 .../calcite/linq4j/tree/NewExpression.java      |  14 +-
 .../org/apache/calcite/linq4j/tree/Node.java    |   4 +-
 .../calcite/linq4j/tree/OptimizeShuttle.java    | 422 ++++++++++++++++++
 .../calcite/linq4j/tree/OptimizeVisitor.java    | 423 -------------------
 .../linq4j/tree/ParameterExpression.java        |   6 +-
 .../org/apache/calcite/linq4j/tree/Shuttle.java | 335 +++++++++++++++
 .../apache/calcite/linq4j/tree/Statement.java   |   2 +-
 .../calcite/linq4j/tree/SwitchStatement.java    |   7 +-
 .../calcite/linq4j/tree/TernaryExpression.java  |  16 +-
 .../calcite/linq4j/tree/ThrowStatement.java     |  12 +-
 .../calcite/linq4j/tree/TryStatement.java       |   6 +-
 .../linq4j/tree/TypeBinaryExpression.java       |  12 +-
 .../calcite/linq4j/tree/UnaryExpression.java    |  12 +-
 .../org/apache/calcite/linq4j/tree/Visitor.java | 351 ++-------------
 .../apache/calcite/linq4j/tree/VisitorImpl.java | 206 +++++++++
 .../calcite/linq4j/tree/WhileStatement.java     |  14 +-
 .../calcite/linq4j/test/BlockBuilderTest.java   |   8 +-
 .../calcite/linq4j/test/ExpressionTest.java     |  12 +-
 site/_docs/adapter.md                           |   5 +-
 51 files changed, 1336 insertions(+), 924 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
index bc88333..90105e0 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java
@@ -36,7 +36,7 @@ import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.linq4j.tree.Statement;
 import org.apache.calcite.linq4j.tree.Types;
-import org.apache.calcite.linq4j.tree.Visitor;
+import org.apache.calcite.linq4j.tree.VisitorImpl;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.runtime.Bindable;
 import org.apache.calcite.util.BuiltInMethod;
@@ -458,26 +458,19 @@ public class EnumerableRelImplementor extends JavaRelImplementor {
   }
 
   /** Visitor that finds types in an {@link Expression} tree. */
-  private static class TypeFinder extends Visitor {
+  private static class TypeFinder extends VisitorImpl<Void> {
     private final Collection<Type> types;
 
     TypeFinder(Collection<Type> types) {
       this.types = types;
     }
 
-    @Override public Expression visit(
-        NewExpression newExpression,
-        List<Expression> arguments,
-        List<MemberDeclaration> memberDeclarations) {
+    @Override public Void visit(NewExpression newExpression) {
       types.add(newExpression.type);
-      return super.visit(
-          newExpression,
-          arguments,
-          memberDeclarations);
+      return super.visit(newExpression);
     }
 
-    @Override public Expression visit(NewArrayExpression newArrayExpression,
-        int dimension, Expression bound, List<Expression> expressions) {
+    @Override public Void visit(NewArrayExpression newArrayExpression) {
       Type type = newArrayExpression.type;
       for (;;) {
         final Type componentType = Types.getComponentType(type);
@@ -487,7 +480,7 @@ public class EnumerableRelImplementor extends JavaRelImplementor {
         type = componentType;
       }
       types.add(type);
-      return super.visit(newArrayExpression, dimension, bound, expressions);
+      return super.visit(newArrayExpression);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 5984fca..ddcb8dc 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -27,7 +27,7 @@ import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.linq4j.tree.ExpressionType;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.MemberExpression;
-import org.apache.calcite.linq4j.tree.OptimizeVisitor;
+import org.apache.calcite.linq4j.tree.OptimizeShuttle;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.linq4j.tree.Types;
@@ -640,7 +640,7 @@ public class RexImpTable {
   }
 
   static Expression optimize(Expression expression) {
-    return expression.accept(new OptimizeVisitor());
+    return expression.accept(new OptimizeShuttle());
   }
 
   static Expression optimize2(Expression operand, Expression expression) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
index c74adc6..38aec48 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/AbstractNode.java
@@ -65,7 +65,7 @@ public abstract class AbstractNode implements Node {
         "un-parse not supported: " + getClass() + ":" + nodeType);
   }
 
-  public Node accept(Visitor visitor) {
+  public Node accept(Shuttle shuttle) {
     throw new RuntimeException(
         "visit not supported: " + getClass() + ":" + nodeType);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
index eb73da3..f8056c7 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BinaryExpression.java
@@ -37,13 +37,17 @@ public class BinaryExpression extends Expression {
     this.primitive = Primitive.of(expression0.getType());
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle visitor) {
     visitor = visitor.preVisit(this);
     Expression expression0 = this.expression0.accept(visitor);
     Expression expression1 = this.expression1.accept(visitor);
     return visitor.visit(this, expression0, expression1);
   }
 
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
+  }
+
   public Object evaluate(Evaluator evaluator) {
     switch (nodeType) {
     case AndAlso:

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
index c58a258..ff13d66 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockBuilder.java
@@ -32,18 +32,18 @@ import java.util.Set;
  * <p>Has methods that help ensure that variable names are unique.</p>
  */
 public class BlockBuilder {
-  final List<Statement> statements = new ArrayList<Statement>();
-  final Set<String> variables = new HashSet<String>();
+  final List<Statement> statements = new ArrayList<>();
+  final Set<String> variables = new HashSet<>();
   /** Contains final-fine-to-reuse-declarations.
    * An entry to this map is added when adding final declaration of a
    * statement with optimize=true parameter. */
   final Map<Expression, DeclarationStatement> expressionForReuse =
-      new HashMap<Expression, DeclarationStatement>();
+      new HashMap<>();
 
   private final boolean optimizing;
   private final BlockBuilder parent;
 
-  private static final Visitor OPTIMIZE_VISITOR = new OptimizeVisitor();
+  private static final Shuttle OPTIMIZE_SHUTTLE = new OptimizeShuttle();
 
   /**
    * Creates a non-optimizing BlockBuilder.
@@ -111,13 +111,13 @@ public class BlockBuilder {
     }
     Expression result = null;
     final Map<ParameterExpression, Expression> replacements =
-        new IdentityHashMap<ParameterExpression, Expression>();
-    final Visitor visitor = new SubstituteVariableVisitor(replacements);
+        new IdentityHashMap<>();
+    final Shuttle shuttle = new SubstituteVariableVisitor(replacements);
     for (int i = 0; i < block.statements.size(); i++) {
       Statement statement = block.statements.get(i);
       if (!replacements.isEmpty()) {
         // Save effort, and only substitute variables if there are some.
-        statement = statement.accept(visitor);
+        statement = statement.accept(shuttle);
       }
       if (statement instanceof DeclarationStatement) {
         DeclarationStatement declaration = (DeclarationStatement) statement;
@@ -303,11 +303,11 @@ public class BlockBuilder {
       // loop. Optimize should not loop forever, however it is hard to prove if
       // it always finishes in reasonable time.
       for (int i = 0; i < 10; i++) {
-        if (!optimize(createOptimizeVisitor(), true)) {
+        if (!optimize(createOptimizeShuttle(), true)) {
           break;
         }
       }
-      optimize(createFinishingOptimizeVisitor(), false);
+      optimize(createFinishingOptimizeShuttle(), false);
     }
     return Expressions.block(statements);
   }
@@ -318,7 +318,7 @@ public class BlockBuilder {
    *
    * @return whether any optimizations were made
    */
-  private boolean optimize(Visitor optimizer, boolean performInline) {
+  private boolean optimize(Shuttle optimizer, boolean performInline) {
     int optimizeCount = 0;
     final UseCounter useCounter = new UseCounter();
     for (Statement statement : statements) {
@@ -334,12 +334,10 @@ public class BlockBuilder {
       }
     }
     final Map<ParameterExpression, Expression> subMap =
-        new IdentityHashMap<ParameterExpression, Expression>(
-            useCounter.map.size());
+        new IdentityHashMap<>(useCounter.map.size());
     final SubstituteVariableVisitor visitor = new SubstituteVariableVisitor(
         subMap);
-    final ArrayList<Statement> oldStatements = new ArrayList<Statement>(
-        statements);
+    final ArrayList<Statement> oldStatements = new ArrayList<>(statements);
     statements.clear();
 
     for (Statement oldStatement : oldStatements) {
@@ -400,10 +398,10 @@ public class BlockBuilder {
               DeclarationStatement newDecl =
                   (DeclarationStatement) oldStatement;
               subMap.put(newDecl.parameter, normalizeDeclaration(newDecl));
-              oldStatement = OptimizeVisitor.EMPTY_STATEMENT;
+              oldStatement = OptimizeShuttle.EMPTY_STATEMENT;
             }
           }
-          if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
+          if (oldStatement != OptimizeShuttle.EMPTY_STATEMENT) {
             if (oldStatement instanceof DeclarationStatement) {
               addExpressionForReuse((DeclarationStatement) oldStatement);
             }
@@ -420,7 +418,7 @@ public class BlockBuilder {
         if (beforeOptimize != oldStatement) {
           ++optimizeCount;
         }
-        if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
+        if (oldStatement != OptimizeShuttle.EMPTY_STATEMENT) {
           statements.add(oldStatement);
         }
       }
@@ -429,23 +427,23 @@ public class BlockBuilder {
   }
 
   /**
-   * Creates a visitor that will be used during block optimization.
-   * Subclasses might provide more specific optimizations (e.g. partial
+   * Creates a shuttle that will be used during block optimization.
+   * Sub-classes might provide more specific optimizations (e.g. partial
    * evaluation).
    *
-   * @return visitor used to optimize the statements when converting to block
+   * @return shuttle used to optimize the statements when converting to block
    */
-  protected Visitor createOptimizeVisitor() {
-    return OPTIMIZE_VISITOR;
+  protected Shuttle createOptimizeShuttle() {
+    return OPTIMIZE_SHUTTLE;
   }
 
   /**
-   * Creates a final optimization visitor.
+   * Creates a final optimization shuttle.
    * Typically, the visitor will factor out constant expressions.
    *
-   * @return visitor that is used to finalize the optimization
+   * @return shuttle that is used to finalize the optimization
    */
-  protected Visitor createFinishingOptimizeVisitor() {
+  protected Shuttle createFinishingOptimizeShuttle() {
     return ClassDeclarationFinder.create();
   }
 
@@ -484,10 +482,10 @@ public class BlockBuilder {
   }
 
   /** Substitute Variable Visitor. */
-  private static class SubstituteVariableVisitor extends Visitor {
+  private static class SubstituteVariableVisitor extends Shuttle {
     private final Map<ParameterExpression, Expression> map;
     private final Map<ParameterExpression, Boolean> actives =
-        new IdentityHashMap<ParameterExpression, Boolean>();
+        new IdentityHashMap<>();
 
     public SubstituteVariableVisitor(Map<ParameterExpression, Expression> map) {
       this.map = map;
@@ -544,11 +542,10 @@ public class BlockBuilder {
   }
 
   /** Use counter. */
-  private static class UseCounter extends Visitor {
-    private final Map<ParameterExpression, Slot> map =
-        new IdentityHashMap<ParameterExpression, Slot>();
+  private static class UseCounter extends VisitorImpl<Void> {
+    private final Map<ParameterExpression, Slot> map = new IdentityHashMap<>();
 
-    @Override public Expression visit(ParameterExpression parameter) {
+    @Override public Void visit(ParameterExpression parameter) {
       final Slot slot = map.get(parameter);
       if (slot != null) {
         // Count use of parameter, if it's registered. It's OK if
@@ -558,6 +555,14 @@ public class BlockBuilder {
       }
       return super.visit(parameter);
     }
+
+    @Override public Void visit(DeclarationStatement declarationStatement) {
+      // Unlike base class, do not visit declarationStatement.parameter.
+      if (declarationStatement.initializer != null) {
+        declarationStatement.initializer.accept(this);
+      }
+      return null;
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
index 26a8c09..54e62e4 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/BlockStatement.java
@@ -54,11 +54,15 @@ public class BlockStatement extends Statement {
     return true;
   }
 
-  @Override public BlockStatement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public BlockStatement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     List<Statement> newStatements = Expressions.acceptStatements(statements,
-        visitor);
-    return visitor.visit(this, newStatements);
+        shuttle);
+    return shuttle.visit(this, newStatements);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
index 172112f..424ce54 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclaration.java
@@ -59,11 +59,15 @@ public class ClassDeclaration extends MemberDeclaration {
     writer.newlineAndIndent();
   }
 
-  public ClassDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  public ClassDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     final List<MemberDeclaration> members1 =
-        Expressions.acceptMemberDeclarations(memberDeclarations, visitor);
-    return visitor.visit(this, members1);
+        Expressions.acceptMemberDeclarations(memberDeclarations, shuttle);
+    return shuttle.visit(this, members1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override public boolean equals(Object o) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
index 2388538..3af0fe6 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ClassDeclarationFinder.java
@@ -29,7 +29,7 @@ import java.util.List;
  * Instances of this class should not be reused, so new visitor should be
  * created for optimizing a new expression tree.
  */
-public class ClassDeclarationFinder extends Visitor {
+public class ClassDeclarationFinder extends Shuttle {
   protected final ClassDeclarationFinder parent;
 
   /**
@@ -144,7 +144,7 @@ public class ClassDeclarationFinder extends Visitor {
    * @param newExpression expression to optimize
    * @return nested visitor if anonymous class is given
    */
-  @Override public Visitor preVisit(NewExpression newExpression) {
+  @Override public Shuttle preVisit(NewExpression newExpression) {
     if (newExpression.memberDeclarations == null) {
       return this;
     }
@@ -159,7 +159,7 @@ public class ClassDeclarationFinder extends Visitor {
    * @param classDeclaration expression to optimize
    * @return nested visitor
    */
-  @Override public Visitor preVisit(ClassDeclaration classDeclaration) {
+  @Override public Shuttle preVisit(ClassDeclaration classDeclaration) {
     ClassDeclarationFinder visitor = goDeeper();
     visitor.learnFinalStaticDeclarations(classDeclaration.memberDeclarations);
     return visitor;
@@ -228,7 +228,7 @@ public class ClassDeclarationFinder extends Visitor {
       return memberDeclarations;
     }
     List<MemberDeclaration> newDecls =
-        new ArrayList<MemberDeclaration>(memberDeclarations.size()
+        new ArrayList<>(memberDeclarations.size()
             + addedDeclarations.size());
     newDecls.addAll(memberDeclarations);
     newDecls.addAll(addedDeclarations);

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
index 6491aa0..1b49a81 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalExpression.java
@@ -33,7 +33,7 @@ import java.util.Objects;
  * </p>
  */
 public class ConditionalExpression extends AbstractNode {
-  private final List<Node> expressionList;
+  final List<Node> expressionList;
 
   public ConditionalExpression(List<Node> expressionList, Type type) {
     super(ExpressionType.Conditional, type);
@@ -41,6 +41,10 @@ public class ConditionalExpression extends AbstractNode {
     this.expressionList = expressionList;
   }
 
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
+  }
+
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {
     for (int i = 0; i < expressionList.size(); i += 2) {
       writer.append(i > 0 ? " else if (" : "if (")

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
index 2334557..64e54d4 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConditionalStatement.java
@@ -40,10 +40,14 @@ public class ConditionalStatement extends Statement {
     this.expressionList = expressionList;
   }
 
-  @Override public Statement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    List<Node> list = Expressions.acceptNodes(expressionList, visitor);
-    return visitor.visit(this, list);
+  @Override public Statement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    List<Node> list = Expressions.acceptNodes(expressionList, shuttle);
+    return shuttle.visit(this, list);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
index 52c6975..3fc112b 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
@@ -58,7 +58,11 @@ public class ConstantExpression extends Expression {
     return value;
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
index 471357d..1aa28b4 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
@@ -48,11 +48,15 @@ public class ConstructorDeclaration extends MemberDeclaration {
     this.body = body;
   }
 
-  @Override public MemberDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public MemberDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameters
-    final BlockStatement body = this.body.accept(visitor);
-    return visitor.visit(this, body);
+    final BlockStatement body = this.body.accept(shuttle);
+    return shuttle.visit(this, body);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public void accept(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
index f835d1e..c080c84 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DeclarationStatement.java
@@ -36,13 +36,17 @@ public class DeclarationStatement extends Statement {
     this.initializer = initializer;
   }
 
-  @Override public DeclarationStatement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public DeclarationStatement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameter - visit may not return a ParameterExpression
     Expression initializer = this.initializer != null
-        ? this.initializer.accept(visitor)
+        ? this.initializer.accept(shuttle)
         : null;
-    return visitor.visit(this, initializer);
+    return shuttle.visit(this, initializer);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
index 8569528..c78847d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DefaultExpression.java
@@ -24,9 +24,14 @@ public class DefaultExpression extends Expression {
     super(ExpressionType.Default, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End DefaultExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
index ff03001..f9c7c4f 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/DynamicExpression.java
@@ -24,9 +24,14 @@ public class DynamicExpression extends Expression {
     super(ExpressionType.Dynamic, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End DynamicExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
index 4c3427b..ff5f38f 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expression.java
@@ -41,7 +41,7 @@ public abstract class Expression extends AbstractNode {
   }
 
   @Override // More specific return type.
-  public abstract Expression accept(Visitor visitor);
+  public abstract Expression accept(Shuttle shuttle);
 
   /**
    * Indicates that the node can be reduced to a simpler node. If this

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
index fae932e..0651024 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java
@@ -3090,28 +3090,28 @@ public abstract class Expressions {
     return toCollection(iterable).toArray(a);
   }
 
-  static <T extends Expression> Expression accept(T node, Visitor visitor) {
+  static <T extends Expression> Expression accept(T node, Shuttle shuttle) {
     if (node == null) {
       return null;
     }
-    return node.accept(visitor);
+    return node.accept(shuttle);
   }
 
-  static <T extends Statement> Statement accept(T node, Visitor visitor) {
+  static <T extends Statement> Statement accept(T node, Shuttle shuttle) {
     if (node == null) {
       return null;
     }
-    return node.accept(visitor);
+    return node.accept(shuttle);
   }
 
   static List<Statement> acceptStatements(List<Statement> statements,
-      Visitor visitor) {
+      Shuttle shuttle) {
     if (statements.isEmpty()) {
       return statements; // short cut
     }
     final List<Statement> statements1 = new ArrayList<Statement>();
     for (Statement statement : statements) {
-      Statement newStatement = statement.accept(visitor);
+      Statement newStatement = statement.accept(shuttle);
       if (newStatement instanceof GotoStatement) {
         GotoStatement goto_ = (GotoStatement) newStatement;
         if (goto_.kind == GotoExpressionKind.Sequence
@@ -3125,67 +3125,77 @@ public abstract class Expressions {
     return statements1;
   }
 
-  static List<Node> acceptNodes(List<Node> nodes, Visitor visitor) {
+  static List<Node> acceptNodes(List<Node> nodes, Shuttle shuttle) {
     if (nodes.isEmpty()) {
       return nodes; // short cut
     }
     final List<Node> statements1 = new ArrayList<Node>();
     for (Node node : nodes) {
-      statements1.add(node.accept(visitor));
+      statements1.add(node.accept(shuttle));
     }
     return statements1;
   }
 
   static List<Expression> acceptParameterExpressions(
-      List<ParameterExpression> parameterExpressions, Visitor visitor) {
+      List<ParameterExpression> parameterExpressions, Shuttle shuttle) {
     if (parameterExpressions.isEmpty()) {
       return Collections.emptyList(); // short cut
     }
     final List<Expression> parameterExpressions1 = new ArrayList<Expression>();
     for (ParameterExpression parameterExpression : parameterExpressions) {
-      parameterExpressions1.add(parameterExpression.accept(visitor));
+      parameterExpressions1.add(parameterExpression.accept(shuttle));
     }
     return parameterExpressions1;
   }
 
   static List<DeclarationStatement> acceptDeclarations(
-      List<DeclarationStatement> declarations, Visitor visitor) {
+      List<DeclarationStatement> declarations, Shuttle shuttle) {
     if (declarations == null || declarations.isEmpty()) {
       return declarations; // short cut
     }
     final List<DeclarationStatement> declarations1 =
         new ArrayList<DeclarationStatement>();
     for (DeclarationStatement declaration : declarations) {
-      declarations1.add(declaration.accept(visitor));
+      declarations1.add(declaration.accept(shuttle));
     }
     return declarations1;
   }
 
   static List<MemberDeclaration> acceptMemberDeclarations(
-      List<MemberDeclaration> memberDeclarations, Visitor visitor) {
+      List<MemberDeclaration> memberDeclarations, Shuttle shuttle) {
     if (memberDeclarations == null || memberDeclarations.isEmpty()) {
       return memberDeclarations; // short cut
     }
     final List<MemberDeclaration> memberDeclarations1 =
         new ArrayList<MemberDeclaration>();
     for (MemberDeclaration memberDeclaration : memberDeclarations) {
-      memberDeclarations1.add(memberDeclaration.accept(visitor));
+      memberDeclarations1.add(memberDeclaration.accept(shuttle));
     }
     return memberDeclarations1;
   }
 
   static List<Expression> acceptExpressions(List<Expression> expressions,
-      Visitor visitor) {
+      Shuttle shuttle) {
     if (expressions.isEmpty()) {
       return expressions; // short cut
     }
-    final List<Expression> expressions1 = new ArrayList<Expression>();
+    final List<Expression> expressions1 = new ArrayList<>();
     for (Expression expression : expressions) {
-      expressions1.add(expression.accept(visitor));
+      expressions1.add(expression.accept(shuttle));
     }
     return expressions1;
   }
 
+  static <R> R acceptNodes(List<? extends Node> nodes, Visitor<R> visitor) {
+    R r = null;
+    if (nodes != null) {
+      for (Node node : nodes) {
+        r = node.accept(visitor);
+      }
+    }
+    return r;
+  }
+
   // ~ Classes and interfaces ------------------------------------------------
 
   // Some interfaces we'd rather not implement yet. They don't seem relevant

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
index 2a8db07..29ea7a7 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FieldDeclaration.java
@@ -35,12 +35,16 @@ public class FieldDeclaration extends MemberDeclaration {
     this.initializer = initializer;
   }
 
-  @Override public MemberDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public MemberDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameter - visit may not return a ParameterExpression
     final Expression initializer =
-        this.initializer == null ? null : this.initializer.accept(visitor);
-    return visitor.visit(this, initializer);
+        this.initializer == null ? null : this.initializer.accept(shuttle);
+    return shuttle.visit(this, initializer);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public void accept(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
index e8a9fba..d39809b 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ForStatement.java
@@ -45,15 +45,19 @@ public class ForStatement extends Statement {
     this.body = body; // may be empty block, not null
   }
 
-  @Override public ForStatement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public ForStatement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     List<DeclarationStatement> decls1 =
-        Expressions.acceptDeclarations(declarations, visitor);
+        Expressions.acceptDeclarations(declarations, shuttle);
     final Expression condition1 =
-        condition == null ? null : condition.accept(visitor);
-    final Expression post1 = post == null ? null : post.accept(visitor);
-    final Statement body1 = body.accept(visitor);
-    return visitor.visit(this, decls1, condition1, post1, body1);
+        condition == null ? null : condition.accept(shuttle);
+    final Expression post1 = post == null ? null : post.accept(shuttle);
+    final Statement body1 = body.accept(shuttle);
+    return shuttle.visit(this, decls1, condition1, post1, body1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
index 4bbc99b..14c67ca 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/FunctionExpression.java
@@ -68,10 +68,14 @@ public final class FunctionExpression<F extends Function<?>>
     this(type, null, body, parameters);
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    BlockStatement body = this.body.accept(visitor);
-    return visitor.visit(this, body);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    BlockStatement body = this.body.accept(shuttle);
+    return shuttle.visit(this, body);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public Invokable compile() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
index 239f0e5..ff5582a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/GotoStatement.java
@@ -54,11 +54,15 @@ public class GotoStatement extends Statement {
     }
   }
 
-  @Override public Statement accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Statement accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     Expression expression1 =
-        expression == null ? null : expression.accept(visitor);
-    return visitor.visit(this, expression1);
+        expression == null ? null : expression.accept(shuttle);
+    return shuttle.visit(this, expression1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept0(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
index 9c7eb61..10e8463 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/IndexExpression.java
@@ -35,14 +35,17 @@ public class IndexExpression extends Expression {
     this.indexExpressions = indexExpressions;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
-    Expression array = this.array.accept(visitor);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
+    Expression array = this.array.accept(shuttle);
     List<Expression> indexExpressions = Expressions.acceptExpressions(
-        this.indexExpressions, visitor);
-    return visitor.visit(this, array, indexExpressions);
+        this.indexExpressions, shuttle);
+    return shuttle.visit(this, array, indexExpressions);
   }
 
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
+  }
 
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {
     array.accept(writer, lprec, nodeType.lprec);

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
index 666ab07..140c20d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/InvocationExpression.java
@@ -25,9 +25,14 @@ public class InvocationExpression extends Expression {
     super(nodeType, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End InvocationExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
index 15b6f44..4d23339 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LabelStatement.java
@@ -33,7 +33,11 @@ public class LabelStatement extends Statement {
     this.defaultValue = defaultValue;
   }
 
-  @Override public LabelStatement accept(Visitor visitor) {
+  @Override public LabelStatement accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
index d406e8f..6fbf61c 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/LambdaExpression.java
@@ -25,9 +25,14 @@ public class LambdaExpression extends Expression {
     super(nodeType, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End LambdaExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
index bf22c11..daf289a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ListInitExpression.java
@@ -24,9 +24,14 @@ public class ListInitExpression extends Expression {
     super(nodeType, type);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End ListInitExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
index c3c10b4..b553f7a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberDeclaration.java
@@ -20,7 +20,7 @@ package org.apache.calcite.linq4j.tree;
  * Declaration of a member of a class.
  */
 public abstract class MemberDeclaration implements Node {
-  public abstract MemberDeclaration accept(Visitor visitor);
+  public abstract MemberDeclaration accept(Shuttle shuttle);
 }
 
 // End MemberDeclaration.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
index 9947c10..5e0c72d 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberExpression.java
@@ -40,12 +40,16 @@ public class MemberExpression extends Expression {
     this.field = field;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     Expression expression1 = expression == null
         ? null
-        : expression.accept(visitor);
-    return visitor.visit(this, expression1);
+        : expression.accept(shuttle);
+    return shuttle.visit(this, expression1);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public Object evaluate(Evaluator evaluator) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
index 79b4c46..5becd3c 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MemberInitExpression.java
@@ -25,9 +25,14 @@ public class MemberInitExpression extends Expression {
     super(ExpressionType.MemberInit, Void.TYPE);
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
+
 }
 
 // End MemberInitExpression.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
index 7b63a00..bd3cd91 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodCallExpression.java
@@ -53,13 +53,17 @@ public class MethodCallExpression extends Expression {
     this(method.getGenericReturnType(), method, targetExpression, expressions);
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     Expression targetExpression = Expressions.accept(this.targetExpression,
-        visitor);
+        shuttle);
     List<Expression> expressions = Expressions.acceptExpressions(
-        this.expressions, visitor);
-    return visitor.visit(this, targetExpression, expressions);
+        this.expressions, shuttle);
+    return shuttle.visit(this, targetExpression, expressions);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override public Object evaluate(Evaluator evaluator) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
index b279434..800f387 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
@@ -47,11 +47,15 @@ public class MethodDeclaration extends MemberDeclaration {
     this.body = body;
   }
 
-  @Override public MemberDeclaration accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public MemberDeclaration accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     // do not visit parameters
-    final BlockStatement body = this.body.accept(visitor);
-    return visitor.visit(this, body);
+    final BlockStatement body = this.body.accept(shuttle);
+    return shuttle.visit(this, body);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   public void accept(ExpressionWriter writer) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
index 13670ae..36e64c0 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewArrayExpression.java
@@ -41,14 +41,18 @@ public class NewArrayExpression extends Expression {
     this.expressions = expressions;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     List<Expression> expressions =
         this.expressions == null
             ? null
-            : Expressions.acceptExpressions(this.expressions, visitor);
-    Expression bound = Expressions.accept(this.bound, visitor);
-    return visitor.visit(this, dimension, bound, expressions);
+            : Expressions.acceptExpressions(this.expressions, shuttle);
+    Expression bound = Expressions.accept(this.bound, shuttle);
+    return shuttle.visit(this, dimension, bound, expressions);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
index e4ca7ea..0c168a3 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/NewExpression.java
@@ -43,13 +43,17 @@ public class NewExpression extends Expression {
     this.memberDeclarations = memberDeclarations;
   }
 
-  @Override public Expression accept(Visitor visitor) {
-    visitor = visitor.preVisit(this);
+  @Override public Expression accept(Shuttle shuttle) {
+    shuttle = shuttle.preVisit(this);
     final List<Expression> arguments = Expressions.acceptExpressions(
-        this.arguments, visitor);
+        this.arguments, shuttle);
     final List<MemberDeclaration> memberDeclarations =
-        Expressions.acceptMemberDeclarations(this.memberDeclarations, visitor);
-    return visitor.visit(this, arguments, memberDeclarations);
+        Expressions.acceptMemberDeclarations(this.memberDeclarations, shuttle);
+    return shuttle.visit(this, arguments, memberDeclarations);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
+    return visitor.visit(this);
   }
 
   @Override void accept(ExpressionWriter writer, int lprec, int rprec) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
index 7c04f08..560f66a 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Node.java
@@ -20,7 +20,9 @@ package org.apache.calcite.linq4j.tree;
  * <p>Parse tree node.</p>
  */
 public interface Node {
-  Node accept(Visitor visitor);
+  <R> R accept(Visitor<R> visitor);
+
+  Node accept(Shuttle shuttle);
 
   void accept(ExpressionWriter expressionWriter);
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java
new file mode 100644
index 0000000..fa90a4c
--- /dev/null
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeShuttle.java
@@ -0,0 +1,422 @@
+/*
+ * 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.calcite.linq4j.tree;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.calcite.linq4j.tree.ExpressionType.Equal;
+import static org.apache.calcite.linq4j.tree.ExpressionType.NotEqual;
+
+/**
+ * Shuttle that optimizes expressions.
+ *
+ * <p>The optimizations are essential, not mere tweaks. Without
+ * optimization, expressions such as {@code false == null} will be left in,
+ * which are invalid to Janino (because it does not automatically box
+ * primitives).
+ */
+public class OptimizeShuttle extends Shuttle {
+  public static final ConstantExpression FALSE_EXPR =
+      Expressions.constant(false);
+  public static final ConstantExpression TRUE_EXPR =
+      Expressions.constant(true);
+  public static final MemberExpression BOXED_FALSE_EXPR =
+      Expressions.field(null, Boolean.class, "FALSE");
+  public static final MemberExpression BOXED_TRUE_EXPR =
+      Expressions.field(null, Boolean.class, "TRUE");
+  public static final Statement EMPTY_STATEMENT = Expressions.statement(null);
+
+  private static final Set<Method> KNOWN_NON_NULL_METHODS = new HashSet<>();
+
+  static {
+    for (Class aClass : new Class[]{Boolean.class, Byte.class, Short.class,
+      Integer.class, Long.class, String.class}) {
+      for (Method method : aClass.getMethods()) {
+        if ("valueOf".equals(method.getName())
+            && Modifier.isStatic(method.getModifiers())) {
+          KNOWN_NON_NULL_METHODS.add(method);
+        }
+      }
+    }
+  }
+
+  private static final
+  Map<ExpressionType, ExpressionType> NOT_BINARY_COMPLEMENT =
+      new EnumMap<>(ExpressionType.class);
+
+  static {
+    addComplement(ExpressionType.Equal, ExpressionType.NotEqual);
+    addComplement(ExpressionType.GreaterThanOrEqual, ExpressionType.LessThan);
+    addComplement(ExpressionType.GreaterThan, ExpressionType.LessThanOrEqual);
+  }
+
+  private static void addComplement(ExpressionType eq, ExpressionType ne) {
+    NOT_BINARY_COMPLEMENT.put(eq, ne);
+    NOT_BINARY_COMPLEMENT.put(ne, eq);
+  }
+
+  private static final Method BOOLEAN_VALUEOF_BOOL =
+      Types.lookupMethod(Boolean.class, "valueOf", boolean.class);
+
+  @Override public Expression visit(
+      TernaryExpression ternary,
+      Expression expression0,
+      Expression expression1,
+      Expression expression2) {
+    switch (ternary.getNodeType()) {
+    case Conditional:
+      Boolean always = always(expression0);
+      if (always != null) {
+        // true ? y : z  ===  y
+        // false ? y : z  === z
+        return always
+            ? expression1
+            : expression2;
+      }
+      if (expression1.equals(expression2)) {
+        // a ? b : b   ===   b
+        return expression1;
+      }
+      // !a ? b : c == a ? c : b
+      if (expression0 instanceof UnaryExpression) {
+        UnaryExpression una = (UnaryExpression) expression0;
+        if (una.getNodeType() == ExpressionType.Not) {
+          return Expressions.makeTernary(ternary.getNodeType(),
+              una.expression, expression2, expression1);
+        }
+      }
+
+      // a ? true : b  === a || b
+      // a ? false : b === !a && b
+      always = always(expression1);
+      if (always != null && isKnownNotNull(expression2)) {
+        return (always
+                 ? Expressions.orElse(expression0, expression2)
+                 : Expressions.andAlso(Expressions.not(expression0),
+            expression2)).accept(this);
+      }
+
+      // a ? b : true  === !a || b
+      // a ? b : false === a && b
+      always = always(expression2);
+      if (always != null && isKnownNotNull(expression1)) {
+        return (always
+                 ? Expressions.orElse(Expressions.not(expression0),
+                    expression1)
+                 : Expressions.andAlso(expression0, expression1)).accept(this);
+      }
+
+      if (expression0 instanceof BinaryExpression
+          && (expression0.getNodeType() == ExpressionType.Equal
+              || expression0.getNodeType() == ExpressionType.NotEqual)) {
+        BinaryExpression cmp = (BinaryExpression) expression0;
+        Expression expr = null;
+        if (eq(cmp.expression0, expression2)
+            && eq(cmp.expression1, expression1)) {
+          // a == b ? b : a === a (hint: if a==b, then a == b ? a : a)
+          // a != b ? b : a === b (hint: if a==b, then a != b ? b : b)
+          expr = expression0.getNodeType() == ExpressionType.Equal
+              ? expression2 : expression1;
+        }
+        if (eq(cmp.expression0, expression1)
+            && eq(cmp.expression1, expression2)) {
+          // a == b ? a : b === b (hint: if a==b, then a == b ? b : b)
+          // a != b ? a : b === a (hint: if a==b, then a == b ? a : a)
+          expr = expression0.getNodeType() == ExpressionType.Equal
+              ? expression2 : expression1;
+        }
+        if (expr != null) {
+          return expr;
+        }
+      }
+    }
+    return super.visit(ternary, expression0, expression1, expression2);
+  }
+
+  @Override public Expression visit(
+      BinaryExpression binary,
+      Expression expression0,
+      Expression expression1) {
+    //
+    Expression result;
+    switch (binary.getNodeType()) {
+    case AndAlso:
+    case OrElse:
+      if (eq(expression0, expression1)) {
+        return expression0;
+      }
+    }
+    switch (binary.getNodeType()) {
+    case Equal:
+    case NotEqual:
+      if (eq(expression0, expression1)) {
+        return binary.getNodeType() == Equal ? TRUE_EXPR : FALSE_EXPR;
+      } else if (expression0 instanceof ConstantExpression && expression1
+        instanceof ConstantExpression) {
+        ConstantExpression c0 = (ConstantExpression) expression0;
+        ConstantExpression c1 = (ConstantExpression) expression1;
+        if (c0.getType() == c1.getType()
+            || !(Primitive.is(c0.getType()) || Primitive.is(c1.getType()))) {
+          return binary.getNodeType() == NotEqual ? TRUE_EXPR : FALSE_EXPR;
+        }
+      }
+      if (expression0 instanceof TernaryExpression
+          && expression0.getNodeType() == ExpressionType.Conditional) {
+        TernaryExpression ternary = (TernaryExpression) expression0;
+        Expression expr = null;
+        if (eq(ternary.expression1, expression1)) {
+          // (a ? b : c) == b === a || c == b
+          expr = Expressions.orElse(ternary.expression0,
+              Expressions.equal(ternary.expression2, expression1));
+        } else if (eq(ternary.expression2, expression1)) {
+          // (a ? b : c) == c === !a || b == c
+          expr = Expressions.orElse(Expressions.not(ternary.expression0),
+              Expressions.equal(ternary.expression1, expression1));
+        }
+        if (expr != null) {
+          if (binary.getNodeType() == ExpressionType.NotEqual) {
+            expr = Expressions.not(expr);
+          }
+          return expr.accept(this);
+        }
+      }
+      // drop down
+    case AndAlso:
+    case OrElse:
+      result = visit0(binary, expression0, expression1);
+      if (result != null) {
+        return result;
+      }
+      result = visit0(binary, expression1, expression0);
+      if (result != null) {
+        return result;
+      }
+    }
+    return super.visit(binary, expression0, expression1);
+  }
+
+  private Expression visit0(
+      BinaryExpression binary,
+      Expression expression0,
+      Expression expression1) {
+    Boolean always;
+    switch (binary.getNodeType()) {
+    case AndAlso:
+      always = always(expression0);
+      if (always != null) {
+        return always
+            ? expression1
+            : FALSE_EXPR;
+      }
+      break;
+    case OrElse:
+      always = always(expression0);
+      if (always != null) {
+        // true or x  --> true
+        // false or x --> x
+        return always
+            ? TRUE_EXPR
+            : expression1;
+      }
+      break;
+    case Equal:
+      if (isConstantNull(expression1)
+          && Primitive.is(expression0.getType())) {
+        return FALSE_EXPR;
+      }
+      // a == true  -> a
+      // a == false -> !a
+      always = always(expression0);
+      if (always != null) {
+        return always ? expression1 : Expressions.not(expression1);
+      }
+      break;
+    case NotEqual:
+      if (isConstantNull(expression1)
+          && Primitive.is(expression0.getType())) {
+        return TRUE_EXPR;
+      }
+      // a != true  -> !a
+      // a != false -> a
+      always = always(expression0);
+      if (always != null) {
+        return always ? Expressions.not(expression1) : expression1;
+      }
+      break;
+    }
+    return null;
+  }
+
+  @Override public Expression visit(UnaryExpression unaryExpression,
+      Expression expression) {
+    switch (unaryExpression.getNodeType()) {
+    case Convert:
+      if (expression.getType() == unaryExpression.getType()) {
+        return expression;
+      }
+      if (expression instanceof ConstantExpression) {
+        return Expressions.constant(((ConstantExpression) expression).value,
+            unaryExpression.getType());
+      }
+      break;
+    case Not:
+      Boolean always = always(expression);
+      if (always != null) {
+        return always ? FALSE_EXPR : TRUE_EXPR;
+      }
+      if (expression instanceof UnaryExpression) {
+        UnaryExpression arg = (UnaryExpression) expression;
+        if (arg.getNodeType() == ExpressionType.Not) {
+          return arg.expression;
+        }
+      }
+      if (expression instanceof BinaryExpression) {
+        BinaryExpression bin = (BinaryExpression) expression;
+        ExpressionType comp = NOT_BINARY_COMPLEMENT.get(bin.getNodeType());
+        if (comp != null) {
+          return Expressions.makeBinary(comp, bin.expression0, bin.expression1);
+        }
+      }
+    }
+    return super.visit(unaryExpression, expression);
+  }
+
+  @Override public Statement visit(ConditionalStatement conditionalStatement,
+      List<Node> list) {
+    // if (false) { <-- remove branch
+    // } if (true) { <-- stop here
+    // } else if (...)
+    // } else {...}
+    boolean optimal = true;
+    for (int i = 0; i < list.size() - 1 && optimal; i += 2) {
+      Boolean always = always((Expression) list.get(i));
+      if (always == null) {
+        continue;
+      }
+      if (i == 0 && always) {
+        // when the very first test is always true, just return its statement
+        return (Statement) list.get(1);
+      }
+      optimal = false;
+    }
+    if (optimal) {
+      // Nothing to optimize
+      return super.visit(conditionalStatement, list);
+    }
+    List<Node> newList = new ArrayList<>(list.size());
+    // Iterate over all the tests, except the latest "else"
+    for (int i = 0; i < list.size() - 1; i += 2) {
+      Expression test = (Expression) list.get(i);
+      Node stmt = list.get(i + 1);
+      Boolean always = always(test);
+      if (always == null) {
+        newList.add(test);
+        newList.add(stmt);
+        continue;
+      }
+      if (always) {
+        // No need to verify other tests
+        newList.add(stmt);
+        break;
+      }
+    }
+    // We might have dangling "else", however if we have just single item
+    // it means we have if (false) else if(false) else if (true) {...} code.
+    // Then we just return statement from true branch
+    if (list.size() == 1) {
+      return (Statement) list.get(0);
+    }
+    // Add "else" from original list
+    if (newList.size() % 2 == 0 && list.size() % 2 == 1) {
+      Node elseBlock = list.get(list.size() - 1);
+      if (newList.isEmpty()) {
+        return (Statement) elseBlock;
+      }
+      newList.add(elseBlock);
+    }
+    if (newList.isEmpty()) {
+      return EMPTY_STATEMENT;
+    }
+    return super.visit(conditionalStatement, newList);
+  }
+
+  @Override public Expression visit(MethodCallExpression methodCallExpression,
+      Expression targetExpression,
+      List<Expression> expressions) {
+    if (BOOLEAN_VALUEOF_BOOL.equals(methodCallExpression.method)) {
+      Boolean always = always(expressions.get(0));
+      if (always != null) {
+        return always ? TRUE_EXPR : FALSE_EXPR;
+      }
+    }
+    return super.visit(methodCallExpression, targetExpression, expressions);
+  }
+
+  private boolean isConstantNull(Expression expression) {
+    return expression instanceof ConstantExpression
+        && ((ConstantExpression) expression).value == null;
+  }
+
+  /**
+   * Returns whether an expression always evaluates to true or false.
+   * Assumes that expression has already been optimized.
+   */
+  private static Boolean always(Expression x) {
+    if (x.equals(FALSE_EXPR) || x.equals(BOXED_FALSE_EXPR)) {
+      return Boolean.FALSE;
+    }
+    if (x.equals(TRUE_EXPR) || x.equals(BOXED_TRUE_EXPR)) {
+      return Boolean.TRUE;
+    }
+    return null;
+  }
+
+  /**
+   * Returns whether an expression always returns a non-null result.
+   * For instance, primitive types cannot contain null values.
+   *
+   * @param expression expression to test
+   * @return true when the expression is known to be not-null
+   */
+  protected boolean isKnownNotNull(Expression expression) {
+    return Primitive.is(expression.getType())
+        || always(expression) != null
+        || (expression instanceof MethodCallExpression
+            && KNOWN_NON_NULL_METHODS.contains(
+                ((MethodCallExpression) expression).method));
+  }
+
+  /**
+   * Treats two expressions equal even if they represent different null types
+   */
+  private static boolean eq(Expression a, Expression b) {
+    return a.equals(b)
+        || (a instanceof ConstantExpression
+            && b instanceof ConstantExpression
+            && ((ConstantExpression) a).value
+                == ((ConstantExpression) b).value);
+  }
+}
+
+// End OptimizeShuttle.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java
deleted file mode 100644
index f0bed0f..0000000
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/OptimizeVisitor.java
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * 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.calcite.linq4j.tree;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.EnumMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.apache.calcite.linq4j.tree.ExpressionType.Equal;
-import static org.apache.calcite.linq4j.tree.ExpressionType.NotEqual;
-
-/**
- * Visitor that optimizes expressions.
- *
- * <p>The optimizations are essential, not mere tweaks. Without
- * optimization, expressions such as {@code false == null} will be left in,
- * which are invalid to Janino (because it does not automatically box
- * primitives).</p>
- */
-public class OptimizeVisitor extends Visitor {
-  public static final ConstantExpression FALSE_EXPR =
-      Expressions.constant(false);
-  public static final ConstantExpression TRUE_EXPR =
-      Expressions.constant(true);
-  public static final MemberExpression BOXED_FALSE_EXPR =
-      Expressions.field(null, Boolean.class, "FALSE");
-  public static final MemberExpression BOXED_TRUE_EXPR =
-      Expressions.field(null, Boolean.class, "TRUE");
-  public static final Statement EMPTY_STATEMENT = Expressions.statement(null);
-
-  private static final Set<Method> KNOWN_NON_NULL_METHODS =
-      new HashSet<Method>();
-
-  static {
-    for (Class aClass : new Class[]{Boolean.class, Byte.class, Short.class,
-      Integer.class, Long.class, String.class}) {
-      for (Method method : aClass.getMethods()) {
-        if ("valueOf".equals(method.getName())
-            && Modifier.isStatic(method.getModifiers())) {
-          KNOWN_NON_NULL_METHODS.add(method);
-        }
-      }
-    }
-  }
-
-  private static final Map<ExpressionType, ExpressionType>
-  NOT_BINARY_COMPLEMENT =
-      new EnumMap<ExpressionType, ExpressionType>(ExpressionType.class);
-
-  static {
-    addComplement(ExpressionType.Equal, ExpressionType.NotEqual);
-    addComplement(ExpressionType.GreaterThanOrEqual, ExpressionType.LessThan);
-    addComplement(ExpressionType.GreaterThan, ExpressionType.LessThanOrEqual);
-  }
-
-  private static void addComplement(ExpressionType eq, ExpressionType ne) {
-    NOT_BINARY_COMPLEMENT.put(eq, ne);
-    NOT_BINARY_COMPLEMENT.put(ne, eq);
-  }
-
-  private static final Method BOOLEAN_VALUEOF_BOOL =
-      Types.lookupMethod(Boolean.class, "valueOf", boolean.class);
-
-  @Override public Expression visit(
-      TernaryExpression ternary,
-      Expression expression0,
-      Expression expression1,
-      Expression expression2) {
-    switch (ternary.getNodeType()) {
-    case Conditional:
-      Boolean always = always(expression0);
-      if (always != null) {
-        // true ? y : z  ===  y
-        // false ? y : z  === z
-        return always
-            ? expression1
-            : expression2;
-      }
-      if (expression1.equals(expression2)) {
-        // a ? b : b   ===   b
-        return expression1;
-      }
-      // !a ? b : c == a ? c : b
-      if (expression0 instanceof UnaryExpression) {
-        UnaryExpression una = (UnaryExpression) expression0;
-        if (una.getNodeType() == ExpressionType.Not) {
-          return Expressions.makeTernary(ternary.getNodeType(),
-              una.expression, expression2, expression1);
-        }
-      }
-
-      // a ? true : b  === a || b
-      // a ? false : b === !a && b
-      always = always(expression1);
-      if (always != null && isKnownNotNull(expression2)) {
-        return (always
-                 ? Expressions.orElse(expression0, expression2)
-                 : Expressions.andAlso(Expressions.not(expression0),
-            expression2)).accept(this);
-      }
-
-      // a ? b : true  === !a || b
-      // a ? b : false === a && b
-      always = always(expression2);
-      if (always != null && isKnownNotNull(expression1)) {
-        return (always
-                 ? Expressions.orElse(Expressions.not(expression0),
-                    expression1)
-                 : Expressions.andAlso(expression0, expression1)).accept(this);
-      }
-
-      if (expression0 instanceof BinaryExpression
-          && (expression0.getNodeType() == ExpressionType.Equal
-              || expression0.getNodeType() == ExpressionType.NotEqual)) {
-        BinaryExpression cmp = (BinaryExpression) expression0;
-        Expression expr = null;
-        if (eq(cmp.expression0, expression2)
-            && eq(cmp.expression1, expression1)) {
-          // a == b ? b : a === a (hint: if a==b, then a == b ? a : a)
-          // a != b ? b : a === b (hint: if a==b, then a != b ? b : b)
-          expr = expression0.getNodeType() == ExpressionType.Equal
-              ? expression2 : expression1;
-        }
-        if (eq(cmp.expression0, expression1)
-            && eq(cmp.expression1, expression2)) {
-          // a == b ? a : b === b (hint: if a==b, then a == b ? b : b)
-          // a != b ? a : b === a (hint: if a==b, then a == b ? a : a)
-          expr = expression0.getNodeType() == ExpressionType.Equal
-              ? expression2 : expression1;
-        }
-        if (expr != null) {
-          return expr;
-        }
-      }
-    }
-    return super.visit(ternary, expression0, expression1, expression2);
-  }
-
-  @Override public Expression visit(
-      BinaryExpression binary,
-      Expression expression0,
-      Expression expression1) {
-    //
-    Expression result;
-    switch (binary.getNodeType()) {
-    case AndAlso:
-    case OrElse:
-      if (eq(expression0, expression1)) {
-        return expression0;
-      }
-    }
-    switch (binary.getNodeType()) {
-    case Equal:
-    case NotEqual:
-      if (eq(expression0, expression1)) {
-        return binary.getNodeType() == Equal ? TRUE_EXPR : FALSE_EXPR;
-      } else if (expression0 instanceof ConstantExpression && expression1
-        instanceof ConstantExpression) {
-        ConstantExpression c0 = (ConstantExpression) expression0;
-        ConstantExpression c1 = (ConstantExpression) expression1;
-        if (c0.getType() == c1.getType()
-            || !(Primitive.is(c0.getType()) || Primitive.is(c1.getType()))) {
-          return binary.getNodeType() == NotEqual ? TRUE_EXPR : FALSE_EXPR;
-        }
-      }
-      if (expression0 instanceof TernaryExpression
-          && expression0.getNodeType() == ExpressionType.Conditional) {
-        TernaryExpression ternary = (TernaryExpression) expression0;
-        Expression expr = null;
-        if (eq(ternary.expression1, expression1)) {
-          // (a ? b : c) == b === a || c == b
-          expr = Expressions.orElse(ternary.expression0,
-              Expressions.equal(ternary.expression2, expression1));
-        } else if (eq(ternary.expression2, expression1)) {
-          // (a ? b : c) == c === !a || b == c
-          expr = Expressions.orElse(Expressions.not(ternary.expression0),
-              Expressions.equal(ternary.expression1, expression1));
-        }
-        if (expr != null) {
-          if (binary.getNodeType() == ExpressionType.NotEqual) {
-            expr = Expressions.not(expr);
-          }
-          return expr.accept(this);
-        }
-      }
-      // drop down
-    case AndAlso:
-    case OrElse:
-      result = visit0(binary, expression0, expression1);
-      if (result != null) {
-        return result;
-      }
-      result = visit0(binary, expression1, expression0);
-      if (result != null) {
-        return result;
-      }
-    }
-    return super.visit(binary, expression0, expression1);
-  }
-
-  private Expression visit0(
-      BinaryExpression binary,
-      Expression expression0,
-      Expression expression1) {
-    Boolean always;
-    switch (binary.getNodeType()) {
-    case AndAlso:
-      always = always(expression0);
-      if (always != null) {
-        return always
-            ? expression1
-            : FALSE_EXPR;
-      }
-      break;
-    case OrElse:
-      always = always(expression0);
-      if (always != null) {
-        // true or x  --> true
-        // false or x --> x
-        return always
-            ? TRUE_EXPR
-            : expression1;
-      }
-      break;
-    case Equal:
-      if (isConstantNull(expression1)
-          && Primitive.is(expression0.getType())) {
-        return FALSE_EXPR;
-      }
-      // a == true  -> a
-      // a == false -> !a
-      always = always(expression0);
-      if (always != null) {
-        return always ? expression1 : Expressions.not(expression1);
-      }
-      break;
-    case NotEqual:
-      if (isConstantNull(expression1)
-          && Primitive.is(expression0.getType())) {
-        return TRUE_EXPR;
-      }
-      // a != true  -> !a
-      // a != false -> a
-      always = always(expression0);
-      if (always != null) {
-        return always ? Expressions.not(expression1) : expression1;
-      }
-      break;
-    }
-    return null;
-  }
-
-  @Override public Expression visit(UnaryExpression unaryExpression,
-      Expression expression) {
-    switch (unaryExpression.getNodeType()) {
-    case Convert:
-      if (expression.getType() == unaryExpression.getType()) {
-        return expression;
-      }
-      if (expression instanceof ConstantExpression) {
-        return Expressions.constant(((ConstantExpression) expression).value,
-            unaryExpression.getType());
-      }
-      break;
-    case Not:
-      Boolean always = always(expression);
-      if (always != null) {
-        return always ? FALSE_EXPR : TRUE_EXPR;
-      }
-      if (expression instanceof UnaryExpression) {
-        UnaryExpression arg = (UnaryExpression) expression;
-        if (arg.getNodeType() == ExpressionType.Not) {
-          return arg.expression;
-        }
-      }
-      if (expression instanceof BinaryExpression) {
-        BinaryExpression bin = (BinaryExpression) expression;
-        ExpressionType comp = NOT_BINARY_COMPLEMENT.get(bin.getNodeType());
-        if (comp != null) {
-          return Expressions.makeBinary(comp, bin.expression0, bin.expression1);
-        }
-      }
-    }
-    return super.visit(unaryExpression, expression);
-  }
-
-  @Override public Statement visit(ConditionalStatement conditionalStatement,
-      List<Node> list) {
-    // if (false) { <-- remove branch
-    // } if (true) { <-- stop here
-    // } else if (...)
-    // } else {...}
-    boolean optimal = true;
-    for (int i = 0; i < list.size() - 1 && optimal; i += 2) {
-      Boolean always = always((Expression) list.get(i));
-      if (always == null) {
-        continue;
-      }
-      if (i == 0 && always) {
-        // when the very first test is always true, just return its statement
-        return (Statement) list.get(1);
-      }
-      optimal = false;
-    }
-    if (optimal) {
-      // Nothing to optimize
-      return super.visit(conditionalStatement, list);
-    }
-    List<Node> newList = new ArrayList<Node>(list.size());
-    // Iterate over all the tests, except the latest "else"
-    for (int i = 0; i < list.size() - 1; i += 2) {
-      Expression test = (Expression) list.get(i);
-      Node stmt = list.get(i + 1);
-      Boolean always = always(test);
-      if (always == null) {
-        newList.add(test);
-        newList.add(stmt);
-        continue;
-      }
-      if (always) {
-        // No need to verify other tests
-        newList.add(stmt);
-        break;
-      }
-    }
-    // We might have dangling "else", however if we have just single item
-    // it means we have if (false) else if(false) else if (true) {...} code.
-    // Then we just return statement from true branch
-    if (list.size() == 1) {
-      return (Statement) list.get(0);
-    }
-    // Add "else" from original list
-    if (newList.size() % 2 == 0 && list.size() % 2 == 1) {
-      Node elseBlock = list.get(list.size() - 1);
-      if (newList.isEmpty()) {
-        return (Statement) elseBlock;
-      }
-      newList.add(elseBlock);
-    }
-    if (newList.isEmpty()) {
-      return EMPTY_STATEMENT;
-    }
-    return super.visit(conditionalStatement, newList);
-  }
-
-  @Override public Expression visit(MethodCallExpression methodCallExpression,
-      Expression targetExpression,
-      List<Expression> expressions) {
-    if (BOOLEAN_VALUEOF_BOOL.equals(methodCallExpression.method)) {
-      Boolean always = always(expressions.get(0));
-      if (always != null) {
-        return always ? TRUE_EXPR : FALSE_EXPR;
-      }
-    }
-    return super.visit(methodCallExpression, targetExpression, expressions);
-  }
-
-  private boolean isConstantNull(Expression expression) {
-    return expression instanceof ConstantExpression
-        && ((ConstantExpression) expression).value == null;
-  }
-
-  /**
-   * Returns whether an expression always evaluates to true or false.
-   * Assumes that expression has already been optimized.
-   */
-  private static Boolean always(Expression x) {
-    if (x.equals(FALSE_EXPR) || x.equals(BOXED_FALSE_EXPR)) {
-      return Boolean.FALSE;
-    }
-    if (x.equals(TRUE_EXPR) || x.equals(BOXED_TRUE_EXPR)) {
-      return Boolean.TRUE;
-    }
-    return null;
-  }
-
-  /**
-   * Returns whether an expression always returns a non-null result.
-   * For instance, primitive types cannot contain null values.
-   *
-   * @param expression expression to test
-   * @return true when the expression is known to be not-null
-   */
-  protected boolean isKnownNotNull(Expression expression) {
-    return Primitive.is(expression.getType())
-        || always(expression) != null
-        || (expression instanceof MethodCallExpression
-            && KNOWN_NON_NULL_METHODS.contains(
-                ((MethodCallExpression) expression).method));
-  }
-
-  /**
-   * Treats two expressions equal even if they represent different null types
-   */
-  private static boolean eq(Expression a, Expression b) {
-    return a.equals(b)
-        || (a instanceof ConstantExpression
-            && b instanceof ConstantExpression
-            && ((ConstantExpression) a).value
-                == ((ConstantExpression) b).value);
-  }
-}
-
-// End OptimizeVisitor.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/267e2f3e/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
index a437a46..f883f50 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ParameterExpression.java
@@ -43,7 +43,11 @@ public class ParameterExpression extends Expression {
     this.name = name;
   }
 
-  @Override public Expression accept(Visitor visitor) {
+  @Override public Expression accept(Shuttle shuttle) {
+    return shuttle.visit(this);
+  }
+
+  public <R> R accept(Visitor<R> visitor) {
     return visitor.visit(this);
   }
 


Mime
View raw message