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

spmallette pushed a commit to branch gvalue
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 1eec10961d99e68f49c2393ac36e6a15507008d2
Author: Stephen Mallette <[email protected]>
AuthorDate: Wed Aug 7 15:06:28 2024 -0400

    wip
---
 .../grammar/DefaultGremlinBaseVisitor.java         |  12 +--
 .../language/grammar/TraversalMethodVisitor.java   | 100 ++++++++++--------
 .../grammar/TraversalSourceSpawnMethodVisitor.java |  15 ++-
 .../translator/DotNetTranslateVisitor.java         |  23 ++--
 .../language/translator/TranslateVisitor.java      |   5 -
 .../gremlin/process/traversal/Operator.java        |  10 +-
 .../traversal/dsl/graph/GraphTraversal.java        | 117 ++++++++++++++++++++-
 .../traversal/dsl/graph/GraphTraversalSource.java  |  32 +++++-
 .../gremlin/process/traversal/step/GValue.java     |   9 +-
 .../process/traversal/step/map/AddEdgeStep.java    |   9 +-
 .../process/traversal/step/map/CallStep.java       |  36 +++++--
 .../process/traversal/step/map/ConstantStep.java   |   2 +-
 .../process/traversal/step/map/DifferenceStep.java |  16 ++-
 .../process/traversal/step/map/DisjunctStep.java   |  12 ++-
 .../process/traversal/step/map/ProductStep.java    |  15 ++-
 .../traversal/step/map/TraversalMergeStep.java     |   3 +-
 .../traversal/step/sideEffect/InjectStep.java      |   2 +-
 .../strategy/decoration/SideEffectStrategy.java    |   7 +-
 gremlin-language/src/main/antlr4/Gremlin.g4        |   7 +-
 .../tinkerpop/gremlin/features/StepDefinition.java |  25 ++---
 20 files changed, 333 insertions(+), 124 deletions(-)

diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
index 3bfb22d17b..f32e40e44b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
@@ -414,11 +414,11 @@ public class DefaultGremlinBaseVisitor<T> extends 
AbstractParseTreeVisitor<T> im
        /**
         * {@inheritDoc}
         */
-       @Override public T visitTraversalMethod_from_Traversal(final 
GremlinParser.TraversalMethod_from_TraversalContext ctx) { notImplemented(ctx); 
return null; }
+       @Override public T visitTraversalMethod_from_Vertex(final 
GremlinParser.TraversalMethod_from_VertexContext ctx) { notImplemented(ctx); 
return null; }
        /**
         * {@inheritDoc}
         */
-       @Override public T visitTraversalMethod_from_Vertex(final 
GremlinParser.TraversalMethod_from_VertexContext ctx) { notImplemented(ctx); 
return null; }
+       @Override public T visitTraversalMethod_from_Traversal(final 
GremlinParser.TraversalMethod_from_TraversalContext ctx) { notImplemented(ctx); 
return null; }
        /**
         * {@inheritDoc}
         */
@@ -854,11 +854,11 @@ public class DefaultGremlinBaseVisitor<T> extends 
AbstractParseTreeVisitor<T> im
        /**
         * {@inheritDoc}
         */
-       @Override public T visitTraversalMethod_to_Traversal(final 
GremlinParser.TraversalMethod_to_TraversalContext ctx) { notImplemented(ctx); 
return null; }
+       @Override public T visitTraversalMethod_to_Vertex(final 
GremlinParser.TraversalMethod_to_VertexContext ctx) { notImplemented(ctx); 
return null; }
        /**
         * {@inheritDoc}
         */
-       @Override public T visitTraversalMethod_to_Vertex(final 
GremlinParser.TraversalMethod_to_VertexContext ctx) { notImplemented(ctx); 
return null; }
+       @Override public T visitTraversalMethod_to_Traversal(final 
GremlinParser.TraversalMethod_to_TraversalContext ctx) { notImplemented(ctx); 
return null; }
        /**
         * {@inheritDoc}
         */
@@ -1395,10 +1395,6 @@ public class DefaultGremlinBaseVisitor<T> extends 
AbstractParseTreeVisitor<T> im
         * {@inheritDoc}
         */
        @Override public T visitTraversalMethod_option_Merge_Map(final 
GremlinParser.TraversalMethod_option_Merge_MapContext ctx) { 
notImplemented(ctx); return null; }
-       /**
-        * {@inheritDoc}
-        */
-       @Override public T visitTraversalMethod_option_Merge_Traversal(final 
GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) { 
notImplemented(ctx); return null; }
        /**
         * {@inheritDoc}
         */
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index fe500e6210..daf72820d4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
@@ -25,14 +25,12 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
 import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality;
 
-import java.util.Collection;
 import java.util.Map;
 import java.util.function.BiFunction;
 
-import static 
org.apache.tinkerpop.gremlin.process.traversal.SackFunctions.Barrier.normSack;
-
 /**
  * Specific case of TraversalRootVisitor where all TraversalMethods returns
  * a GraphTraversal object.
@@ -535,7 +533,11 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_difference_Object(final 
GremlinParser.TraversalMethod_difference_ObjectContext ctx) {
-        return 
graphTraversal.difference(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType().isCollection())
+            return graphTraversal.difference((GValue<Object>) literalOrVar);
+        else
+            return graphTraversal.difference(literalOrVar);
     }
 
     /**
@@ -543,7 +545,11 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_disjunct_Object(final 
GremlinParser.TraversalMethod_disjunct_ObjectContext ctx) {
-        return 
graphTraversal.disjunct(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType().isCollection())
+            return graphTraversal.disjunct((GValue<Object>) literalOrVar);
+        else
+            return graphTraversal.disjunct(literalOrVar);
     }
 
     /**
@@ -640,8 +646,22 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      * {@inheritDoc}
      */
     @Override
-    public GraphTraversal visitTraversalMethod_from_String(final 
GremlinParser.TraversalMethod_from_StringContext ctx) {
-        return 
graphTraversal.from(antlr.argumentVisitor.parseString(ctx.stringArgument()));
+    public Traversal visitTraversalMethod_from_String(final 
GremlinParser.TraversalMethod_from_StringContext ctx) {
+        return 
graphTraversal.from(antlr.genericVisitor.parseString(ctx.stringLiteral()));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Traversal visitTraversalMethod_from_Vertex(final 
GremlinParser.TraversalMethod_from_VertexContext ctx) {
+        final Object literalOrVar = 
antlr.argumentVisitor.visitStructureVertexArgument(ctx.structureVertexArgument());
+        if (literalOrVar instanceof Vertex)
+            return graphTraversal.from((Vertex) literalOrVar);
+        else if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType() == GType.VERTEX)
+            return graphTraversal.from((GValue<Vertex>) literalOrVar);
+        else
+            throw new IllegalArgumentException("from argument must be a 
vertex");
     }
 
     /**
@@ -1162,15 +1182,6 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
             return 
graphTraversal.option(antlr.argumentVisitor.parseMerge(ctx.traversalMergeArgument()),
 (Map) literalOrVar);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public GraphTraversal visitTraversalMethod_option_Merge_Traversal(final 
GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
-        return 
this.graphTraversal.option(antlr.argumentVisitor.parseMerge(ctx.traversalMergeArgument()),
-                antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -1298,7 +1309,11 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_product_Object(final 
GremlinParser.TraversalMethod_product_ObjectContext ctx) {
-        return 
graphTraversal.product(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType().isCollection())
+            return graphTraversal.product((GValue<Object>) literalOrVar);
+        else
+            return graphTraversal.product(literalOrVar);
     }
 
     /**
@@ -1641,7 +1656,7 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_to_Direction_String(final 
GremlinParser.TraversalMethod_to_Direction_StringContext ctx) {
-        return 
graphTraversal.to(antlr.argumentVisitor.parseDirection(ctx.traversalDirectionArgument()),
+        return 
graphTraversal.to(TraversalEnumParser.parseTraversalDirectionFromContext(ctx.traversalDirection()),
                 
antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs()));
     }
 
@@ -1649,8 +1664,22 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      * {@inheritDoc}
      */
     @Override
-    public GraphTraversal visitTraversalMethod_to_String(final 
GremlinParser.TraversalMethod_to_StringContext ctx) {
-        return 
graphTraversal.to(antlr.argumentVisitor.parseString(ctx.stringArgument()));
+    public Traversal visitTraversalMethod_to_String(final 
GremlinParser.TraversalMethod_to_StringContext ctx) {
+        return 
graphTraversal.to(antlr.genericVisitor.parseString(ctx.stringLiteral()));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Traversal visitTraversalMethod_to_Vertex(final 
GremlinParser.TraversalMethod_to_VertexContext ctx) {
+        final Object literalOrVar = 
antlr.argumentVisitor.visitStructureVertexArgument(ctx.structureVertexArgument());
+        if (literalOrVar instanceof Vertex)
+            return graphTraversal.to((Vertex) literalOrVar);
+        else if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType() == GType.VERTEX)
+            return graphTraversal.to((GValue<Vertex>) literalOrVar);
+        else
+            throw new IllegalArgumentException("from argument must be a 
vertex");
     }
 
     /**
@@ -1789,22 +1818,6 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
                 antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Traversal visitTraversalMethod_from_Vertex(final 
GremlinParser.TraversalMethod_from_VertexContext ctx) {
-        return 
graphTraversal.from(antlr.argumentVisitor.parseVertex(ctx.structureVertexArgument()));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Traversal visitTraversalMethod_to_Vertex(final 
GremlinParser.TraversalMethod_to_VertexContext ctx) {
-        return 
graphTraversal.to(antlr.argumentVisitor.parseVertex(ctx.structureVertexArgument()));
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -1826,8 +1839,11 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public Traversal visitTraversalMethod_call_string_map(final 
GremlinParser.TraversalMethod_call_string_mapContext ctx) {
-        return 
graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
-                                   
antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType() == GType.MAP)
+            return 
graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), 
(GValue<Map>) literalOrVar);
+        else
+            return 
graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), 
(Map) literalOrVar);
     }
 
     /**
@@ -1844,9 +1860,11 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public Traversal visitTraversalMethod_call_string_map_traversal(final 
GremlinParser.TraversalMethod_call_string_map_traversalContext ctx) {
-        return 
graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
-                
antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument()),
-                antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType() == GType.MAP)
+            return 
graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), 
(GValue<Map>) literalOrVar, 
antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+        else
+            return 
graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), 
(Map) literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
     }
 
     /**
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
index 8e5ba3ded2..bedf28d487 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
@@ -177,8 +177,11 @@ public class TraversalSourceSpawnMethodVisitor extends 
DefaultGremlinBaseVisitor
      */
     @Override
     public GraphTraversal 
visitTraversalSourceSpawnMethod_call_string_map(final 
GremlinParser.TraversalSourceSpawnMethod_call_string_mapContext ctx) {
-        return 
this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
-                
antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType() == GType.MAP)
+            return 
this.traversalSource.asAdmin().call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
 (GValue<Map>) literalOrVar);
+        else
+            return 
this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
 (Map) literalOrVar);
     }
 
     /**
@@ -195,9 +198,11 @@ public class TraversalSourceSpawnMethodVisitor extends 
DefaultGremlinBaseVisitor
      */
     @Override
     public GraphTraversal 
visitTraversalSourceSpawnMethod_call_string_map_traversal(final 
GremlinParser.TraversalSourceSpawnMethod_call_string_map_traversalContext ctx) {
-        return 
this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
-                
antlr.argumentVisitor.parseMap(ctx.genericLiteralMapArgument()),
-                anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+        final Object literalOrVar = 
antlr.argumentVisitor.visitGenericLiteralMapArgument(ctx.genericLiteralMapArgument());
+        if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType() == GType.MAP)
+            return 
this.traversalSource.asAdmin().call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
 (GValue<Map>) literalOrVar, 
anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+        else
+            return 
this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()),
 (Map) literalOrVar, 
anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
     }
 
     /**
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
index 2701819624..f4607ae087 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
@@ -872,16 +872,19 @@ public class DotNetTranslateVisitor extends 
AbstractTranslateVisitor {
     }
 
     @Override
-    public Void visitTraversalMethod_option_Merge_Traversal(final 
GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
-        // call is ambiguous without an explicit cast
-        visit(ctx.getChild(0));
-        sb.append("(");
-        visit(ctx.traversalMergeArgument());
-        sb.append(", ");
-        sb.append("(ITraversal) ");
-        visit(ctx.nestedTraversal());
-        sb.append(")");
-        return null;
+    public Void visitTraversalMethod_option_Object_Traversal(final 
GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
+        if (ctx.genericLiteralArgument().genericLiteral().traversalMerge() != 
null) {
+            visit(ctx.getChild(0));
+            sb.append("(");
+            visit(ctx.genericLiteralArgument());
+            sb.append(", ");
+            sb.append("(ITraversal) ");
+            visit(ctx.nestedTraversal());
+            sb.append(")");
+            return null;
+        } else {
+            return super.visitTraversalMethod_option_Object_Traversal(ctx);
+        }
     }
 
     @Override
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
index 00a8523b45..553ae00be7 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/TranslateVisitor.java
@@ -902,11 +902,6 @@ public class TranslateVisitor extends 
AbstractParseTreeVisitor<Void> implements
         return visitChildren(ctx);
     }
 
-    @Override
-    public Void visitTraversalMethod_option_Merge_Traversal(final 
GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
-        return visitChildren(ctx);
-    }
-
     @Override
     public Void visitTraversalMethod_option_Object_Traversal(final 
GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
         return visitChildren(ctx);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java
index 5bb2c85b3a..2e2a2ee91d 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Operator.java
@@ -186,9 +186,13 @@ public enum Operator implements BinaryOperator<Object> {
 
             if (a instanceof Map && b instanceof Map)
                 ((Map<?,?>) a).putAll((Map) b);
-            else if (a instanceof Collection && a instanceof Collection)
-                ((Collection<?>) a).addAll((Collection) b);
-            else
+            else if (a instanceof Collection && a instanceof Collection) {
+                try {
+                    ((Collection<?>) a).addAll((Collection) b);
+                } catch (UnsupportedOperationException uoe) {
+                    uoe.printStackTrace();
+                }
+            } else
                 throw new IllegalArgumentException(String.format("Objects must 
be both of Map or Collection: a=%s b=%s",
                         a.getClass().getSimpleName(), 
b.getClass().getSimpleName()));
             return a;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 7967688a87..0a392fc334 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -550,6 +550,30 @@ public interface GraphTraversal<S, E> extends Traversal<S, 
E> {
             return this.asAdmin().addStep(new ConjoinStep<>(this.asAdmin(), 
delimiter));
         }
 
+        /**
+         * Calculates the difference between the list traverser and list 
argument.
+         *
+         * @return the traversal with an appended {@link DifferenceStep}.
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#difference-step";
 target="_blank">Reference Documentation - Difference Step</a>
+         * @since 3.7.1
+         */
+        public default GraphTraversal<S, Set<?>> difference(final 
GValue<Object> values) {
+            
this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.difference, values);
+            return this.asAdmin().addStep(new DifferenceStep<>(this.asAdmin(), 
values));
+        }
+
+        /**
+         * Calculates the disjunction between the list traverser and list 
argument.
+         *
+         * @return the traversal with an appended {@link DisjunctStep}.
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#disjunct-step";
 target="_blank">Reference Documentation - Disjunct Step</a>
+         * @since 3.7.3
+         */
+        public default GraphTraversal<S, Set<?>> disjunct(final GValue<Object> 
values) {
+            
this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.disjunct, values);
+            return this.asAdmin().addStep(new DisjunctStep<>(this.asAdmin(), 
values));
+        }
+
         /**
          * Calculates the intersection between the list traverser and list 
argument.
          *
@@ -567,13 +591,98 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
          *
          * @return the traversal with an appended {@link TraversalMergeStep}.
          * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#merge-step";
 target="_blank">Reference Documentation - Merge Step</a>
-         * @since 3.7.1
+         * @since 3.7.3
          */
         public default <E2> GraphTraversal<S, E2> merge(final GValue<Object> 
values) {
             this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.merge, 
values);
             return this.asAdmin().addStep(new 
TraversalMergeStep<>(this.asAdmin(), values));
         }
 
+        /**
+         * Calculates the cartesian product between the list traverser and 
list argument.
+         *
+         * @return the traversal with an appended {@link ProductStep}.
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#product-step";
 target="_blank">Reference Documentation - Product Step</a>
+         * @since 3.7.3
+         */
+        public default GraphTraversal<S, List<List<?>>> product(final 
GValue<Object> values) {
+            
this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.product, values);
+            return this.asAdmin().addStep(new ProductStep<>(this.asAdmin(), 
values));
+        }
+
+        /**
+         * When used as a modifier to {@link #addE(String)} this method 
specifies the traversal to use for selecting the
+         * incoming vertex of the newly added {@link Edge}.
+         *
+         * @param toVertex the vertex for selecting the incoming vertex
+         * @return the traversal with the modified {@link AddEdgeStep}
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step";
 target="_blank">Reference Documentation - From Step</a>
+         * @since 4.0.0
+         */
+        public default GraphTraversal<S, E> to(final GValue<Vertex> toVertex) {
+            final Step<?,?> prev = this.asAdmin().getEndStep();
+            if (!(prev instanceof FromToModulating))
+                throw new IllegalArgumentException(String.format(
+                        "The to() step cannot follow %s", 
prev.getClass().getSimpleName()));
+
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.to, 
toVertex);
+            ((FromToModulating) prev).addTo(__.constant(toVertex).asAdmin());
+            return this;
+        }
+
+        /**
+         * When used as a modifier to {@link #addE(String)} this method 
specifies the traversal to use for selecting the
+         * outgoing vertex of the newly added {@link Edge}.
+         *
+         * @param fromVertex the vertex for selecting the outgoing vertex
+         * @return the traversal with the modified {@link AddEdgeStep}
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step";
 target="_blank">Reference Documentation - From Step</a>
+         * @since 4.0.0
+         */
+        public default GraphTraversal<S, E> from(final GValue<Vertex> 
fromVertex) {
+            final Step<?,?> prev = this.asAdmin().getEndStep();
+            if (!(prev instanceof FromToModulating))
+                throw new IllegalArgumentException(String.format(
+                        "The from() step cannot follow %s", 
prev.getClass().getSimpleName()));
+
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.from, 
fromVertex);
+            ((FromToModulating) 
prev).addFrom(__.constant(fromVertex).asAdmin());
+            return this;
+        }
+
+        /**
+         * Perform the specified service call with the specified static 
parameters.
+         *
+         * @param service the name of the service call
+         * @param params static parameter map (no nested traversals)
+         * @return the traversal with an appended {@link CallStep}.
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#call-step"; 
target="_blank">Reference Documentation - Call Step</a>
+         * @since 4.0.0
+         */
+        default <E> GraphTraversal<S, E> call(final String service, final 
GValue<Map> params) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.call, 
service, params);
+            final CallStep<S,E> call = new CallStep<>(this.asAdmin(), false, 
service, params);
+            return this.asAdmin().addStep(call);
+        }
+        /**
+         * Perform the specified service call with both static and dynamic 
parameters produced by the specified child
+         * traversal. These parameters will be merged at execution time per 
the provider implementation. Reference
+         * implementation merges dynamic into static (dynamic will overwrite 
static).
+         *
+         * @param service the name of the service call
+         * @param params static parameter map (no nested traversals)
+         * @param childTraversal a traversal that will produce a Map of 
parameters for the service call when invoked.
+         * @return the traversal with an appended {@link CallStep}.
+         * @see <a 
href="http://tinkerpop.apache.org/docs/${project.version}/reference/#call-step"; 
target="_blank">Reference Documentation - Call Step</a>
+         * @since 4.0.0
+         */
+        default <E> GraphTraversal<S, E> call(final String service, final 
GValue<Map> params, final Traversal<?, Map<?,?>> childTraversal) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.call, 
service, params, childTraversal);
+            final CallStep<S,E> step = null == childTraversal ? new 
CallStep(this.asAdmin(), false, service, params) :
+                    new CallStep(this.asAdmin(), false, service, params, 
childTraversal.asAdmin());
+            return this.asAdmin().addStep(step);
+        }
+
         @Override
         public default <E2> GraphTraversal.Admin<S, E2> addStep(final Step<?, 
E2> step) {
             return (GraphTraversal.Admin<S, E2>) 
Traversal.Admin.super.addStep((Step) step);
@@ -2725,8 +2834,7 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
     public default GraphTraversal<S, E> hasId(final Object id, final Object... 
otherIds) {
         if (id instanceof P) {
             return this.hasId((P) id);
-        }
-        else {
+        } else {
             this.asAdmin().getBytecode().addStep(Symbols.hasId, id, otherIds);
 
             //using ArrayList given P.within() turns all arguments into lists
@@ -2737,8 +2845,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
                 // as ids are unrolled when it's in array, they should also be 
unrolled when it's a list.
                 // this also aligns with behavior of hasId() when it's pushed 
down to g.V() (TINKERPOP-2863)
                 ids.addAll((Collection<?>) id);
-            } else
+            } else {
                 ids.add(id);
+            }
 
             // unrolling ids from lists works cleaner with Collection too, as 
otherwise they will need to
             // be turned into array first
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index 0c0670a7ca..be9ec2d44e 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -638,6 +638,36 @@ public class GraphTraversalSource implements 
TraversalSource {
      */
     public class Admin {
 
+        /**
+         * Spawns a {@link GraphTraversal} starting with values produced by 
the specified service call with the specified
+         * static parameters.
+         *
+         * @param service the name of the service call
+         * @param params static parameter map (no nested traversals)
+         * @since 4.0.0
+         */
+        public <S> GraphTraversal<S, S> call(final String service, final 
GValue<Map> params) {
+            final GraphTraversalSource clone = 
GraphTraversalSource.this.clone();
+            clone.bytecode.addStep(GraphTraversal.Symbols.call, service, 
params);
+            final GraphTraversal.Admin<S, S> traversal = new 
DefaultGraphTraversal<>(clone);
+            return traversal.addStep(new CallStep<>(traversal, true, service, 
params));
+        }
+
+        /**
+         * Spawns a {@link GraphTraversal} starting with values produced by 
the specified service call with the specified
+         * static parameters.
+         *
+         * @param service the name of the service call
+         * @param params static parameter map (no nested traversals)
+         * @since 4.0.0
+         */
+        public <S> GraphTraversal<S, S> call(final String service, final 
GValue<Map> params, final Traversal<S, Map> childTraversal) {
+            final GraphTraversalSource clone = 
GraphTraversalSource.this.clone();
+            clone.bytecode.addStep(GraphTraversal.Symbols.call, service, 
params);
+            final GraphTraversal.Admin<S, S> traversal = new 
DefaultGraphTraversal<>(clone);
+            return traversal.addStep(new CallStep<>(traversal, true, service, 
params, childTraversal.asAdmin()));
+        }
+
         /**
          * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) 
style operation for an {@link Vertex} using a
          * {@code Map} as an argument. The {@code Map} represents search 
criteria and will match each of the supplied
@@ -645,7 +675,7 @@ public class GraphTraversalSource implements 
TraversalSource {
          * made it will use that search criteria to create the new {@link 
Vertex}.
          *
          * @param searchCreate This {@code Map} can have a key of {@link T} or 
a {@code String}.
-         * @since 3.6.0
+         * @since 4.0.0
          */
         public GraphTraversal<Vertex, Vertex> mergeV(final GValue<Map<Object, 
Object>> searchCreate) {
             final GraphTraversalSource clone = 
GraphTraversalSource.this.clone();
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
index e05a9e91f4..41caaea1a2 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -79,6 +79,13 @@ public class GValue<V> implements Cloneable, Serializable {
         return this.type;
     }
 
+    /**
+     * Determines if the value held is of a {@code null} value.
+     */
+    public boolean isNull() {
+        return this.value == null;
+    }
+
     /**
      * Gets the value.
      */
@@ -96,7 +103,7 @@ public class GValue<V> implements Cloneable, Serializable {
     public boolean equals(final Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-        GValue<?> gValue = (GValue<?>) o;
+        final GValue<?> gValue = (GValue<?>) o;
         return Objects.equals(name, gValue.name) && type == gValue.type && 
Objects.equals(value, gValue.value);
     }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
index 9dfa4ce754..82c7f3893b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
@@ -21,6 +21,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.map;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
 import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
@@ -113,7 +114,7 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
                     edgeLabel, e.getMessage()));
         }
 
-        if (!(theTo instanceof Vertex))
+        if (!(theTo instanceof Vertex) && (theTo instanceof GValue && 
((GValue) theTo).getType() != GType.VERTEX))
             throw new IllegalStateException(String.format(
                     "The value given to addE(%s).to() must resolve to a Vertex 
but %s was specified instead", edgeLabel,
                     null == theTo ? "null" : 
theTo.getClass().getSimpleName()));
@@ -127,13 +128,13 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
                     edgeLabel, e.getMessage()));
         }
 
-        if (!(theFrom instanceof Vertex))
+        if (!(theFrom instanceof Vertex) && (theFrom instanceof GValue && 
((GValue) theTo).getType() != GType.VERTEX))
             throw new IllegalStateException(String.format(
                     "The value given to addE(%s).to() must resolve to a Vertex 
but %s was specified instead", edgeLabel,
                     null == theFrom ? "null" : 
theFrom.getClass().getSimpleName()));
 
-        Vertex toVertex = (Vertex) theTo;
-        Vertex fromVertex = (Vertex) theFrom;
+        Vertex toVertex = theTo instanceof Vertex ? (Vertex) theTo : 
((GValue<Vertex>) theTo).get();
+        Vertex fromVertex = theFrom instanceof Vertex ? (Vertex) theFrom : 
((GValue<Vertex>) theFrom).get();
 
         if (toVertex instanceof Attachable)
             toVertex = ((Attachable<Vertex>) toVertex)
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
index 2435be373c..3dd99d1703 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java
@@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
@@ -62,7 +63,7 @@ public final class CallStep<S, E> extends AbstractStep<S, E> 
implements Traversa
     private ServiceCallContext ctx;
     private String serviceName;
     private Service<S, E> service;
-    private Map staticParams;
+    private GValue<Map> staticParams;
     private Traversal.Admin<S,Map> mapTraversal;
     private Parameters parameters;
 
@@ -74,20 +75,29 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
     }
 
     public CallStep(final Traversal.Admin traversal, final boolean isStart, 
final String service) {
-        this(traversal, isStart, service, null);
+        this(traversal, isStart, service, (Map) null);
     }
 
     public CallStep(final Traversal.Admin traversal, final boolean isStart, 
final String service, final Map staticParams) {
+        this(traversal, isStart, service, GValue.ofMap(staticParams));
+    }
+
+    public CallStep(final Traversal.Admin traversal, final boolean isStart, 
final String service, final GValue<Map> staticParams) {
         this(traversal, isStart, service, staticParams, null);
     }
 
     public CallStep(final Traversal.Admin traversal, final boolean isStart, 
final String service, final Map staticParams,
                     final Traversal.Admin<S, Map> mapTraversal) {
+        this(traversal, isStart, service, GValue.ofMap(staticParams), 
mapTraversal);
+    }
+
+    public CallStep(final Traversal.Admin traversal, final boolean isStart, 
final String service, final GValue<Map> staticParams,
+                    final Traversal.Admin<S, Map> mapTraversal) {
         super(traversal);
 
         this.isStart = isStart;
         this.serviceName = service;
-        this.staticParams = staticParams == null ? new LinkedHashMap() : 
staticParams;
+        this.staticParams = staticParams == null || staticParams.isNull() ? 
GValue.ofMap(staticParams.getName(), new LinkedHashMap()) : staticParams;
         this.mapTraversal = mapTraversal == null ? null : 
integrateChild(mapTraversal);
         this.parameters = new Parameters();
         this.ctx = new ServiceCallContext(traversal, this);
@@ -95,13 +105,17 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
 
     protected Service<S, E> service() {
         // throws exception for unrecognized service
-        return service != null ? service : (service = 
getServiceRegistry().get(serviceName, isStart, staticParams));
+        return service != null ? service : (service = 
getServiceRegistry().get(serviceName, isStart, staticParams.get()));
     }
 
     public String getServiceName() {
         return serviceName;
     }
 
+    public GValue<Map> getStaticParams() {
+        return staticParams;
+    }
+
     @Override
     protected Traverser.Admin<E> processNextStart() {
         if (isStart && first) {
@@ -199,7 +213,7 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
     public Map getMergedParams() {
         if (mapTraversal == null && parameters.isEmpty()) {
             // static params only
-            return Collections.unmodifiableMap(this.staticParams);
+            return Collections.unmodifiableMap(this.staticParams.get());
         }
 
         return getMergedParams(new 
DummyTraverser(this.traversal.getTraverserGenerator()));
@@ -208,11 +222,11 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
     protected Map getMergedParams(final Traverser.Admin<S> traverser) {
         if (mapTraversal == null && parameters.isEmpty()) {
             // static params only
-            return Collections.unmodifiableMap(this.staticParams);
+            return Collections.unmodifiableMap(this.staticParams.get());
         }
 
         // merge dynamic with static params
-        final Map params = new LinkedHashMap(this.staticParams);
+        final Map params = new LinkedHashMap(this.staticParams.get());
         if (mapTraversal != null) params.putAll(TraversalUtil.apply(traverser, 
mapTraversal));
         final Object[] kvs = this.parameters.getKeyValues(traverser);
         for (int i = 0; i < kvs.length; i += 2) {
@@ -225,7 +239,7 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
     protected Map getMergedParams(final TraverserSet<S> traverserSet) {
         if (mapTraversal == null && parameters.isEmpty()) {
             // static params only
-            return Collections.unmodifiableMap(this.staticParams);
+            return Collections.unmodifiableMap(this.staticParams.get());
         }
 
         /*
@@ -302,7 +316,7 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
     public String toString() {
         final ArrayList args = new ArrayList();
         args.add(serviceName);
-        if (!staticParams.isEmpty())
+        if (!staticParams.get().isEmpty())
             args.add(staticParams);
         if (mapTraversal != null)
             args.add(mapTraversal);
@@ -314,8 +328,8 @@ public final class CallStep<S, E> extends AbstractStep<S, 
E> implements Traversa
     @Override
     public int hashCode() {
         int hashCode = super.hashCode() ^ Objects.hashCode(this.serviceName);
-        if (!staticParams.isEmpty())
-            hashCode ^= staticParams.hashCode();
+        if (!staticParams.get().isEmpty())
+            hashCode ^= staticParams.get().hashCode();
         if (mapTraversal != null)
             hashCode ^= mapTraversal.hashCode();
         if (!parameters.isEmpty())
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
index 245a443e5a..2145f7e966 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
@@ -33,7 +33,7 @@ public class ConstantStep<S, E> extends ScalarMapStep<S, E> {
     private final GValue<E> constant;
 
     public ConstantStep(final Traversal.Admin traversal, final E constant) {
-        this(traversal, GValue.of(constant));
+        this(traversal, constant instanceof GValue ? (GValue) constant : 
GValue.of(constant));
     }
 
     public ConstantStep(final Traversal.Admin traversal, final GValue<E> 
constant) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java
index 1317f931c4..87f44f8639 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java
@@ -20,6 +20,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction;
@@ -36,24 +37,33 @@ import java.util.Set;
  */
 public final class DifferenceStep<S, E> extends ScalarMapStep<S, Set<?>> 
implements TraversalParent, ListFunction {
     private Traversal.Admin<S, E> valueTraversal;
-    private Object parameterItems;
+    private GValue<Object> parameterItems;
+
     public DifferenceStep(final Traversal.Admin traversal, final Object 
values) {
         super(traversal);
 
         if (values instanceof Traversal) {
             valueTraversal = integrateChild(((Traversal<S, E>) 
values).asAdmin());
         } else {
-            parameterItems = values;
+            parameterItems = values instanceof GValue ? (GValue<Object>) 
values : GValue.of(values);
         }
     }
 
+    public Traversal.Admin<S,E> getValueTraversal() {
+        return this.valueTraversal;
+    }
+
+    public GValue<Object> getParameterItems() {
+        return parameterItems;
+    }
+
     @Override
     public String getStepName() { return "difference"; }
 
     @Override
     protected Set<?> map(Traverser.Admin<S> traverser) {
         final Collection setA = convertTraverserToCollection(traverser);
-        final Collection setB = (null != valueTraversal) ? 
convertTraversalToCollection(traverser, valueTraversal) : 
convertArgumentToCollection(parameterItems);
+        final Collection setB = (null != valueTraversal) ? 
convertTraversalToCollection(traverser, valueTraversal) : 
convertArgumentToCollection(parameterItems.get());
         final Set differenceSet = new HashSet();
 
         for (Object element : setA) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java
index 60eebf0457..fc890dd2a2 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java
@@ -20,6 +20,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction;
@@ -35,14 +36,15 @@ import java.util.Set;
  */
 public final class DisjunctStep<S, E> extends ScalarMapStep<S, Set<?>> 
implements TraversalParent, ListFunction {
     private Traversal.Admin<S, E> valueTraversal;
-    private Object parameterItems;
+    private GValue<Object> parameterItems;
+
     public DisjunctStep(final Traversal.Admin traversal, final Object values) {
         super(traversal);
 
         if (values instanceof Traversal) {
             valueTraversal = integrateChild(((Traversal<S, E>) 
values).asAdmin());
         } else {
-            parameterItems = values;
+            parameterItems = values instanceof GValue ? (GValue<Object>) 
values : GValue.of(values);
         }
     }
 
@@ -50,8 +52,8 @@ public final class DisjunctStep<S, E> extends 
ScalarMapStep<S, Set<?>> implement
         return this.valueTraversal;
     }
 
-    public Object getParameterItems() {
-        return this.parameterItems;
+    public GValue<Object> getParameterItems() {
+        return parameterItems;
     }
 
     @Override
@@ -60,7 +62,7 @@ public final class DisjunctStep<S, E> extends 
ScalarMapStep<S, Set<?>> implement
     @Override
     protected Set<?> map(Traverser.Admin<S> traverser) {
         final Set setA = convertTraverserToSet(traverser);
-        final Set setB = (null != valueTraversal) ? 
convertTraversalToSet(traverser, this.valueTraversal) : 
convertArgumentToSet(parameterItems);
+        final Set setB = (null != valueTraversal) ? 
convertTraversalToSet(traverser, this.valueTraversal) : 
convertArgumentToSet(parameterItems.get());
         final Set disjunctSet = new HashSet();
 
         if (setA.size() == 0) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java
index b14c02ba92..4842a313bb 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java
@@ -20,6 +20,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction;
@@ -36,7 +37,7 @@ import java.util.Set;
  */
 public final class ProductStep<S, E> extends ScalarMapStep<S, List<List<?>>> 
implements TraversalParent, ListFunction {
     private Traversal.Admin<S, E> valueTraversal;
-    private Object parameterItems;
+    private GValue<Object> parameterItems;
 
     public ProductStep(final Traversal.Admin traversal, final Object values) {
         super(traversal);
@@ -44,17 +45,25 @@ public final class ProductStep<S, E> extends 
ScalarMapStep<S, List<List<?>>> imp
         if (values instanceof Traversal) {
             valueTraversal = integrateChild(((Traversal<S, E>) 
values).asAdmin());
         } else {
-            parameterItems = values;
+            parameterItems = values instanceof GValue ? (GValue<Object>) 
values : GValue.of(values);
         }
     }
 
+    public Traversal.Admin<S,E> getValueTraversal() {
+        return this.valueTraversal;
+    }
+
+    public GValue<Object> getParameterItems() {
+        return parameterItems;
+    }
+
     @Override
     public String getStepName() { return "product"; }
 
     @Override
     protected List<List<?>> map(Traverser.Admin<S> traverser) {
         final Collection listA = convertTraverserToCollection(traverser);
-        final Collection listB = (null != valueTraversal) ? 
convertTraversalToCollection(traverser, valueTraversal) : 
convertArgumentToCollection(parameterItems);
+        final Collection listB = (null != valueTraversal) ? 
convertTraversalToCollection(traverser, valueTraversal) : 
convertArgumentToCollection(parameterItems.get());
         final List elements = new ArrayList();
 
         for (Object elementInA : listA) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java
index 74d5c185de..eb82dbf381 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMergeStep.java
@@ -85,9 +85,10 @@ public final class TraversalMergeStep<S, E> extends 
ScalarMapStep<S, E> implemen
         } else {
             final Collection listA = convertTraverserToCollection(traverser);
 
-            if (parameterItems.get() instanceof Map) {
+            if (parameterItems != null && parameterItems.get() instanceof Map) 
{
                 throw new IllegalArgumentException(getStepName() + " step type 
mismatch: expected argument to be Iterable but got Map");
             }
+
             final Collection listB =
                     (null != valueTraversal)
                             ? convertTraversalToCollection(traverser, 
valueTraversal)
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java
index ab57c05ce5..cc3a970f93 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/InjectStep.java
@@ -39,7 +39,7 @@ public final class InjectStep<S> extends StartStep<S> {
     @Override
     public InjectStep<S> clone() {
         final InjectStep<S> clone = (InjectStep<S>) super.clone();
-        clone.start = new ArrayIterator<>(clone.injections);
+        clone.start = new ArrayIterator<>(resolveToValues(clone.injections));
         return clone;
     }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
index ce794b8b6a..9b309dba3f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SideEffectStrategy.java
@@ -22,6 +22,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
@@ -60,7 +61,11 @@ public final class SideEffectStrategy extends 
AbstractTraversalStrategy<Traversa
             strategy = cloneStrategy;
             traversalStrategies.addStrategies(strategy);
         }
-        strategy.sideEffects.add(new Triplet<>(key, value instanceof Supplier 
? (Supplier) value : new ConstantSupplier<>(value), reducer));
+
+        // don't want the GValue to leak beyond strategy application or else 
the Supplier will start producing it
+        // during execution
+        final ConstantSupplier initialValue = value instanceof GValue ? new 
ConstantSupplier<>(((GValue) value).get()) : new ConstantSupplier<>(value);
+        strategy.sideEffects.add(new Triplet<>(key, value instanceof Supplier 
? (Supplier) value : initialValue, reducer));
     }
 
     public boolean contains(final String sideEffectKey) {
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 
b/gremlin-language/src/main/antlr4/Gremlin.g4
index 57bfcca445..5775c27cbb 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -487,7 +487,7 @@ traversalMethod_fold
     ;
 
 traversalMethod_from
-    : 'from' LPAREN stringArgument RPAREN #traversalMethod_from_String
+    : 'from' LPAREN stringLiteral RPAREN #traversalMethod_from_String
     | 'from' LPAREN structureVertexArgument RPAREN #traversalMethod_from_Vertex
     | 'from' LPAREN nestedTraversal RPAREN #traversalMethod_from_Traversal
     ;
@@ -644,7 +644,6 @@ traversalMethod_option
     : 'option' LPAREN traversalPredicate COMMA nestedTraversal RPAREN 
#traversalMethod_option_Predicate_Traversal
     | 'option' LPAREN traversalMergeArgument COMMA 
genericLiteralMapNullableArgument RPAREN #traversalMethod_option_Merge_Map
     | 'option' LPAREN traversalMergeArgument COMMA 
genericLiteralMapNullableArgument COMMA traversalCardinality RPAREN 
#traversalMethod_option_Merge_Map_Cardinality
-    | 'option' LPAREN traversalMergeArgument COMMA nestedTraversal RPAREN 
#traversalMethod_option_Merge_Traversal
     | 'option' LPAREN genericLiteralArgument COMMA nestedTraversal RPAREN 
#traversalMethod_option_Object_Traversal
     | 'option' LPAREN nestedTraversal RPAREN #traversalMethod_option_Traversal
     ;
@@ -808,8 +807,8 @@ traversalMethod_times
     ;
 
 traversalMethod_to
-    : 'to' LPAREN traversalDirectionArgument (COMMA stringLiteralVarargs)? 
RPAREN #traversalMethod_to_Direction_String
-    | 'to' LPAREN stringArgument RPAREN #traversalMethod_to_String
+    : 'to' LPAREN traversalDirection (COMMA stringLiteralVarargs)? RPAREN 
#traversalMethod_to_Direction_String
+    | 'to' LPAREN stringLiteral RPAREN #traversalMethod_to_String
     | 'to' LPAREN structureVertexArgument RPAREN #traversalMethod_to_Vertex
     | 'to' LPAREN nestedTraversal RPAREN #traversalMethod_to_Traversal
     ;
diff --git 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
index 380313e29a..e31b3ff2d4 100644
--- 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
+++ 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
@@ -75,6 +75,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -183,13 +184,13 @@ public final class StepDefinition {
             }
         }));
 
-        add(Pair.with(Pattern.compile("l\\[\\]"), s -> 
Collections.emptyList()));
+        add(Pair.with(Pattern.compile("l\\[\\]"), s -> new ArrayList<>()));
         add(Pair.with(Pattern.compile("l\\[(.*)\\]"), s -> {
             final String[] items = s.split(",");
             return Stream.of(items).map(String::trim).map(x -> 
convertToObject(x)).collect(Collectors.toList());
         }));
 
-        add(Pair.with(Pattern.compile("s\\[\\]"), s -> 
Collections.emptySet()));
+        add(Pair.with(Pattern.compile("s\\[\\]"), s -> new HashSet<>()));
         add(Pair.with(Pattern.compile("s\\[(.*)\\]"), s -> {
             final String[] items = s.split(",");
             return Stream.of(items).map(String::trim).map(x -> 
convertToObject(x)).collect(Collectors.toSet());
@@ -235,7 +236,7 @@ public final class StepDefinition {
         add(Pair.with(Pattern.compile("e\\[(.+)\\]"), s -> getEdge(g, s)));
 
         add(Pair.with(Pattern.compile("t\\[(.*)\\]"), T::valueOf));
-        add(Pair.with(Pattern.compile("D\\[(.*)\\]"), Direction::valueOf));
+        add(Pair.with(Pattern.compile("D\\[(.*)\\]"), 
StepDefinition::getDirection));
         add(Pair.with(Pattern.compile("M\\[(.*)\\]"), Merge::valueOf));
 
         add(Pair.with(Pattern.compile("c\\[(.*)\\]"), s -> {
@@ -382,17 +383,11 @@ public final class StepDefinition {
     }
 
     @Then("the graph should return {int} for count of {string}")
-    public void theGraphShouldReturnForCountOf(final Integer count, final 
String gremlin) {
+    public void theGraphShouldReturnForCountOf(final Integer count, final 
String rawGremlin) {
         assertThatNoErrorWasThrown();
 
-        assertEquals(count.longValue(), ((GraphTraversal) 
parseGremlin(applyParameters(gremlin))).count().next());
-    }
-
-    @Then("debug the graph should return {int} for count of {string}")
-    public void debugTheGraphShouldReturnForCountOf(final Integer count, final 
String gremlin) {
-        assertThatNoErrorWasThrown();
-
-        assertEquals(count.longValue(), ((GraphTraversal) 
parseGremlin(applyParameters(gremlin))).count().next());
+        final String gremlin = world.useParametersLiterally() ? 
applyParameters(rawGremlin) : rawGremlin;
+        assertEquals(count.longValue(), ((GraphTraversal) 
parseGremlin(gremlin)).count().next());
     }
 
     @Then("the result should be empty")
@@ -604,6 +599,12 @@ public final class StepDefinition {
         return docString.replace(relPath, escapeJava(absPath));
     }
 
+    private static Direction getDirection(final String direction) {
+        if (direction.equals("from")) return Direction.OUT;
+        if (direction.equals("to")) return Direction.IN;
+        return Direction.valueOf(direction);
+    }
+
     /**
      * TinkerPop version of Hamcrest's {code containsInAnyOrder} that can use 
our custom assertions for {@link Path}.
      */

Reply via email to