You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2024/11/20 14:42:38 UTC

(tinkerpop) 01/01: TINKERPOP-2959 Allow parameters to work for primitives

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 0f64df12648600b2cd9b5b6fde9ef15b6a8e85f4
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Fri Jul 12 10:48:20 2024 -0400

    TINKERPOP-2959 Allow parameters to work for primitives
---
 .../gremlin/jsr223/GremlinLangScriptEngine.java    |  17 +-
 .../gremlin/jsr223/VariableResolverCustomizer.java |  40 ++
 .../gremlin/jsr223/VariableResolverPlugin.java     |  95 +++
 .../grammar/DefaultGremlinBaseVisitor.java         |  16 +-
 .../language/grammar/GenericLiteralVisitor.java    |  14 +
 .../language/grammar/TraversalMethodVisitor.java   | 191 ++++--
 .../grammar/TraversalSourceSpawnMethodVisitor.java |  29 +-
 .../gremlin/language/grammar/VariableResolver.java |  37 +-
 .../translator/DotNetTranslateVisitor.java         |  62 +-
 .../translator/GroovyTranslateVisitor.java         |  31 +-
 .../language/translator/TranslateVisitor.java      |   6 +-
 .../tinkerpop/gremlin/process/traversal/P.java     |  14 +-
 .../gremlin/process/traversal/SackFunctions.java   |   5 +-
 .../traversal/dsl/graph/GraphTraversal.java        | 547 ++++++++++++++++--
 .../traversal/dsl/graph/GraphTraversalSource.java  |  61 ++
 .../gremlin/process/traversal/dsl/graph/__.java    | 177 ++++++
 .../traversal/lambda/ConstantTraversal.java        |  15 +-
 .../gremlin/process/traversal/step/GType.java      | 103 ++++
 .../gremlin/process/traversal/step/GValue.java     | 443 ++++++++++++++
 .../process/traversal/step/filter/CoinStep.java    |  24 +-
 .../process/traversal/step/map/AddEdgeStep.java    |  15 +-
 .../process/traversal/step/map/AddVertexStep.java  |   5 +
 .../process/traversal/step/map/CallStep.java       |  36 +-
 .../process/traversal/step/map/CombineStep.java    |  15 +-
 .../process/traversal/step/map/ConjoinStep.java    |  19 +-
 .../process/traversal/step/map/ConstantStep.java   |  18 +-
 .../process/traversal/step/map/DifferenceStep.java |  20 +-
 .../process/traversal/step/map/DisjunctStep.java   |  14 +-
 .../process/traversal/step/map/GraphStep.java      |  87 ++-
 .../process/traversal/step/map/IntersectStep.java  |  15 +-
 .../process/traversal/step/map/MergeEdgeStep.java  |   5 +
 .../traversal/step/map/MergeElementStep.java       |  14 +-
 .../process/traversal/step/map/MergeStep.java      |  23 +-
 .../traversal/step/map/MergeVertexStep.java        |   5 +
 .../process/traversal/step/map/ProductStep.java    |  19 +-
 .../process/traversal/step/map/VertexStep.java     |  27 +-
 .../traversal/step/sideEffect/InjectStep.java      |  23 +-
 .../process/traversal/step/util/AbstractStep.java  |   2 +-
 .../process/traversal/step/util/HasContainer.java  |   6 +-
 .../process/traversal/step/util/Parameters.java    |  21 +-
 .../strategy/decoration/ElementIdStrategy.java     |   7 +-
 .../strategy/decoration/SideEffectStrategy.java    |   7 +-
 .../strategy/decoration/SubgraphStrategy.java      |   2 +-
 .../optimization/AdjacentToIncidentStrategy.java   |   2 +-
 .../optimization/IncidentToAdjacentStrategy.java   |   2 +-
 .../optimization/InlineFilterStrategy.java         |  19 +-
 .../process/traversal/util/ListFunction.java       |  16 +-
 .../gremlin/structure/VertexProperty.java          |   3 -
 .../gremlin/structure/io/gryo/GryoVersion.java     |  12 +-
 .../tinkerpop/gremlin/util/CollectionUtil.java     |  44 +-
 .../gremlin/jsr223/VariableResolverPluginTest.java | 117 ++++
 .../language/grammar/ArgumentVisitorTest.java      |  92 ++-
 .../language/grammar/GremlinQueryParserTest.java   |   8 +-
 .../language/translator/GremlinTranslatorTest.java |  58 +-
 .../gremlin/process/traversal/step/GTypeTest.java  |  77 +++
 .../gremlin/process/traversal/step/GValueTest.java | 641 +++++++++++++++++++++
 .../traversal/step/map/ConjoinStepTest.java        |   2 +-
 .../traversal/step/util/ParametersTest.java        |  11 +
 .../tinkerpop/gremlin/util/CollectionUtilTest.java | 110 ++++
 .../Gherkin/CommonSteps.cs                         |   7 -
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  61 +-
 gremlin-go/driver/cucumber/cucumberSteps_test.go   |  15 +-
 gremlin-go/driver/cucumber/gremlin.go              |  15 +-
 .../test/cucumber/feature-steps.js                 |   4 -
 .../gremlin-javascript/test/cucumber/gremlin.js    |  54 +-
 gremlin-language/src/main/antlr4/Gremlin.g4        |   4 +-
 .../src/main/python/radish/feature_steps.py        |  11 -
 gremlin-python/src/main/python/radish/gremlin.py   |  54 +-
 .../tinkerpop/gremlin/features/StepDefinition.java |  55 +-
 .../apache/tinkerpop/gremlin/features/World.java   |   9 +
 .../gremlin/test/features/filter/Has.feature       |  24 +
 .../gremlin/test/features/filter/HasId.feature     |  13 +-
 .../gremlin/test/features/filter/HasLabel.feature  |  28 +
 .../gremlin/test/features/map/Conjoin.feature      |  14 +-
 .../gremlin/test/features/map/Edge.feature         | 261 ++++++++-
 .../gremlin/test/features/map/Vertex.feature       | 248 +-------
 .../traversal/step/sideEffect/Neo4jGraphStep.java  |   4 +-
 .../process/traversal/strategy/SparqlStrategy.java |   1 -
 .../traversal/step/sideEffect/TinkerGraphStep.java |  14 +-
 .../tinkerpop/gremlin/tinkergraph/TinkerWorld.java |   5 +
 .../tinkergraph/structure/TinkerGraphPlayTest.java |  33 +-
 81 files changed, 3773 insertions(+), 707 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
index 440c27ad56..5528b280b1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngine.java
@@ -31,7 +31,11 @@ import javax.script.ScriptException;
 import javax.script.SimpleBindings;
 import java.io.IOException;
 import java.io.Reader;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
 
 /**
  * A {@link GremlinScriptEngine} implementation that evaluates Gremlin scripts using {@code gremlin-language}. As it
@@ -50,6 +54,8 @@ import java.util.Map;
 public class GremlinLangScriptEngine extends AbstractScriptEngine implements GremlinScriptEngine {
     private volatile GremlinScriptEngineFactory factory;
 
+    private final Function<Map<String, Object>, VariableResolver> variableResolverMaker;
+
     /**
      * Creates a new instance using no {@link Customizer}.
      */
@@ -58,6 +64,15 @@ public class GremlinLangScriptEngine extends AbstractScriptEngine implements Gre
     }
 
     public GremlinLangScriptEngine(final Customizer... customizers) {
+        final List<Customizer> listOfCustomizers = Arrays.asList(customizers);
+
+        // this ScriptEngine really only supports the VariableResolverCustomizer to configure the VariableResolver
+        // and can't configure it more than once. first one wins
+        final Optional<Customizer> opt = listOfCustomizers.stream().filter(c -> c instanceof VariableResolverCustomizer).findFirst();
+        variableResolverMaker = opt.isPresent() ?
+                ((VariableResolverCustomizer) opt.get()).getVariableResolverMaker() :
+                VariableResolver.DirectVariableResolver::new;
+
     }
 
     @Override
@@ -84,7 +99,7 @@ public class GremlinLangScriptEngine extends AbstractScriptEngine implements Gre
 
         final Map<String, Object> m = context.getBindings(ScriptContext.ENGINE_SCOPE);
         final GremlinAntlrToJava antlr = new GremlinAntlrToJava((GraphTraversalSource) o,
-                new VariableResolver.DefaultVariableResolver(m));
+                variableResolverMaker.apply(m));
 
         try {
             return GremlinQueryParser.parse(script, antlr);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverCustomizer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverCustomizer.java
new file mode 100644
index 0000000000..1be1f3d448
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverCustomizer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.tinkerpop.gremlin.jsr223;
+
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
+
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * Supplies a {@link VariableResolver} implementation to the {@link GremlinLangScriptEngine}. This {@link Customizer}
+ * is not relevant to any other {@link GremlinScriptEngine} implementation.
+ */
+public class VariableResolverCustomizer implements Customizer {
+    private final Function<Map<String,Object>, VariableResolver> variableResolverMaker;
+
+    public VariableResolverCustomizer(final Function<Map<String, Object>, VariableResolver> variableResolverMaker) {
+        this.variableResolverMaker = variableResolverMaker;
+    }
+
+    public Function<Map<String, Object>, VariableResolver> getVariableResolverMaker() {
+        return variableResolverMaker;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPlugin.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPlugin.java
new file mode 100644
index 0000000000..587f9666a1
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPlugin.java
@@ -0,0 +1,95 @@
+/*
+ * 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.tinkerpop.gremlin.jsr223;
+
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A plugin that allows for the configuration of a {@link VariableResolver} implementation to be used by the
+ * {@link GremlinLangScriptEngine}. By default, it will use the {@link VariableResolver.DirectVariableResolver} which
+ * directly resolves variable name to a value from the binding in the script engine context. This is the most common
+ * usage relevant for most users and providers. Other options are reserved for more advanced use cases.
+ */
+public class VariableResolverPlugin extends AbstractGremlinPlugin {
+    private static final String NAME = "tinkerpop.variableResolver";
+
+    public static final Map<String, Function<Map<String, Object>, VariableResolver>> VARIABLE_RESOLVERS =
+            new HashMap<String, Function<Map<String, Object>, VariableResolver>>() {{
+                put(VariableResolver.DirectVariableResolver.class.getSimpleName(), VariableResolver.DirectVariableResolver::new);
+                put(VariableResolver.DefaultVariableResolver.class.getSimpleName(), VariableResolver.DefaultVariableResolver::new);
+                put(VariableResolver.NoVariableResolver.class.getSimpleName(), m -> VariableResolver.NoVariableResolver.instance());
+                put(VariableResolver.NullVariableResolver.class.getSimpleName(), m -> VariableResolver.NullVariableResolver.instance());
+    }};
+
+    private VariableResolverPlugin(final VariableResolverPlugin.Builder builder) {
+        super(NAME, new VariableResolverCustomizer(builder.variableResolverMaker));
+    }
+
+    /**
+     * Builds a set of static bindings.
+     */
+    public static VariableResolverPlugin.Builder build() {
+        return new VariableResolverPlugin.Builder();
+    }
+
+    public static final class Builder {
+
+        Function<Map<String,Object>, VariableResolver> variableResolverMaker = VariableResolver.DirectVariableResolver::new;
+
+        private Builder() {}
+
+        /**
+         * Sets the type of {@link VariableResolver} to use by specifying a simple class name associated with the
+         * inner classes in that interface or a fully qualified class name. The assumption is that implementations
+         * will allow a constructor that takes a {@code Map} which contains the bindings from the script engine context.
+         * Implementations are can then decide how to resolve variables in the script based on that {@code Map} or some
+         * other mechanism.
+         */
+        public VariableResolverPlugin.Builder resolver(final String resolverName) {
+            if (VARIABLE_RESOLVERS.containsKey(resolverName)) {
+                this.variableResolverMaker = VARIABLE_RESOLVERS.get(resolverName);
+            } else {
+                try {
+                    // Assuming resolverName is a fully qualified class name if it's not in the simple name map
+                    final Class<?> clazz = Class.forName(resolverName);
+                    if (VariableResolver.class.isAssignableFrom(clazz)) {
+                        this.variableResolverMaker = map -> {
+                            try {
+                                return (VariableResolver) clazz.getConstructor(Map.class).newInstance(map);
+                            } catch (Exception e) {
+                                throw new RuntimeException("Error instantiating VariableResolver", e);
+                            }
+                        };
+                    }
+                } catch (ClassNotFoundException e) {
+                    throw new RuntimeException("VariableResolver class not found: " + resolverName, e);
+                }
+            }
+            return this;
+        }
+
+        public VariableResolverPlugin create() {
+            return new VariableResolverPlugin(this);
+        }
+    }
+}
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 2cade8cac7..c7a255cd34 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}
 	 */
@@ -631,6 +631,10 @@ public class DefaultGremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
 	 * {@inheritDoc}
 	 */
 	@Override public T visitTraversalMethod_option_Traversal(final GremlinParser.TraversalMethod_option_TraversalContext 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}
 	 */
@@ -854,11 +858,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 +1399,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/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
index ced6c832d1..fb124ec910 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
@@ -658,4 +658,18 @@ public class GenericLiteralVisitor extends DefaultGremlinBaseVisitor<Object> {
         else
             return StringEscapeUtils.unescapeJava(stripQuotes(ctx.getText()));
     }
+
+    @Override
+    public Object[] visitStringLiteralVarargs(final GremlinParser.StringLiteralVarargsContext ctx) {
+        if (ctx == null) {
+            return new Object[0];
+        }
+        return ctx.children
+                .stream()
+                .filter(Objects::nonNull)
+                .filter(p -> p instanceof GremlinParser.StringNullableArgumentContext)
+                .map(p -> (GremlinParser.StringNullableArgumentContext) p)
+                .map(antlr.argumentVisitor::visitStringNullableArgument)
+                .toArray(Object[]::new);
+    }
 }
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 c4437d9f75..1d107e6a88 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
@@ -27,16 +27,18 @@ import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 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.Column;
 import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality;
 
+import java.util.Arrays;
 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.
@@ -45,11 +47,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
     /**
      * This object is used to append the traversal methods.
      */
-    private final GraphTraversal graphTraversal;
+    private final GraphTraversal.Admin graphTraversal;
 
     public TraversalMethodVisitor(final GremlinAntlrToJava antlr, final GraphTraversal graphTraversal) {
         super(antlr, graphTraversal);
-        this.graphTraversal = graphTraversal;
+        this.graphTraversal = graphTraversal.asAdmin();
     }
 
     /**
@@ -97,7 +99,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_mergeV_Map(final GremlinParser.TraversalMethod_mergeV_MapContext ctx) {
-        return this.graphTraversal.mergeV(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+        if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return graphTraversal.mergeV((GValue<Map<Object, Object>>) literalOrVar);
+        else
+            return graphTraversal.mergeV((Map) literalOrVar);
     }
 
     /**
@@ -129,7 +135,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_mergeE_Map(final GremlinParser.TraversalMethod_mergeE_MapContext ctx) {
-        return this.graphTraversal.mergeE(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+        if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return graphTraversal.mergeE((GValue<Map<Object, Object>>) literalOrVar);
+        else
+            return graphTraversal.mergeE((Map) literalOrVar);
     }
 
     /**
@@ -440,7 +450,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_combine_Object(final GremlinParser.TraversalMethod_combine_ObjectContext ctx) {
-        return graphTraversal.combine(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection())
+            return graphTraversal.combine((GValue<Object>) literalOrVar);
+        else
+            return graphTraversal.combine(literalOrVar);
     }
 
     /**
@@ -448,7 +462,12 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_coin(final GremlinParser.TraversalMethod_coinContext ctx) {
-        return graphTraversal.coin(((Number) antlr.argumentVisitor.visitFloatArgument(ctx.floatArgument())).doubleValue());
+        final Object literalOrVar = antlr.argumentVisitor.visitFloatArgument(ctx.floatArgument());
+        if (GValue.valueInstanceOfNumeric(literalOrVar))
+            return graphTraversal.coin((GValue<Double>) literalOrVar);
+        else
+            return graphTraversal.coin(((Number) literalOrVar).doubleValue());
+
     }
 
     /**
@@ -456,7 +475,13 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_conjoin_String(final GremlinParser.TraversalMethod_conjoin_StringContext ctx) {
-        return graphTraversal.conjoin(antlr.argumentVisitor.parseString(ctx.stringArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitStringArgument(ctx.stringArgument());
+        if (literalOrVar instanceof String)
+            return graphTraversal.conjoin((String) literalOrVar);
+        else if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType() == GType.STRING)
+            return graphTraversal.conjoin((GValue<String>) literalOrVar);
+        else
+            throw new IllegalArgumentException("conjoin argument must be a string");
     }
 
     /**
@@ -514,7 +539,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);
     }
 
     /**
@@ -522,7 +551,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);
     }
 
     /**
@@ -619,8 +652,20 @@ 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 (GValue.valueInstanceOf(literalOrVar, GType.VERTEX))
+            return graphTraversal.from((GValue<Vertex>) literalOrVar);
+        else
+            return graphTraversal.from((Vertex) literalOrVar);
     }
 
     /**
@@ -715,10 +760,30 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
     @Override
     public GraphTraversal visitTraversalMethod_hasLabel_String_String(final GremlinParser.TraversalMethod_hasLabel_String_StringContext ctx) {
         if (ctx.getChildCount() == 4) {
-            return graphTraversal.hasLabel(antlr.argumentVisitor.parseString(ctx.stringNullableArgument()));
+            final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument());
+            if (GValue.valueInstanceOf(literalOrVar, GType.STRING))
+                return graphTraversal.hasLabel((GValue) literalOrVar);
+            else
+                return graphTraversal.hasLabel((String) literalOrVar);
         } else {
-            return graphTraversal.hasLabel(antlr.argumentVisitor.parseString(ctx.stringNullableArgument()),
-                    antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs()));
+            Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument());
+            Object[] literalOrVars = antlr.genericVisitor.visitStringLiteralVarargs(ctx.stringLiteralVarargs());
+
+            // if any are GValue then they all need to be GValue to call hasLabel
+            if (literalOrVar instanceof GValue || Arrays.stream(literalOrVars).anyMatch(lov -> lov instanceof GValue)) {
+                literalOrVar = GValue.of(literalOrVar);
+                literalOrVars = GValue.ensureGValues(literalOrVars);
+            }
+
+            // since we normalized above to gvalue or literal we can just test the first arg for gvalue-ness
+            if (GValue.valueInstanceOf(literalOrVar, GType.STRING)) {
+                final GValue[] gvalueLiteralOrVars = literalOrVars == null ? null : Arrays.stream(literalOrVars).map(o -> (GValue) o).toArray(GValue[]::new);
+                return graphTraversal.hasLabel((GValue) literalOrVar, (GValue[]) gvalueLiteralOrVars);
+            } else {
+                // convert object array to string array
+                final String[] stringLiteralOrVars = literalOrVars == null ? null : Arrays.stream(literalOrVars).map(o -> (String) o).toArray(String[]::new);
+                return graphTraversal.hasLabel((String) literalOrVar, stringLiteralOrVars);
+            }
         }
     }
 
@@ -778,9 +843,16 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_has_String_String_Object(final GremlinParser.TraversalMethod_has_String_String_ObjectContext ctx) {
-        return graphTraversal.has(antlr.argumentVisitor.parseString(ctx.stringNullableArgument(0)),
-                antlr.argumentVisitor.parseString(ctx.stringNullableArgument(1)),
-                antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitStringNullableArgument(ctx.stringNullableArgument(0));
+        if (GValue.valueInstanceOf(literalOrVar, GType.STRING)) {
+            return graphTraversal.has((GValue) literalOrVar,
+                    antlr.argumentVisitor.parseString(ctx.stringNullableArgument(1)),
+                    antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        } else {
+            return graphTraversal.has((String) literalOrVar,
+                    antlr.argumentVisitor.parseString(ctx.stringNullableArgument(1)),
+                    antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        }
     }
 
     /**
@@ -866,7 +938,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_intersect_Object(final GremlinParser.TraversalMethod_intersect_ObjectContext ctx) {
-        return graphTraversal.intersect(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection())
+            return graphTraversal.intersect((GValue<Object>) literalOrVar);
+        else
+            return graphTraversal.intersect(literalOrVar);
     }
 
     /**
@@ -1066,7 +1142,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_merge_Object(final GremlinParser.TraversalMethod_merge_ObjectContext ctx) {
-        return graphTraversal.merge(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue && ((GValue) literalOrVar).getType().isCollection())
+            return graphTraversal.merge((GValue<Object>) literalOrVar);
+        else
+            return graphTraversal.merge(literalOrVar);
     }
 
     /**
@@ -1106,8 +1186,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
-        return graphTraversal.option(antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument()),
-                antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralArgument(ctx.genericLiteralArgument());
+        if (literalOrVar instanceof GValue)
+            return graphTraversal.option((GValue) literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+        else
+            return graphTraversal.option(literalOrVar, antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
     }
 
     /**
@@ -1123,8 +1206,11 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_option_Merge_Map(final GremlinParser.TraversalMethod_option_Merge_MapContext ctx) {
-        return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()),
-                (Map) antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+        if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()), (GValue<Map>) literalOrVar);
+        else
+            return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()), (Map) literalOrVar);
     }
 
     /**
@@ -1263,7 +1349,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);
     }
 
     /**
@@ -1607,7 +1697,7 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      */
     @Override
     public GraphTraversal visitTraversalMethod_to_Direction_String(final GremlinParser.TraversalMethod_to_Direction_StringContext ctx) {
-        return graphTraversal.to(TraversalEnumParser.parseTraversalEnumFromContext(Direction.class, ctx.traversalDirection()),
+        return graphTraversal.to(TraversalEnumParser.parseTraversalDirectionFromContext(ctx.traversalDirection()),
                 antlr.genericVisitor.parseStringVarargs(ctx.stringLiteralVarargs()));
     }
 
@@ -1615,8 +1705,20 @@ 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 (GValue.valueInstanceOf(literalOrVar, GType.VERTEX))
+            return graphTraversal.to((GValue<Vertex>) literalOrVar);
+        else
+            return graphTraversal.to((Vertex) literalOrVar);
     }
 
     /**
@@ -1755,22 +1857,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}
      */
@@ -1792,8 +1878,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 (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar);
+        else
+            return graphTraversal.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar);
     }
 
     /**
@@ -1810,9 +1899,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 (GValue.valueInstanceOf(literalOrVar, 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 2227635f80..02fb654451 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
@@ -21,6 +21,8 @@ package org.apache.tinkerpop.gremlin.language.grammar;
 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.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
 
 import java.util.Map;
 
@@ -119,7 +121,11 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
      */
     @Override
     public GraphTraversal visitTraversalSourceSpawnMethod_mergeV_Map(final GremlinParser.TraversalSourceSpawnMethod_mergeV_MapContext ctx) {
-        return this.traversalSource.mergeV(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+        if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return this.traversalSource.mergeV((GValue) literalOrVar);
+        else
+            return this.traversalSource.mergeV((Map) literalOrVar);
     }
 
     /**
@@ -143,7 +149,11 @@ public class TraversalSourceSpawnMethodVisitor extends DefaultGremlinBaseVisitor
      */
     @Override
     public GraphTraversal visitTraversalSourceSpawnMethod_mergeE_Map(final GremlinParser.TraversalSourceSpawnMethod_mergeE_MapContext ctx) {
-        return this.traversalSource.mergeE(antlr.argumentVisitor.parseMap(ctx.genericLiteralMapNullableArgument()));
+        final Object literalOrVar = antlr.argumentVisitor.visitGenericLiteralMapNullableArgument(ctx.genericLiteralMapNullableArgument());
+        if (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return this.traversalSource.mergeE((GValue) literalOrVar);
+        else
+            return this.traversalSource.mergeE((Map) literalOrVar);
     }
 
     /**
@@ -167,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 (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (GValue<Map>) literalOrVar);
+        else
+            return this.traversalSource.call(antlr.argumentVisitor.parseString(ctx.stringArgument()), (Map) literalOrVar);
     }
 
     /**
@@ -185,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 (GValue.valueInstanceOf(literalOrVar, GType.MAP))
+            return this.traversalSource.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/grammar/VariableResolver.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/VariableResolver.java
index a97bd4b646..e017808faf 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/VariableResolver.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/VariableResolver.java
@@ -18,24 +18,25 @@
  */
 package org.apache.tinkerpop.gremlin.language.grammar;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import java.util.Map;
 import java.util.function.BiFunction;
 
 /**
  * Resolves parameters in Gremlin to objects.
  */
-public interface VariableResolver extends BiFunction<String, GremlinParser.VariableContext, Object> {
+public interface VariableResolver<T> extends BiFunction<String, GremlinParser.VariableContext, T> {
 
     /**
      * This function resolves a variable name and the given parsers context to an object.
      */
     @Override
-    Object apply(final String varName, final GremlinParser.VariableContext variableContext);
+    T apply(final String varName, final GremlinParser.VariableContext variableContext);
 
     /**
      * This {@link VariableResolver} implementation throws exceptions for all variable names.
      */
-    class NoVariableResolver implements VariableResolver {
+    class NoVariableResolver implements VariableResolver<Object> {
         private static NoVariableResolver instance = new NoVariableResolver();
 
         public static VariableResolver instance() {
@@ -48,12 +49,35 @@ public interface VariableResolver extends BiFunction<String, GremlinParser.Varia
         }
     }
 
+    /**
+     * Allows for a provided variable set in the form of a {@code Map}, where the keys are variable names and the
+     * values are the parameter values to be injected into the traversal in their place. The value is provided to a
+     * {@link GValue} object along with the variable name for further reference.
+     */
+    class DefaultVariableResolver implements VariableResolver<GValue<?>> {
+
+        private final Map<String, Object> variables;
+
+        public DefaultVariableResolver(final Map<String, Object> variables) {
+            this.variables = variables;
+        }
+
+        @Override
+        public GValue<?> apply(final String s, final GremlinParser.VariableContext variableContext) {
+            if (!variables.containsKey(s)) {
+                throw new VariableResolverException(String.format("No variable found for %s", s));
+            }
+
+            return GValue.of(s, variables.get(s));
+        }
+    }
+
     /**
      * This {@link VariableResolver} simply provides a {@code null} value for all variable names. It's typical use
      * is for when you really don't intend to execute the traversal and just want to get an instance of one when
      * bindings are being used as with {@link NoOpTerminalVisitor}.
      */
-    class NullVariableResolver implements VariableResolver {
+    class NullVariableResolver implements VariableResolver<Object> {
         private static NullVariableResolver instance = new NullVariableResolver();
 
         public static VariableResolver instance() {
@@ -70,11 +94,11 @@ public interface VariableResolver extends BiFunction<String, GremlinParser.Varia
      * Allows for a provided variable set in the form of a {@code Map}, where the keys are variable names and the
      * values are the parameter values to be injected into the traversal in their place.
      */
-    class DefaultVariableResolver implements VariableResolver {
+    class DirectVariableResolver implements VariableResolver<Object> {
 
         private final Map<String, Object> variables;
 
-        public DefaultVariableResolver(final Map<String, Object> variables) {
+        public DirectVariableResolver(final Map<String, Object> variables) {
             this.variables = variables;
         }
 
@@ -87,4 +111,5 @@ public interface VariableResolver extends BiFunction<String, GremlinParser.Varia
             return variables.get(s);
         }
     }
+
 }
\ No newline at end of file
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 21c4d20ea4..60ce2f8e30 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
@@ -739,10 +739,36 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
             sb.append(")");
             return null;
         } else {
-            return super.visitTraversalMethod_hasLabel_String_String(ctx);
+            final String step = ctx.getChild(0).getText();
+            sb.append(convertToPascalCase(step));
+            sb.append("(");
+            tryAppendCastToString(ctx.stringNullableArgument());
+            visit(ctx.stringNullableArgument());
+
+            // more arguments to come
+            if (!ctx.stringLiteralVarargs().isEmpty())  sb.append(", ");
+            visit(ctx.stringLiteralVarargs());
+
+            sb.append(")");
+            return null;
         }
     }
 
+    @Override
+    public Void visitStringLiteralVarargs(final GremlinParser.StringLiteralVarargsContext ctx) {
+        for (int ix = 0; ix < ctx.getChildCount(); ix++) {
+            final ParseTree pt = ctx.getChild(ix);
+            if (pt instanceof GremlinParser.StringNullableArgumentContext) {
+                GremlinParser.StringNullableArgumentContext sna = (GremlinParser.StringNullableArgumentContext) pt;
+                tryAppendCastToString(sna);
+                visit(sna);
+            } else {
+                visit(pt);
+            }
+        };
+        return null;
+    }
+
     @Override
     public Void visitTraversalMethod_index(final GremlinParser.TraversalMethod_indexContext ctx) {
         return handleGenerics(ctx);
@@ -870,9 +896,24 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
         return null;
     }
 
+    @Override
+    public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
+        if (ctx.genericLiteralArgument().genericLiteral() != null && 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
     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.traversalMerge());
@@ -923,6 +964,17 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
         }
     }
 
+    @Override
+    public Void visitTraversalMethod_conjoin_String(final GremlinParser.TraversalMethod_conjoin_StringContext ctx) {
+        final String step = ctx.getChild(0).getText();
+        sb.append(convertToPascalCase(step));
+        sb.append("(");
+        tryAppendCastToString(ctx.stringArgument());
+        visit(ctx.stringArgument());
+        sb.append(")");
+        return null;
+    }
+
     @Override
     public Void visitTraversalMethod_propertyMap(final GremlinParser.TraversalMethod_propertyMapContext ctx) {
         return handleGenerics(ctx);
@@ -1138,6 +1190,12 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
         }
     }
 
+    private void tryAppendCastToString(final GremlinParser.StringArgumentContext ctx) {
+        if (ctx.variable() != null || ctx.stringLiteral() != null) {
+            sb.append("(string) ");
+        }
+    }
+
     private void tryAppendCastToString(final GremlinParser.StringNullableArgumentContext ctx) {
         if (ctx.variable() != null || ctx.stringNullableLiteral().NullLiteral() != null) {
             sb.append("(string) ");
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java
index 3c87b6249a..20a6b6434e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GroovyTranslateVisitor.java
@@ -186,8 +186,35 @@ public class GroovyTranslateVisitor extends TranslateVisitor {
         return handleInject(ctx);
     }
 
-    /*
-    * very special handling for inject with second `null` argument like g.inject(1, null)
+    @Override
+    public Void visitTraversalMethod_hasLabel_String_String(final GremlinParser.TraversalMethod_hasLabel_String_StringContext ctx) {
+        // special handling for resolving ambiguous invocations of the hasLabel() step. coerces to the string form
+        if (ctx.getChildCount() > 4 && ctx.getChild(2).getText().equals("null")) {
+            final GremlinParser.StringLiteralVarargsContext varArgs = (GremlinParser.StringLiteralVarargsContext) ctx.getChild(4);
+            sb.append(ctx.getChild(0).getText());
+            sb.append("((String) null, ");
+
+            for (int i = 0; i < varArgs.getChildCount(); i += 2) {
+                if (varArgs.getChild(i).getText().equals("null")) {
+                    sb.append("(String) null");
+                } else {
+                    visit(varArgs.getChild(i));
+                }
+
+                if (i < varArgs.getChildCount() - 1) {
+                    sb.append(", ");
+                }
+            }
+
+            sb.append(")");
+            return null;
+        }
+
+        return visitChildren(ctx);
+    }
+
+    /**
+    * Special handling for inject with second `null` argument like g.inject(1, null)
     * inject() ends up being ambiguous with groovy's jdk extension of inject(Object initialValue, Closure closure)
     */
     private Void handleInject(final ParserRuleContext ctx) {
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 2712262678..beb6040091 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
@@ -903,17 +903,17 @@ public class TranslateVisitor extends AbstractParseTreeVisitor<Void> implements
     }
 
     @Override
-    public Void visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
+    public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
         return visitChildren(ctx);
     }
 
     @Override
-    public Void visitTraversalMethod_option_Object_Traversal(final GremlinParser.TraversalMethod_option_Object_TraversalContext ctx) {
+    public Void visitTraversalMethod_option_Traversal(final GremlinParser.TraversalMethod_option_TraversalContext ctx) {
         return visitChildren(ctx);
     }
 
     @Override
-    public Void visitTraversalMethod_option_Traversal(final GremlinParser.TraversalMethod_option_TraversalContext ctx) {
+    public Void visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
         return visitChildren(ctx);
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 917a13891d..a878bbb839 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
@@ -18,13 +18,16 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * Predefined {@code Predicate} values that can be used to define filters to {@code has()} and {@code where()}.
@@ -74,7 +77,16 @@ public class P<V> implements Predicate<V>, Serializable, Cloneable {
 
     @Override
     public boolean test(final V testValue) {
-        return this.biPredicate.test(testValue, this.value);
+        if (this.value instanceof GValue) {
+            return this.biPredicate.test(testValue, ((GValue<V>) this.value).get());
+        } else {
+            // this might be a bunch of GValue that need to be resolved. zomg
+            if (this.value instanceof List) {
+                return this.biPredicate.test(testValue, (V) ((List) this.value).stream().map(GValue::valueOf).collect(Collectors.toList()));
+            } else {
+                return this.biPredicate.test(testValue, this.value);
+            }
+        }
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java
index 4752bf0b32..3985efe699 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/SackFunctions.java
@@ -19,6 +19,7 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
 
 import java.util.function.Consumer;
@@ -42,10 +43,10 @@ public final class SackFunctions {
             public void accept(final TraverserSet<Object> traverserSet) {
                 Number total = 0.0;
                 for (final Traverser.Admin<Object> traverser : traverserSet) {
-                    total = add(total, mul(traverser.sack(), traverser.bulk()));
+                    total = add(total, mul(GValue.numberOf(traverser.sack()), traverser.bulk()));
                 }
                 for (final Traverser.Admin<Object> traverser : traverserSet) {
-                    traverser.sack(div(mul(traverser.sack(), traverser.bulk()), total));
+                    traverser.sack(div(mul(GValue.numberOf(traverser.sack()), traverser.bulk()), total));
                 }
             }
         }
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 9d5b500376..ab5af2445b 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
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPressureVertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ProgramVertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPathVertexProgramStep;
+import org.apache.tinkerpop.gremlin.process.traversal.Contains;
 import org.apache.tinkerpop.gremlin.process.traversal.DT;
 import org.apache.tinkerpop.gremlin.process.traversal.Failure;
 import org.apache.tinkerpop.gremlin.process.traversal.Merge;
@@ -47,6 +48,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.lambda.TrueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Configuring;
 import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ReadWriting;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TimesModulating;
@@ -203,8 +205,10 @@ import org.apache.tinkerpop.gremlin.structure.PropertyType;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.util.CollectionUtil;
 import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
 
+import java.lang.reflect.Array;
 import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -230,6 +234,11 @@ import static org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality.
  */
 public interface GraphTraversal<S, E> extends Traversal<S, E> {
 
+    /**
+     * Exposes administrative methods that are either internal to TinkerPop or for users with advanced needs. This
+     * separation helps keep the Gremlin API more concise. Any {@code GraphTraversal} can get an instance of its
+     * administrative form by way of {@link GraphTraversal#asAdmin()}.
+     */
     public interface Admin<S, E> extends Traversal.Admin<S, E>, GraphTraversal<S, E> {
 
         @Override
@@ -356,6 +365,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new ConstantStep<E, E2>(this.asAdmin(), e));
     }
 
+    /**
+     * Map any object to a fixed <code>E</code> value. For internal use for  parameterization features.
+     *
+     * @return the traversal with an appended {@link ConstantStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#constant-step" target="_blank">Reference Documentation - Constant Step</a>
+     * @since 4.0.0
+     */
+    public default <E2> GraphTraversal<S, E2> constant(final GValue<E2> e) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.constant, e);
+        return this.asAdmin().addStep(new ConstantStep<E, E2>(this.asAdmin(), e));
+    }
+
     /**
      * A {@code V} step is usually used to start a traversal but it may also be used mid-traversal.
      *
@@ -400,6 +421,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, direction, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its adjacent vertices given a direction and edge labels. The arguments for the
+     * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param direction  the direction to traverse from the current vertex
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Vertex> to(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.to, direction, edgeLabel, edgeLabels);
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, edgeLabel, GValue.class);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, direction, labels));
+    }
+
     /**
      * Map the {@link Vertex} to its outgoing adjacent vertices given the edge labels.
      *
@@ -413,6 +450,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.OUT, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its outgoing adjacent vertices given the edge labels. The arguments for the
+     * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 3.7.3
+     */
+    public default GraphTraversal<S, Vertex> out(final GValue<String> label, final GValue<String>... edgeLabels) {
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.out, label, edgeLabels);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.OUT, labels));
+    }
+
     /**
      * Map the {@link Vertex} to its incoming adjacent vertices given the edge labels.
      *
@@ -426,6 +478,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.IN, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its incoming adjacent vertices given the edge labels. The arguments for the
+     * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Vertex> in(final GValue<String> label, final GValue<String>... edgeLabels) {
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.in, label, edgeLabels);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.IN, labels));
+    }
+
     /**
      * Map the {@link Vertex} to its adjacent vertices given the edge labels.
      *
@@ -439,6 +506,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.BOTH, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its adjacent vertices given the edge labels. The arguments for the labels must be
+     * either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Vertex> both(final GValue<String> label, final GValue<String>... edgeLabels) {
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.both, label, edgeLabels);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Vertex.class, Direction.BOTH, labels));
+    }
+
     /**
      * Map the {@link Vertex} to its incident edges given the direction and edge labels.
      *
@@ -453,6 +535,23 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, direction, edgeLabels));
     }
 
+
+    /**
+     * Map the {@link Vertex} to its incident edges given the direction and edge labels. The arguments for the
+     * labels must be either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param direction  the direction to traverse from the current vertex
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Edge> toE(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.toE, direction, edgeLabel, edgeLabels);
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, edgeLabel, GValue.class);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, direction, labels));
+    }
+
     /**
      * Map the {@link Vertex} to its outgoing incident edges given the edge labels.
      *
@@ -466,6 +565,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.OUT, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its outgoing incident edges given the edge labels. The arguments for the labels
+     * must be either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Edge> outE(final GValue<String> label, final GValue<String>... edgeLabels) {
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.outE, label, edgeLabels);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.OUT, labels));
+    }
+
     /**
      * Map the {@link Vertex} to its incoming incident edges given the edge labels.
      *
@@ -479,6 +593,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.IN, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its incoming incident edges given the edge labels. The arguments for the labels
+     * must be either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Edge> inE(final GValue<String> label, final GValue<String>... edgeLabels) {
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.inE, label, edgeLabels);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.IN, labels));
+    }
+
+
     /**
      * Map the {@link Vertex} to its incident edges given the edge labels.
      *
@@ -492,6 +622,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.BOTH, edgeLabels));
     }
 
+    /**
+     * Map the {@link Vertex} to its incident edges given the edge labels. The arguments for the labels must be
+     * either a {@code String} or a {@link GValue<String>}. For internal use for  parameterization.
+     *
+     * @param edgeLabels the edge labels to traverse
+     * @return the traversal with an appended {@link VertexStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#vertex-steps" target="_blank">Reference Documentation - Vertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Edge> bothE(final GValue<String> label, final GValue<String>... edgeLabels) {
+        final GValue<String>[] labels = CollectionUtil.addFirst(edgeLabels, label, GValue.class);
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.bothE, label, edgeLabels);
+        return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), Edge.class, Direction.BOTH, labels));
+    }
+
     /**
      * Map the {@link Edge} to its incident vertices given the direction.
      *
@@ -1121,6 +1266,20 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), vertexLabelTraversal.asAdmin()));
     }
 
+    /**
+     * Adds a {@link Vertex}.
+     *
+     * @param vertexLabel the label of the {@link Vertex} to add
+     * @return the traversal with the {@link AddVertexStep} added
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addvertex-step" target="_blank">Reference Documentation - AddVertex Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Vertex> addV(final GValue<String> vertexLabel) {
+        if (null == vertexLabel || null == vertexLabel.get()) throw new IllegalArgumentException("vertexLabel cannot be null");
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.addV, vertexLabel);
+        return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), vertexLabel));
+    }
+
     /**
      * Adds a {@link Vertex} with a default vertex label.
      *
@@ -1179,6 +1338,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(step);
     }
 
+    /**
+     * Performs 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 key/value pairs where the keys
+     * may be {@code String} property values or a value of {@link T}. If a match is not 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 4.0.0
+     */
+    public default GraphTraversal<S, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.mergeV, searchCreate);
+        final MergeVertexStep<S> step = new MergeVertexStep(this.asAdmin(), false, null == searchCreate ? GValue.ofMap(null) : searchCreate);
+        return this.asAdmin().addStep(step);
+    }
+
     /**
      * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using an
      * incoming {@code Map} as an argument.
@@ -1220,6 +1394,20 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(step);
     }
 
+    /**
+     * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
+     * {@code Map} as an argument.
+     *
+     * @param searchCreate This {@code Map} can have a key of {@link T} {@link Direction} or a {@code String}.
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Edge> mergeE(final GValue<Map<Object, Object>> searchCreate) {
+        // get a construction time exception if the Map is bad
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.mergeE, searchCreate);
+        final MergeEdgeStep<S> step = new MergeEdgeStep(this.asAdmin(), false, null == searchCreate ? GValue.ofMap(null) : searchCreate);
+        return this.asAdmin().addStep(step);
+    }
+
     /**
      * Adds an {@link Edge} with the specified edge label.
      *
@@ -1246,21 +1434,35 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
-     * Provide {@code to()}-modulation to respective steps.
+     * Adds an {@link Edge} with the specified edge label.
      *
-     * @param toStepLabel the step label to modulate to.
-     * @return the traversal with the modified {@link FromToModulating} step.
-     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#to-step" target="_blank">Reference Documentation - To Step</a>
+     * @param edgeLabel the label of the newly added edge
+     * @return the traversal with the {@link AddEdgeStep} added
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#addedge-step" target="_blank">Reference Documentation - AddEdge Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Edge> addE(final GValue<String> edgeLabel) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.addE, edgeLabel);
+        return this.asAdmin().addStep(new AddEdgeStep<>(this.asAdmin(), edgeLabel));
+    }
+
+    /**
+     * 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 traversal 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 3.1.0-incubating
      */
-    public default GraphTraversal<S, E> to(final String toStepLabel) {
+    public default GraphTraversal<S, E> from(final Traversal<?, Vertex> fromVertex) {
         final Step<?,?> prev = this.asAdmin().getEndStep();
         if (!(prev instanceof FromToModulating))
             throw new IllegalArgumentException(String.format(
-                    "The to() step cannot follow %s", prev.getClass().getSimpleName()));
+                    "The from() step cannot follow %s", prev.getClass().getSimpleName()));
 
-        this.asAdmin().getGremlinLang().addStep(Symbols.to, toStepLabel);
-        ((FromToModulating) prev).addTo(toStepLabel);
+        this.asAdmin().getGremlinLang().addStep(Symbols.from, fromVertex);
+        ((FromToModulating) prev).addFrom(fromVertex.asAdmin());
         return this;
     }
 
@@ -1285,21 +1487,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
 
     /**
      * 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}.
+     * outgoing vertex of the newly added {@link Edge}.
      *
-     * @param toVertex the traversal for selecting the incoming vertex
+     * @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 3.1.0-incubating
+     * @since 4.0.0
      */
-    public default GraphTraversal<S, E> to(final Traversal<?, Vertex> toVertex) {
+    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 to() step cannot follow %s", prev.getClass().getSimpleName()));
+                    "The from() step cannot follow %s", prev.getClass().getSimpleName()));
 
-        this.asAdmin().getGremlinLang().addStep(Symbols.to, toVertex);
-        ((FromToModulating) prev).addTo(toVertex.asAdmin());
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.from, fromVertex);
+        ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
         return this;
     }
 
@@ -1307,19 +1509,38 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * 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 traversal for selecting the outgoing vertex
+     * @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 3.1.0-incubating
+     * @since 3.3.0
      */
-    public default GraphTraversal<S, E> from(final Traversal<?, Vertex> fromVertex) {
+    public default GraphTraversal<S, E> from(final 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().getGremlinLang().addStep(Symbols.from, fromVertex);
-        ((FromToModulating) prev).addFrom(fromVertex.asAdmin());
+        ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
+        return this;
+    }
+
+    /**
+     * Provide {@code to()}-modulation to respective steps.
+     *
+     * @param toStepLabel the step label to modulate to.
+     * @return the traversal with the modified {@link FromToModulating} step.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#to-step" target="_blank">Reference Documentation - To Step</a>
+     * @since 3.1.0-incubating
+     */
+    public default GraphTraversal<S, E> to(final String toStepLabel) {
+        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().getGremlinLang().addStep(Symbols.to, toStepLabel);
+        ((FromToModulating) prev).addTo(toStepLabel);
         return this;
     }
 
@@ -1330,36 +1551,56 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @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 3.3.0
+     * @since 4.0.0
      */
-    public default GraphTraversal<S, E> to(final Vertex toVertex) {
+    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().getGremlinLang().addStep(Symbols.to, toVertex);
+        this.asAdmin().getGremlinLang().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}.
+     * incoming vertex of the newly added {@link Edge}.
      *
-     * @param fromVertex the vertex for selecting the outgoing vertex
+     * @param toVertex the traversal 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 3.1.0-incubating
+     */
+    public default GraphTraversal<S, E> to(final Traversal<?, 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().getGremlinLang().addStep(Symbols.to, toVertex);
+        ((FromToModulating) prev).addTo(toVertex.asAdmin());
+        return this;
+    }
+
+    /**
+     * 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 3.3.0
      */
-    public default GraphTraversal<S, E> from(final Vertex fromVertex) {
+    public default GraphTraversal<S, E> to(final Vertex toVertex) {
         final Step<?,?> prev = this.asAdmin().getEndStep();
         if (!(prev instanceof FromToModulating))
             throw new IllegalArgumentException(String.format(
-                    "The from() step cannot follow %s", prev.getClass().getSimpleName()));
+                    "The to() step cannot follow %s", prev.getClass().getSimpleName()));
 
-        this.asAdmin().getGremlinLang().addStep(Symbols.from, fromVertex);
-        ((FromToModulating) prev).addFrom(__.constant(fromVertex).asAdmin());
+        this.asAdmin().getGremlinLang().addStep(Symbols.to, toVertex);
+        ((FromToModulating) prev).addTo(__.constant(toVertex).asAdmin());
         return this;
     }
 
@@ -1416,6 +1657,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(call);
     }
 
+    /**
+     * 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().getGremlinLang().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 dynamic parameters produced by the specified child traversal.
      *
@@ -1451,6 +1707,25 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(step);
     }
 
+    /**
+     * 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().getGremlinLang().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);
+    }
+
     /**
      * Concatenate values of an arbitrary number of string traversals to the incoming traverser.
      *
@@ -1900,6 +2175,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new DifferenceStep<>(this.asAdmin(), values));
     }
 
+    /**
+     * 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 4.0.0
+     */
+    public default GraphTraversal<S, Set<?>> difference(final GValue<Object> values) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.difference, values);
+        return this.asAdmin().addStep(new DifferenceStep<>(this.asAdmin(), values));
+    }
+
     /**
      * Calculates the disjunction between the list traverser and list argument.
      *
@@ -1912,6 +2199,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new DisjunctStep<>(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 4.0.0
+     */
+    public default GraphTraversal<S, Set<?>> disjunct(final GValue<Object> values) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.disjunct, values);
+        return this.asAdmin().addStep(new DisjunctStep<>(this.asAdmin(), values));
+    }
+
     /**
      * Calculates the intersection between the list traverser and list argument.
      *
@@ -1924,6 +2223,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new IntersectStep<>(this.asAdmin(), values));
     }
 
+    /**
+     * Calculates the intersection between the list traverser and list argument.
+     *
+     * @return the traversal with an appended {@link IntersectStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#intersect-step" target="_blank">Reference Documentation - Intersect Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, Set<?>> intersect(final GValue<Object> values) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.intersect, values);
+        return this.asAdmin().addStep(new IntersectStep<>(this.asAdmin(), values));
+    }
+
     /**
      * Joins together the elements of the incoming list traverser together with the provided delimiter.
      *
@@ -1936,6 +2247,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new ConjoinStep<>(this.asAdmin(), delimiter));
     }
 
+    /**
+     * Joins together the elements of the incoming list traverser together with the provided delimiter.
+     *
+     * @return the traversal with an appended {@link ConjoinStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#conjoin-step" target="_blank">Reference Documentation - Conjoin Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, String> conjoin(final GValue<String> delimiter) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.conjoin, delimiter);
+        return this.asAdmin().addStep(new ConjoinStep<>(this.asAdmin(), delimiter));
+    }
+
     /**
      * Merges the list traverser and list argument. Also known as union.
      *
@@ -1948,6 +2271,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new MergeStep<>(this.asAdmin(), values));
     }
 
+    /**
+     * Merges the list traverser and list argument. Also known as union.
+     *
+     * @return the traversal with an appended {@link MergeStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#merge-step" target="_blank">Reference Documentation - Merge Step</a>
+     * @since 4.0.0
+     */
+    public default <E2> GraphTraversal<S, E2> merge(final GValue<Object> values) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.merge, values);
+        return this.asAdmin().addStep(new MergeStep<>(this.asAdmin(), values));
+    }
+
     /**
      * Combines the list traverser and list argument. Also known as concatenation or append.
      *
@@ -1960,6 +2295,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new CombineStep<>(this.asAdmin(), values));
     }
 
+    /**
+     * Combines the list traverser and list argument. Also known as concatenation or append.
+     *
+     * @return the traversal with an appended {@link CombineStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#combine-step" target="_blank">Reference Documentation - Combine Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, List<?>> combine(final GValue<Object> values) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.combine, values);
+        return this.asAdmin().addStep(new CombineStep<>(this.asAdmin(), values));
+    }
+
     /**
      * Calculates the cartesian product between the list traverser and list argument.
      *
@@ -1972,6 +2319,18 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new ProductStep<>(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 4.0.0
+     */
+    public default GraphTraversal<S, List<List<?>>> product(final GValue<Object> values) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.product, values);
+        return this.asAdmin().addStep(new ProductStep<>(this.asAdmin(), values));
+    }
+
     ///////////////////// FILTER STEPS /////////////////////
 
     /**
@@ -2310,6 +2669,22 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new TraversalFilterStep(this.asAdmin(), __.values(propertyKey)));
     }
 
+    /**
+     * Filters vertices, edges and vertex properties based on their properties.
+     *
+     * @param label       the label of the {@link Element}
+     * @param propertyKey the key of the property to filter on
+     * @param value       the value to compare the accessor value to for equality
+     * @return the traversal with an appended {@link HasStep}
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, E> has(final GValue<String> label, final String propertyKey, final Object value) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.has, label.get(), propertyKey, value);
+        TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), P.eq(label)));
+        return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(propertyKey, value instanceof P ? (P) value : P.eq(value)));
+    }
+
     /**
      * Filters vertices, edges and vertex properties based on the non-existence of properties.
      *
@@ -2337,11 +2712,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
 
         // groovy evaluation seems to do strange things with varargs given hasLabel(null, null). odd someone would
         // do this but the failure is ugly if not handled.
-        final int otherLabelsLength = null == otherLabels ? 0 : otherLabels.length;
-        final String[] labels = new String[otherLabelsLength + 1];
-        labels[0] = label;
-        if (otherLabelsLength > 0)
-            System.arraycopy(otherLabels, 0, labels, 1, otherLabelsLength);
+        final String[] labels = CollectionUtil.addFirst(otherLabels, label, String.class);
         return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), labels.length == 1 ? P.eq(labels[0]) : P.within(labels)));
     }
 
@@ -2364,6 +2735,24 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         }
     }
 
+    /**
+     * Filters vertices, edges and vertex properties based on their label.
+     *
+     * @param label       the label of the {@link Element}
+     * @param otherLabels additional labels of the {@link Element}
+     * @return the traversal with an appended {@link HasStep}
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#has-step" target="_blank">Reference Documentation - Has Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, E> hasLabel(final GValue<String> label, final GValue<String>... otherLabels) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.hasLabel, label, otherLabels);
+
+        // groovy evaluation seems to do strange things with varargs given hasLabel(null, null). odd someone would
+        // do this but the failure is ugly if not handled.
+        final Object[] labels = CollectionUtil.addFirst(otherLabels, label, GValue.class);
+        return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.label.getAccessor(), labels.length == 1 ? P.eq(labels[0]) : P.within(labels)));
+    }
+
     /**
      * Filters vertices, edges and vertex properties based on their identifier.
      *
@@ -2376,10 +2765,15 @@ 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().getGremlinLang().addStep(Symbols.hasId, id, otherIds);
 
+            // the logic for dealing with hasId([]) is sketchy historically, just trying to maintain what we were
+            // originally testing prior to GValue.
+            if (id instanceof GValue && ((GValue) id).getType().isCollection()) {
+                return TraversalHelper.addHasContainer(this.asAdmin(), new HasContainer(T.id.getAccessor(), new P(Contains.within, id)));
+            }
+
             //using ArrayList given P.within() turns all arguments into lists
             final List<Object> ids = new ArrayList<>();
             if (id instanceof Object[]) {
@@ -2388,8 +2782,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
@@ -2575,6 +2970,19 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), probability));
     }
 
+    /**
+     * Filter the <code>E</code> object given a biased coin toss. For internal use for  parameterization features.
+     *
+     * @param probability the probability that the object will pass through the filter
+     * @return the traversal with an appended {@link CoinStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#coin-step" target="_blank">Reference Documentation - Coin Step</a>
+     * @since 4.0.0
+     */
+    public default GraphTraversal<S, E> coin(final GValue<Double> probability) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.coin, probability);
+        return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), probability));
+    }
+
     /**
      * Filter the objects in the traversal by the number of them to pass through the stream. Those before the value
      * of {@code low} do not pass through and those that exceed the value of {@code high} will end the iteration.
@@ -3970,6 +4378,73 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this;
     }
 
+    /**
+     * This is a step modulator to a {@link TraversalOptionParent} like {@code choose()} or {@code mergeV()} where the
+     * provided argument associated to the {@code token} is applied according to the semantics of the step. Please see
+     * the documentation of such steps to understand the usage context.
+     *
+     * @param token       the token that would trigger this option which may be a {@link Pick}, {@link Merge},
+     *                    a {@link Traversal}, {@link Predicate}, or object depending on the step being modulated.
+     * @param traversalOption the option as a traversal
+     * @return the traversal with the modulated step
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#choose-step" target="_blank">Reference Documentation - Choose Step</a>
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+     * @since 3.0.0-incubating
+     */
+    public default <M, E2> GraphTraversal<S, E> option(final GValue<M> token, final Traversal<?, E2> traversalOption) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.option, token, traversalOption);
+
+        // handle null similar to how option() with Map handles it, otherwise we get a NPE if this one gets used
+        final Traversal.Admin<E,E2> t = null == traversalOption ?
+                new ConstantTraversal<>(null) : (Traversal.Admin<E, E2>) traversalOption.asAdmin();
+        ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption(token.get(), t);
+        return this;
+    }
+
+    /**
+     * This is a step modulator to a {@link TraversalOptionParent} like {@code choose()} or {@code mergeV()} where the
+     * provided argument associated to the {@code token} is applied according to the semantics of the step. Please see
+     * the documentation of such steps to understand the usage context.
+     *
+     * @param m Provides a {@code Map} as the option which is the same as doing {@code constant(m)}.
+     * @return the traversal with the modulated step
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+     * @since 3.7.3
+     */
+    public default <M, E2> GraphTraversal<S, E> option(final M token, final GValue<Map<Object, Object>> m) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.option, token, m);
+        ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption(token, (Traversal.Admin<E, E2>) new ConstantTraversal<>(m).asAdmin());
+        return this;
+    }
+
+    /**
+     * This is a step modulator to a {@link TraversalOptionParent} like {@code choose()} or {@code mergeV()} where the
+     * provided argument associated to the {@code token} is applied according to the semantics of the step. Please see
+     * the documentation of such steps to understand the usage context.
+     *
+     * @param m Provides a {@code Map} as the option which is the same as doing {@code constant(m)}.
+     * @return the traversal with the modulated step
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+     * @since 3.7.3
+     */
+    public default <M, E2> GraphTraversal<S, E> option(final Merge merge, final GValue<Map<Object, Object>> m, final VertexProperty.Cardinality cardinality) {
+        this.asAdmin().getGremlinLang().addStep(GraphTraversal.Symbols.option, merge, m, cardinality);
+
+        final Map<Object, Object> map = m.get();
+
+        // do explicit cardinality for every single pair in the map
+        for (Object k : map.keySet()) {
+            final Object o = map.get(k);
+            if (!(o instanceof CardinalityValueTraversal))
+                map.put(k, new CardinalityValueTraversal(cardinality, o));
+        }
+        ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption((M) merge, (Traversal.Admin<E, E2>) new ConstantTraversal<>(m).asAdmin());
+        return this;
+    }
+
     ////
 
     ///////////////////// IO STEPS /////////////////////
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 a28089247f..63e49e243f 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
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 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.branch.UnionStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStartStep;
@@ -406,6 +407,22 @@ public class GraphTraversalSource implements TraversalSource {
         return traversal.addStep(step);
     }
 
+    /**
+     * 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
+     * key/value pairs where the keys may be {@code String} property values or a value of {@link T}. If a match is not
+     * 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 4.0.0
+     */
+    public GraphTraversal<Vertex, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) {
+        final GraphTraversalSource clone = GraphTraversalSource.this.clone();
+        clone.gremlinLang.addStep(GraphTraversal.Symbols.mergeV, searchCreate);
+        final GraphTraversal.Admin<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(clone);
+        return traversal.addStep(new MergeVertexStep(traversal, true, searchCreate));
+    }
+
     /**
      * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
      * {@code Map} as an argument.
@@ -438,6 +455,20 @@ public class GraphTraversalSource implements TraversalSource {
         return traversal.addStep(step);
     }
 
+    /**
+     * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
+     * {@code Map} as an argument.
+     *
+     * @param searchCreate This {@code Map} can have a key of {@link T} {@link Direction} or a {@code String}.
+     * @since 4.0.0
+     */
+    public GraphTraversal<Edge, Edge> mergeE(final GValue<Map<?, Object>> searchCreate) {
+        final GraphTraversalSource clone = GraphTraversalSource.this.clone();
+        clone.gremlinLang.addStep(GraphTraversal.Symbols.mergeE, searchCreate);
+        final GraphTraversal.Admin<Edge, Edge> traversal = new DefaultGraphTraversal<>(clone);
+        return traversal.addStep(new MergeEdgeStep(traversal, true, searchCreate));
+    }
+
     /**
      * Spawns a {@link GraphTraversal} starting it with arbitrary values.
      */
@@ -557,6 +588,36 @@ public class GraphTraversalSource implements TraversalSource {
         return traversal.addStep(step);
     }
 
+    /**
+     * 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.gremlinLang.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.gremlinLang.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()));
+    }
+
     /**
      * Merges the results of an arbitrary number of traversals.
      *
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 57776db82e..59fdf5f605 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -25,6 +25,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 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.map.FormatStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
 import org.apache.tinkerpop.gremlin.structure.Column;
@@ -110,6 +112,13 @@ public class __ {
         return __.<A>start().constant(a);
     }
 
+    /**
+     * @see GraphTraversal#constant(GValue)
+     */
+    public static <A> GraphTraversal<A, A> constant(final GValue<A> a) {
+        return __.<A>start().constant(a);
+    }
+
     /**
      * @see GraphTraversal#label()
      */
@@ -145,6 +154,13 @@ public class __ {
         return __.<Vertex>start().to(direction, edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#to(Direction, GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Vertex> to(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().to(direction, edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#out(String...)
      */
@@ -152,6 +168,13 @@ public class __ {
         return __.<Vertex>start().out(edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#out(GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Vertex> out(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().out(edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#in(String...)
      */
@@ -159,6 +182,13 @@ public class __ {
         return __.<Vertex>start().in(edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#in(String...)
+     */
+    public static GraphTraversal<Vertex, Vertex> in(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().in(edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#both(String...)
      */
@@ -166,6 +196,13 @@ public class __ {
         return __.<Vertex>start().both(edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#both(GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Vertex> both(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().both(edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#toE(Direction, String...)
      */
@@ -173,6 +210,13 @@ public class __ {
         return __.<Vertex>start().toE(direction, edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#toE(Direction, GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Edge> toE(final Direction direction, final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().toE(direction, edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#outE(String...)
      */
@@ -180,6 +224,13 @@ public class __ {
         return __.<Vertex>start().outE(edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#outE(GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Edge> outE(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().outE(edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#inE(String...)
      */
@@ -187,6 +238,13 @@ public class __ {
         return __.<Vertex>start().inE(edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#inE(GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Edge> inE(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().inE(edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#bothE(String...)
      */
@@ -194,6 +252,13 @@ public class __ {
         return __.<Vertex>start().bothE(edgeLabels);
     }
 
+    /**
+     * @see GraphTraversal#bothE(GValue, GValue...)
+     */
+    public static GraphTraversal<Vertex, Edge> bothE(final GValue<String> edgeLabel, final GValue<String>... edgeLabels) {
+        return __.<Vertex>start().bothE(edgeLabel, edgeLabels);
+    }
+
     /**
      * @see GraphTraversal#toV(Direction)
      */
@@ -512,6 +577,13 @@ public class __ {
         return __.<A>start().addV(vertexLabel);
     }
 
+    /**
+     * @see GraphTraversal#addV(GValue)
+     */
+    public static <A> GraphTraversal<A, Vertex> addV(final GValue<String> vertexLabel) {
+        return __.<A>start().addV(vertexLabel);
+    }
+
     /**
      * @see GraphTraversal#addV(org.apache.tinkerpop.gremlin.process.traversal.Traversal)
      */
@@ -540,6 +612,13 @@ public class __ {
         return __.<A>start().mergeV(searchCreate);
     }
 
+    /**
+     * @see GraphTraversal#mergeV(GValue)
+     */
+    public static <A> GraphTraversal<A, Vertex> mergeV(final GValue<Map<Object, Object>> searchCreate) {
+        return __.<A>start().mergeV(searchCreate);
+    }
+
     /**
      * @see GraphTraversal#mergeV(Traversal)
      */
@@ -554,6 +633,13 @@ public class __ {
         return __.<A>start().addE(edgeLabel);
     }
 
+    /**
+     * @see GraphTraversal#addE(GValue)
+     */
+    public static <A> GraphTraversal<A, Edge> addE(final GValue<String> edgeLabel) {
+        return __.<A>start().addE(edgeLabel);
+    }
+
     /**
      * @see GraphTraversal#addE(Traversal)
      */
@@ -575,6 +661,13 @@ public class __ {
         return __.<A>start().mergeE(searchCreate);
     }
 
+    /**
+     * @see GraphTraversal#mergeE(GValue)
+     */
+    public static <A> GraphTraversal<A, Edge> mergeE(final GValue<Map<Object, Object>> searchCreate) {
+        return __.<A>start().mergeE(searchCreate);
+    }
+
     /**
      * @see GraphTraversal#mergeE(Traversal)
      */
@@ -806,6 +899,13 @@ public class __ {
         return __.<A>start().difference(values);
     }
 
+    /**
+     * @see GraphTraversal#difference(GValue)
+     */
+    public static <A> GraphTraversal<A, Set<?>> difference(final GValue<Object> values) {
+        return __.<A>start().difference(values);
+    }
+
     /**
      * @see GraphTraversal#disjunct(Object)
      */
@@ -813,6 +913,13 @@ public class __ {
         return __.<A>start().disjunct(values);
     }
 
+    /**
+     * @see GraphTraversal#disjunct(GValue)
+     */
+    public static <A> GraphTraversal<A, Set<?>> disjunct(final GValue<Object> values) {
+        return __.<A>start().disjunct(values);
+    }
+
     /**
      * @see GraphTraversal#intersect(Object)
      */
@@ -820,6 +927,13 @@ public class __ {
         return __.<A>start().intersect(values);
     }
 
+    /**
+     * @see GraphTraversal#intersect(GValue)
+     */
+    public static <A> GraphTraversal<A, Set<?>> intersect(final GValue<Object> values) {
+        return __.<A>start().intersect(values);
+    }
+
     /**
      * @see GraphTraversal#conjoin(String)
      */
@@ -827,6 +941,13 @@ public class __ {
         return __.<A>start().conjoin(values);
     }
 
+    /**
+     * @see GraphTraversal#conjoin(GValue)
+     */
+    public static <A> GraphTraversal<A, String> conjoin(final GValue<String> values) {
+        return __.<A>start().conjoin(values);
+    }
+
     /**
      * @see GraphTraversal#merge(Object)
      */
@@ -834,6 +955,13 @@ public class __ {
         return __.<A>start().merge(values);
     }
 
+    /**
+     * @see GraphTraversal#merge(GValue)
+     */
+    public static <A, B> GraphTraversal<A, B> merge(final GValue<Object> values) {
+        return __.<A>start().merge(values);
+    }
+
     /**
      * @see GraphTraversal#combine(Object)
      */
@@ -841,6 +969,13 @@ public class __ {
         return __.<A>start().combine(values);
     }
 
+    /**
+     * @see GraphTraversal#combine(GValue)
+     */
+    public static <A> GraphTraversal<A, List<?>> combine(final GValue<Object> values) {
+        return __.<A>start().combine(values);
+    }
+
     /**
      * @see GraphTraversal#product(Object)
      */
@@ -848,6 +983,13 @@ public class __ {
         return __.<A>start().product(values);
     }
 
+    /**
+     * @see GraphTraversal#product(GValue)
+     */
+    public static <A> GraphTraversal<A, List<List<?>>> product(final GValue<Object> values) {
+        return __.<A>start().product(values);
+    }
+
     ///////////////////// FILTER STEPS /////////////////////
 
     /**
@@ -934,6 +1076,13 @@ public class __ {
         return __.<A>start().has(label, propertyKey, value);
     }
 
+    /**
+     * @see GraphTraversal#has(GValue, String, Object)
+     */
+    public static <A> GraphTraversal<A, A> has(final GValue<String> label, final String propertyKey, final Object value) {
+        return __.<A>start().has(label, propertyKey, value);
+    }
+
     /**
      * @see GraphTraversal#has(String, String, P)
      */
@@ -976,6 +1125,13 @@ public class __ {
         return __.<A>start().hasLabel(label, otherLabels);
     }
 
+    /**
+     * @see GraphTraversal#hasLabel(GValue, GValue...)
+     */
+    public static <A> GraphTraversal<A, A> hasLabel(final GValue<String> label, GValue<String>... otherLabels) {
+        return __.<A>start().hasLabel(label, otherLabels);
+    }
+
     /**
      * @see GraphTraversal#hasLabel(P)
      */
@@ -1074,6 +1230,13 @@ public class __ {
         return __.<A>start().coin(probability);
     }
 
+    /**
+     * @see GraphTraversal#coin(GValue)
+     */
+    public static <A> GraphTraversal<A, A> coin(final GValue<Double> probability) {
+        return __.<A>start().coin(probability);
+    }
+
     /**
      * @see GraphTraversal#range(long, long)
      */
@@ -1517,6 +1680,13 @@ public class __ {
         return __.<A>start().call(service, params);
     }
 
+    /**
+     * @see GraphTraversal#call(String, GValue)
+     */
+    public static <A, B> GraphTraversal<A, B> call(final String service, final GValue<Map> params) {
+        return __.<A>start().call(service, params);
+    }
+
     /**
      * @see GraphTraversal#call(String, Traversal)
      */
@@ -1530,4 +1700,11 @@ public class __ {
     public static <A, B> GraphTraversal<A, B> call(final String service, final Map params, final Traversal<?, Map<?,?>> childTraversal) {
         return __.<A>start().call(service, params, childTraversal);
     }
+
+    /**
+     * @see GraphTraversal#call(String, GValue, Traversal)
+     */
+    public static <A, B> GraphTraversal<A, B> call(final String service, final GValue<Map> params, final Traversal<?, Map<?,?>> childTraversal) {
+        return __.<A>start().call(service, params, childTraversal);
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java
index b22d88e66c..3bac69ce48 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/lambda/ConstantTraversal.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal.lambda;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 
 import java.util.Objects;
 
@@ -29,15 +30,23 @@ import java.util.Objects;
  */
 public final class ConstantTraversal<S, E> extends AbstractLambdaTraversal<S, E> {
 
-    private final E end;
+    private final GValue<E> end;
 
     public ConstantTraversal(final E end) {
-        this.end = end;
+        this.end = null == end ? GValue.of(null) : GValue.of(end);
+    }
+
+    public ConstantTraversal(final GValue<E> end) {
+        this.end = null == end ? GValue.of(null) : end;
     }
 
     @Override
     public E next() {
-        return this.end;
+        return this.end.get();
+    }
+
+    public GValue<E> getEnd() {
+        return end;
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java
new file mode 100644
index 0000000000..4c8777d290
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java
@@ -0,0 +1,103 @@
+/*
+ * 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.tinkerpop.gremlin.process.traversal.step;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An enum that describes types that are used in the Gremlin language.
+ */
+public enum GType {
+    BIG_DECIMAL(BigDecimal.class),
+    BIG_INTEGER(BigInteger.class),
+    BOOLEAN(Boolean.class),
+    DOUBLE(Double.class),
+    EDGE(Edge.class),
+    INTEGER(Integer.class),
+    LIST(List.class),
+    LONG(Long.class),
+    MAP(Map.class),
+    PATH(Path.class),
+    PROPERTY(Property.class),
+    SET(Set.class),
+    STRING(String.class),
+    UNKNOWN(null),
+    VERTEX(Vertex.class);
+
+    private Class<?> javaType;
+
+    GType(final Class<?> javaType) {
+        this.javaType = javaType;
+    }
+
+    public Class<?> getJavaType() {
+        return this.javaType;
+    }
+
+    /**
+     * Returns {@code true} if the type is a number.
+     */
+    public boolean isNumeric() {
+        return this == INTEGER || this == DOUBLE || this == LONG || this == BIG_INTEGER || this == BIG_DECIMAL;
+    }
+
+    /**
+     * Returns {@code true} if the type is a collection.v
+     */
+    public boolean isCollection() {
+        return this == LIST || this == SET;
+    }
+
+    /**
+     * Returns {@code true} if the type is an element.
+     */
+    public boolean isElement() {
+        return this == VERTEX || this == EDGE;
+    }
+
+    /**
+     * Convert an object to a matching {@link GType} and if not matched return {@link GType#UNKNOWN}.
+     */
+    public static GType getType(final Object object) {
+        if (object instanceof String) return STRING;
+        else if (object instanceof Integer) return INTEGER;
+        else if (object instanceof Boolean) return BOOLEAN;
+        else if (object instanceof Double) return DOUBLE;
+        else if (object instanceof Long) return LONG;
+        else if (object instanceof Map) return MAP;
+        else if (object instanceof List) return LIST;
+        else if (object instanceof Set) return SET;
+        else if (object instanceof Vertex) return VERTEX;
+        else if (object instanceof Edge) return EDGE;
+        else if (object instanceof Path) return PATH;
+        else if (object instanceof Property) return PROPERTY;
+        else if (object instanceof BigInteger) return BIG_INTEGER;
+        else if (object instanceof BigDecimal) return BIG_DECIMAL;
+        else return UNKNOWN;
+    }
+}
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
new file mode 100644
index 0000000000..0608d94a19
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -0,0 +1,443 @@
+/*
+ * 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.tinkerpop.gremlin.process.traversal.step;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ * A {@code GValue} is a variable or literal value that is used in a {@link Traversal}. It is composed of a key-value
+ * pair where the key is the name given to the variable and the value is the object that the variable resolved to. If
+ * the name is not given, the value was provided literally in the traversal. The value of the variable can be any
+ * object. The {@code GValue} also includes the {@link GType} that describes the type it contains.
+ */
+public class GValue<V> implements Cloneable, Serializable {
+    private final String name;
+    private final GType type;
+
+    private final V value;
+
+    private GValue(final GType type, final V value) {
+        this(null, type, value);
+    }
+
+    private GValue(final String name, final GType type, final V value) {
+        this.name = name;
+        this.type = type;
+        this.value = value;
+    }
+
+    /**
+     * Determines if the value held by this object was defined as a variable or a literal value. Literal values simply
+     * have no name.
+     */
+    public boolean isVariable() {
+        return this.name != null;
+    }
+
+    /**
+     * Gets the name of the variable if it was defined as such and returns empty if the value was a literal.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * Gets the type of the value. The explicit type could be determined with {@code instanceof} on the value, but this
+     * might be helpful for cases where the value was constructed with a {@code null} value which might just return as
+     * {@code Object}.
+     */
+    public GType getType() {
+        return this.type;
+    }
+
+    /**
+     * Determines if the value held is of a {@code null} value.
+     */
+    public boolean isNull() {
+        return this.value == null;
+    }
+
+    /**
+     * Gets the value.
+     */
+    public V get() {
+        return this.value;
+    }
+
+    @Override
+    public String toString() {
+        return isVariable() ?
+                String.format("%s&%s", name, value) : Objects.toString(value);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        final GValue<?> gValue = (GValue<?>) o;
+        return Objects.equals(name, gValue.name) && type == gValue.type && Objects.equals(value, gValue.value);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, type, value);
+    }
+
+    /**
+     * Create a new {@code Var} from a particular value but without the specified name. If the argument provide is
+     * already a {@code GValue} then it is returned as-is.
+     *
+     * @param value the value of the variable
+     */
+    public static <V> GValue<V> of(final V value) {
+        if (value instanceof GValue) return (GValue) value;
+        return new GValue<>(GType.getType(value), value);
+    }
+
+    /**
+     * Create a new {@code Var} with the specified name and value.. If the argument provide is  already a
+     * {@code GValue} then it is returned as-is.
+     *
+     * @param name the name of the variable
+     * @param value the value of the variable
+     */
+    public static <V> GValue<V> of(final String name, final V value) {
+        if (value instanceof GValue) throw new IllegalArgumentException("value cannot be a GValue");
+        return new GValue<>(name, GType.getType(value), value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a string value.
+     */
+    public static GValue<String> ofString(final String value) {
+        return new GValue<>(GType.STRING, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a string value with a specified name.
+     */
+    public static GValue<String> ofString(final String name, final String value) {
+        return new GValue<>(name, GType.STRING, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for an integer value.
+     */
+    public static GValue<Integer> ofInteger(final Integer value) {
+        return new GValue<>(GType.INTEGER, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for an integer value with a specified name.
+     */
+    public static GValue<Integer> ofInteger(final String name, final Integer value) {
+        return new GValue<>(name, GType.INTEGER, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a boolean value.
+     */
+    public static GValue<Boolean> ofBoolean(final Boolean value) {
+        return new GValue<>(GType.BOOLEAN, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a boolean value with a specified name.
+     */
+    public static GValue<Boolean> ofBoolean(final String name, final Boolean value) {
+        return new GValue<>(name, GType.BOOLEAN, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a double value.
+     */
+    public static GValue<Double> ofDouble(final Double value) {
+        return new GValue<>(GType.DOUBLE, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a double value with a specified name.
+     */
+    public static GValue<Double> ofDouble(final String name, final Double value) {
+        return new GValue<>(name, GType.DOUBLE, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a BigInteger value.
+     */
+    public static GValue<BigInteger> ofBigInteger(final BigInteger value) {
+        return new GValue<>(GType.BIG_INTEGER, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a BigInteger value with a specified name.
+     */
+    public static GValue<BigInteger> ofBigInteger(final String name, final BigInteger value) {
+        return new GValue<>(name, GType.BIG_INTEGER, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a BigDecimal value.
+     */
+    public static GValue<BigDecimal> ofBigDecimal(final BigDecimal value) {
+        return new GValue<>(GType.BIG_DECIMAL, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a BigDecimal value with a specified name.
+     */
+    public static GValue<BigDecimal> ofBigDecimal(final String name, final BigDecimal value) {
+        return new GValue<>(name, GType.BIG_DECIMAL, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a long value.
+     */
+    public static GValue<Long> ofLong(final Long value) {
+        return new GValue<>(GType.LONG, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a long value with a specified name.
+     */
+    public static GValue<Long> ofLong(final String name, final Long value) {
+        return new GValue<>(name, GType.LONG, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a map value.
+     */
+    public static GValue<Map> ofMap(final Map value) {
+        return new GValue<>(GType.MAP, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a map value with a specified name.
+     */
+    public static GValue<Map> ofMap(final String name, final Map value) {
+        return new GValue<>(name, GType.MAP, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a list value.
+     */
+    public static <T> GValue<List<T>> ofList(final List<T> value) {
+        return new GValue<>(GType.LIST, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a list value with a specified name.
+     */
+    public static <T> GValue<List<T>> ofList(final String name, final List<T> value) {
+        return new GValue<>(name, GType.LIST, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a set value.
+     */
+    public static GValue<Set> ofSet(final Set value) {
+        return new GValue<>(GType.SET, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a set value with a specified name.
+     */
+    public static GValue<Set> ofSet(final String name, final Set value) {
+        return new GValue<>(name, GType.SET, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a vertex value.
+     */
+    public static GValue<Vertex> ofVertex(final Vertex value) {
+        return new GValue<>(GType.VERTEX, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a vertex value with a specified name.
+     */
+    public static GValue<Vertex> ofVertex(final String name, final Vertex value) {
+        return new GValue<>(name, GType.VERTEX, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for an edge value.
+     */
+    public static GValue<Edge> ofEdge(final Edge value) {
+        return new GValue<>(GType.EDGE, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for an edge value with a specified name.
+     */
+    public static GValue<Edge> ofEdge(final String name, final Edge value) {
+        return new GValue<>(name, GType.EDGE, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a path value.
+     */
+    public static GValue<Path> ofPath(final Path value) {
+        return new GValue<>(GType.PATH, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a path value with a specified name.
+     */
+    public static GValue<Path> ofPath(final String name, final Path value) {
+        return new GValue<>(name, GType.PATH, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a property value.
+     */
+    public static GValue<Property> ofProperty(final Property value) {
+        return new GValue<>(GType.PROPERTY, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a property value with a specified name.
+     */
+    public static GValue<Property> ofProperty(final String name, final Property value) {
+        return new GValue<>(name, GType.PROPERTY, value);
+    }
+
+    /**
+     * If the object is a {@code GValue} then get its value, otherwise return the object as-is.
+     */
+    public static <T> T getFrom(final Object o) {
+        return o instanceof GValue ? ((GValue<T>) o).get() : (T) o;
+    }
+
+    /**
+     * Tests if the object is a {@link GValue} and if so, checks the type of the value against the provided
+     * {@link GType}.
+     */
+    public static boolean valueInstanceOf(final Object o, final GType type) {
+        return o instanceof GValue && ((GValue) o).getType() == type;
+    }
+
+    /**
+     * Tests if the object is a {@link GValue} and if so, checks if the type of the value is a collection.
+     */
+    public static boolean valueInstanceOfCollection(final Object o) {
+        return o instanceof GValue && ((GValue) o).getType().isCollection();
+    }
+
+    /**
+     * Tests if the object is a {@link GValue} and if so, checks if the type of the value is a numeric.
+     */
+    public static boolean valueInstanceOfNumeric(final Object o) {
+        return o instanceof GValue && ((GValue) o).getType().isNumeric();
+    }
+
+    /**
+     * Checks the type of the object against the provided {@link GType}. If the object is a {@link GValue} then it
+     * can directly check the type, otherwise it will test the given object's class itself using the mappign on the
+     * {@link GType}.
+     */
+    public static boolean instanceOf(final Object o, final GType type) {
+        if (null == o)
+            return false;
+        else if (o instanceof GValue)
+            return ((GValue) o).getType() == type;
+        else
+            return type.getJavaType().isAssignableFrom(o.getClass());
+    }
+
+    /**
+     * Returns {@code true} if the object is a collection or a {@link GValue} that contains a {@link Collection}.
+     */
+    public static boolean instanceOfCollection(final Object o) {
+        return o instanceof Collection || (o instanceof GValue && ((GValue) o).getType().isCollection());
+    }
+
+    /**
+     * Returns {@code true} if the object is an element or a {@link GValue} that contains an {@link Element}.
+     */
+    public static boolean instanceOfElement(final Object o) {
+        return o instanceof Element || (o instanceof GValue && ((GValue) o).getType().isElement());
+    }
+
+    /**
+     * Returns {@code true} if the object is a number or a {@link GValue} that contains a number.
+     */
+    public static boolean instanceOfNumber(final Object o) {
+        return o instanceof Number || (o instanceof GValue && ((GValue) o).getType().isNumeric());
+    }
+
+    /**
+     * The elements in object array argument are examined to see if they are {@link GValue} objects. If they are, they
+     * are preserved as is. If they are not then they are wrapped in a {@link GValue} object.
+     */
+    public static <T> GValue<T>[] ensureGValues(final Object[] args) {
+        return Stream.of(args).map(GValue::of).toArray(GValue[]::new);
+    }
+
+    /**
+     * Converts {@link GValue} objects argument array to their values to prevent them from leaking to the Graph API.
+     * Providers extending from this step should use this method to get actual values to prevent any {@link GValue}
+     * objects from leaking to the Graph API.
+     */
+    public static Object[] resolveToValues(final GValue<?>[] gvalues) {
+        final Object[] values = new Object[gvalues.length];
+        for (int i = 0; i < gvalues.length; i++) {
+            values[i] = gvalues[i].get();
+        }
+        return values;
+    }
+
+    /**
+     * Takes an argument that is either a {@code GValue} or an object and if the former, returns the child object and
+     * if the latter returns the object itself.
+     */
+    public static Object valueOf(final Object either) {
+        if (either instanceof GValue)
+            return ((GValue<?>) either).get();
+        else
+            return either;
+    }
+
+    /**
+     * Takes an argument that is either a {@code GValue} or an object and returns its {@code Number} form, otherwise
+     * throws an exception.
+     */
+    public static Number numberOf(final Object either) {
+        final Object o = valueOf(either);
+        if (o instanceof Number)
+            return (Number) o;
+        else
+            throw new IllegalStateException("Argument is not a number");
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
index e4a44abe93..5fd63ee3de 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Seedable;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -29,16 +30,23 @@ import java.util.Random;
 import java.util.Set;
 
 /**
+ * A filter step that will randomly allow traversers to pass through the step based on a probability value.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public final class CoinStep<S> extends FilterStep<S> implements Seedable {
 
     private final Random random = new Random();
-    private final double probability;
+    private final GValue<Double> probability;
 
     public CoinStep(final Traversal.Admin traversal, final double probability) {
         super(traversal);
-        this.probability = probability;
+        this.probability = GValue.ofDouble(probability);
+    }
+
+    public CoinStep(final Traversal.Admin traversal, final GValue<Double> probability) {
+        super(traversal);
+        this.probability = null == probability ? GValue.ofDouble(null) : probability;
     }
 
     @Override
@@ -47,7 +55,11 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable {
     }
 
     public double getProbability() {
-        return this.probability;
+        return probability.get();
+    }
+
+    public GValue<Double> getProbabilityGValue() {
+        return probability;
     }
 
     @Override
@@ -55,11 +67,11 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable {
         long newBulk = 0l;
         if (traverser.bulk() < 100) {
             for (int i = 0; i < traverser.bulk(); i++) {
-                if (this.probability >= random.nextDouble())
+                if (this.probability.get() >= random.nextDouble())
                     newBulk++;
             }
         } else {
-            newBulk = Math.round(this.probability * traverser.bulk());
+            newBulk = Math.round(this.probability.get() * traverser.bulk());
         }
         if (0 == newBulk) return false;
         traverser.setBulk(newBulk);
@@ -73,7 +85,7 @@ public final class CoinStep<S> extends FilterStep<S> implements Seedable {
 
     @Override
     public int hashCode() {
-        return super.hashCode() ^ Double.hashCode(this.probability);
+        return super.hashCode() ^ Double.hashCode(this.probability.get());
     }
 
     @Override
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 f5f7280764..db3f72cfe7 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,8 @@ 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;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Writing;
@@ -59,6 +61,11 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
         this.parameters.set(this, T.label, edgeLabel);
     }
 
+    public AddEdgeStep(final Traversal.Admin traversal, final GValue<String> edgeLabel) {
+        super(traversal);
+        this.parameters.set(this, T.label, edgeLabel);
+    }
+
     public AddEdgeStep(final Traversal.Admin traversal, final Traversal.Admin<S,String> edgeLabelTraversal) {
         super(traversal);
         this.parameters.set(this, T.label, edgeLabelTraversal);
@@ -107,7 +114,7 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
                     edgeLabel, e.getMessage()));
         }
 
-        if (!(theTo instanceof Vertex))
+        if (!GValue.instanceOf(theTo, 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()));
@@ -121,13 +128,13 @@ public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
                     edgeLabel, e.getMessage()));
         }
 
-        if (!(theFrom instanceof Vertex))
+        if (!GValue.instanceOf(theFrom, 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 = GValue.getFrom(theTo);
+        Vertex fromVertex = GValue.getFrom(theFrom);
 
         if (toVertex instanceof Attachable)
             toVertex = ((Attachable<Vertex>) toVertex)
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
index 0dfb55c2a1..cfde7d84fc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.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.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Writing;
@@ -52,6 +53,10 @@ public class AddVertexStep<S> extends ScalarMapStep<S, Vertex>
         this.parameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label);
         userProvidedLabel = label != null;
     }
+    public AddVertexStep(final Traversal.Admin traversal, final GValue<String> label) {
+        super(traversal);
+        this.parameters.set(this, T.label, null == label ? Vertex.DEFAULT_LABEL : label);
+    }
 
     public AddVertexStep(final Traversal.Admin traversal, final Traversal.Admin<S,String> vertexLabelTraversal) {
         super(traversal);
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/CombineStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.java
index ccf601acab..67c120c03a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.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;
@@ -37,7 +38,7 @@ import java.util.Set;
  */
 public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implements TraversalParent, ListFunction {
     private Traversal.Admin<S, E> valueTraversal;
-    private Object parameterItems;
+    private GValue<Object> parameterItems;
 
     public CombineStep(final Traversal.Admin traversal, final Object values) {
         super(traversal);
@@ -45,7 +46,7 @@ public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implement
         if (values instanceof Traversal) {
             valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin());
         } else {
-            parameterItems = values;
+            parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values);
         }
     }
 
@@ -53,9 +54,9 @@ public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implement
     public String getStepName() { return "combine"; }
 
     @Override
-    protected List<?> map(Traverser.Admin<S> traverser) {
+    protected List<?> map(final 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 combined = new ArrayList(listA);
         combined.addAll(listB);
@@ -68,7 +69,11 @@ public final class CombineStep<S, E> extends ScalarMapStep<S, List<?>> implement
         return (null == valueTraversal) ? Collections.emptyList() : Collections.singletonList(valueTraversal);
     }
 
-    public Object getParameterItems() {
+    public Object getParameter() {
+        return parameterItems.get();
+    }
+
+    public GValue<Object> getParameterItems() {
         return parameterItems;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
index ce6818b473..e6bb27a2e7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.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.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ListFunction;
 
@@ -34,11 +35,15 @@ import java.util.Set;
  * A map step that returns the result of joining every element in the traverser using the delimiter argument.
  */
 public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements ListFunction {
-    private String delimiter;
+    private GValue<String> delimiter;
 
     public ConjoinStep(final Traversal.Admin traversal, final String delimiter) {
+        this(traversal, GValue.of(delimiter));
+    }
+
+    public ConjoinStep(final Traversal.Admin traversal, final GValue<String> delimiter) {
         super(traversal);
-        if (null == delimiter) { throw new IllegalArgumentException("Input delimiter to conjoin step can't be null."); }
+        if (null == delimiter || null == delimiter.get()) { throw new IllegalArgumentException("Input delimiter to conjoin step can't be null."); }
         this.delimiter = delimiter;
     }
 
@@ -46,7 +51,7 @@ public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements Li
     public String getStepName() { return "conjoin"; }
 
     @Override
-    protected String map(Traverser.Admin<S> traverser) {
+    protected String map(final Traverser.Admin<S> traverser) {
         final Collection elements = convertTraverserToCollection(traverser);
         if (elements.isEmpty()) { return ""; }
 
@@ -54,12 +59,12 @@ public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements Li
 
         for (Object elem : elements) {
             if (elem != null) {
-                joinResult.append(String.valueOf(elem)).append(delimiter);
+                joinResult.append(elem).append(delimiter.get());
             }
         }
 
         if (joinResult.length() != 0) {
-            joinResult.delete(joinResult.length() - delimiter.length(), joinResult.length());
+            joinResult.delete(joinResult.length() - delimiter.get().length(), joinResult.length());
             return joinResult.toString();
         } else {
             return null;
@@ -67,6 +72,10 @@ public final class ConjoinStep<S> extends ScalarMapStep<S, String> implements Li
     }
 
     public String getDelimiter() {
+        return this.delimiter.get();
+    }
+
+    public GValue<String> getDelimiterGValue() {
         return this.delimiter;
     }
 
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 9434cc3b47..3646b599b2 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
@@ -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.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -29,29 +30,36 @@ import java.util.Set;
 
 public class ConstantStep<S, E> extends ScalarMapStep<S, E> {
 
-    private final E constant;
+    private final GValue<E> constant;
 
     public ConstantStep(final Traversal.Admin traversal, final E constant) {
+        this(traversal, constant instanceof GValue ? (GValue) constant : GValue.of(constant));
+    }
+
+    public ConstantStep(final Traversal.Admin traversal, final GValue<E> constant) {
         super(traversal);
-        this.constant = constant;
+        this.constant = null == constant ? GValue.of(null) : constant;
     }
 
     public E getConstant() {
+        return this.constant.get();
+    }
+    public GValue<E> getConstantGValue() {
         return this.constant;
     }
 
     @Override
     protected E map(final Traverser.Admin<S> traverser) {
-        return this.constant;
+        return this.constant.get();
     }
 
     @Override
     public String toString() {
-        return StringFactory.stepString(this, this.constant);
+        return StringFactory.stepString(this, this.constant.get());
     }
 
     @Override
     public int hashCode() {
-        return super.hashCode() ^ Objects.hashCode(this.constant);
+        return super.hashCode() ^ Objects.hashCode(this.constant.get());
     }
 }
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..27922b984e 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,37 @@ 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 Object getParameterItems() {
+        return parameterItems;
+    }
+
+    public GValue<Object> getParameterItemsGValue() {
+        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..c82eac3f64 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);
         }
     }
 
@@ -51,7 +53,11 @@ public final class DisjunctStep<S, E> extends ScalarMapStep<S, Set<?>> implement
     }
 
     public Object getParameterItems() {
-        return this.parameterItems;
+        return parameterItems;
+    }
+
+    public GValue<Object> getParameterItemsGValue() {
+        return parameterItems;
     }
 
     @Override
@@ -60,7 +66,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/GraphStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
index 3b1720ff9a..c009588864 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
@@ -25,6 +25,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.GraphComputing;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
@@ -42,7 +43,9 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.function.Supplier;
 
 /**
@@ -53,7 +56,8 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
 
     protected Parameters parameters = new Parameters();
     protected final Class<E> returnClass;
-    protected Object[] ids;
+    protected GValue<?>[] ids;
+    protected boolean legacyLogicForPassingNoIds = false;
     protected transient Supplier<Iterator<E>> iteratorSupplier;
     protected boolean isStart;
     protected boolean done = false;
@@ -64,11 +68,40 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
     public GraphStep(final Traversal.Admin traversal, final Class<E> returnClass, final boolean isStart, final Object... ids) {
         super(traversal);
         this.returnClass = returnClass;
-        this.ids = (ids != null && ids.length == 1 && ids[0] instanceof Collection) ? ((Collection) ids[0]).toArray(new Object[((Collection) ids[0]).size()]) : ids;
+
+        // if ids is a single collection like g.V(['a','b','c']), then unroll it into an array of ids
+        this.ids = GValue.ensureGValues(tryUnrollSingleCollectionArgument(ids));
+
         this.isStart = isStart;
+
         this.iteratorSupplier = () -> (Iterator<E>) (Vertex.class.isAssignableFrom(this.returnClass) ?
-                this.getTraversal().getGraph().get().vertices(this.ids) :
-                this.getTraversal().getGraph().get().edges(this.ids));
+                this.getTraversal().getGraph().get().vertices(GValue.resolveToValues(this.ids)) :
+                this.getTraversal().getGraph().get().edges(GValue.resolveToValues(this.ids)));
+    }
+
+    /**
+     * Unrolls a single collection argument into an array of ids. This is useful for steps like
+     * {@code g.V(['a','b','c'])}.
+     */
+    protected static Object[] tryUnrollSingleCollectionArgument(final Object[] ids) {
+        final Object[] tempIds;
+        if (ids != null && ids.length == 1) {
+            final Optional<Collection> opt;
+            if (ids[0] instanceof GValue && ((GValue<?>) ids[0]).getType().isCollection())
+                opt = Optional.of((Collection) ((GValue) ids[0]).get());
+            else if (ids[0] instanceof Collection)
+                opt = Optional.of((Collection) ids[0]);
+            else
+                opt = Optional.empty();
+
+            if (opt.isPresent()) {
+                tempIds = opt.get().toArray(new Object[opt.get().size()]);
+            } else
+                tempIds = ids;
+        } else {
+            tempIds = ids;
+        }
+        return tempIds;
     }
 
     public String toString() {
@@ -109,24 +142,39 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
         this.iteratorSupplier = iteratorSupplier;
     }
 
-    public Object[] getIds() {
+    /**
+     * Get the ids associated with this step. If there are {@link GValue} objects present they will be returned
+     * alongside literal ids. Prefer {@link #getIdsAsValues()} if you prefer to work with literal ids only.
+     */
+    public GValue[] getIds() {
         return this.ids;
     }
 
+    /**
+     * Gets the ids associated with this step as literal values rather than {@link GValue} objects.
+     */
+    public Object[] getIdsAsValues() {
+        if (legacyLogicForPassingNoIds) return null;
+        return GValue.resolveToValues(this.ids);
+    }
+
     public void addIds(final Object... newIds) {
-        if ((this.ids == null || this.ids.length == 0) &&
-                newIds.length == 1 &&
-                newIds[0] instanceof Collection && ((Collection) newIds[0]).isEmpty())
-            this.ids = null;
-        else
-            this.ids = ArrayUtils.addAll(this.ids,
-                    (newIds.length == 1 && newIds[0] instanceof Collection) ?
-                            ((Collection) newIds[0]).toArray(new Object[((Collection) newIds[0]).size()]) :
-                            newIds);
+        // there is some logic that has been around for a long time that used to set ids to null. it only happened here
+        // in this method and only occurred when the ids were already null or empty and the newIds were length 1 and
+        // an instance of List and that list was empty. so basically it would trigger for something like g.V().hasId([])
+        // which in turn would trigger an empty iterator in TinkerGraphStep and zero results. trying to maintain that
+        // logic now with GValue in the mix is tough because the context of what the meaning is gets lost by the time
+        // you get to calling getResolvedIds(). using a flag to try to maintain that legacy logic, but ultimately, all
+        // this needs to be rethought.
+        this.legacyLogicForPassingNoIds = newIds.length == 1 && ((newIds[0] instanceof List && ((List) newIds[0]).isEmpty()) ||
+                (newIds[0] instanceof GValue && ((GValue) newIds[0]).getType().isCollection() && ((List) ((GValue) newIds[0]).get()).isEmpty()));
+
+        final GValue[] gvalues = GValue.ensureGValues(tryUnrollSingleCollectionArgument(newIds));
+        this.ids = ArrayUtils.addAll(this.ids, gvalues);
     }
 
     public void clearIds() {
-        this.ids = new Object[0];
+        this.ids = new GValue[0];
     }
 
     @Override
@@ -137,9 +185,12 @@ public class GraphStep<S, E extends Element> extends AbstractStep<S, E> implemen
 
     public void convertElementsToIds() {
         if (null != this.ids) {
-            for (int i = 0; i < this.ids.length; i++) {    // if this is going to OLAP, convert to ids so you don't serialize elements
-                if (this.ids[i] instanceof Element)
-                    this.ids[i] = ((Element) this.ids[i]).id();
+            // if this is going to OLAP, convert to ids so you don't serialize elements
+            for (int i = 0; i < this.ids.length; i++) {
+                final GValue<?> current = this.ids[i];
+                if (current.getType().isElement()) {
+                    this.ids[i] = GValue.of(current.getName(), ((Element) current.get()).id());
+                }
             }
         }
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java
index 651dec7502..3c37db29e0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.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 IntersectStep<S, E> extends ScalarMapStep<S, Set<?>> implements TraversalParent, ListFunction {
     private Traversal.Admin<S, E> valueTraversal;
-    private Object parameterItems;
+    private GValue<Object> parameterItems;
 
     public IntersectStep(final Traversal.Admin traversal, final Object values) {
         super(traversal);
@@ -44,7 +45,7 @@ public final class IntersectStep<S, E> extends ScalarMapStep<S, Set<?>> implemen
         if (values instanceof Traversal) {
             valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin());
         } else {
-            parameterItems = values;
+            parameterItems = values instanceof GValue ? (GValue<Object>) values : GValue.of(values);
         }
     }
 
@@ -53,16 +54,20 @@ public final class IntersectStep<S, E> extends ScalarMapStep<S, Set<?>> implemen
     }
 
     public Object getParameterItems() {
-        return this.parameterItems;
+        return parameterItems;
+    }
+
+    public GValue<Object> getParameterItemsGValue() {
+        return parameterItems;
     }
 
     @Override
     public String getStepName() { return "intersect"; }
 
     @Override
-    protected Set<?> map(Traverser.Admin<S> traverser) {
+    protected Set<?> map(final Traverser.Admin<S> traverser) {
         final Set setA = convertTraverserToSet(traverser);
-        final Collection setB = (null != valueTraversal) ? convertTraversalToCollection(traverser, this.valueTraversal) : convertArgumentToCollection(parameterItems);
+        final Collection setB = (null != valueTraversal) ? convertTraversalToCollection(traverser, this.valueTraversal) : convertArgumentToCollection(parameterItems.get());
         final Set intersection = new HashSet();
 
         for (Object element : setB) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
index bb22d218e5..5beb203a24 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java
@@ -34,6 +34,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventUtil;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -71,6 +72,10 @@ public class MergeEdgeStep<S> extends MergeElementStep<S, Edge, Object> {
         super(traversal, isStart, merge);
     }
 
+    public MergeEdgeStep(final Traversal.Admin traversal, final boolean isStart, final GValue<Map> merge) {
+        super(traversal, isStart, merge);
+    }
+
     public MergeEdgeStep(final Traversal.Admin traversal, final boolean isStart, final Traversal.Admin<S,Map> mergeTraversal) {
         super(traversal, isStart, mergeTraversal);
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java
index 44e954fb31..6835387c5e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeElementStep.java
@@ -35,6 +35,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.IdentityTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Deleting;
+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.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Writing;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
@@ -80,6 +82,11 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
         validate(mergeMap, false);
     }
 
+    public MergeElementStep(final Traversal.Admin traversal, final boolean isStart, final GValue<Map> mergeMap) {
+        this(traversal, isStart, new ConstantTraversal<>(mergeMap));
+        validate(mergeMap.get(), false);
+    }
+
     public MergeElementStep(final Traversal.Admin traversal, final boolean isStart,
                             final Traversal.Admin mergeTraversal) {
         super(traversal);
@@ -279,7 +286,7 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
                             op, allowedTokens, k));
                 }
                 if (k == T.label) {
-                    if (!(v instanceof String)) {
+                    if (!(GValue.instanceOf(v, GType.STRING))) {
                         throw new IllegalArgumentException(String.format(
                                 "%s() and option(onCreate) args expect T.label value to be of String - found: %s", op,
                                 v.getClass().getSimpleName()));
@@ -318,7 +325,8 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
      * null Map == empty Map
      */
     protected Map materializeMap(final Traverser.Admin<S> traverser, Traversal.Admin<S, ?> mapTraversal) {
-        Map map = (Map) TraversalUtil.apply(traverser, mapTraversal);
+        final Object o = TraversalUtil.apply(traverser, mapTraversal);
+        Map map = GValue.getFrom(o);
 
         // PartitionStrategy uses parameters as a mechanism for setting the partition key. trying to be as specific
         // as possible here wrt parameters usage to avoid misuse
@@ -360,7 +368,7 @@ public abstract class MergeElementStep<S, E, C> extends FlatMapStep<S, E>
         return id != null ? graph.traversal().V(id) : graph.traversal().V();
     }
 
-    protected GraphTraversal searchVerticesLabelConstraint(GraphTraversal t, final String label) {
+    protected GraphTraversal searchVerticesLabelConstraint(final GraphTraversal t, final String label) {
         return label != null ? t.hasLabel(label) : t;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java
index d11fdf0894..2f86240a42 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.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;
@@ -40,7 +41,7 @@ import java.util.Set;
  */
 public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements TraversalParent, ListFunction {
     private Traversal.Admin<S, E> valueTraversal;
-    private Object parameterItems;
+    private GValue<Object> parameterItems;
 
     public MergeStep(final Traversal.Admin traversal, final Object values) {
         super(traversal);
@@ -48,10 +49,22 @@ public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements Traver
         if (values instanceof Traversal) {
             valueTraversal = integrateChild(((Traversal<S, E>) values).asAdmin());
         } else {
-            parameterItems = values;
+            parameterItems = GValue.of(values);;
         }
     }
 
+    public Traversal.Admin<S, E> getValueTraversal() {
+        return valueTraversal;
+    }
+
+    public Object getParameterItems() {
+        return parameterItems;
+    }
+
+    public GValue<Object> getParameterItemsGValue() {
+        return parameterItems;
+    }
+
     @Override
     public String getStepName() { return "merge"; }
 
@@ -61,7 +74,7 @@ public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements Traver
 
         final Map mapA = (incoming instanceof Map) ? (Map) incoming : null;
         if (mapA != null) {
-            final Object mapB = (valueTraversal != null) ? TraversalUtil.apply(traverser, valueTraversal) : parameterItems;
+            final Object mapB = (valueTraversal != null) ? TraversalUtil.apply(traverser, valueTraversal) : parameterItems.get();
             if (!(mapB instanceof Map)) {
                 throw new IllegalArgumentException(
                         String.format(
@@ -76,13 +89,13 @@ public final class MergeStep<S, E> extends ScalarMapStep<S, E> implements Traver
         } else {
             final Collection listA = convertTraverserToCollection(traverser);
 
-            if (parameterItems 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)
-                            : convertArgumentToCollection(parameterItems);
+                            : convertArgumentToCollection(parameterItems.get());
 
             final Set elements = new HashSet();
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
index 9aab3790ac..e15ff745bc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
@@ -30,6 +30,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.CardinalityValueTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventUtil;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.T;
@@ -60,6 +61,10 @@ public class MergeVertexStep<S> extends MergeElementStep<S, Vertex, Map> {
         super(traversal, isStart, merge);
     }
 
+    public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final GValue<Map> merge) {
+        super(traversal, isStart, merge);
+    }
+
     public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final Traversal.Admin<S,Map> mergeTraversal) {
         super(traversal, isStart, mergeTraversal);
     }
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..a07b204190 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,29 @@ 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 Object getParameterItems() {
+        return parameterItems;
+    }
+
+    public GValue<Object> getParameterItemsGValue() {
+        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/VertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java
index bd429f049c..b6230e0538 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.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.Configuring;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -39,20 +40,31 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
+ * Handles the logic of traversing to adjacent vertices or edges given a direction and edge labels for steps like,
+ * {@code out}, {@code in}, {@code both}, {@code outE}, {@code inE}, and {@code bothE}.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implements AutoCloseable, Configuring {
 
     protected Parameters parameters = new Parameters();
     private final String[] edgeLabels;
+    private final GValue<String>[] edgeLabelsGValue;
     private Direction direction;
     private final Class<E> returnClass;
 
     public VertexStep(final Traversal.Admin traversal, final Class<E> returnClass, final Direction direction, final String... edgeLabels) {
+        this(traversal, returnClass, direction, GValue.ensureGValues(edgeLabels));
+    }
+
+    public VertexStep(final Traversal.Admin traversal, final Class<E> returnClass, final Direction direction, final GValue<String>... edgeLabels) {
         super(traversal);
         this.direction = direction;
-        this.edgeLabels = edgeLabels;
         this.returnClass = returnClass;
+        this.edgeLabelsGValue = edgeLabels;
+
+        // convert the GValue<String> to a String[] for the edgeLabels field to cache the values
+        this.edgeLabels = Arrays.stream(this.edgeLabelsGValue).map(GValue::get).toArray(String[]::new);
     }
 
     @Override
@@ -67,6 +79,9 @@ public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implem
 
     @Override
     protected Iterator<E> flatMap(final Traverser.Admin<Vertex> traverser) {
+        // not passing GValue to graphs at this point. if a graph wants to support GValue, it should implement
+        // its own step to do so. in this way, we keep things backwards compatible and don't force folks to have
+        // deal with this until they are ready.
         return Vertex.class.isAssignableFrom(this.returnClass) ?
                 (Iterator<E>) traverser.get().vertices(this.direction, this.edgeLabels) :
                 (Iterator<E>) traverser.get().edges(this.direction, this.edgeLabels);
@@ -80,6 +95,10 @@ public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implem
         return this.edgeLabels;
     }
 
+    public GValue<String>[] getEdgeLabelsGValue() {
+        return this.edgeLabelsGValue;
+    }
+
     public Class<E> getReturnClass() {
         return this.returnClass;
     }
@@ -88,10 +107,16 @@ public class VertexStep<E extends Element> extends FlatMapStep<Vertex, E> implem
         this.direction = this.direction.opposite();
     }
 
+    /**
+     * Determines if the step returns vertices.
+     */
     public boolean returnsVertex() {
         return this.returnClass.equals(Vertex.class);
     }
 
+    /**
+     * Determines if the step returns edges.
+     */
     public boolean returnsEdge() {
         return this.returnClass.equals(Edge.class);
     }
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 0502f18541..fa27d5af92 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
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
 
 /**
@@ -26,29 +27,39 @@ import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator;
  */
 public final class InjectStep<S> extends StartStep<S> {
 
-    private final S[] injections;
+    private final GValue<S>[] injections;
 
     @SafeVarargs
     public InjectStep(final Traversal.Admin traversal, final S... injections) {
         super(traversal);
-        this.injections = injections;
-        this.start = new ArrayIterator<>(this.injections);
+        this.injections = GValue.ensureGValues(injections);
+        this.start = new ArrayIterator<>(GValue.resolveToValues(this.injections));
     }
 
     @Override
     public InjectStep<S> clone() {
         final InjectStep<S> clone = (InjectStep<S>) super.clone();
-        clone.start = new ArrayIterator<>(clone.injections);
+        clone.start = new ArrayIterator<>(GValue.resolveToValues(clone.injections));
         return clone;
     }
 
     @Override
     public void reset() {
         super.reset();
-        this.start = new ArrayIterator<>(this.injections);
+        this.start = new ArrayIterator<>(GValue.resolveToValues(this.injections));
     }
 
-    public S[] getInjections() {
+    /**
+     * Get the injections of the step.
+     */
+    public GValue<S>[] getInjectionsGValue() {
         return this.injections;
     }
+
+    /**
+     * Gets the injections of the step but unwraps the {@link GValue}.
+     */
+    public S[] getInjections() {
+        return (S[]) GValue.resolveToValues(this.injections);
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
index d4545ead5c..f0af790c73 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
@@ -228,5 +229,4 @@ public abstract class AbstractStep<S, E> implements Step<S, E> {
         }
         return traverser;
     }
-
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java
index c20c68fde0..35689f8367 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/HasContainer.java
@@ -19,10 +19,12 @@
 package org.apache.tinkerpop.gremlin.process.traversal.step.util;
 
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GType;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 
 import java.io.Serializable;
 import java.util.Collection;
@@ -154,11 +156,11 @@ public class HasContainer implements Serializable, Cloneable, Predicate<Element>
             if (predicateValue instanceof Collection) {
                 final Collection collection = (Collection) predicateValue;
                 if (!collection.isEmpty()) {
-                    return ((Collection) predicateValue).stream().allMatch(c -> null == c || c instanceof String);
+                    return ((Collection) predicateValue).stream().allMatch(c -> null == c || GValue.instanceOf(c, GType.STRING));
                 }
             }
 
-            return predicateValue instanceof String;
+            return GValue.instanceOf(predicateValue, GType.STRING);
         }
 
         return false;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
index d1654a344e..9b4a926c74 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/Parameters.java
@@ -22,6 +22,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.util;
 import org.apache.commons.lang3.ArrayUtils;
 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.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
@@ -165,7 +166,7 @@ public class Parameters implements Cloneable, Serializable {
 
     /**
      * Gets the array of keys/values of the parameters while resolving parameter values that contain
-     * {@link Traversal} instances.
+     * {@link Traversal} or {@link GValue} instances.
      */
     public <S> Object[] getKeyValues(final Traverser.Admin<S> traverser, final Object... exceptKeys) {
         if (this.parameters.isEmpty()) return EMPTY_ARRAY;
@@ -173,14 +174,28 @@ public class Parameters implements Cloneable, Serializable {
         for (final Map.Entry<Object, List<Object>> entry : this.parameters.entrySet()) {
             if (!ArrayUtils.contains(exceptKeys, entry.getKey())) {
                 for (final Object value : entry.getValue()) {
-                    keyValues.add(entry.getKey() instanceof Traversal.Admin ? TraversalUtil.apply(traverser, (Traversal.Admin<S, ?>) entry.getKey()) : entry.getKey());
-                    keyValues.add(value instanceof Traversal.Admin ? TraversalUtil.apply(traverser, (Traversal.Admin<S, ?>) value) : value);
+                    keyValues.add(resolve(entry.getKey(), traverser));
+                    keyValues.add(resolve(value, traverser));
                 }
             }
         }
         return keyValues.toArray(new Object[keyValues.size()]);
     }
 
+    /**
+     * Takes an object and tests if it is a {@link GValue} or a {@link Traversal} and if so, resolves it to its value
+     * otherwise it just returns itself.
+     */
+    private static <S> Object resolve(final Object object, final Traverser.Admin<S> traverser) {
+        if (object instanceof Traversal.Admin) {
+            return TraversalUtil.apply(traverser, (Traversal.Admin<S, ?>) object);
+        } else if (object instanceof GValue) {
+            return ((GValue) object).get();
+        } else {
+            return object;
+        }
+    }
+
     /**
      * Gets an immutable set of the parameters without evaluating them in the context of a {@link Traverser} as
      * is done in {@link #getKeyValues(Traverser.Admin, Object...)}.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
index 67c08254a8..e47b782185 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/ElementIdStrategy.java
@@ -94,11 +94,12 @@ public final class ElementIdStrategy extends AbstractTraversalStrategy<Traversal
             // note that it is then only necessary to replace the step if the id is a non-element.  other tests
             // in the suite validate that items in getIds() is uniform so it is ok to just test the first item
             // in the list.
-            if (graphStep.getIds().length > 0 && !(graphStep.getIds()[0] instanceof Element)) {
+            final Object[] ids = graphStep.getIdsAsValues();
+            if (ids.length > 0 && !(ids[0] instanceof Element)) {
                 if (graphStep instanceof HasContainerHolder)
-                    ((HasContainerHolder) graphStep).addHasContainer(new HasContainer(this.idPropertyKey, P.within(Arrays.asList(graphStep.getIds()))));
+                    ((HasContainerHolder) graphStep).addHasContainer(new HasContainer(this.idPropertyKey, P.within(Arrays.asList(ids))));
                 else
-                    TraversalHelper.insertAfterStep(new HasStep(traversal, new HasContainer(this.idPropertyKey, P.within(Arrays.asList(graphStep.getIds())))), graphStep, traversal);
+                    TraversalHelper.insertAfterStep(new HasStep(traversal, new HasContainer(this.idPropertyKey, P.within(Arrays.asList(ids)))), graphStep, traversal);
                 graphStep.clearIds();
             }
         }
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-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
index 6f34d62226..b44b62f0e3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
@@ -193,7 +193,7 @@ public final class SubgraphStrategy extends AbstractTraversalStrategy<TraversalS
                 continue;
 
             if (edgeCriterion != null) {
-                final VertexStep<Edge> someEStep = new VertexStep<>(traversal, Edge.class, step.getDirection(), step.getEdgeLabels());
+                final VertexStep<Edge> someEStep = new VertexStep<>(traversal, Edge.class, step.getDirection(), step.getEdgeLabelsGValue());
                 final Step<Edge, Vertex> someVStep = step.getDirection() == Direction.BOTH ?
                         new EdgeOtherVertexStep(traversal) :
                         new EdgeVertexStep(traversal, step.getDirection().opposite());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java
index d8e538ab37..b33d527c2c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/AdjacentToIncidentStrategy.java
@@ -118,7 +118,7 @@ public final class AdjacentToIncidentStrategy extends AbstractTraversalStrategy<
         final Step newStep;
         if (step instanceof VertexStep) {
             final VertexStep vs = (VertexStep) step;
-            newStep = new VertexStep<>(traversal, Edge.class, vs.getDirection(), vs.getEdgeLabels());
+            newStep = new VertexStep<>(traversal, Edge.class, vs.getDirection(), vs.getEdgeLabelsGValue());
         } else if (step instanceof PropertiesStep) {
             final PropertiesStep ps = (PropertiesStep) step;
             newStep = new PropertiesStep(traversal, PropertyType.PROPERTY, ps.getPropertyKeys());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
index 75d55adcd0..813b60b955 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/IncidentToAdjacentStrategy.java
@@ -110,7 +110,7 @@ public final class IncidentToAdjacentStrategy extends AbstractTraversalStrategy<
      * @param step2     the vertex-emitting step to replace
      */
     private static void optimizeSteps(final Traversal.Admin traversal, final VertexStep step1, final Step step2) {
-        final Step newStep = new VertexStep(traversal, Vertex.class, step1.getDirection(), step1.getEdgeLabels());
+        final Step newStep = new VertexStep(traversal, Vertex.class, step1.getDirection(), step1.getEdgeLabelsGValue());
         for (final String label : (Iterable<String>) step2.getLabels()) {
             newStep.addLabel(label);
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index d2713218c5..e8b154fef6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -26,6 +26,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+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.LambdaHolder;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalStep;
@@ -124,26 +126,25 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
                 && ((VertexStep) step.getPreviousStep()).returnsEdge()
                 && 0 == ((VertexStep) step.getPreviousStep()).getEdgeLabels().length) {
             final VertexStep<Edge> previousStep = (VertexStep<Edge>) step.getPreviousStep();
-            final List<String> edgeLabels = new ArrayList<>();
+            final List<Object> edgeLabels = new ArrayList<>();
             for (final HasContainer hasContainer : new ArrayList<>(step.getHasContainers())) {
                 if (hasContainer.getKey().equals(T.label.getAccessor())) {
-                    if (hasContainer.getBiPredicate() == Compare.eq &&
-                            hasContainer.getValue() instanceof String &&
+                    if (hasContainer.getBiPredicate() == Compare.eq && GValue.instanceOf(hasContainer.getValue(), GType.STRING) &&
                             edgeLabels.isEmpty()) {
-                        edgeLabels.add((String) hasContainer.getValue());
+                        edgeLabels.add(hasContainer.getValue());
                         step.removeHasContainer(hasContainer);
                     } else if (hasContainer.getBiPredicate() == Contains.within &&
                             hasContainer.getValue() instanceof Collection &&
                             ((Collection) hasContainer.getValue()).containsAll(edgeLabels)) {
-                        edgeLabels.addAll((Collection<String>) hasContainer.getValue());
+                        edgeLabels.addAll((Collection) hasContainer.getValue());
                         step.removeHasContainer(hasContainer);
                     } else if (hasContainer.getPredicate() instanceof OrP && edgeLabels.isEmpty()) {
                         boolean removeContainer = true;
                         final List<P<?>> orps = ((OrP) hasContainer.getPredicate()).getPredicates();
-                        final List<String> newEdges = new ArrayList<>();
+                        final List<Object> newEdges = new ArrayList<>();
                         for (int i = 0; i < orps.size(); i++) {
-                            if (orps.get(i).getBiPredicate() == Compare.eq && orps.get(i).getValue() instanceof String)
-                                newEdges.add((String) orps.get(i).getValue());
+                            if (orps.get(i).getBiPredicate() == Compare.eq && GValue.instanceOf(orps.get(i).getValue(), GType.STRING))
+                                newEdges.add(orps.get(i).getValue());
                             else {
                                 removeContainer = false;
                                 break;
@@ -157,7 +158,7 @@ public final class InlineFilterStrategy extends AbstractTraversalStrategy<Traver
                 }
             }
             if (!edgeLabels.isEmpty()) {
-                final VertexStep<Edge> newVertexStep = new VertexStep<>(traversal, Edge.class, previousStep.getDirection(), edgeLabels.toArray(new String[edgeLabels.size()]));
+                final VertexStep<Edge> newVertexStep = new VertexStep<>(traversal, Edge.class, previousStep.getDirection(), GValue.ensureGValues(edgeLabels.toArray()));
                 TraversalHelper.replaceStep(previousStep, newVertexStep, traversal);
                 TraversalHelper.copyLabels(previousStep, newVertexStep, false);
                 if (step.getHasContainers().isEmpty()) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java
index ab693b9e29..5bf91c41e8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ListFunction.java
@@ -39,7 +39,7 @@ public interface ListFunction {
      * @param iterable an Iterable or array.
      * @return The iterable type as a Collection or null if argument isn't iterable.
      */
-    public static Collection asCollection(Object iterable) {
+    public static Collection asCollection(final Object iterable) {
         if (iterable instanceof Collection) {
             return (Collection) iterable;
         } else if ((iterable != null && iterable.getClass().isArray()) || iterable instanceof Iterable) {
@@ -56,7 +56,7 @@ public interface ListFunction {
      * @param iterable an Iterable or array.
      * @return The iterable type as a Collection or null if argument isn't iterable.
      */
-    public static Set asSet(Object iterable) {
+    public static Set asSet(final Object iterable) {
         if (iterable instanceof Iterable || iterable != null && iterable.getClass().isArray()) {
             return IteratorUtils.asSet(iterable);
         } else {
@@ -71,7 +71,7 @@ public interface ListFunction {
      */
     public String getStepName();
 
-    public default Collection convertArgumentToCollection(Object arg) {
+    public default Collection convertArgumentToCollection(final Object arg) {
         if (null == arg) {
             throw new IllegalArgumentException(
                     String.format("Argument provided for %s step can't be null.", getStepName()));
@@ -90,7 +90,7 @@ public interface ListFunction {
         return incoming;
     }
 
-    public default <S> Collection convertTraverserToCollection(Traverser.Admin<S> traverser) {
+    public default <S> Collection convertTraverserToCollection(final Traverser.Admin<S> traverser) {
         final S items = traverser.get();
 
         if (null == items) {
@@ -111,7 +111,7 @@ public interface ListFunction {
         return incoming;
     }
 
-    public default <S, E> Collection convertTraversalToCollection(Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
+    public default <S, E> Collection convertTraversalToCollection(final Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
         final Object array = TraversalUtil.apply(traverser, traversal);
 
         if (null == array) {
@@ -134,7 +134,7 @@ public interface ListFunction {
         return input;
     }
 
-    public default Set convertArgumentToSet(Object arg) {
+    public default Set convertArgumentToSet(final Object arg) {
         if (null == arg) {
             throw new IllegalArgumentException(
                     String.format("Argument provided for %s step can't be null.", getStepName()));
@@ -153,7 +153,7 @@ public interface ListFunction {
         return incoming;
     }
 
-    public default <S> Set convertTraverserToSet(Traverser.Admin<S> traverser) {
+    public default <S> Set convertTraverserToSet(final Traverser.Admin<S> traverser) {
         final S items = traverser.get();
 
         if (null == items) {
@@ -174,7 +174,7 @@ public interface ListFunction {
         return incoming;
     }
 
-    public default <S, E> Set convertTraversalToSet(Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
+    public default <S, E> Set convertTraversalToSet(final Traverser.Admin<S> traverser, final Traversal.Admin<S, E> traversal) {
         final Object array = TraversalUtil.apply(traverser, traversal);
 
         if (null == array) {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java
index af7a18a1d9..962140adb5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/VertexProperty.java
@@ -18,9 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.structure;
 
-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.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.CardinalityValueTraversal;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyVertexProperty;
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index b06509a4b0..7fa37b5acb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -38,6 +38,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.Text;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
+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.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
@@ -325,7 +327,7 @@ public enum GryoVersion {
 
             add(GryoTypeReg.of(P.class, 124, new GryoSerializersV3.PSerializer()));
             add(GryoTypeReg.of(TextP.class, 186, new GryoSerializersV3.TextPSerializer()));
-            add(GryoTypeReg.of(Text.RegexPredicate.class, 197));                                       // ***LAST ID***
+            add(GryoTypeReg.of(Text.RegexPredicate.class, 197));
             add(GryoTypeReg.of(Lambda.class, 125, new GryoSerializersV3.LambdaSerializer()));
             add(GryoTypeReg.of(Order.class, 127));
             add(GryoTypeReg.of(Scope.class, 128));
@@ -422,6 +424,9 @@ public enum GryoVersion {
             add(GryoTypeReg.of(Stack.class, 181));
             add(GryoTypeReg.of(ReferenceMap.class, 182));
 
+            add(GryoTypeReg.of(GValue.class, 199, new JavaSerializer()));
+            add(GryoTypeReg.of(GType.class, 200, new JavaSerializer()));        // ***LAST ID***
+
             // placeholder serializers for classes that don't live here in core. this will allow them to be used if
             // present  or ignored if the class isn't available. either way the registration numbers are held as
             // placeholders so that the format stays stable
@@ -538,7 +543,7 @@ public enum GryoVersion {
             add(GryoTypeReg.of(Pop.class, 133));
             add(GryoTypeReg.of(SackFunctions.Barrier.class, 135));
             add(GryoTypeReg.of(Pick.class, 137));
-            add(GryoTypeReg.of(DT.class, 198));     // ***LAST ID***
+            add(GryoTypeReg.of(DT.class, 198));
             add(GryoTypeReg.of(Merge.class, 196));
             add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer()));
             add(GryoTypeReg.of(MultiComparator.class, 165));
@@ -629,6 +634,9 @@ public enum GryoVersion {
             add(GryoTypeReg.of(LabelledCounter.class, 180));
             add(GryoTypeReg.of(Stack.class, 181));
             add(GryoTypeReg.of(ReferenceMap.class, 182));
+
+            add(GryoTypeReg.of(GValue.class, 199, new JavaSerializer()));
+            add(GryoTypeReg.of(GType.class, 200, new JavaSerializer()));        // ***LAST ID***
         }};
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java
index 1242d16af7..27d41d8e18 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/CollectionUtil.java
@@ -19,6 +19,9 @@
 
 package org.apache.tinkerpop.gremlin.util;
 
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -29,22 +32,36 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+/**
+ * Utility class for working with collections and arrays.
+ */
 public final class CollectionUtil {
-    private CollectionUtil() {
-    }
+    private CollectionUtil() { }
 
+    /**
+     * Converts varargs to a {@code List}.
+     */
     public static <E> List<E> asList(final E... elements) {
         return new ArrayList<>(Arrays.asList(elements));
     }
 
+    /**
+     * Converts varargs to a {@code Set}.
+     */
     public static <E> LinkedHashSet<E> asSet(final E... elements) {
         return asSet(Arrays.asList(elements));
     }
 
+    /**
+     * Converts {@code Collection} to a {@code Set}.
+     */
     public static <E> LinkedHashSet<E> asSet(final Collection<E> elements) {
         return new LinkedHashSet<>(elements);
     }
 
+    /**
+     * Converts varargs to a {@code Map} where the elements are key/value pairs.
+     */
     public static <K,V> LinkedHashMap<K,V> asMap(final Object... elements) {
         final LinkedHashMap<K,V> map = new LinkedHashMap<>();
         for (int i = 0; i < elements.length; i+=2) {
@@ -55,6 +72,11 @@ public final class CollectionUtil {
         return map;
     }
 
+    /**
+     * Clones a given {@code ConcurrentHashMap} by creating a new map and copying all entries from the original map.
+     * If the value of an entry is a {@code Set} or an {@code ArrayList}, a deep copy of the value is created.
+     * Otherwise, the value is copied as is.
+     */
     public static <K,V> ConcurrentHashMap<K,V> clone(final ConcurrentHashMap<K,V> map) {
         final ConcurrentHashMap<K, V> result = new ConcurrentHashMap<>(map.size());
 
@@ -74,4 +96,22 @@ public final class CollectionUtil {
 
         return result;
     }
+
+    /**
+     * Adds the element argument to the start of the supplied array argument, but if the array is null then return the
+     * element as a new array with just that item in it.
+     */
+    public static <T> T[] addFirst(final T[] array, final T element, final Class<T> clazz) {
+        if (null == array && null == element) {
+            final T[] singleElementArray = (T[]) Array.newInstance(clazz, 1);
+            singleElementArray[0] = null;
+            return singleElementArray;
+        } else if (null == array) {
+            final T[] singleElementArray = (T[]) Array.newInstance(clazz, 1);
+            singleElementArray[0] = element;
+            return singleElementArray;
+        } else {
+            return ArrayUtils.addFirst(array, element);
+        }
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPluginTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPluginTest.java
new file mode 100644
index 0000000000..0d3dc5fd96
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/VariableResolverPluginTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.tinkerpop.gremlin.jsr223;
+
+import org.apache.tinkerpop.gremlin.language.grammar.GremlinParser;
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
+import org.junit.Test;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class VariableResolverPluginTest {
+
+    @Test
+    public void shouldProduceNullVariableResolver() {
+        final Map<String, Object> bindings = new HashMap<>();
+        final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+                resolver(VariableResolver.NullVariableResolver.class.getSimpleName()).create();
+        final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+                get()[0]).getVariableResolverMaker().apply(bindings);
+        assertThat(resolver, instanceOf(VariableResolver.NullVariableResolver.class));
+    }
+
+    @Test
+    public void shouldProduceNoVariableResolver() {
+        final Map<String, Object> bindings = new HashMap<>();
+        final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+                resolver(VariableResolver.NoVariableResolver.class.getSimpleName()).create();
+        final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+                get()[0]).getVariableResolverMaker().apply(bindings);
+        assertThat(resolver, instanceOf(VariableResolver.NoVariableResolver.class));
+    }
+
+    @Test
+    public void shouldProduceDefaultVariableResolver() {
+        final Map<String, Object> bindings = new HashMap<>();
+        final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+                resolver(VariableResolver.DefaultVariableResolver.class.getSimpleName()).create();
+        final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+                get()[0]).getVariableResolverMaker().apply(bindings);
+        assertThat(resolver, instanceOf(VariableResolver.DefaultVariableResolver.class));
+    }
+
+    @Test
+    public void shouldProduceDirectVariableResolver() {
+        final Map<String, Object> bindings = new HashMap<>();
+        final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+                resolver(VariableResolver.DirectVariableResolver.class.getSimpleName()).create();
+        final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+                get()[0]).getVariableResolverMaker().apply(bindings);
+        assertThat(resolver, instanceOf(VariableResolver.DirectVariableResolver.class));
+    }
+
+    @Test
+    public void shouldProduceDefaultedVariableResolverWhenNoSpecified() {
+        final Map<String, Object> bindings = new HashMap<>();
+        final VariableResolverPlugin plugin = VariableResolverPlugin.build().create();
+        final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+                get()[0]).getVariableResolverMaker().apply(bindings);
+        assertThat(resolver, instanceOf(VariableResolver.DirectVariableResolver.class));
+    }
+
+    @Test
+    public void shouldProduceCustomVariableResolverForFullyQualifiedClassName() {
+        final Map<String, Object> bindings = new HashMap<>();
+        final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+                resolver(CustomVariableResolver.class.getName()).create();
+        final VariableResolver resolver = ((VariableResolverCustomizer) plugin.getCustomizers().
+                get()[0]).getVariableResolverMaker().apply(bindings);
+        assertThat(resolver, instanceOf(CustomVariableResolver.class));
+    }
+
+    @Test
+    public void shouldProduceExceptionVariableResolverIfResolverNotFound() {
+        try {
+            final VariableResolverPlugin plugin = VariableResolverPlugin.build().
+                    resolver("NotAResolver").create();
+            fail("The resolver does not exist and should have failed");
+        } catch (Exception re) {
+            assertThat(re.getMessage(), containsString("VariableResolver class not found: NotAResolver"));
+        }
+    }
+
+    /**
+     * Custom test implementation of {@link VariableResolver} that is not part of the standard set of implementations.
+     * This class does nothing.
+     */
+    public static class CustomVariableResolver implements VariableResolver<Object> {
+        public CustomVariableResolver(final Map<String, Object> m) {
+        }
+
+        @Override
+        public Object apply(final String varName, final GremlinParser.VariableContext variableContext) {
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
index 4dd0af45c6..6a665787d3 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitorTest.java
@@ -84,58 +84,56 @@ public class ArgumentVisitorTest {
     public static Iterable<Object[]> generateTestParameters() {
         return Arrays.asList(new Object[][]{
                 {Boolean.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {Boolean.class, "true", true, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", true)))},
-                {Boolean.class, "false", false, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", true)))},
-                {Boolean.class, "x", true, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", true)))},
+                {Boolean.class, "true", true, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", true)))},
+                {Boolean.class, "false", false, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", true)))},
+                {Boolean.class, "x", true, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", true)))},
                 {Integer.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {Integer.class, "0", 0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
-                {Integer.class, "0i", 0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
-                {Integer.class, "0L", 0L, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100)))},
-                {Integer.class, "x", 0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0)))},
-                {Integer.class, "x", 0L, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0L)))},
+                {Integer.class, "0", 0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100)))},
+                {Integer.class, "0i", 0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100)))},
+                {Integer.class, "0L", 0L, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100)))},
+                {Integer.class, "x", 0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0)))},
+                {Integer.class, "x", 0L, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0L)))},
                 {Float.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {Float.class, "0.0d", 0.0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0)))},
-                {Float.class, "0d", 0.0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0)))},
-                {Float.class, "0F", 0.0F, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 1000.0F)))},
-                {Float.class, "x", 0.0, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0.0)))},
-                {Float.class, "x", 0.0F, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 0.0F)))},
+                {Float.class, "0.0d", 0.0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 1000.0)))},
+                {Float.class, "0d", 0.0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 1000.0)))},
+                {Float.class, "0F", 0.0F, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 1000.0F)))},
+                {Float.class, "x", 0.0, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0.0)))},
+                {Float.class, "x", 0.0F, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 0.0F)))},
                 {String.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {String.class, "'test'", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {String.class, "x", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "test")))},
-                {String.class, "x", "graphson", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", IO.graphson)))},
+                {String.class, "'test'", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {String.class, "x", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "test")))},
+                {String.class, "x", "graphson", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", IO.graphson)))},
                 {StringNullable.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {StringNullable.class, "null", null, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {StringNullable.class, "x", null, createAntlr(new VariableResolver.DefaultVariableResolver(nullMap))},
+                {StringNullable.class, "null", null, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {StringNullable.class, "x", null, createAntlr(new VariableResolver.DirectVariableResolver(nullMap))},
                 {Object.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {Object.class, "'test'", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Object.class, "x", "test", createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "test")))},
-                {Object.class, "x", now, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", now)))},
-                {Object.class, "[1,2,3]", Arrays.asList(1, 2, 3), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", now)))},
-                {Object.class, "x", P.eq(100), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", P.eq(100))))},
-                {Direction.class, "Direction.OUT", Direction.OUT, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Direction.class, "OUT", Direction.OUT, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Vertex.class, "x", new VariableResolverException("x"), createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {Vertex.class, "new Vertex(1i,'person')", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Direction.from)))},
-                {Vertex.class, "x", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", new ReferenceVertex(1, "person"))))},
-                {Order.class, "Order.desc", Order.desc, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Scope.class, "Scope.local", Scope.local, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Scope.class, "local", Scope.local, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {T.class, "T.label", T.label, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {T.class, "label", T.label, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {VertexProperty.Cardinality.class, "Cardinality.list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {VertexProperty.Cardinality.class, "list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {DT.class, "DT.hour", DT.hour, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {DT.class, "hour", DT.hour, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Merge.class, "Merge.onMatch", Merge.onMatch, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Merge.class, "onMatch", Merge.onMatch, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Pop.class, "Pop.last", Pop.last, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Pop.class, "last", Pop.last, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Operator.class, "Operator.sum", Operator.sum, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Operator.class, "sum", Operator.sum, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Column.class, "Column.keys", Column.keys, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Column.class, "keys", Column.keys, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Object.class, "'test'", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Object.class, "x", "test", createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "test")))},
+                {Object.class, "x", now, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", now)))},
+                {Object.class, "[1,2,3]", Arrays.asList(1, 2, 3), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", now)))},
+                {Object.class, "x", P.eq(100), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", P.eq(100))))},
+                {Direction.class, "Direction.OUT", Direction.OUT, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Direction.class, "OUT", Direction.OUT, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Vertex.class, "new Vertex(1i,'person')", new ReferenceVertex(1, "person"), createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Direction.from)))},
+                {Order.class, "Order.desc", Order.desc, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Scope.class, "Scope.local", Scope.local, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Scope.class, "local", Scope.local, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {T.class, "T.label", T.label, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {T.class, "label", T.label, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {VertexProperty.Cardinality.class, "Cardinality.list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {VertexProperty.Cardinality.class, "list", VertexProperty.Cardinality.list, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {DT.class, "DT.hour", DT.hour, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {DT.class, "hour", DT.hour, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Merge.class, "Merge.onMatch", Merge.onMatch, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Merge.class, "onMatch", Merge.onMatch, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Pop.class, "Pop.last", Pop.last, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Pop.class, "last", Pop.last, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Operator.class, "Operator.sum", Operator.sum, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Operator.class, "sum", Operator.sum, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Column.class, "Column.keys", Column.keys, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Column.class, "keys", Column.keys, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {SackFunctions.Barrier.class, "Barrier.normSack", SackFunctions.Barrier.normSack, createAntlr(new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
         });
     }
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java
index 4e7168a7f5..a286e2e5fd 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParserTest.java
@@ -41,7 +41,7 @@ public class GremlinQueryParserTest {
     public void shouldParseVariables() {
         final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
                 EmptyGraph.instance(), __::start, g,
-                new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("z", 50)));
+                new VariableResolver.DirectVariableResolver(ElementHelper.asMap("z", 50)));
         final GraphTraversal<?, ?> t = (GraphTraversal<?, ?>) GremlinQueryParser.parse("g.V().has('name',gt(z))", gremlinAntlrToJava);
 
         assertEquals(g.V().has("name", P.gt(50)).asAdmin().getGremlinLang(),
@@ -52,7 +52,7 @@ public class GremlinQueryParserTest {
     public void shouldParseVariablesInVarargs() {
         final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
                 EmptyGraph.instance(), __::start, g,
-                new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100,
+                new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100,
                                                                                  "y", 200,
                                                                                  "z", 50)));
 
@@ -73,7 +73,7 @@ public class GremlinQueryParserTest {
     public void shouldNotParseVariablesInList() {
         final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
                 EmptyGraph.instance(), __::start, g,
-                new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100,
+                new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100,
                         "y", 200,
                         "z", 50)));
         GremlinQueryParser.parse("g.V([x, y, 300]).has('name',gt(z))", gremlinAntlrToJava);
@@ -83,7 +83,7 @@ public class GremlinQueryParserTest {
     public void shouldNotParseVariablesWhichAreTraversalBased() {
         final GremlinAntlrToJava gremlinAntlrToJava = new GremlinAntlrToJava("g",
                 EmptyGraph.instance(), __::start, g,
-                new VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 100,
+                new VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 100,
                         "y", 200,
                         "z", __.out())));
         GremlinQueryParser.parse("g.V([x, y, 300]).where(z)", gremlinAntlrToJava);
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
index 90022b34d5..82e3461cc5 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
@@ -703,6 +703,33 @@ public class GremlinTranslatorTest {
                             null,
                             null,
                             "g.V().has_label(None)"},
+                    {"g.V().hasLabel(null, null)",
+                            null,
+                            "g.V().hasLabel(string0, string0)",
+                            "g.V().HasLabel((string) null, (string) null)",
+                            "g.V().HasLabel(nil, nil)",
+                            "g.V().hasLabel((String) null, (String) null)",
+                            null,
+                            null,
+                            "g.V().has_label(None, None)"},
+                    {"g.V().hasLabel(null, null, null)",
+                            null,
+                            "g.V().hasLabel(string0, string0, string0)",
+                            "g.V().HasLabel((string) null, (string) null, (string) null)",
+                            "g.V().HasLabel(nil, nil, nil)",
+                            "g.V().hasLabel((String) null, (String) null, (String) null)",
+                            null,
+                            null,
+                            "g.V().has_label(None, None, None)"},
+                    {"g.V().hasLabel(\"person\", null)",
+                            null,
+                            "g.V().hasLabel(string0, string1)",
+                            "g.V().HasLabel(\"person\", (string) null)",
+                            "g.V().HasLabel(\"person\", nil)",
+                            "g.V().hasLabel(\"person\", null)",
+                            null,
+                            null,
+                            "g.V().has_label('person', None)"},
                     {"g.V().hasLabel('person')",
                             null,
                             "g.V().hasLabel(string0)",
@@ -724,9 +751,9 @@ public class GremlinTranslatorTest {
                     {"g.V().hasLabel(null, 'software', 'class')",
                             null,
                             "g.V().hasLabel(string0, string1, string2)",
-                            "g.V().HasLabel(null, \"software\", \"class\")",
+                            "g.V().HasLabel((string) null, \"software\", \"class\")",
                             "g.V().HasLabel(nil, \"software\", \"class\")",
-                            "g.V().hasLabel(null, 'software', 'class')",
+                            "g.V().hasLabel((String) null, 'software', 'class')",
                             "g.V().hasLabel(null, \"software\", \"class\")",
                             "g.V().hasLabel(null, \"software\", \"class\")",
                             "g.V().has_label(None, 'software', 'class')"},
@@ -1045,6 +1072,24 @@ public class GremlinTranslatorTest {
                             null,
                             null,
                             null},
+                    {"g.V().hasLabel(x, y)",
+                            null,
+                            null,
+                            "g.V().HasLabel((string) x, (string) y)",
+                            "g.V().HasLabel(x, y)",
+                            null,
+                            null,
+                            null,
+                            "g.V().has_label(x, y)"},
+                    {"g.V().conjoin(x)",
+                            null,
+                            null,
+                            "g.V().Conjoin((string) x)",
+                            "g.V().Conjoin(x)",
+                            null,
+                            null,
+                            null,
+                            null},
                     {"g.mergeV([name:\"alice\", T.label:\"person\"]).option(Merge.onCreate, [age:Cardinality.single(81)])",
                             null,
                             "g.mergeV(map0).option(Merge.onCreate, map1)",
@@ -1063,6 +1108,15 @@ public class GremlinTranslatorTest {
                             "g.mergeV(new LinkedHashMap<Object, Object>() {{ put(\"name\", \"alice\"); put(T.label, \"person\"); }}).option(Merge.onCreate, new LinkedHashMap<Object, Object>() {{ put(\"age\", Cardinality.single(81)); }})",
                             "g.mergeV(new Map([[\"name\", \"alice\"], [T.label, \"person\"]])).option(Merge.onCreate, new Map([[\"age\", CardinalityValue.single(81)]]))",
                             "g.merge_v({ 'name': 'alice', T.label: 'person' }).option(Merge.on_create, { 'age': CardinalityValue.single(81) })"},
+                    {"g.V().branch(__.label().is(\"person\").count()).option(xx1, __.values(\"age\")).option(xx2, __.values(\"lang\")).option(xx2, __.values(\"name\")).option(Pick.any, __.label())",
+                            null,
+                            "g.V().branch(__.label().is(string0).count()).option(xx1, __.values(string1)).option(xx2, __.values(string2)).option(xx2, __.values(string3)).option(Pick.any, __.label())",
+                            "g.V().Branch<object>(__.Label().Is(\"person\").Count()).Option(xx1, __.Values<object>(\"age\")).Option(xx2, __.Values<object>(\"lang\")).Option(xx2, __.Values<object>(\"name\")).Option(Pick.Any, __.Label())",
+                            "g.V().Branch(gremlingo.T__.Label().Is(\"person\").Count()).Option(xx1, gremlingo.T__.Values(\"age\")).Option(xx2, gremlingo.T__.Values(\"lang\")).Option(xx2, gremlingo.T__.Values(\"name\")).Option(gremlingo.Pick.Any, gremlingo.T__.Label())",
+                            null,
+                            null,
+                            null,
+                            "g.V().branch(__.label().is_('person').count()).option(xx1, __.values('age')).option(xx2, __.values('lang')).option(xx2, __.values('name')).option(Pick.any_, __.label())"},
                     {"g.V().toList()",
                             null,
                             null,
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GTypeTest.java
new file mode 100644
index 0000000000..9596445860
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GTypeTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.tinkerpop.gremlin.process.traversal.step;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class GTypeTest {
+
+    @Test
+    public void shouldReturnTrueForNumericTypes() {
+        assertThat(GType.INTEGER.isNumeric(), is(true));
+        assertThat(GType.DOUBLE.isNumeric(), is(true));
+        assertThat(GType.LONG.isNumeric(), is(true));
+        assertThat(GType.BIG_INTEGER.isNumeric(), is(true));
+        assertThat(GType.BIG_DECIMAL.isNumeric(), is(true));
+    }
+
+    @Test
+    public void shouldReturnFalseForNonNumericTypes() {
+        assertThat(GType.STRING.isNumeric(), is(false));
+        assertThat(GType.BOOLEAN.isNumeric(), is(false));
+        assertThat(GType.EDGE.isNumeric(), is(false));
+        assertThat(GType.VERTEX.isNumeric(), is(false));
+    }
+
+    @Test
+    public void shouldReturnCorrectGType() {
+        assertEquals(GType.STRING, GType.getType("test"));
+        assertEquals(GType.INTEGER, GType.getType(123));
+        assertEquals(GType.BOOLEAN, GType.getType(true));
+        assertEquals(GType.DOUBLE, GType.getType(123.45));
+        assertEquals(GType.LONG, GType.getType(123L));
+        assertEquals(GType.MAP, GType.getType(Collections.emptyMap()));
+        assertEquals(GType.LIST, GType.getType(Collections.emptyList()));
+        assertEquals(GType.SET, GType.getType(Collections.emptySet()));
+        assertEquals(GType.VERTEX, GType.getType(mock(Vertex.class)));
+        assertEquals(GType.EDGE, GType.getType(mock(Edge.class)));
+        assertEquals(GType.PATH, GType.getType(mock(Path.class)));
+        assertEquals(GType.PROPERTY, GType.getType(mock(Property.class)));
+        assertEquals(GType.BIG_INTEGER, GType.getType(BigInteger.ONE));
+        assertEquals(GType.BIG_DECIMAL, GType.getType(BigDecimal.ONE));
+    }
+
+    @Test
+    public void shouldReturnUnknownForUnmatchedTypes() {
+        assertEquals(GType.UNKNOWN, GType.getType(new Object()));
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java
new file mode 100644
index 0000000000..10bfafed29
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java
@@ -0,0 +1,641 @@
+/*
+ * 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.tinkerpop.gremlin.process.traversal.step;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+
+public class GValueTest {
+
+    @Test
+    public void shouldReturnAnExistingGValue() {
+        final GValue<Integer> gValue = GValue.of(123);
+        final Object returnedGValue = GValue.of(gValue);
+        assertEquals(gValue, returnedGValue);
+        assertSame(gValue, returnedGValue);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldReturnAnExistInTypedGValue() {
+        final Object gValue = GValue.of("x", 123);
+        GValue.of("x", gValue);
+    }
+
+    @Test
+    public void shouldCreateGValueFromValue() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertEquals(123, gValue.get().intValue());
+        assertEquals(GType.INTEGER, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromNameAndValue() {
+        final GValue<Integer> gValue = GValue.of("varName", 123);
+        assertEquals(123, gValue.get().intValue());
+        assertEquals(GType.INTEGER, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromString() {
+        final GValue<String> gValue = GValue.ofString("test");
+        assertEquals("test", gValue.get());
+        assertEquals(GType.STRING, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromStringWithName() {
+        final GValue<String> gValue = GValue.ofString("varName", "test");
+        assertEquals("test", gValue.get());
+        assertEquals(GType.STRING, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromInteger() {
+        final GValue<Integer> gValue = GValue.ofInteger(123);
+        assertEquals(123, gValue.get().intValue());
+        assertEquals(GType.INTEGER, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromIntegerWithName() {
+        final GValue<Integer> gValue = GValue.ofInteger("varName", 123);
+        assertEquals(123, gValue.get().intValue());
+        assertEquals(GType.INTEGER, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromBoolean() {
+        final GValue<Boolean> gValue = GValue.ofBoolean(true);
+        assertEquals(true, gValue.get());
+        assertEquals(GType.BOOLEAN, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromBooleanWithName() {
+        final GValue<Boolean> gValue = GValue.ofBoolean("varName", true);
+        assertEquals(true, gValue.get());
+        assertEquals(GType.BOOLEAN, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromDouble() {
+        final GValue<Double> gValue = GValue.ofDouble(123.45);
+        assertEquals(123.45, gValue.get(), 0.0);
+        assertEquals(GType.DOUBLE, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromDoubleWithName() {
+        final GValue<Double> gValue = GValue.ofDouble("varName", 123.45);
+        assertEquals(123.45, gValue.get(), 0.0);
+        assertEquals(GType.DOUBLE, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromBigInteger() {
+        final GValue<BigInteger> gValue = GValue.ofBigInteger(BigInteger.ONE);
+        assertEquals(BigInteger.ONE, gValue.get());
+        assertEquals(GType.BIG_INTEGER, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromBigIntegerWithName() {
+        final GValue<BigInteger> gValue = GValue.ofBigInteger("varName", BigInteger.ONE);
+        assertEquals(BigInteger.ONE, gValue.get());
+        assertEquals(GType.BIG_INTEGER, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromBigDecimal() {
+        final GValue<BigDecimal> gValue = GValue.ofBigDecimal(BigDecimal.ONE);
+        assertEquals(BigDecimal.ONE, gValue.get());
+        assertEquals(GType.BIG_DECIMAL, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromBigDecimalWithName() {
+        final GValue<BigDecimal> gValue = GValue.ofBigDecimal("varName", BigDecimal.ONE);
+        assertEquals(BigDecimal.ONE, gValue.get());
+        assertEquals(GType.BIG_DECIMAL, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromLong() {
+        final GValue<Long> gValue = GValue.ofLong(123L);
+        assertEquals(123L, gValue.get().longValue());
+        assertEquals(GType.LONG, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromLongWithName() {
+        final GValue<Long> gValue = GValue.ofLong("varName", 123L);
+        assertEquals(123L, gValue.get().longValue());
+        assertEquals(GType.LONG, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromMap() {
+        final Map<String, String> map = new HashMap<String,String>() {{
+            put("key", "value");
+        }};
+        final GValue<Map> gValue = GValue.ofMap(map);
+        assertEquals(map, gValue.get());
+        assertEquals(GType.MAP, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromMapWithName() {
+        final Map<String, String> map = new HashMap<String,String>() {{
+            put("key", "value");
+        }};
+        final GValue<Map> gValue = GValue.ofMap("varName", map);
+        assertEquals(map, gValue.get());
+        assertEquals(GType.MAP, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromList() {
+        final List<String> list = Arrays.asList("value1", "value2");
+        final GValue<List<String>> gValue = GValue.ofList(list);
+        assertEquals(list, gValue.get());
+        assertEquals(GType.LIST, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromListWithName() {
+        final List<String> list = Arrays.asList("value1", "value2");
+        final GValue<List<String>> gValue = GValue.ofList("varName", list);
+        assertEquals(list, gValue.get());
+        assertEquals(GType.LIST, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromSet() {
+        final Set<String> set = new HashSet<>(Arrays.asList("value1", "value2"));
+        final GValue<Set> gValue = GValue.ofSet(set);
+        assertEquals(set, gValue.get());
+        assertEquals(GType.SET, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromSetWithName() {
+        final Set<String> set = new HashSet<>(Arrays.asList("value1", "value2"));
+        final GValue<Set> gValue = GValue.ofSet("varName", set);
+        assertEquals(set, gValue.get());
+        assertEquals(GType.SET, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromVertex() {
+        final Vertex vertex = mock(Vertex.class);
+        final GValue<Vertex> gValue = GValue.ofVertex(vertex);
+        assertEquals(vertex, gValue.get());
+        assertEquals(GType.VERTEX, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromVertexWithName() {
+        final Vertex vertex = mock(Vertex.class);
+        final GValue<Vertex> gValue = GValue.ofVertex("varName", vertex);
+        assertEquals(vertex, gValue.get());
+        assertEquals(GType.VERTEX, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromEdge() {
+        final Edge edge = mock(Edge.class);
+        final GValue<Edge> gValue = GValue.ofEdge(edge);
+        assertEquals(edge, gValue.get());
+        assertEquals(GType.EDGE, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromEdgeWithName() {
+        final Edge edge = mock(Edge.class);
+        final GValue<Edge> gValue = GValue.ofEdge("varName", edge);
+        assertEquals(edge, gValue.get());
+        assertEquals(GType.EDGE, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromPath() {
+        final Path path = mock(Path.class);
+        final GValue<Path> gValue = GValue.ofPath(path);
+        assertEquals(path, gValue.get());
+        assertEquals(GType.PATH, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromPathWithName() {
+        final Path path = mock(Path.class);
+        final GValue<Path> gValue = GValue.ofPath("varName", path);
+        assertEquals(path, gValue.get());
+        assertEquals(GType.PATH, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromProperty() {
+        final Property property = mock(Property.class);
+        final GValue<Property> gValue = GValue.ofProperty(property);
+        assertEquals(property, gValue.get());
+        assertEquals(GType.PROPERTY, gValue.getType());
+        assertThat(gValue.isVariable(), is(false));
+    }
+
+    @Test
+    public void shouldCreateGValueFromPropertyWithName() {
+        final Property property = mock(Property.class);
+        final GValue<Property> gValue = GValue.ofProperty("varName", property);
+        assertEquals(property, gValue.get());
+        assertEquals(GType.PROPERTY, gValue.getType());
+        assertEquals("varName", gValue.getName());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldBeAnInstanceOf() {
+        assertThat(GValue.instanceOf(GValue.of("string"), GType.STRING), is(true));
+        assertThat(GValue.instanceOf(GValue.ofInteger(1), GType.INTEGER), is(true));
+        assertThat(GValue.instanceOf("string", GType.STRING), is(true));
+        assertThat(GValue.instanceOf(1, GType.INTEGER), is(true));
+    }
+
+    @Test
+    public void shouldNotBeAnInstanceOf() {
+        assertThat(GValue.instanceOf(GValue.of("string"), GType.INTEGER), is(false));
+        assertThat(GValue.instanceOf(GValue.ofInteger(1), GType.STRING), is(false));
+        assertThat(GValue.instanceOf("string", GType.INTEGER), is(false));
+        assertThat(GValue.instanceOf(1, GType.STRING), is(false));
+    }
+
+    @Test
+    public void shouldBeAnInstanceOfCollection() {
+        assertThat(GValue.instanceOfCollection(GValue.of(Arrays.asList("string"))), is(true));
+        assertThat(GValue.instanceOfCollection(GValue.ofSet(new HashSet(Arrays.asList("string")))), is(true));
+        assertThat(GValue.instanceOfCollection(Arrays.asList("string")), is(true));
+        assertThat(GValue.instanceOfCollection(new HashSet(Arrays.asList("string"))), is(true));
+    }
+
+    @Test
+    public void shouldNotBeAnInstanceOfCollection() {
+        assertThat(GValue.instanceOfCollection(GValue.of(new HashMap())), is(false));
+        assertThat(GValue.instanceOfCollection(GValue.ofInteger(1)), is(false));
+        assertThat(GValue.instanceOfCollection(new HashMap()), is(false));
+        assertThat(GValue.instanceOfCollection(1), is(false));
+    }
+
+    @Test
+    public void shouldBeAnInstanceOfNumber() {
+        assertThat(GValue.instanceOfNumber(GValue.of(1)), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.of(1L)), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.of(1D)), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.of(BigInteger.valueOf((1L)))), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.of(BigDecimal.valueOf((1.0)))), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.ofInteger(1)), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.ofLong(1L)), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.ofDouble(1D)), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.ofBigInteger(BigInteger.valueOf((1L)))), is(true));
+        assertThat(GValue.instanceOfNumber(GValue.ofBigDecimal(BigDecimal.valueOf((1.0)))), is(true));
+    }
+
+    @Test
+    public void shouldNotBeAnInstanceOfNumber() {
+        assertThat(GValue.instanceOfNumber(GValue.of("string")), is(false));
+        assertThat(GValue.instanceOfNumber(GValue.of(Arrays.asList("string"))), is(false));
+    }
+
+    @Test
+    public void shouldBeAnInstanceOfElement() {
+        assertThat(GValue.instanceOfElement(GValue.ofVertex(mock(Vertex.class))), is(true));
+        assertThat(GValue.instanceOfElement(GValue.ofEdge(mock(Edge.class))), is(true));
+    }
+
+    @Test
+    public void shouldNotBeAnInstanceOfElement() {
+        assertThat(GValue.instanceOfElement(GValue.of("string")), is(false));
+        assertThat(GValue.instanceOfElement(GValue.of(Arrays.asList("string"))), is(false));
+    }
+
+    @Test
+    public void shouldHaveForMatchingType() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertThat(GValue.valueInstanceOf(gValue, GType.INTEGER), is(true));
+    }
+
+    @Test
+    public void valueInstanceOfShouldReturnFalseForNonMatchingType() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertThat(GValue.valueInstanceOf(gValue, GType.STRING), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfShouldReturnFalseForNonGValueObject() {
+        String nonGValue = "test";
+        assertThat(GValue.valueInstanceOf(nonGValue, GType.STRING), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfShouldReturnFalseForNullObject() {
+        assertThat(GValue.valueInstanceOf(null, GType.STRING), is(false));
+    }
+
+    @Test
+    public void getShouldReturnGValueValue() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertThat(GValue.getFrom(gValue), is(123));
+    }
+
+    @Test
+    public void getShouldReturnObjectAsIs() {
+        final String value = "test";
+        assertThat(GValue.getFrom(value), is(value));
+    }
+
+    @Test
+    public void getShouldReturnNullForNullInput() {
+        assertThat(GValue.getFrom(null), is((Object) null));
+    }
+
+    @Test
+    public void valueInstanceOfCollectionShouldReturnTrueForGValueWithCollectionType() {
+        final GValue<List<String>> gValue = GValue.ofList(Arrays.asList("value1", "value2"));
+        assertThat(GValue.valueInstanceOfCollection(gValue), is(true));
+    }
+
+    @Test
+    public void valueInstanceOfCollectionShouldReturnFalseForGValueWithNonCollectionType() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertThat(GValue.valueInstanceOfCollection(gValue), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfCollectionShouldReturnFalseForNonGValueObject() {
+        assertThat(GValue.valueInstanceOfCollection("test"), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfCollectionShouldReturnFalseForNullObject() {
+        assertThat(GValue.valueInstanceOfCollection(null), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfNumericShouldReturnTrueForGValueWithNumericType() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertThat(GValue.valueInstanceOfNumeric(gValue), is(true));
+    }
+
+    @Test
+    public void valueInstanceOfNumericShouldReturnFalseForGValueWithNonNumericType() {
+        assertThat(GValue.valueInstanceOfNumeric("test"), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfNumericShouldReturnFalseForNonGValueObject() {
+        assertThat(GValue.valueInstanceOfNumeric("test"), is(false));
+    }
+
+    @Test
+    public void valueInstanceOfNumericShouldReturnFalseForNullObject() {
+        assertThat(GValue.valueInstanceOfNumeric(null), is(false));
+    }
+
+    @Test
+    public void shouldConvertObjectArrayToGValues() {
+        final Object[] input = {1, "string", true};
+        final GValue<?>[] expected = {GValue.of(1), GValue.of("string"), GValue.of(true)};
+        final GValue<?>[] result = GValue.ensureGValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldPreserveExistingGValuesInArray() {
+        final GValue<Integer> gValue = GValue.of(123);
+        final Object[] input = {gValue, "string"};
+        final GValue<?>[] expected = {gValue, GValue.of("string")};
+        final GValue<?>[] result = GValue.ensureGValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldHandleEmptyArray() {
+        final Object[] input = {};
+        final GValue<?>[] expected = {};
+        final GValue<?>[] result = GValue.ensureGValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldHandleArrayWithNullValues() {
+        final Object[] input = {null, "string"};
+        final GValue<?>[] expected = {GValue.of(null), GValue.of("string")};
+        final GValue<?>[] result = GValue.ensureGValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldResolveGValuesToValues() {
+        final GValue<?>[] input = {GValue.of(1), GValue.of("string"), GValue.of(true)};
+        final Object[] expected = {1, "string", true};
+        final Object[] result = GValue.resolveToValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldHandleEmptyGValuesArray() {
+        final GValue<?>[] input = {};
+        final Object[] expected = {};
+        final Object[] result = GValue.resolveToValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldHandleGValuesArrayWithNullValues() {
+        final GValue<?>[] input = {GValue.of(null), GValue.of("string")};
+        final Object[] expected = {null, "string"};
+        final Object[] result = GValue.resolveToValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void shouldHandleMixedTypeGValuesArray() {
+        final GValue<?>[] input = {GValue.of(1), GValue.of("string"), GValue.of(true), GValue.of(123.45)};
+        final Object[] expected = {1, "string", true, 123.45};
+        final Object[] result = GValue.resolveToValues(input);
+        assertArrayEquals(expected, result);
+    }
+
+    @Test
+    public void equalsShouldReturnTrueForSameObject() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertEquals(true, gValue.equals(gValue));
+    }
+
+    @Test
+    public void equalsShouldReturnFalseForNull() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertEquals(false, gValue.equals(null));
+    }
+
+    @Test
+    public void equalsShouldReturnFalseForDifferentClass() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertEquals(false, gValue.equals("string"));
+    }
+
+    @Test
+    public void equalsShouldReturnTrueForEqualGValues() {
+        final GValue<Integer> gValue1 = GValue.of(123);
+        final GValue<Integer> gValue2 = GValue.of(123);
+        assertEquals(true, gValue1.equals(gValue2));
+    }
+
+    @Test
+    public void equalsShouldReturnFalseForDifferentNames() {
+        final GValue<Integer> gValue1 = GValue.of("name1", 123);
+        final GValue<Integer> gValue2 = GValue.of("name2", 123);
+        assertEquals(false, gValue1.equals(gValue2));
+    }
+
+    @Test
+    public void equalsShouldReturnFalseForDifferentTypes() {
+        final GValue<Integer> gValue1 = GValue.of(123);
+        final GValue<String> gValue2 = GValue.of("123");
+        assertEquals(false, gValue1.equals(gValue2));
+    }
+
+    @Test
+    public void equalsShouldReturnFalseForDifferentValues() {
+        final GValue<Integer> gValue1 = GValue.of(123);
+        final GValue<Integer> gValue2 = GValue.of(456);
+        assertEquals(false, gValue1.equals(gValue2));
+    }
+
+    @Test
+    public void valueOfShouldReturnGValueValue() {
+        final GValue<Integer> gValue = GValue.of(123);
+        assertEquals(123, GValue.valueOf(gValue));
+    }
+
+    @Test
+    public void valueOfShouldReturnObjectAsIs() {
+        final String value = "test";
+        assertEquals("test", GValue.valueOf(value));
+    }
+
+    @Test
+    public void valueOfShouldReturnNullForNullInput() {
+        assertNull(GValue.valueOf(null));
+        assertNull(null);
+    }
+
+    @Test
+    public void numberOfShouldReturnGValueValue() {
+        final GValue<Integer> gValue = GValue.ofInteger(1234);
+        assertEquals(1234, GValue.numberOf(gValue));
+    }
+
+    @Test
+    public void numberOfShouldReturnObjectAsIs() {
+        assertEquals(1234, GValue.numberOf(1234));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void numberOfShouldThrowBecauseGValueNotNumberType() {
+        assertEquals(1234, GValue.numberOf("1234"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void numberOfShouldThrowBecauseObjectNotNumberType() {
+        final GValue<String> gValue = GValue.of("1234");
+        GValue.numberOf(gValue);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void numberOfShouldThrowBecauseNullIntegerGType() {
+        GValue.numberOf(GValue.of(null, GType.INTEGER));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void numberOfShouldThrowBecauseNullObject() {
+        GValue.numberOf(null);
+    }
+}
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java
index a84c691182..35d9fe29f9 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStepTest.java
@@ -41,7 +41,7 @@ public class ConjoinStepTest extends StepTest {
     @Test
     public void testReturnTypes() {
         try {
-            __.__(Collections.emptyList()).conjoin(null).next();
+            __.__(Collections.emptyList()).conjoin((String) null).next();
             fail();
         } catch (Exception e) {
             assertTrue(e.getMessage().contains("Input delimiter to conjoin step can't be null"));
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
index 0983540dcb..f509926359 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ParametersTest.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.util;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.junit.Test;
 
@@ -356,4 +357,14 @@ public class ParametersTest {
 
         verify(mock).integrateChild(__.outE("knows").asAdmin());
     }
+
+    @Test
+    public void shouldGetKeyValuesAndResolveGValues() {
+        final Parameters parameters = new Parameters();
+        parameters.set(null, "a", "axe", "b", GValue.of("B", "bat"), "c", GValue.of("C", "cat"));
+
+        final Object[] params = parameters.getKeyValues(mock(Traverser.Admin.class));
+        assertEquals(6, params.length);
+        assertThat(Arrays.equals(new Object[] {"a", "axe", "b", "bat", "c", "cat"}, params), is(true));
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java
index 73bd39b415..7b938c1a22 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/CollectionUtilTest.java
@@ -22,10 +22,20 @@ import org.apache.tinkerpop.gremlin.AssertHelper;
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 public class CollectionUtilTest {
@@ -70,4 +80,104 @@ public class CollectionUtilTest {
         final ConcurrentHashMap<?, ?> cloned = CollectionUtil.clone(source);
         assertTrue(source.equals(cloned));
     }
+
+    @Test
+    public void shouldCloneEmptyConcurrentHashMap() {
+        final ConcurrentHashMap<String, String> source = new ConcurrentHashMap<>();
+        final ConcurrentHashMap<?, ?> cloned = CollectionUtil.clone(source);
+        assertTrue(source.equals(cloned));
+    }
+
+    @Test
+    public void shouldCloneConcurrentHashMapWithMixedTypes() {
+        final ConcurrentHashMap<String, Object> source = new ConcurrentHashMap<>();
+        source.put("key1", "value1");
+        source.put("key2", new ArrayList<>(Arrays.asList("a", "b")));
+        source.put("key3", new HashSet<>(Arrays.asList("x", "y")));
+
+        final ConcurrentHashMap<?, ?> cloned = CollectionUtil.clone(source);
+        assertTrue(source.equals(cloned));
+    }
+
+    @Test
+    public void shouldAddFirstWhenBothArgumentsNull() {
+        String[] result = CollectionUtil.addFirst(null, null, String.class);
+        assertArrayEquals(new String[]{null}, result);
+    }
+
+    @Test
+    public void shouldAddFirstWhenArrayNull() {
+        String[] result = CollectionUtil.addFirst(null, "element", String.class);
+        assertArrayEquals(new String[]{"element"}, result);
+    }
+
+    @Test
+    public void shoulAddFirstWhenNeitherArgumentNull() {
+        Integer[] array = {1, 2, 3};
+        Integer[] result = CollectionUtil.addFirst(array, 0, Integer.class);
+        assertArrayEquals(new Integer[]{0, 1, 2, 3}, result);
+    }
+
+    @Test
+    public void shouldAddFirstWhenEmptyArray() {
+        String[] array = {};
+        String[] result = CollectionUtil.addFirst(array, "element", String.class);
+        assertArrayEquals(new String[]{"element"}, result);
+    }
+
+    @Test
+    public void shouldAddFirstWhenIntegers() {
+        Integer[] array = {1, 2, 3};
+        Integer[] result = CollectionUtil.addFirst(array, 0, Integer.class);
+        assertArrayEquals(new Integer[]{0, 1, 2, 3}, result);
+    }
+
+    @Test
+    public void shouldConvertVarargsToList() {
+        List<String> result = CollectionUtil.asList("a", "b", "c");
+        assertEquals(Arrays.asList("a", "b", "c"), result);
+    }
+
+    @Test
+    public void shouldConvertEmptyVarargsToList() {
+        List<String> result = CollectionUtil.asList();
+        assertEquals(Collections.emptyList(), result);
+    }
+
+    @Test
+    public void shouldConvertVarargsToSet() {
+        Set<String> result = CollectionUtil.asSet("a", "b", "c");
+        assertEquals(new LinkedHashSet<>(Arrays.asList("a", "b", "c")), result);
+    }
+
+    @Test
+    public void shouldConvertEmptyVarargsToSet() {
+        Set<String> result = CollectionUtil.asSet();
+        assertEquals(new LinkedHashSet<>(), result);
+    }
+
+    @Test
+    public void shouldConvertCollectionToSet() {
+        Collection<String> collection = Arrays.asList("a", "b", "c");
+        Set<String> result = CollectionUtil.asSet(collection);
+        assertEquals(new LinkedHashSet<>(collection), result);
+    }
+
+    @Test
+    public void shouldConvertVarargsToMap() {
+        Map<String, String> result = CollectionUtil.asMap("key1", "value1", "key2", "value2");
+        Map<String, String> expected = new LinkedHashMap<>();
+        expected.put("key1", "value1");
+        expected.put("key2", "value2");
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void shouldConvertVarargsToMapWithOddNumberOfElements() {
+        Map<String, String> result = CollectionUtil.asMap("key1", "value1", "key2");
+        Map<String, String> expected = new LinkedHashMap<>();
+        expected.put("key1", "value1");
+        expected.put("key2", null);
+        assertEquals(expected, result);
+    }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
index 98f8b0b5b4..98d49d8df7 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
@@ -115,13 +115,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
             _parameters.Add(name, parsedValue);
         }
 
-        [Given("using the parameter (\\w+) of P.(\\w+)\\(\"(.*)\"\\)")]
-        public void UsingParameterP(string name, string pval, string value)
-        {
-            var parsedValue = ParseValue(value.Replace("\\\"", "\""), _graphName!);
-            _parameters.Add(name, new P(pval, parsedValue));
-        }
-
         [Given("the traversal of")]
         public void TranslateTraversal(string traversalText)
         {
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index e72e7aa112..b324e8be68 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -63,17 +63,17 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
             new Dictionary<string, List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>>
             {
                {"g_V_branchXlabel_eq_person__a_bX_optionXa__ageX_optionXb__langX_optionXb__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>()},  // skipping as it contains a lambda
-               {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], (ITraversal) __.Values<object>("age")).Option(p["xx2"], (ITraversal) __.Values<object>("lang")).Option(p["xx2"], (ITraversal) __.Values<object>("name"))}}, 
-               {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], (ITraversal) __.Values<object>("age")).Option(p["xx2"], (ITraversal) __.Values<object>("lang")).Option(p["xx2"], (ITraversal) __.Values<object>("name")).Option(Pick.Any, __.Label())}}, 
+               {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], __.Values<object>("age")).Option(p["xx2"], __.Values<object>("lang")).Option(p["xx2"], __.Values<object>("name"))}}, 
+               {"g_V_branchXlabel_isXpersonX_countX_optionX1__ageX_optionX0__langX_optionX0__nameX_optionXany__labelX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Label().Is("person").Count()).Option(p["xx1"], __.Values<object>("age")).Option(p["xx2"], __.Values<object>("lang")).Option(p["xx2"], __.Values<object>("name")).Option(Pick.Any, __.Label())}}, 
                {"g_V_branchXageX_optionXltX30X__youngX_optionXgtX30X__oldX_optionXnone__on_the_edgeX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Branch<object>(__.Values<object>("age")).Option(P.Lt(30), __.Constant<object>("young")).Option(P.Gt(30), __.Constant<object>("old")).Option(Pick.None, __.Constant<object>("on the edge"))}}, 
                {"g_V_branchXidentityX_optionXhasLabelXsoftwareX__inXcreatedX_name_order_foldX_optionXhasXname_vadasX__ageX_optionXneqX123X__bothE_countX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Branch<object>(__.Identity()).Option(__.HasLabel("software"), __.In("created").Values<object>("name").Order().Fold()).Option(__.Has("name", "vadas"), __.Values<object>("age")).Option(P.Neq(123), __.BothE().Count())}}, 
-               {"g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out().Count()).Option(p["xx1"], (ITraversal) __.Values<object>("name")).Option(p["xx2"], (ITraversal) __.Values<object>("age"))}}, 
+               {"g_V_chooseXout_countX_optionX2L_nameX_optionX3L_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out().Count()).Option(p["xx1"], __.Values<object>("name")).Option(p["xx2"], __.Values<object>("age"))}}, 
                {"g_V_chooseXlabel_eqXpersonX__outXknowsX__inXcreatedXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>>()},  // skipping as it contains a lambda
                {"g_V_chooseXhasLabelXpersonX_and_outXcreatedX__outXknowsX__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.HasLabel("person").And().Out("created"), __.Out("knows"), __.Identity()).Values<object>("name")}}, 
                {"g_V_chooseXlabelX_optionXblah__outXknowsXX_optionXbleep__outXcreatedXX_optionXnone__identityX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Label()).Option("blah", __.Out("knows")).Option("bleep", __.Out("created")).Option(Pick.None, __.Identity()).Values<object>("name")}}, 
                {"g_V_chooseXoutXknowsX_count_isXgtX0XX__outXknowsXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Choose<object>(__.Out("knows").Count().Is(P.Gt(0)), __.Out("knows")).Values<object>("name")}}, 
                {"g_V_hasLabelXpersonX_asXp1X_chooseXoutEXknowsX__outXknowsXX_asXp2X_selectXp1_p2X_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").As("p1").Choose<object>(__.OutE("knows"), __.Out("knows")).As("p2").Select<object>("p1", "p2").By("name")}}, 
-               {"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(p["xx1"], (ITraversal) __.Constant<object>("young")).Option(Pick.None, __.Constant<object>("old")).GroupCount<object>()}}, 
+               {"g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Choose<object>(__.Values<object>("age")).Option(p["xx1"], __.Constant<object>("young")).Option(Pick.None, __.Constant<object>("old")).GroupCount<object>()}}, 
                {"g_injectX1X_chooseXisX1X__constantX10Xfold__foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx2"]).Choose<object>(__.Is(p["xx2"]), __.Constant<object>(p["xx1"]).Fold(), __.Fold<object>())}}, 
                {"g_injectX2X_chooseXisX1X__constantX10Xfold__foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx3"]).Choose<object>(__.Is(p["xx2"]), __.Constant<object>(p["xx1"]).Fold(), __.Fold<object>())}}, 
                {"g_V_localXpropertiesXlocationX_order_byXvalueX_limitX2XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Local<object>(__.Properties<object>("location").Order().By(T.Value, Order.Asc).Range<object>(0, 2)).Value<object>()}}, 
@@ -234,6 +234,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_VX1X_out_hasXid_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V((Vertex) p["v2"]).Has("age", P.Gt(30))}}, 
                {"g_V_hasXblahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("blah")}}, 
                {"g_V_hasXperson_name_markoX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", "marko").Values<object>("age")}}, 
+               {"g_V_hasXperson_name_markovarX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("person", "name", (object) p["xx1"]).Values<object>("age")}}, 
+               {"g_V_hasXpersonvar_name_markoX_age", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has((string) p["xx1"], "name", "marko").Values<object>("age")}}, 
                {"g_VX1X_outE_hasXweight_inside_0_06X_inV", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().Has("weight", P.Inside(0.0, 0.6)).InV()}}, 
                {"g_EX11X_outV_outE_hasXid_10X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).OutV().OutE().Has(T.Id, (object) p["eid10"])}}, 
                {"g_EX11X_outV_outE_hasXid_10AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).OutV().OutE().Has(T.Id, (object) p["eid10"])}}, 
@@ -269,9 +271,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasXlabel_isXpersonXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, __.Is("person"))}}, 
                {"g_V_hasXname_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("name", (object) null)}}, 
                {"g_V_hasIdXemptyX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
-               {"g_V_hasIdXwithinXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
-               {"g_V_hasIdXwithoutXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["xx1"]).Count()}}, 
-               {"g_V_notXhasIdXwithinXemptyXXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Not(__.HasId(p["xx1"])).Count()}}, 
+               {"g_V_hasIdXwithinXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(P.Within(new List<object> {  })).Count()}}, 
+               {"g_V_hasIdXwithoutXemptyXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(P.Without(new List<object> {  })).Count()}}, 
+               {"g_V_notXhasIdXwithinXemptyXXX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Not(__.HasId(P.Within(new List<object> {  }))).Count()}}, 
                {"g_V_hasIdXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(null)}}, 
                {"g_V_hasIdXeqXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(P.Eq(null))}}, 
                {"g_V_hasIdX2_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid2"], null)}}, 
@@ -279,7 +281,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasIdX1AsString_2AsString_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid1"], p["vid2"], null)}}, 
                {"g_V_hasIdXnull_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(null, p["vid2"])}}, 
                {"g_V_hasIdX1X_hasIdX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasId(p["vid1"]).HasId(p["vid2"])}}, 
-               {"g_V_in_hasIdXneqX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().In().HasId(p["xx1"])}}, 
+               {"g_V_in_hasIdXneqX1XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().In().HasId(P.Neq(p["xx1"]))}}, 
                {"g_VX1X_out_hasIdX2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"])}}, 
                {"g_VX1X_out_hasXid_2_3X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}}, 
                {"g_VX1X_out_hasXid_2AsString_3AsStringX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}}, 
@@ -292,21 +294,23 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_bothE_properties_dedup_hasKeyXweightX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").Value<object>()}}, 
                {"g_V_bothE_properties_dedup_hasKeyXweightX_hasValueXltX0d3XX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").HasValue(P.Lt(0.3)).Value<object>(), (g,p) =>g.V().BothE().Properties<object>().Dedup().HasKey("weight").HasValue(P.Lt(0.3)).Value<object>()}}, 
                {"g_V_properties_hasKeyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey((string) null)}}, 
-               {"g_V_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey(null, null)}}, 
+               {"g_V_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey(null, (string) null)}}, 
                {"g_V_properties_hasKeyXnull_ageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasKey(null, "age").Value<object>()}}, 
                {"g_E_properties_hasKeyXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey((string) null)}}, 
-               {"g_E_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey(null, null)}}, 
+               {"g_E_properties_hasKeyXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey(null, (string) null)}}, 
                {"g_E_properties_hasKeyXnull_weightX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Properties<object>().HasKey(null, "weight").Value<object>()}}, 
                {"g_EX7X_hasLabelXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid7"]).HasLabel("knows")}}, 
                {"g_E_hasLabelXknowsX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel("knows")}}, 
                {"g_E_hasLabelXuses_traversesX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel("uses", "traverses")}}, 
                {"g_V_hasLabelXperson_software_blahX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person", "software", "blah")}}, 
                {"g_V_hasLabelXpersonX_hasLabelXsoftwareX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").HasLabel("software")}}, 
+               {"g_V_hasLabelXpersonvarX_hasLabelXsoftwareX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) p["xx1"]).HasLabel("software")}}, 
+               {"g_V_hasLabelXpersonvar_softwarevarX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) p["xx1"], (string) p["xx2"])}}, 
                {"g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Has("age", P.Not(P.Lte(10).And(P.Not(P.Between(11, 20)))).And(P.Lt(29).Or(P.Eq(35)))).Values<object>("name")}}, 
                {"g_V_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) null)}}, 
                {"g_V_hasXlabel_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has(T.Label, (object) null)}}, 
-               {"g_V_hasLabelXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel(null, null)}}, 
-               {"g_V_hasLabelXnull_personX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel(null, "person")}}, 
+               {"g_V_hasLabelXnull_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) null, (string) null)}}, 
+               {"g_V_hasLabelXnull_personX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel((string) null, "person")}}, 
                {"g_E_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().HasLabel((string) null)}}, 
                {"g_E_hasXlabel_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E().Has(T.Label, (object) null)}}, 
                {"g_V_properties_hasLabelXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>().HasLabel((string) null)}}, 
@@ -695,7 +699,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_injectXaX_concat_Xinject_List_b_cX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("a").Concat(__.Inject(p["xx1"]))}}, 
                {"g_injectXListXa_bXcX_concat_XdX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"], "c").Concat("d")}}, 
                {"g_injectXnullX_concat_XinjectX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Concat()}}, 
-               {"g_injectXnull_aX_concat_Xnull_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null, "a").Concat(null, "b")}}, 
+               {"g_injectXnull_aX_concat_Xnull_bX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null, "a").Concat((string) null, "b")}}, 
                {"g_injectXhello_hiX_concat_XV_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("hello", "hi").Concat(__.V().Order().By(T.Id).Values<object>("name"))}}, 
                {"g_V_hasLabel_value_concat_X_X_concat_XpersonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("name").Concat(" ").Concat("person")}}, 
                {"g_hasLabelXpersonX_valuesXnameX_asXaX_constantXMrX_concatXselectXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Values<object>("name").As("a").Constant<object>("Mr.").Concat(__.Select<object>("a"))}}, 
@@ -703,17 +707,18 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_VX1X_outE_asXaX_VX1X_valuesXnamesX_concatXselectXaX_labelX_concatXselectXaX_inV_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().As("a").V(p["vid1"]).Values<object>("name").Concat(__.Select<object>("a").Label()).Concat(__.Select<object>("a").InV().Values<object>("name"))}}, 
                {"g_VX1X_outE_asXaX_VX1X_valuesXnamesX_concatXselectXaX_label_selectXaX_inV_valuesXnameXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).OutE().As("a").V(p["vid1"]).Values<object>("name").Concat(__.Select<object>("a").Label(), __.Select<object>("a").InV().Values<object>("name"))}}, 
                {"g_addVXconstantXprefix_X_concatXVX1X_labelX_label", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property("name", "ripple [...]
-               {"g_injectXnullX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Conjoin("1")}}, 
-               {"g_V_valuesXnameX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Conjoin("1")}}, 
-               {"g_V_valuesXnonexistantX_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("nonexistant").Fold().Conjoin(";")}}, 
-               {"g_V_valuesXnameX_order_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Fold().Conjoin("_")}}, 
-               {"g_V_valuesXageX_order_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().Fold().Conjoin(";")}}, 
-               {"g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Path().By(__.Values<object>("name").ToUpper()).Conjoin("MARKO")}}, 
-               {"g_injectXmarkoX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin("-")}}, 
-               {"g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("location").Select<object>(Column.Values).Unfold<object>().Order(Scope.Local).Conjoin("1")}}, 
-               {"g_V_out_out_path_byXnameX_conjoinXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Path().By("name").Conjoin("")}}, 
-               {"g_injectXa_null_bX_conjoinXxyzX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin("xyz")}}, 
-               {"g_injectX3_threeX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin(";")}}, 
+               {"g_injectXnullX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(null).Conjoin((string) "1")}}, 
+               {"g_V_valuesXnameX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Conjoin((string) "1")}}, 
+               {"g_V_valuesXnonexistantX_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("nonexistant").Fold().Conjoin((string) ";")}}, 
+               {"g_V_valuesXnameX_order_fold_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name").Order().Fold().Conjoin((string) "_")}}, 
+               {"g_V_valuesXageX_order_fold_conjoinXsemicolonX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().Fold().Conjoin((string) ";")}}, 
+               {"g_V_valuesXageX_order_fold_conjoinXslashX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("age").Order().Fold().Conjoin((string) p["xx1"])}}, 
+               {"g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Path().By(__.Values<object>("name").ToUpper()).Conjoin((string) "MARKO")}}, 
+               {"g_injectXmarkoX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin((string) "-")}}, 
+               {"g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("location").Select<object>(Column.Values).Unfold<object>().Order(Scope.Local).Conjoin((string) "1")}}, 
+               {"g_V_out_out_path_byXnameX_conjoinXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Out().Out().Path().By("name").Conjoin((string) "")}}, 
+               {"g_injectXa_null_bX_conjoinXxyzX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin((string) "xyz")}}, 
+               {"g_injectX3_threeX_conjoinX_X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).Conjoin((string) ";")}}, 
                {"g_V_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}}, 
                {"g_V_dedup_connectedComponent_hasXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Dedup().ConnectedComponent().Has("gremlin.connectedComponentVertexProgram.component")}}, 
                {"g_V_hasLabelXsoftwareX_connectedComponent_project_byXnameX_byXcomponentX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("software").ConnectedComponent().Project<object>("name", "component").By("name").By("gremlin.connectedComponentVertexProgram.component")}}, 
@@ -797,7 +802,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>()}}, 
                {"g_V_elementMapXname_ageX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name", "age")}}, 
                {"g_EX11X_elementMap", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.E(p["eid11"]).ElementMap<object>()}}, 
-               {"g_V_elementMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name", "age", null)}}, 
+               {"g_V_elementMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ElementMap<object>("name", "age", (string) null)}}, 
                {"g_V_asXaX_flatMapXselectXaXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").FlatMap<object>(__.Select<object>("a"))}}, 
                {"g_V_fold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold()}}, 
                {"g_V_fold_unfold", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fold().Unfold<object>()}}, 
@@ -1169,8 +1174,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasXageX_propertiesXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("name").Value<object>()}}, 
                {"g_V_hasXageX_propertiesXname_ageX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("name", "age").Value<object>()}}, 
                {"g_V_hasXageX_propertiesXage_nameX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Has("age").Properties<object>("age", "name").Value<object>()}}, 
-               {"g_V_propertiesXname_age_nullX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>("name", "age", null).Value<object>()}}, 
-               {"g_V_valuesXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name", "age", null)}}, 
+               {"g_V_propertiesXname_age_nullX_value", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Properties<object>("name", "age", (string) null).Value<object>()}}, 
+               {"g_V_valuesXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Values<object>("name", "age", (string) null)}}, 
                {"g_injectX__feature___test__nullX_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("feature  ", "one test ", null, "", " ", " abc", "abc ", " abc ", "  ").RTrim()}}, 
                {"g_injectX__feature___test__nullX_rTrimXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new List<object> { "  feature  ", " one test ", null, "", " ", " abc", "abc ", " abc ", "  " }).RTrim<object>(Scope.Local)}}, 
                {"g_injectX__feature__X_rTrim", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("  feature  ").RTrim()}}, 
@@ -1356,7 +1361,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object, object>(true)}}, 
                {"g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().HasLabel("person").Filter(__.OutE("created")).ValueMap<object, object>().With(WithOptions.Tokens)}}, 
                {"g_VX1X_valueMapXname_locationX_byXunfoldX_by", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).ValueMap<object, object>("name", "location").By(__.Unfold<object>()).By()}}, 
-               {"g_V_valueMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("name", "age", null)}}, 
+               {"g_V_valueMapXname_age_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("name", "age", (string) null)}}, 
                {"g_V_valueMapXname_ageX_byXisXxXXbyXunfoldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().ValueMap<object, object>("name", "age").By(__.Is("x")).By(__.Unfold<object>())}}, 
                {"g_VXnullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(null)}}, 
                {"g_VXlistXnullXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["xx1"])}}, 
diff --git a/gremlin-go/driver/cucumber/cucumberSteps_test.go b/gremlin-go/driver/cucumber/cucumberSteps_test.go
index fd49c7d8b4..38fbdb6207 100644
--- a/gremlin-go/driver/cucumber/cucumberSteps_test.go
+++ b/gremlin-go/driver/cucumber/cucumberSteps_test.go
@@ -47,7 +47,7 @@ var parsers map[*regexp.Regexp]func(string, string) interface{}
 
 func init() {
 	parsers = map[*regexp.Regexp]func(string, string) interface{}{
-		regexp.MustCompile(`^str\[(.*)]$`): func(stringVal, graphName string) interface{} { return stringVal }, //returns the string value as is
+		regexp.MustCompile(`^str\[(.*)]$`):          func(stringVal, graphName string) interface{} { return stringVal }, //returns the string value as is
 		regexp.MustCompile(`^dt\[(.*)]$`):           toDateTime,
 		regexp.MustCompile(`^d\[(.*)]\.[bslfdmn]$`): toNumeric,
 		regexp.MustCompile(`^d\[(.*)]\.[i]$`):       toInt32,
@@ -821,18 +821,6 @@ func (tg *tinkerPopGraph) usingTheParameterDefined(name string, params string) e
 	return nil
 }
 
-func (tg *tinkerPopGraph) usingTheParameterOfP(paramName, pVal, stringVal string) error {
-	predicate := reflect.ValueOf(gremlingo.P).MethodByName(strings.Title(pVal)).Interface().(func(...interface{}) gremlingo.Predicate)
-	values := parseValue(stringVal, tg.graphName)
-	switch reflect.TypeOf(values).Kind() {
-	case reflect.Array, reflect.Slice:
-		tg.parameters[paramName] = predicate(values.([]interface{})...)
-	default:
-		tg.parameters[paramName] = predicate(values)
-	}
-	return nil
-}
-
 func (tg *tinkerPopGraph) theTraversalWillRaiseAnError() error {
 	if _, ok := tg.error[true]; ok {
 		return nil
@@ -912,7 +900,6 @@ func InitializeScenario(ctx *godog.ScenarioContext) {
 	ctx.Step(`^the result should have a count of (\d+)$`, tg.theResultShouldHaveACountOf)
 	ctx.Step(`^the traversal of$`, tg.theTraversalOf)
 	ctx.Step(`^using the parameter (.+) defined as "(.+)"$`, tg.usingTheParameterDefined)
-	ctx.Step(`^using the parameter (.+) of P\.(.+)\("(.+)"\)$`, tg.usingTheParameterOfP)
 	ctx.Step(`^the traversal will raise an error$`, tg.theTraversalWillRaiseAnError)
 	ctx.Step(`^the traversal will raise an error with message (\w+) text of "(.+)"$`, tg.theTraversalWillRaiseAnErrorWithMessageContainingTextOf)
 }
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 591bdd0c7c..667ae6d1f3 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -204,6 +204,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_VX1X_out_hasXid_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["v2"]).Has("age", gremlingo.P.Gt(30))}}, 
     "g_V_hasXblahX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("blah")}}, 
     "g_V_hasXperson_name_markoX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "marko").Values("age")}}, 
+    "g_V_hasXperson_name_markovarX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", p["xx1"]).Values("age")}}, 
+    "g_V_hasXpersonvar_name_markoX_age": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(p["xx1"], "name", "marko").Values("age")}}, 
     "g_VX1X_outE_hasXweight_inside_0_06X_inV": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).OutE().Has("weight", gremlingo.P.Inside(0.0, 0.6)).InV()}}, 
     "g_EX11X_outV_outE_hasXid_10X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"]).OutV().OutE().Has(gremlingo.T.Id, p["eid10"])}}, 
     "g_EX11X_outV_outE_hasXid_10AsStringX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"]).OutV().OutE().Has(gremlingo.T.Id, p["eid10"])}}, 
@@ -239,9 +241,9 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_V_hasXlabel_isXpersonXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, gremlingo.T__.Is("person"))}}, 
     "g_V_hasXname_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("name", nil)}}, 
     "g_V_hasIdXemptyX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}}, 
-    "g_V_hasIdXwithinXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}}, 
-    "g_V_hasIdXwithoutXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["xx1"]).Count()}}, 
-    "g_V_notXhasIdXwithinXemptyXXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Not(gremlingo.T__.HasId(p["xx1"])).Count()}}, 
+    "g_V_hasIdXwithinXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(gremlingo.P.Within([]interface{}{})).Count()}}, 
+    "g_V_hasIdXwithoutXemptyXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(gremlingo.P.Without([]interface{}{})).Count()}}, 
+    "g_V_notXhasIdXwithinXemptyXXX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Not(gremlingo.T__.HasId(gremlingo.P.Within([]interface{}{}))).Count()}}, 
     "g_V_hasIdXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(nil)}}, 
     "g_V_hasIdXeqXnullXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(gremlingo.P.Eq(nil))}}, 
     "g_V_hasIdX2_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["vid2"], nil)}}, 
@@ -249,7 +251,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_V_hasIdX1AsString_2AsString_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["vid1"], p["vid2"], nil)}}, 
     "g_V_hasIdXnull_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(nil, p["vid2"])}}, 
     "g_V_hasIdX1X_hasIdX2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasId(p["vid1"]).HasId(p["vid2"])}}, 
-    "g_V_in_hasIdXneqX1XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().In().HasId(p["xx1"])}}, 
+    "g_V_in_hasIdXneqX1XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().In().HasId(gremlingo.P.Neq(p["xx1"]))}}, 
     "g_VX1X_out_hasIdX2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out().HasId(p["vid2"])}}, 
     "g_VX1X_out_hasXid_2_3X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}}, 
     "g_VX1X_out_hasXid_2AsString_3AsStringX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).Out().HasId(p["vid2"], p["vid3"])}}, 
@@ -272,6 +274,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_E_hasLabelXuses_traversesX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().HasLabel("uses", "traverses")}}, 
     "g_V_hasLabelXperson_software_blahX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person", "software", "blah")}}, 
     "g_V_hasLabelXpersonX_hasLabelXsoftwareX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").HasLabel("software")}}, 
+    "g_V_hasLabelXpersonvarX_hasLabelXsoftwareX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel(p["xx1"]).HasLabel("software")}}, 
+    "g_V_hasLabelXpersonvar_softwarevarX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel(p["xx1"], p["xx2"])}}, 
     "g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel("person").Has("age", gremlingo.P.Not(gremlingo.P.Lte(10).And(gremlingo.P.Not(gremlingo.P.Between(11, 20)))).And(gremlingo.P.Lt(29).Or(gremlingo.P.Eq(35)))).Values("name")}}, 
     "g_V_hasLabelXnullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().HasLabel(nil)}}, 
     "g_V_hasXlabel_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has(gremlingo.T.Label, nil)}}, 
@@ -677,7 +681,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_V_valuesXnameX_conjoinX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Conjoin("1")}}, 
     "g_V_valuesXnonexistantX_fold_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("nonexistant").Fold().Conjoin(";")}}, 
     "g_V_valuesXnameX_order_fold_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name").Order().Fold().Conjoin("_")}}, 
-    "g_V_valuesXageX_order_fold_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().Fold().Conjoin(";")}}, 
+    "g_V_valuesXageX_order_fold_conjoinXsemicolonX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().Fold().Conjoin(";")}}, 
+    "g_V_valuesXageX_order_fold_conjoinXslashX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("age").Order().Fold().Conjoin(p["xx1"])}}, 
     "g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Out().Path().By(gremlingo.T__.Values("name").ToUpper()).Conjoin("MARKO")}}, 
     "g_injectXmarkoX_conjoinX_X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).Conjoin("-")}}, 
     "g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().ValueMap("location").Select(gremlingo.Column.Values).Unfold().Order(gremlingo.Scope.Local).Conjoin("1")}}, 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
index e590415406..bad8161e70 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
@@ -117,10 +117,6 @@ Given('the traversal of', function (traversalText) {
   this.traversal = gremlin[this.scenario].shift()(p);
 });
 
-Given(/^using the parameter (.+) of P\.(.+)\("(.+)"\)$/, function (paramName, pval, stringValue) {
-  this.parameters[paramName] =  new P(pval, parseValue.call(this, stringValue))
-});
-
 Given(/^using the parameter (.+) defined as "(.+)"$/, function (paramName, stringValue) {
   // Remove escaped chars
   stringValue = stringValue.replace(/\\"/g, '"');
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 5251007c64..89e85ac91d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -225,6 +225,8 @@ const gremlins = {
     g_VX1X_out_hasXid_2X: [function({g, v2}) { return g.V(v2).has("age", P.gt(30)) }], 
     g_V_hasXblahX: [function({g}) { return g.V().has("blah") }], 
     g_V_hasXperson_name_markoX_age: [function({g}) { return g.V().has("person", "name", "marko").values("age") }], 
+    g_V_hasXperson_name_markovarX_age: [function({g, xx1}) { return g.V().has("person", "name", xx1).values("age") }], 
+    g_V_hasXpersonvar_name_markoX_age: [function({g, xx1}) { return g.V().has(xx1, "name", "marko").values("age") }], 
     g_VX1X_outE_hasXweight_inside_0_06X_inV: [function({g, vid1}) { return g.V(vid1).outE().has("weight", P.inside(0.0, 0.6)).inV() }], 
     g_EX11X_outV_outE_hasXid_10X: [function({g, eid11, eid10}) { return g.E(eid11).outV().outE().has(T.id, eid10) }], 
     g_EX11X_outV_outE_hasXid_10AsStringX: [function({g, eid11, eid10}) { return g.E(eid11).outV().outE().has(T.id, eid10) }], 
@@ -260,9 +262,9 @@ const gremlins = {
     g_V_hasXlabel_isXpersonXX: [function({g}) { return g.V().has(T.label, __.is("person")) }], 
     g_V_hasXname_nullX: [function({g}) { return g.V().has("name", null) }], 
     g_V_hasIdXemptyX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }], 
-    g_V_hasIdXwithinXemptyXX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }], 
-    g_V_hasIdXwithoutXemptyXX_count: [function({g, xx1}) { return g.V().hasId(xx1).count() }], 
-    g_V_notXhasIdXwithinXemptyXXX_count: [function({g, xx1}) { return g.V().not(__.hasId(xx1)).count() }], 
+    g_V_hasIdXwithinXemptyXX_count: [function({g}) { return g.V().hasId(P.within([])).count() }], 
+    g_V_hasIdXwithoutXemptyXX_count: [function({g}) { return g.V().hasId(P.without([])).count() }], 
+    g_V_notXhasIdXwithinXemptyXXX_count: [function({g}) { return g.V().not(__.hasId(P.within([]))).count() }], 
     g_V_hasIdXnullX: [function({g}) { return g.V().hasId(null) }], 
     g_V_hasIdXeqXnullXX: [function({g}) { return g.V().hasId(P.eq(null)) }], 
     g_V_hasIdX2_nullX: [function({g, vid2}) { return g.V().hasId(vid2, null) }], 
@@ -270,7 +272,7 @@ const gremlins = {
     g_V_hasIdX1AsString_2AsString_nullX: [function({g, vid2, vid1}) { return g.V().hasId(vid1, vid2, null) }], 
     g_V_hasIdXnull_2X: [function({g, vid2}) { return g.V().hasId(null, vid2) }], 
     g_V_hasIdX1X_hasIdX2X: [function({g, vid2, vid1}) { return g.V().hasId(vid1).hasId(vid2) }], 
-    g_V_in_hasIdXneqX1XX: [function({g, xx1}) { return g.V().in_().hasId(xx1) }], 
+    g_V_in_hasIdXneqX1XX: [function({g, xx1}) { return g.V().in_().hasId(P.neq(xx1)) }], 
     g_VX1X_out_hasIdX2X: [function({g, vid2, vid1}) { return g.V(vid1).out().hasId(vid2) }], 
     g_VX1X_out_hasXid_2_3X: [function({g, vid3, vid2, vid1}) { return g.V(vid1).out().hasId(vid2, vid3) }], 
     g_VX1X_out_hasXid_2AsString_3AsStringX: [function({g, vid3, vid2, vid1}) { return g.V(vid1).out().hasId(vid2, vid3) }], 
@@ -293,6 +295,8 @@ const gremlins = {
     g_E_hasLabelXuses_traversesX: [function({g}) { return g.E().hasLabel("uses", "traverses") }], 
     g_V_hasLabelXperson_software_blahX: [function({g}) { return g.V().hasLabel("person", "software", "blah") }], 
     g_V_hasLabelXpersonX_hasLabelXsoftwareX: [function({g}) { return g.V().hasLabel("person").hasLabel("software") }], 
+    g_V_hasLabelXpersonvarX_hasLabelXsoftwareX: [function({g, xx1}) { return g.V().hasLabel(xx1).hasLabel("software") }], 
+    g_V_hasLabelXpersonvar_softwarevarX: [function({g, xx1, xx2}) { return g.V().hasLabel(xx1, xx2) }], 
     g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name: [function({g}) { return g.V().hasLabel("person").has("age", P.not(P.lte(10).and(P.not(P.between(11, 20)))).and(P.lt(29).or(P.eq(35)))).values("name") }], 
     g_V_hasLabelXnullX: [function({g}) { return g.V().hasLabel(null) }], 
     g_V_hasXlabel_nullX: [function({g}) { return g.V().has(T.label, null) }], 
@@ -694,7 +698,8 @@ const gremlins = {
     g_V_valuesXnameX_conjoinX1X: [function({g}) { return g.V().values("name").conjoin("1") }], 
     g_V_valuesXnonexistantX_fold_conjoinX_X: [function({g}) { return g.V().values("nonexistant").fold().conjoin(";") }], 
     g_V_valuesXnameX_order_fold_conjoinX_X: [function({g}) { return g.V().values("name").order().fold().conjoin("_") }], 
-    g_V_valuesXageX_order_fold_conjoinX_X: [function({g}) { return g.V().values("age").order().fold().conjoin(";") }], 
+    g_V_valuesXageX_order_fold_conjoinXsemicolonX: [function({g}) { return g.V().values("age").order().fold().conjoin(";") }], 
+    g_V_valuesXageX_order_fold_conjoinXslashX: [function({g, xx1}) { return g.V().values("age").order().fold().conjoin(xx1) }], 
     g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX: [function({g}) { return g.V().out().path().by(__.values("name").toUpper()).conjoin("MARKO") }], 
     g_injectXmarkoX_conjoinX_X: [function({g, xx1}) { return g.inject(xx1).conjoin("-") }], 
     g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X: [function({g}) { return g.V().valueMap("location").select(Column.values).unfold().order(Scope.local).conjoin("1") }], 
@@ -768,12 +773,32 @@ const gremlins = {
     g_injectXa_null_bX_disjunctXa_cX: [function({g, xx1, xx2}) { return g.inject(xx1).disjunct(xx2) }], 
     g_injectXa_null_bX_disjunctXa_null_cX: [function({g, xx1, xx2}) { return g.inject(xx1).disjunct(xx2) }], 
     g_injectX3_threeX_disjunctXfive_three_7X: [function({g, xx1, xx2}) { return g.inject(xx1).disjunct(xx2) }], 
+    g_E: [function({g}) { return g.E() }], 
+    g_EX11X: [function({g, eid11}) { return g.E(eid11) }], 
+    g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }], 
+    g_EXe11X: [function({g, e11}) { return g.E(e11) }], 
+    g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7, e11) }], 
+    g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }], 
+    g_EXnullX: [function({g}) { return g.E(null) }], 
+    g_EXlistXnullXX: [function({g, xx1}) { return g.E(xx1) }], 
+    g_EX11_nullX: [function({g, eid11}) { return g.E(eid11, null) }], 
     g_V_EX11X: [function({g, eid11}) { return g.V().E(eid11) }], 
     g_EX11X_E: [function({g, eid11}) { return g.E(eid11).E() }], 
     g_V_EXnullX: [function({g}) { return g.V().E(null) }], 
     g_V_EXlistXnullXX: [function({g, xx1}) { return g.V().E(xx1) }], 
     g_injectX1X_EX11_nullX: [function({g, eid11}) { return g.inject(1).E(eid11, null) }], 
     g_injectX1X_coalesceXEX_hasLabelXtestsX_addEXtestsX_from_V_hasXnameX_XjoshXX_toXV_hasXnameX_XvadasXXX: [function({g}) { return g.addV("person").property("name", "josh").addV("person").property("name", "vadas") }, function({g}) { return g.inject(1).coalesce(__.E().hasLabel("tests"), __.addE("tests").from_(__.V().has("name", "josh")).to(__.V().has("name", "vadas"))) }, function({g}) { return g.E().hasLabel("tests") }], 
+    g_VX1X_outE_inV: [function({g, vid1}) { return g.V(vid1).outE().inV() }], 
+    g_VX2X_inE_outV: [function({g, vid2}) { return g.V(vid2).inE().outV() }], 
+    g_V_outE_hasXweight_1X_outV: [function({g}) { return g.V().outE().has("weight", 1.0).outV() }], 
+    g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
+    g_VX4X_bothE_otherV: [function({g, vid4}) { return g.V(vid4).bothE().otherV() }], 
+    g_VX4X_bothE_hasXweight_lt_1X_otherV: [function({g, vid4}) { return g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV() }], 
+    get_g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
+    g_VX1X_outEXknowsX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows").inV() }], 
+    g_VX1X_outEXknows_createdX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows", "created").inV() }], 
+    g_VX1X_outEXknowsX_bothV: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV() }], 
+    g_VX1X_outEXknowsX_bothV_name: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV().values("name") }], 
     g_VX1X_properties_element: [function({g, v2}) { return g.V(v2).properties().element().limit(1) }], 
     g_V_properties_element: [function({g}) { return g.V().properties().element() }], 
     g_V_propertiesXageX_element: [function({g}) { return g.V().properties("age").element() }], 
@@ -1365,34 +1390,15 @@ const gremlins = {
     g_VX1X_out: [function({g, vid1}) { return g.V(vid1).out() }], 
     g_VX2X_in: [function({g, vid2}) { return g.V(vid2).in_() }], 
     g_VX4X_both: [function({g, vid4}) { return g.V(vid4).both() }], 
-    g_E: [function({g}) { return g.E() }], 
-    g_EX11X: [function({g, eid11}) { return g.E(eid11) }], 
-    g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }], 
-    g_EXe11X: [function({g, e11}) { return g.E(e11) }], 
-    g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7, e11) }], 
-    g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }], 
-    g_EXnullX: [function({g}) { return g.E(null) }], 
-    g_EXlistXnullXX: [function({g, xx1}) { return g.E(xx1) }], 
-    g_EX11_nullX: [function({g, eid11}) { return g.E(eid11, null) }], 
     g_VX1X_outE: [function({g, vid1}) { return g.V(vid1).outE() }], 
     g_VX2X_outE: [function({g, vid2}) { return g.V(vid2).inE() }], 
     g_VX4X_bothEXcreatedX: [function({g, vid4}) { return g.V(vid4).bothE("created") }], 
     g_VX4X_bothE: [function({g, vid4}) { return g.V(vid4).bothE() }], 
-    g_VX1X_outE_inV: [function({g, vid1}) { return g.V(vid1).both() }], 
-    g_VX2X_inE_outV: [function({g, vid2}) { return g.V(vid2).inE().outV() }], 
-    g_V_outE_hasXweight_1X_outV: [function({g}) { return g.V().outE().has("weight", 1.0).outV() }], 
     g_V_out_outE_inV_inE_inV_both_name: [function({g}) { return g.V().out().outE().inV().inE().inV().both().values("name") }], 
-    g_VX1X_outEXknowsX_bothV_name: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV().values("name") }], 
-    g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
-    g_VX4X_bothE_otherV: [function({g, vid4}) { return g.V(vid4).bothE().otherV() }], 
-    g_VX4X_bothE_hasXweight_lt_1X_otherV: [function({g, vid4}) { return g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV() }], 
     g_VX2X_inE: [function({g, vid2}) { return g.V(vid2).bothE() }], 
-    get_g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
     g_VX1X_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }], 
     g_VX1AsStringX_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }], 
     g_VX1X_outXknows_createdX: [function({g, vid1}) { return g.V(vid1).out("knows", "created") }], 
-    g_VX1X_outEXknowsX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows").inV() }], 
-    g_VX1X_outEXknows_createdX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows", "created").inV() }], 
     g_V_out_out: [function({g}) { return g.V().out().out() }], 
     g_VX1X_out_out_out: [function({g, vid1}) { return g.V(vid1).out().out().out() }], 
     g_VX1X_out_name: [function({g, vid1}) { return g.V(vid1).out().values("name") }], 
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index cda26269ac..6394c55568 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
     ;
@@ -809,7 +809,7 @@ traversalMethod_times
 
 traversalMethod_to
     : 'to' LPAREN traversalDirection (COMMA stringLiteralVarargs)? RPAREN #traversalMethod_to_Direction_String
-    | 'to' LPAREN stringArgument RPAREN #traversalMethod_to_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-python/src/main/python/radish/feature_steps.py b/gremlin-python/src/main/python/radish/feature_steps.py
index 27b50911de..5f72c5b0dc 100644
--- a/gremlin-python/src/main/python/radish/feature_steps.py
+++ b/gremlin-python/src/main/python/radish/feature_steps.py
@@ -109,17 +109,6 @@ def unsupported_scenario(step):
     return
 
 
-@given("using the parameter {param_name:w} of P.{p_val:w}({param:QuotedString})")
-def add_p_parameter(step, param_name, p_val, param):
-    if (step.context.ignore):
-        return
-
-    if not hasattr(step.context, "traversal_params"):
-        step.context.traversal_params = {}
-
-    step.context.traversal_params[param_name] = getattr(P, p_val)(_convert(param.replace('\\"', '"'), step.context))
-
-
 @given("using the parameter {param_name:w} defined as {param:QuotedString}")
 def add_parameter(step, param_name, param):
     if (step.context.ignore):
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index bba1156256..d082e9e3a3 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -207,6 +207,8 @@ world.gremlins = {
     'g_VX1X_out_hasXid_2X': [(lambda g, v2=None:g.V(v2).has('age', P.gt(30)))], 
     'g_V_hasXblahX': [(lambda g:g.V().has('blah'))], 
     'g_V_hasXperson_name_markoX_age': [(lambda g:g.V().has('person', 'name', 'marko').values('age'))], 
+    'g_V_hasXperson_name_markovarX_age': [(lambda g, xx1=None:g.V().has('person', 'name', xx1).values('age'))], 
+    'g_V_hasXpersonvar_name_markoX_age': [(lambda g, xx1=None:g.V().has(xx1, 'name', 'marko').values('age'))], 
     'g_VX1X_outE_hasXweight_inside_0_06X_inV': [(lambda g, vid1=None:g.V(vid1).out_e().has('weight', P.inside(0.0, 0.6)).in_v())], 
     'g_EX11X_outV_outE_hasXid_10X': [(lambda g, eid11=None,eid10=None:g.E(eid11).out_v().out_e().has(T.id_, eid10))], 
     'g_EX11X_outV_outE_hasXid_10AsStringX': [(lambda g, eid11=None,eid10=None:g.E(eid11).out_v().out_e().has(T.id_, eid10))], 
@@ -242,9 +244,9 @@ world.gremlins = {
     'g_V_hasXlabel_isXpersonXX': [(lambda g:g.V().has(T.label, __.is_('person')))], 
     'g_V_hasXname_nullX': [(lambda g:g.V().has('name', None))], 
     'g_V_hasIdXemptyX_count': [(lambda g, xx1=None:g.V().has_id(xx1).count())], 
-    'g_V_hasIdXwithinXemptyXX_count': [(lambda g, xx1=None:g.V().has_id(xx1).count())], 
-    'g_V_hasIdXwithoutXemptyXX_count': [(lambda g, xx1=None:g.V().has_id(xx1).count())], 
-    'g_V_notXhasIdXwithinXemptyXXX_count': [(lambda g, xx1=None:g.V().not_(__.has_id(xx1)).count())], 
+    'g_V_hasIdXwithinXemptyXX_count': [(lambda g:g.V().has_id(P.within([])).count())], 
+    'g_V_hasIdXwithoutXemptyXX_count': [(lambda g:g.V().has_id(P.without([])).count())], 
+    'g_V_notXhasIdXwithinXemptyXXX_count': [(lambda g:g.V().not_(__.has_id(P.within([]))).count())], 
     'g_V_hasIdXnullX': [(lambda g:g.V().has_id(None))], 
     'g_V_hasIdXeqXnullXX': [(lambda g:g.V().has_id(P.eq(None)))], 
     'g_V_hasIdX2_nullX': [(lambda g, vid2=None:g.V().has_id(vid2, None))], 
@@ -252,7 +254,7 @@ world.gremlins = {
     'g_V_hasIdX1AsString_2AsString_nullX': [(lambda g, vid2=None,vid1=None:g.V().has_id(vid1, vid2, None))], 
     'g_V_hasIdXnull_2X': [(lambda g, vid2=None:g.V().has_id(None, vid2))], 
     'g_V_hasIdX1X_hasIdX2X': [(lambda g, vid2=None,vid1=None:g.V().has_id(vid1).has_id(vid2))], 
-    'g_V_in_hasIdXneqX1XX': [(lambda g, xx1=None:g.V().in_().has_id(xx1))], 
+    'g_V_in_hasIdXneqX1XX': [(lambda g, xx1=None:g.V().in_().has_id(P.neq(xx1)))], 
     'g_VX1X_out_hasIdX2X': [(lambda g, vid2=None,vid1=None:g.V(vid1).out().has_id(vid2))], 
     'g_VX1X_out_hasXid_2_3X': [(lambda g, vid3=None,vid2=None,vid1=None:g.V(vid1).out().has_id(vid2, vid3))], 
     'g_VX1X_out_hasXid_2AsString_3AsStringX': [(lambda g, vid3=None,vid2=None,vid1=None:g.V(vid1).out().has_id(vid2, vid3))], 
@@ -275,6 +277,8 @@ world.gremlins = {
     'g_E_hasLabelXuses_traversesX': [(lambda g:g.E().has_label('uses', 'traverses'))], 
     'g_V_hasLabelXperson_software_blahX': [(lambda g:g.V().has_label('person', 'software', 'blah'))], 
     'g_V_hasLabelXpersonX_hasLabelXsoftwareX': [(lambda g:g.V().has_label('person').has_label('software'))], 
+    'g_V_hasLabelXpersonvarX_hasLabelXsoftwareX': [(lambda g, xx1=None:g.V().has_label(xx1).has_label('software'))], 
+    'g_V_hasLabelXpersonvar_softwarevarX': [(lambda g, xx1=None,xx2=None:g.V().has_label(xx1, xx2))], 
     'g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name': [(lambda g:g.V().has_label('person').has('age', P.not_(P.lte(10).and_(P.not_(P.between(11, 20)))).and_(P.lt(29).or_(P.eq(35)))).values('name'))], 
     'g_V_hasLabelXnullX': [(lambda g:g.V().has_label(None))], 
     'g_V_hasXlabel_nullX': [(lambda g:g.V().has(T.label, None))], 
@@ -676,7 +680,8 @@ world.gremlins = {
     'g_V_valuesXnameX_conjoinX1X': [(lambda g:g.V().values('name').conjoin('1'))], 
     'g_V_valuesXnonexistantX_fold_conjoinX_X': [(lambda g:g.V().values('nonexistant').fold().conjoin(';'))], 
     'g_V_valuesXnameX_order_fold_conjoinX_X': [(lambda g:g.V().values('name').order().fold().conjoin('_'))], 
-    'g_V_valuesXageX_order_fold_conjoinX_X': [(lambda g:g.V().values('age').order().fold().conjoin(';'))], 
+    'g_V_valuesXageX_order_fold_conjoinXsemicolonX': [(lambda g:g.V().values('age').order().fold().conjoin(';'))], 
+    'g_V_valuesXageX_order_fold_conjoinXslashX': [(lambda g, xx1=None:g.V().values('age').order().fold().conjoin(xx1))], 
     'g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX': [(lambda g:g.V().out().path().by(__.values('name').to_upper()).conjoin('MARKO'))], 
     'g_injectXmarkoX_conjoinX_X': [(lambda g, xx1=None:g.inject(xx1).conjoin('-'))], 
     'g_V_valueMapXlocationX_selectXvaluesX_unfold_orderXlocalX_conjoinX1X': [(lambda g:g.V().value_map('location').select(Column.values).unfold().order(Scope.local).conjoin('1'))], 
@@ -750,12 +755,32 @@ world.gremlins = {
     'g_injectXa_null_bX_disjunctXa_cX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).disjunct(xx2))], 
     'g_injectXa_null_bX_disjunctXa_null_cX': [(lambda g, xx1=None,xx2=None:g.inject(xx1).disjunct(xx2))], 
     'g_injectX3_threeX_disjunctXfive_three_7X': [(lambda g, xx1=None,xx2=None:g.inject(xx1).disjunct(xx2))], 
+    'g_E': [(lambda g:g.E())], 
+    'g_EX11X': [(lambda g, eid11=None:g.E(eid11))], 
+    'g_EX11AsStringX': [(lambda g, eid11=None:g.E(eid11))], 
+    'g_EXe11X': [(lambda g, e11=None:g.E(e11))], 
+    'g_EXe7_e11X': [(lambda g, e7=None,e11=None:g.E(e7, e11))], 
+    'g_EXlistXe7_e11XX': [(lambda g, xx1=None:g.E(xx1))], 
+    'g_EXnullX': [(lambda g:g.E(None))], 
+    'g_EXlistXnullXX': [(lambda g, xx1=None:g.E(xx1))], 
+    'g_EX11_nullX': [(lambda g, eid11=None:g.E(eid11, None))], 
     'g_V_EX11X': [(lambda g, eid11=None:g.V().E(eid11))], 
     'g_EX11X_E': [(lambda g, eid11=None:g.E(eid11).E())], 
     'g_V_EXnullX': [(lambda g:g.V().E(None))], 
     'g_V_EXlistXnullXX': [(lambda g, xx1=None:g.V().E(xx1))], 
     'g_injectX1X_EX11_nullX': [(lambda g, eid11=None:g.inject(1).E(eid11, None))], 
     'g_injectX1X_coalesceXEX_hasLabelXtestsX_addEXtestsX_from_V_hasXnameX_XjoshXX_toXV_hasXnameX_XvadasXXX': [(lambda g:g.add_v('person').property('name', 'josh').add_v('person').property('name', 'vadas')), (lambda g:g.inject(1).coalesce(__.E().has_label('tests'), __.add_e('tests').from_(__.V().has('name', 'josh')).to(__.V().has('name', 'vadas')))), (lambda g:g.E().has_label('tests'))], 
+    'g_VX1X_outE_inV': [(lambda g, vid1=None:g.V(vid1).out_e().in_v())], 
+    'g_VX2X_inE_outV': [(lambda g, vid2=None:g.V(vid2).in_e().out_v())], 
+    'g_V_outE_hasXweight_1X_outV': [(lambda g:g.V().out_e().has('weight', 1.0).out_v())], 
+    'g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())], 
+    'g_VX4X_bothE_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().other_v())], 
+    'g_VX4X_bothE_hasXweight_lt_1X_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().has('weight', P.lt(1.0)).other_v())], 
+    'get_g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())], 
+    'g_VX1X_outEXknowsX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows').in_v())], 
+    'g_VX1X_outEXknows_createdX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows', 'created').in_v())], 
+    'g_VX1X_outEXknowsX_bothV': [(lambda g, vid1=None:g.V(vid1).out_e('knows').both_v())], 
+    'g_VX1X_outEXknowsX_bothV_name': [(lambda g, vid1=None:g.V(vid1).out_e('knows').both_v().values('name'))], 
     'g_VX1X_properties_element': [(lambda g, v2=None:g.V(v2).properties().element().limit(1))], 
     'g_V_properties_element': [(lambda g:g.V().properties().element())], 
     'g_V_propertiesXageX_element': [(lambda g:g.V().properties('age').element())], 
@@ -1347,34 +1372,15 @@ world.gremlins = {
     'g_VX1X_out': [(lambda g, vid1=None:g.V(vid1).out())], 
     'g_VX2X_in': [(lambda g, vid2=None:g.V(vid2).in_())], 
     'g_VX4X_both': [(lambda g, vid4=None:g.V(vid4).both())], 
-    'g_E': [(lambda g:g.E())], 
-    'g_EX11X': [(lambda g, eid11=None:g.E(eid11))], 
-    'g_EX11AsStringX': [(lambda g, eid11=None:g.E(eid11))], 
-    'g_EXe11X': [(lambda g, e11=None:g.E(e11))], 
-    'g_EXe7_e11X': [(lambda g, e7=None,e11=None:g.E(e7, e11))], 
-    'g_EXlistXe7_e11XX': [(lambda g, xx1=None:g.E(xx1))], 
-    'g_EXnullX': [(lambda g:g.E(None))], 
-    'g_EXlistXnullXX': [(lambda g, xx1=None:g.E(xx1))], 
-    'g_EX11_nullX': [(lambda g, eid11=None:g.E(eid11, None))], 
     'g_VX1X_outE': [(lambda g, vid1=None:g.V(vid1).out_e())], 
     'g_VX2X_outE': [(lambda g, vid2=None:g.V(vid2).in_e())], 
     'g_VX4X_bothEXcreatedX': [(lambda g, vid4=None:g.V(vid4).both_e('created'))], 
     'g_VX4X_bothE': [(lambda g, vid4=None:g.V(vid4).both_e())], 
-    'g_VX1X_outE_inV': [(lambda g, vid1=None:g.V(vid1).both())], 
-    'g_VX2X_inE_outV': [(lambda g, vid2=None:g.V(vid2).in_e().out_v())], 
-    'g_V_outE_hasXweight_1X_outV': [(lambda g:g.V().out_e().has('weight', 1.0).out_v())], 
     'g_V_out_outE_inV_inE_inV_both_name': [(lambda g:g.V().out().out_e().in_v().in_e().in_v().both().values('name'))], 
-    'g_VX1X_outEXknowsX_bothV_name': [(lambda g, vid1=None:g.V(vid1).out_e('knows').both_v().values('name'))], 
-    'g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())], 
-    'g_VX4X_bothE_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().other_v())], 
-    'g_VX4X_bothE_hasXweight_lt_1X_otherV': [(lambda g, vid4=None:g.V(vid4).both_e().has('weight', P.lt(1.0)).other_v())], 
     'g_VX2X_inE': [(lambda g, vid2=None:g.V(vid2).both_e())], 
-    'get_g_VX1X_outE_otherV': [(lambda g, vid1=None:g.V(vid1).out_e().other_v())], 
     'g_VX1X_outXknowsX': [(lambda g, vid1=None:g.V(vid1).out('knows'))], 
     'g_VX1AsStringX_outXknowsX': [(lambda g, vid1=None:g.V(vid1).out('knows'))], 
     'g_VX1X_outXknows_createdX': [(lambda g, vid1=None:g.V(vid1).out('knows', 'created'))], 
-    'g_VX1X_outEXknowsX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows').in_v())], 
-    'g_VX1X_outEXknows_createdX_inV': [(lambda g, vid1=None:g.V(vid1).out_e('knows', 'created').in_v())], 
     'g_V_out_out': [(lambda g:g.V().out().out())], 
     'g_VX1X_out_out_out': [(lambda g, vid1=None:g.V(vid1).out().out().out())], 
     'g_VX1X_out_name': [(lambda g, vid1=None:g.V(vid1).out().values('name'))], 
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 4bcb90f110..a282f69759 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
@@ -32,6 +32,7 @@ import org.antlr.v4.runtime.CommonTokenStream;
 import org.apache.tinkerpop.gremlin.language.grammar.GremlinAntlrToJava;
 import org.apache.tinkerpop.gremlin.language.grammar.GremlinLexer;
 import org.apache.tinkerpop.gremlin.language.grammar.GremlinParser;
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
 import org.apache.tinkerpop.gremlin.language.translator.GremlinTranslator;
 import org.apache.tinkerpop.gremlin.language.translator.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Merge;
@@ -62,6 +63,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;
@@ -92,7 +94,7 @@ public final class StepDefinition {
 
     private World world;
     private GraphTraversalSource g;
-    private final Map<String, String> stringParameters = new HashMap<>();
+    private final Map<String, Object> stringParameters = new HashMap<>();
     private Traversal traversal;
     private Object result;
     private Throwable error;
@@ -182,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());
@@ -234,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 -> {
@@ -285,19 +287,26 @@ public final class StepDefinition {
 
     @Given("using the parameter {word} defined as {string}")
     public void usingTheParameterXDefinedAsX(final String key, final String value) {
-        stringParameters.put(key, convertToString(value));
-    }
-
-    @Given("using the parameter {word} of P.{word}\\({string})")
-    public void usingTheParameterXOfPX(final String key, final String pval, final String string) {
-        stringParameters.put(key, String.format("P.%s(%s)", pval, convertToString(string)));
+        // when parameters are used literally, they are converted to string representations that can be recognized by
+        // the grammar and parsed inline. when they are used as variables, they are converted to objects that can be
+        // applied to the script as variables.
+        if (world.useParametersLiterally())
+            stringParameters.put(key, convertToString(value));
+        else
+            stringParameters.put(key, convertToObject(value));
     }
 
     @Given("the traversal of")
     public void theTraversalOf(final String docString) {
         try {
-            final String gremlin = tryUpdateDataFilePath(docString);
-            traversal = parseGremlin(applyParameters(gremlin));
+            final String rawGremlin = tryUpdateDataFilePath(docString);
+
+            // when parameters are used literally, they are converted to string representations that can be recognized by
+            // the grammar and parsed inline. when they are used as variables, they are converted to objects that can be
+            // applied to the script as variables.
+            final String gremlin = world.useParametersLiterally() ? applyParameters(rawGremlin) : rawGremlin;
+
+            traversal = parseGremlin(gremlin);
         } catch (Exception ex) {
             ex.printStackTrace();
             error = ex;
@@ -375,10 +384,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());
+        final String gremlin = world.useParametersLiterally() ? applyParameters(rawGremlin) : rawGremlin;
+        assertEquals(count.longValue(), ((GraphTraversal) parseGremlin(gremlin)).count().next());
     }
 
     @Then("the result should be empty")
@@ -450,7 +460,14 @@ public final class StepDefinition {
         final GremlinLexer lexer = new GremlinLexer(CharStreams.fromString(normalizedGremlin));
         final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer));
         final GremlinParser.QueryContext ctx = parser.query();
-        return (Traversal) new GremlinAntlrToJava(g).visitQuery(ctx);
+
+        // when parameters are used literally, they are converted to string representations that can be recognized by
+        // the grammar and parsed inline. when they are used as variables, they are converted to objects that can be
+        // applied to the script as variables.
+        if (world.useParametersLiterally())
+            return (Traversal) new GremlinAntlrToJava(g).visitQuery(ctx);
+        else
+            return (Traversal) new GremlinAntlrToJava(g, new VariableResolver.DefaultVariableResolver(this.stringParameters)).visitQuery(ctx);
     }
 
     private List<Object> translateResultsToActual() {
@@ -574,7 +591,7 @@ public final class StepDefinition {
         final List<String> paramNames = new ArrayList<>(stringParameters.keySet());
         paramNames.sort((a,b) -> b.length() - a.length());
         for (String k : paramNames) {
-            replaced = replaced.replace(k, stringParameters.get(k));
+            replaced = replaced.replace(k, stringParameters.get(k).toString());
         }
         return replaced;
     }
@@ -587,6 +604,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}.
      */
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java
index 52a977e614..726f72631a 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/World.java
@@ -82,6 +82,15 @@ public interface World {
         return id.toString();
     }
 
+    /**
+     * Determines if the test should use parameters literally or treat them as variables to be applied to the script.
+     * By default, they are treated literally.
+     */
+    public default boolean useParametersLiterally() {
+        return true;
+    }
+
+
     /**
      * Allows for some flexibility in error message assertion, where the provider can handle assertions themselves.
      * Providers should use standard assertion logic as they would with tests. Note that if this method is called, then
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
index c10757748d..8a1db09a05 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Has.feature
@@ -206,6 +206,30 @@ Feature: Step - has()
       | result |
       | d[29].i |
 
+  Scenario: g_V_hasXperson_name_markovarX_age
+    Given the modern graph
+    And using the parameter xx1 defined as "marko"
+    And the traversal of
+    """
+    g.V().has("person", "name", xx1).values("age")
+    """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[29].i |
+
+  Scenario: g_V_hasXpersonvar_name_markoX_age
+    Given the modern graph
+    And using the parameter xx1 defined as "person"
+    And the traversal of
+    """
+    g.V().has(xx1, "name", "marko").values("age")
+    """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[29].i |
+
   Scenario: g_VX1X_outE_hasXweight_inside_0_06X_inV
     Given the modern graph
     And using the parameter vid1 defined as "v[marko].id"
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature
index 8c20b41b72..cc85a5c4fe 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasId.feature
@@ -32,10 +32,9 @@ Feature: Step - hasId()
 
   Scenario: g_V_hasIdXwithinXemptyXX_count
     Given the modern graph
-    And using the parameter xx1 of P.within("l[]")
     And the traversal of
     """
-    g.V().hasId(xx1).count()
+    g.V().hasId(P.within([])).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -44,10 +43,9 @@ Feature: Step - hasId()
 
   Scenario: g_V_hasIdXwithoutXemptyXX_count
     Given the modern graph
-    And using the parameter xx1 of P.without("l[]")
     And the traversal of
     """
-    g.V().hasId(xx1).count()
+    g.V().hasId(P.without([])).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -56,10 +54,9 @@ Feature: Step - hasId()
 
   Scenario: g_V_notXhasIdXwithinXemptyXXX_count
     Given the modern graph
-    And using the parameter xx1 of P.within("l[]")
     And the traversal of
     """
-    g.V().not(__.hasId(xx1)).count()
+    g.V().not(__.hasId(P.within([]))).count()
     """
     When iterated to list
     Then the result should be unordered
@@ -147,10 +144,10 @@ Feature: Step - hasId()
 
   Scenario: g_V_in_hasIdXneqX1XX
     Given the modern graph
-    And using the parameter xx1 of P.neq("v[marko].id")
+    And using the parameter xx1 defined as "v[marko].id"
     And the traversal of
     """
-    g.V().in().hasId(xx1)
+    g.V().in().hasId(P.neq(xx1))
     """
     When iterated to list
     Then the result should be unordered
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature
index 470019f36d..2da655e7e6 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/HasLabel.feature
@@ -87,6 +87,34 @@ Feature: Step - hasLabel()
     When iterated to list
     Then the result should be empty
 
+  Scenario: g_V_hasLabelXpersonvarX_hasLabelXsoftwareX
+    Given the modern graph
+    And using the parameter xx1 defined as "person"
+    And the traversal of
+    """
+    g.V().hasLabel(xx1).hasLabel("software")
+    """
+    When iterated to list
+    Then the result should be empty
+
+  Scenario: g_V_hasLabelXpersonvar_softwarevarX
+    Given the modern graph
+    And using the parameter xx1 defined as "person"
+    And using the parameter xx2 defined as "software"
+    And the traversal of
+    """
+    g.V().hasLabel(xx1,xx2)
+    """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[vadas] |
+      | v[josh] |
+      | v[peter] |
+      | v[lop] |
+      | v[ripple] |
+
   Scenario: g_V_hasLabelXpersonX_hasXage_notXlteX10X_andXnotXbetweenX11_20XXXX_andXltX29X_orXeqX35XXXX_name
     Given the modern graph
     And the traversal of
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature
index 9d9d54547e..8f05f14f0d 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Conjoin.feature
@@ -59,7 +59,7 @@ Feature: Step - conjoin()
       | result |
       | josh_lop_marko_peter_ripple_vadas |
 
-  Scenario: g_V_valuesXageX_order_fold_conjoinX_X
+  Scenario: g_V_valuesXageX_order_fold_conjoinXsemicolonX
     Given the modern graph
     And the traversal of
       """
@@ -70,6 +70,18 @@ Feature: Step - conjoin()
       | result |
       | 27;29;32;35 |
 
+  Scenario: g_V_valuesXageX_order_fold_conjoinXslashX
+    Given the modern graph
+    And using the parameter xx1 defined as "/"
+    And the traversal of
+      """
+      g.V().values("age").order().fold().conjoin(xx1)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | 27/29/32/35 |
+
   @GraphComputerVerificationReferenceOnly
   Scenario: g_V_out_path_byXvaluesXnameX_toUpperX_conjoinXMARKOX
     Given the modern graph
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
index f3d92320d2..7d75a251af 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
@@ -16,7 +16,117 @@
 # under the License.
 
 @StepClassMap @StepE
-Feature: Step - E()
+Feature: Step - E(), inV(), outV(), bothV(), otherV()
+
+  Scenario: g_E
+    Given the modern graph
+    And the traversal of
+      """
+      g.E()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[marko-created->lop] |
+      | e[marko-knows->josh] |
+      | e[marko-knows->vadas] |
+      | e[peter-created->lop] |
+      | e[josh-created->lop] |
+      | e[josh-created->ripple] |
+
+  Scenario: g_EX11X
+    Given the modern graph
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(eid11)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[josh-created->lop] |
+
+  Scenario: g_EX11AsStringX
+    Given the modern graph
+    And using the parameter eid11 defined as "e[josh-created->lop].sid"
+    And the traversal of
+      """
+      g.E(eid11)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[josh-created->lop] |
+
+  Scenario: g_EXe11X
+    Given the modern graph
+    And using the parameter e11 defined as "e[josh-created->lop]"
+    And the traversal of
+      """
+      g.E(e11)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[josh-created->lop] |
+
+  Scenario: g_EXe7_e11X
+    Given the modern graph
+    And using the parameter e7 defined as "e[marko-knows->vadas]"
+    And using the parameter e11 defined as "e[josh-created->lop]"
+    And the traversal of
+      """
+      g.E(e7,e11)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[marko-knows->vadas] |
+      | e[josh-created->lop] |
+
+  Scenario: g_EXlistXe7_e11XX
+    Given the modern graph
+    And using the parameter xx1 defined as "l[e[marko-knows->vadas],e[josh-created->lop]]"
+    And the traversal of
+      """
+      g.E(xx1)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[marko-knows->vadas] |
+      | e[josh-created->lop] |
+
+  Scenario: g_EXnullX
+    Given the modern graph
+    And the traversal of
+      """
+      g.E(null)
+      """
+    When iterated to list
+    Then the result should be empty
+
+  Scenario: g_EXlistXnullXX
+    Given the modern graph
+    And using the parameter xx1 defined as "l[null]"
+    And the traversal of
+      """
+      g.E(xx1)
+      """
+    When iterated to list
+    Then the result should be empty
+
+  Scenario: g_EX11_nullX
+    Given the modern graph
+    And using the parameter eid11 defined as "e[josh-created->lop].id"
+    And the traversal of
+      """
+      g.E(eid11,null)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | e[josh-created->lop] |
 
   Scenario: g_V_EX11X
     Given the modern graph
@@ -97,3 +207,152 @@ Feature: Step - E()
     When iterated to list
     Then the result should have a count of 1
     And the graph should return 1 for count of "g.E().hasLabel(\"tests\")"
+
+  Scenario: g_VX1X_outE_inV
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE().inV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[vadas] |
+      | v[josh] |
+      | v[lop] |
+
+  Scenario: g_VX2X_inE_outV
+    Given the modern graph
+    And using the parameter vid2 defined as "v[vadas].id"
+    And the traversal of
+      """
+      g.V(vid2).inE().outV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+
+  Scenario: g_V_outE_hasXweight_1X_outV
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().outE().has("weight",1.0).outV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[josh] |
+
+  Scenario: g_VX1X_outE_otherV
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE().otherV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[vadas] |
+      | v[josh] |
+      | v[lop] |
+
+  Scenario: g_VX4X_bothE_otherV
+    Given the modern graph
+    And using the parameter vid4 defined as "v[josh].id"
+    And the traversal of
+      """
+      g.V(vid4).bothE().otherV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[ripple] |
+      | v[lop] |
+
+  Scenario: g_VX4X_bothE_hasXweight_lt_1X_otherV
+    Given the modern graph
+    And using the parameter vid4 defined as "v[josh].id"
+    And the traversal of
+      """
+      g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[lop] |
+
+  Scenario: get_g_VX1X_outE_otherV
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE().otherV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[vadas] |
+      | v[josh] |
+      | v[lop] |
+
+  Scenario: g_VX1X_outEXknowsX_inV
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE("knows").inV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[vadas] |
+      | v[josh] |
+
+  Scenario: g_VX1X_outEXknows_createdX_inV
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE("knows","created").inV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[vadas] |
+      | v[josh] |
+      | v[lop] |
+
+  Scenario: g_VX1X_outEXknowsX_bothV
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE("knows").bothV()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | v[marko] |
+      | v[marko] |
+      | v[josh] |
+      | v[vadas] |
+
+  Scenario: g_VX1X_outEXknowsX_bothV_name
+    Given the modern graph
+    And using the parameter vid1 defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(vid1).outE("knows").bothV().values("name")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | marko |
+      | marko |
+      | josh |
+      | vadas |
\ No newline at end of file
diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature
index f0b3c95a93..3f8912211b 100644
--- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature
+++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Vertex.feature
@@ -16,7 +16,7 @@
 # under the License.
 
 @StepClassMap @StepVertex
-Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
+Feature: Step - V(), out(), in(), both(), inE(), outE(), bothE()
 
   Scenario: g_VXnullX
     Given the modern graph
@@ -147,116 +147,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | v[lop] |
       | v[ripple] |
 
-  Scenario: g_E
-    Given the modern graph
-    And the traversal of
-      """
-      g.E()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[marko-created->lop] |
-      | e[marko-knows->josh] |
-      | e[marko-knows->vadas] |
-      | e[peter-created->lop] |
-      | e[josh-created->lop] |
-      | e[josh-created->ripple] |
-
-  Scenario: g_EX11X
-    Given the modern graph
-    And using the parameter eid11 defined as "e[josh-created->lop].id"
-    And the traversal of
-      """
-      g.E(eid11)
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[josh-created->lop] |
-
-  Scenario: g_EX11AsStringX
-    Given the modern graph
-    And using the parameter eid11 defined as "e[josh-created->lop].sid"
-    And the traversal of
-      """
-      g.E(eid11)
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[josh-created->lop] |
-
-  Scenario: g_EXe11X
-    Given the modern graph
-    And using the parameter e11 defined as "e[josh-created->lop]"
-    And the traversal of
-      """
-      g.E(e11)
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[josh-created->lop] |
-
-  Scenario: g_EXe7_e11X
-    Given the modern graph
-    And using the parameter e7 defined as "e[marko-knows->vadas]"
-    And using the parameter e11 defined as "e[josh-created->lop]"
-    And the traversal of
-      """
-      g.E(e7,e11)
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[marko-knows->vadas] |
-      | e[josh-created->lop] |
-
-  Scenario: g_EXlistXe7_e11XX
-    Given the modern graph
-    And using the parameter xx1 defined as "l[e[marko-knows->vadas],e[josh-created->lop]]"
-    And the traversal of
-      """
-      g.E(xx1)
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[marko-knows->vadas] |
-      | e[josh-created->lop] |
-
-  Scenario: g_EXnullX
-    Given the modern graph
-    And the traversal of
-      """
-      g.E(null)
-      """
-    When iterated to list
-    Then the result should be empty
-
-  Scenario: g_EXlistXnullXX
-    Given the modern graph
-    And using the parameter xx1 defined as "l[null]"
-    And the traversal of
-      """
-      g.E(xx1)
-      """
-    When iterated to list
-    Then the result should be empty
-
-  Scenario: g_EX11_nullX
-    Given the modern graph
-    And using the parameter eid11 defined as "e[josh-created->lop].id"
-    And the traversal of
-      """
-      g.E(eid11,null)
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | e[josh-created->lop] |
-
   Scenario: g_VX1X_outE
     Given the modern graph
     And using the parameter vid1 defined as "v[marko].id"
@@ -310,44 +200,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | e[josh-created->ripple] |
       | e[marko-knows->josh] |
 
-  Scenario: g_VX1X_outE_inV
-    Given the modern graph
-    And using the parameter vid1 defined as "v[marko].id"
-    And the traversal of
-      """
-      g.V(vid1).both()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[vadas] |
-      | v[josh] |
-      | v[lop] |
-
-  Scenario: g_VX2X_inE_outV
-    Given the modern graph
-    And using the parameter vid2 defined as "v[vadas].id"
-    And the traversal of
-      """
-      g.V(vid2).inE().outV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[marko] |
-
-  Scenario: g_V_outE_hasXweight_1X_outV
-    Given the modern graph
-    And the traversal of
-      """
-      g.V().outE().has("weight",1.0).outV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[marko] |
-      | v[josh] |
-
   Scenario: g_V_out_outE_inV_inE_inV_both_name
     Given the modern graph
     And the traversal of
@@ -368,61 +220,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | peter |
       | peter |
 
-  Scenario: g_VX1X_outEXknowsX_bothV_name
-    Given the modern graph
-    And using the parameter vid1 defined as "v[marko].id"
-    And the traversal of
-      """
-      g.V(vid1).outE("knows").bothV().values("name")
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | marko |
-      | marko |
-      | josh |
-      | vadas |
-
-  Scenario: g_VX1X_outE_otherV
-    Given the modern graph
-    And using the parameter vid1 defined as "v[marko].id"
-    And the traversal of
-      """
-      g.V(vid1).outE().otherV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[vadas] |
-      | v[josh] |
-      | v[lop] |
-
-  Scenario: g_VX4X_bothE_otherV
-    Given the modern graph
-    And using the parameter vid4 defined as "v[josh].id"
-    And the traversal of
-      """
-      g.V(vid4).bothE().otherV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[marko] |
-      | v[ripple] |
-      | v[lop] |
-
-  Scenario: g_VX4X_bothE_hasXweight_lt_1X_otherV
-    Given the modern graph
-    And using the parameter vid4 defined as "v[josh].id"
-    And the traversal of
-      """
-      g.V(vid4).bothE().has("weight", P.lt(1.0)).otherV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[lop] |
-
   Scenario: g_VX2X_inE
     Given the modern graph
     And using the parameter vid2 defined as "v[vadas].id"
@@ -435,20 +232,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | result |
       | e[marko-knows->vadas] |
 
-  Scenario: get_g_VX1X_outE_otherV
-    Given the modern graph
-    And using the parameter vid1 defined as "v[marko].id"
-    And the traversal of
-      """
-      g.V(vid1).outE().otherV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[vadas] |
-      | v[josh] |
-      | v[lop] |
-
   Scenario: g_VX1X_outXknowsX
     Given the modern graph
     And using the parameter vid1 defined as "v[marko].id"
@@ -489,33 +272,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | v[josh] |
       | v[lop] |
 
-  Scenario: g_VX1X_outEXknowsX_inV
-    Given the modern graph
-    And using the parameter vid1 defined as "v[marko].id"
-    And the traversal of
-      """
-      g.V(vid1).outE("knows").inV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[vadas] |
-      | v[josh] |
-
-  Scenario: g_VX1X_outEXknows_createdX_inV
-    Given the modern graph
-    And using the parameter vid1 defined as "v[marko].id"
-    And the traversal of
-      """
-      g.V(vid1).outE("knows","created").inV()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | v[vadas] |
-      | v[josh] |
-      | v[lop] |
-
   Scenario: g_V_out_out
     Given the modern graph
     And the traversal of
@@ -565,8 +321,6 @@ Feature: Step - V(), E(), out(), in(), both(), inE(), outE(), bothE()
       | v[vadas] |
       | v[josh] |
 
-
-
   # the point here is to test g.V() where an id is not present. to do this with the gherkin structure
   # the test establishes the modern graph, does a drop() of "lop" and then tries to query the 4 vertices
   # and we assert the count of 3
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
index 7ab286543c..90d7327cc7 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
@@ -66,7 +66,7 @@ public final class Neo4jGraphStep<S, E extends Element> extends GraphStep<S, E>
     private Iterator<? extends Edge> edges() {
         if (null == this.ids)
             return Collections.emptyIterator();
-        return IteratorUtils.filter(this.getTraversal().getGraph().get().edges(this.ids), edge -> HasContainer.testAll(edge, this.hasContainers));
+        return IteratorUtils.filter(this.getTraversal().getGraph().get().edges(this.getIdsAsValues()), edge -> HasContainer.testAll(edge, this.hasContainers));
     }
 
     private Iterator<? extends Vertex> vertices() {
@@ -76,7 +76,7 @@ public final class Neo4jGraphStep<S, E extends Element> extends GraphStep<S, E>
 
         // ids are present, filter on them first
         if (ids.length > 0)
-            return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers));
+            return IteratorUtils.filter(graph.vertices(this.getIdsAsValues()), vertex -> HasContainer.testAll(vertex, hasContainers));
         ////// do index lookups //////
         graph.tx().readWrite();
         // get a label being search on
diff --git a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
index a4a95cc1c1..5f791b41d5 100644
--- a/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
+++ b/sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/strategy/SparqlStrategy.java
@@ -23,7 +23,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.sparql.SparqlToGremlinCompiler;
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java
index 6a3e965629..5a3d59e80b 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/TinkerGraphStep.java
@@ -71,11 +71,12 @@ public final class TinkerGraphStep<S, E extends Element> extends GraphStep<S, E>
         final AbstractTinkerGraph graph = (AbstractTinkerGraph) this.getTraversal().getGraph().get();
         final HasContainer indexedContainer = getIndexKey(Edge.class);
         Iterator<Edge> iterator;
+        final Object[] resolvedIds = this.getIdsAsValues();
         // ids are present, filter on them first
-        if (null == this.ids)
+        if (null == resolvedIds)
             iterator = Collections.emptyIterator();
-        else if (this.ids.length > 0)
-            iterator = this.iteratorList(graph.edges(this.ids));
+        else if (resolvedIds.length > 0)
+            iterator = this.iteratorList(graph.edges(resolvedIds));
         else
             iterator = null == indexedContainer ?
                     this.iteratorList(graph.edges()) :
@@ -93,11 +94,12 @@ public final class TinkerGraphStep<S, E extends Element> extends GraphStep<S, E>
         final AbstractTinkerGraph graph = (AbstractTinkerGraph) this.getTraversal().getGraph().get();
         final HasContainer indexedContainer = getIndexKey(Vertex.class);
         Iterator<? extends Vertex> iterator;
+        final Object[] resolvedIds = this.getIdsAsValues();
         // ids are present, filter on them first
-        if (null == this.ids)
+        if (null == resolvedIds)
             iterator = Collections.emptyIterator();
-        else if (this.ids.length > 0)
-            iterator = this.iteratorList(graph.vertices(this.ids));
+        else if (resolvedIds.length > 0)
+            iterator = this.iteratorList(graph.vertices(resolvedIds));
         else
             iterator = (null == indexedContainer ?
                     this.iteratorList(graph.vertices()) :
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
index 329a07fbae..52fd414164 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/TinkerWorld.java
@@ -109,6 +109,11 @@ public abstract class TinkerWorld implements World {
         public AbstractTinkerGraph open(final Configuration configuration) {
             return TinkerGraph.open(configuration);
         }
+
+        @Override
+        public boolean useParametersLiterally() {
+            return false;
+        }
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
index 80111709f5..e1d908045b 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java
@@ -18,8 +18,12 @@
  */
 package org.apache.tinkerpop.gremlin.tinkergraph.structure;
 
+import org.apache.tinkerpop.gremlin.jsr223.GremlinLangScriptEngine;
+import org.apache.tinkerpop.gremlin.jsr223.VariableResolverCustomizer;
+import org.apache.tinkerpop.gremlin.language.grammar.VariableResolver;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 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.dsl.graph.GraphTraversalSource;
@@ -38,6 +42,7 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.script.Bindings;
 import java.util.Arrays;
 import java.util.List;
 import java.util.function.BiFunction;
@@ -270,17 +275,25 @@ public class TinkerGraphPlayTest {
     }
 
     @Test
-    @Ignore
-    public void testBugs() {
+    public void testBugs() throws Exception {
         final GraphTraversalSource g = TinkerFactory.createModern().traversal();
-        Object o1 = g.V().map(__.V(1));
-        System.out.println(g.V().as("a").both().as("b").dedup("a", "b").by(T.label).select("a", "b").explain());
-        System.out.println(g.V().as("a").both().as("b").dedup("a", "b").by(T.label).select("a", "b").toList());
-
-        Traversal<?,?> t =
-                g.V("3").
-                        union(__.repeat(out().simplePath()).times(2).count(),
-                                __.repeat(in().simplePath()).times(2).count());
+        final GremlinLangScriptEngine se = new GremlinLangScriptEngine(
+                new VariableResolverCustomizer(VariableResolver.DefaultVariableResolver::new));
+
+        final Bindings b = se.createBindings();
+        b.put("g", g);
+        System.out.println(((GraphTraversal) se.eval("g.V().coin(0.5).count()", b)).toList());
+
+        b.clear();
+        b.put("g", g);
+        b.put("x", 0.5d);
+        System.out.println(((GraphTraversal) se.eval("g.V().coin(x).count()", b)).toList());
+
+        b.clear();
+        b.put("g", g);
+        b.put("x", "josh");
+        b.put("y", 32);
+        System.out.println(((GraphTraversal) se.eval("g.V().has('name', x).has('age', y).count()", b)).toList());
     }
 
     @Test