code: private GroovyExpression optimize(GroovyExpression source, GremlinOptimization optimization,
                                            OptimizationContext context) {
          GroovyExpression result = source;
          if (optimization.appliesTo(source, context)) {
              //Apply the optimization to the expression.
              result = optimization.apply(source, context);
          }
          if (optimization.isApplyRecursively()) {
              //Visit the children, update result with the optimized
              //children.
              List<GroovyExpression> updatedChildren = new ArrayList<>();
              boolean changed = false;
              for (GroovyExpression child : result.getChildren()) {
                  //Recursively optimize this child.
                  GroovyExpression updatedChild = optimize(child, optimization, context);
                  changed |= updatedChild != child;
                  updatedChildren.add(updatedChild);
              }
              if (changed) {
                  //TBD - Can we update in place rather than making a copy?
                  result = result.copy(updatedChildren);
              }
          }
          return result;
      }
docs: Optimizes the expression using the given optimization
  @param source
  @param optimization
  @param context
  @return