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

    wip - params
---
 .../gremlin/jsr223/GremlinLangScriptEngine.java    |  17 +-
 .../gremlin/jsr223/VariableResolverCustomizer.java |  40 +++
 .../gremlin/jsr223/VariableResolverPlugin.java     |  95 ++++++
 .../language/grammar/TraversalMethodVisitor.java   |  11 +-
 .../gremlin/language/grammar/VariableResolver.java |  37 ++-
 .../tinkerpop/gremlin/process/traversal/P.java     |   6 +-
 .../traversal/dsl/graph/GraphTraversal.java        | 270 +++++++++++++++++
 .../traversal/lambda/ConstantTraversal.java        |  15 +-
 .../gremlin/process/traversal/step/GType.java      |  81 ++++++
 .../gremlin/process/traversal/step/GValue.java     | 321 +++++++++++++++++++++
 .../process/traversal/step/filter/CoinStep.java    |  28 +-
 .../process/traversal/step/map/AddEdgeStep.java    |   6 +
 .../process/traversal/step/map/AddVertexStep.java  |   5 +
 .../process/traversal/step/map/ConstantStep.java   |  19 +-
 .../process/traversal/step/map/GraphStep.java      |  30 +-
 .../process/traversal/step/map/MergeEdgeStep.java  |   5 +
 .../traversal/step/map/MergeVertexStep.java        |   5 +
 .../process/traversal/step/map/VertexStep.java     |  37 ++-
 .../process/traversal/step/util/Parameters.java    |  21 +-
 .../strategy/decoration/SubgraphStrategy.java      |   2 +-
 .../optimization/AdjacentToIncidentStrategy.java   |   2 +-
 .../optimization/IncidentToAdjacentStrategy.java   |   2 +-
 .../optimization/InlineFilterStrategy.java         |  20 +-
 .../gremlin/structure/VertexProperty.java          |   3 -
 .../gremlin/structure/io/gryo/GryoVersion.java     |  12 +-
 .../gremlin/jsr223/VariableResolverPluginTest.java | 117 ++++++++
 .../language/grammar/ArgumentVisitorTest.java      | 116 ++++----
 .../language/grammar/GremlinQueryParserTest.java   |   8 +-
 .../gremlin/process/traversal/step/GTypeTest.java  |  77 +++++
 .../gremlin/process/traversal/step/GValueTest.java | 316 ++++++++++++++++++++
 .../traversal/step/util/ParametersTest.java        |  11 +
 .../tinkergraph/structure/TinkerGraphPlayTest.java |  33 ++-
 32 files changed, 1650 insertions(+), 118 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/TraversalMethodVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index 440bd502c8..4f523c092f 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
@@ -23,6 +23,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 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.VertexProperty.Cardinality;
 
 import java.util.Map;
@@ -441,7 +443,14 @@ 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 (literalOrVar instanceof Number)
+            return graphTraversal.coin(((Number) literalOrVar).doubleValue());
+        else if (literalOrVar instanceof GValue && ((GValue) 
literalOrVar).getType().isNumeric())
+            return graphTraversal.asAdmin().coin((GValue<Double>) 
literalOrVar);
+        else
+            throw new IllegalArgumentException("coin() argument must be a 
double");
+
     }
 
     /**
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/process/traversal/P.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/P.java
index 917a13891d..56e1946368 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,6 +18,7 @@
  */
 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;
 
@@ -74,7 +75,10 @@ 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
+            return this.biPredicate.test(testValue, this.value);
     }
 
     @Override
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..327f72135e 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
@@ -47,6 +47,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;
@@ -230,8 +231,277 @@ 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()}.
+     * <p/>
+     * Note that step overloads allowing use of {@link GValue} objects do not 
construct bytecode with that object.
+     * Bytecode does not make use of parameterization in that fashion so it 
there isn't a need to really preserve that
+     * functionality there (doing so would require changes to serializers).
+     */
     public interface Admin<S, E> extends Traversal.Admin<S, E>, 
GraphTraversal<S, E> {
 
+        /**
+         * 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 3.7.3
+         */
+        public default GraphTraversal<S, E> coin(final GValue<Double> 
probability) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.coin, 
probability);
+            return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), 
probability));
+        }
+
+        /**
+         * 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 3.7.3
+         */
+        public default <E2> GraphTraversal<S, E2> constant(final GValue<E2> e) 
{
+            
this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.constant, e);
+            return this.asAdmin().addStep(new ConstantStep<E, 
E2>(this.asAdmin(), e));
+        }
+
+        /**
+         * 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 3.7.3
+         */
+        public default GraphTraversal<S, Vertex> to(final Direction direction, 
final Object... edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.to, 
direction, edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Vertex.class, direction, 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 Object... 
edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.out, 
edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Vertex.class, Direction.OUT, 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 3.7.3
+         */
+        public default GraphTraversal<S, Vertex> in(final Object... 
edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.in, 
edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Vertex.class, Direction.IN, 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 3.7.3
+         */
+        public default GraphTraversal<S, Vertex> both(final Object... 
edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.both, 
edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Vertex.class, Direction.BOTH, 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 3.7.3
+         */
+        public default GraphTraversal<S, Edge> toE(final Direction direction, 
final Object... edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.toE, 
direction, edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Edge.class, direction, 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 3.7.3
+         */
+        public default GraphTraversal<S, Edge> outE(final Object... 
edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.outE, 
edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Edge.class, Direction.OUT, 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 3.7.3
+         */
+        public default GraphTraversal<S, Edge> inE(final Object... edgeLabels) 
{
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.inE, 
edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Edge.class, Direction.IN, 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 3.7.3
+         */
+        public default GraphTraversal<S, Edge> bothE(final Object... 
edgeLabels) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.bothE, 
edgeLabels);
+            return this.asAdmin().addStep(new VertexStep<>(this.asAdmin(), 
Edge.class, Direction.BOTH, edgeLabels));
+        }
+
+        /**
+         * 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 3.7.3
+         */
+        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().getBytecode().addStep(GraphTraversal.Symbols.addV, 
vertexLabel);
+            return this.asAdmin().addStep(new AddVertexStep<>(this.asAdmin(), 
vertexLabel));
+        }
+
+        /**
+         * 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 3.7.3
+         */
+        public default GraphTraversal<S, Vertex> mergeV(final 
GValue<Map<Object, Object>> searchCreate) {
+            
this.asAdmin().getBytecode().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 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 3.7.3
+         */
+        public default GraphTraversal<S, Edge> mergeE(final GValue<Map<Object, 
Object>> searchCreate) {
+            // get a construction time exception if the Map is bad
+            
this.asAdmin().getBytecode().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.
+         *
+         * @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 3.7.3
+         */
+        public default GraphTraversal<S, Edge> addE(final GValue<String> 
edgeLabel) {
+            this.asAdmin().getBytecode().addStep(GraphTraversal.Symbols.addE, 
edgeLabel);
+            return this.asAdmin().addStep(new AddEdgeStep<>(this.asAdmin(), 
edgeLabel));
+        }
+
+        /**
+         * 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 3.2.2
+         */
+        public default GraphTraversal<S, E> hasLabel(final Object label, final 
Object... otherLabels) {
+            
this.asAdmin().getBytecode().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 int otherLabelsLength = null == otherLabels ? 0 : 
otherLabels.length;
+            final Object[] labels = new Object[otherLabelsLength + 1];
+            labels[0] = label;
+            if (otherLabelsLength > 0)
+                System.arraycopy(otherLabels, 0, labels, 1, otherLabelsLength);
+            return TraversalHelper.addHasContainer(this.asAdmin(), new 
HasContainer(T.label.getAccessor(), labels.length == 1 ? P.eq(labels[0]) : 
P.within(labels)));
+        }
+
+        /**
+         * 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().getBytecode().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().getBytecode().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;
+        }
+
         @Override
         public default <E2> GraphTraversal.Admin<S, E2> addStep(final Step<?, 
E2> step) {
             return (GraphTraversal.Admin<S, E2>) 
Traversal.Admin.super.addStep((Step) step);
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..89a8b79098
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GType.java
@@ -0,0 +1,81 @@
+/*
+ * 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,
+    BIG_INTEGER,
+    BOOLEAN,
+    DOUBLE,
+    EDGE,
+    INTEGER,
+    LIST,
+    LONG,
+    MAP,
+    PATH,
+    PROPERTY,
+    SET,
+    STRING,
+    UNKNOWN,
+    VERTEX;
+
+    GType() {}
+
+    /**
+     * Returns true if the type is a number.
+     */
+    public boolean isNumeric() {
+        return this == INTEGER || this == DOUBLE || this == LONG || this == 
BIG_INTEGER || this == BIG_DECIMAL;
+    }
+
+    /**
+     * 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..4de2ca1f8e
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -0,0 +1,321 @@
+/*
+ * 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.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * 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 Optional<String> getName() {
+        return Optional.ofNullable(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;
+    }
+
+    /**
+     * 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;
+        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.
+     *
+     * @param value the value of the variable
+     */
+    public static <V> GValue<V> of(final V value) {
+        return new GValue<>(GType.getType(value), value);
+    }
+
+    /**
+     * Create a new {@code Var} with the specified name and value.
+     *
+     * @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) {
+        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 GValue<List> ofList(final List value) {
+        return new GValue<>(GType.LIST, value);
+    }
+
+    /**
+     * Create a new {@code GValue} for a list value with a specified name.
+     */
+    public static GValue<List> ofList(final String name, final List 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);
+    }
+}
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..e220952200 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,27 @@ 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;
 
+    /**
+     * @deprecated As of release 3.7.3, replaced by {@link 
#CoinStep(Traversal.Admin, GValue)}
+     */
+    @Deprecated
     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
@@ -46,8 +58,12 @@ public final class CoinStep<S> extends FilterStep<S> 
implements Seedable {
         random.setSeed(seed);
     }
 
+    public GValue<Double> getProbabilityGValue() {
+        return probability;
+    }
+
     public double getProbability() {
-        return this.probability;
+        return this.probability.get();
     }
 
     @Override
@@ -55,11 +71,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 +89,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..9dfa4ce754 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
@@ -21,6 +21,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.map;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.FromToModulating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.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 +60,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);
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/ConstantStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
index 9434cc3b47..bf554d1aa9 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,37 @@ 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, 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/GraphStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java
index 3b1720ff9a..ee151aed12 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;
@@ -66,11 +67,28 @@ public class GraphStep<S, E extends Element> extends 
AbstractStep<S, E> implemen
         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;
         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(convertGValuesToIds()) :
+                
this.getTraversal().getGraph().get().edges(convertGValuesToIds()));
     }
 
+    /**
+     * Converts {@link GValue} objects the ids array to their values to 
prevent them from leaking to the Graph API.
+     */
+    private Object[] convertGValuesToIds() {
+        final Object[] newIds = new Object[this.ids.length];
+        for (int i = 0; i < this.ids.length; i++) {
+            if (newIds[i] instanceof GValue) {
+                newIds[i] = ((GValue) this.ids[i]).get();
+            } else {
+                newIds[i] = this.ids[i];
+            }
+        }
+        return newIds;
+    }
+
+
     public String toString() {
         return StringFactory.stepString(this, 
this.returnClass.getSimpleName().toLowerCase(), Arrays.toString(this.ids));
     }
@@ -137,7 +155,13 @@ 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 is going to OLAP, convert to ids so you don't serialize 
elements
+            for (int i = 0; i < this.ids.length; i++) {
+
+                // spare the Graph API from GValue objects, as they are 
Gremlin level objects
+                if (this.ids[i] instanceof GValue)
+                    this.ids[i] = ((GValue) this.ids[i]).get();
+
                 if (this.ids[i] instanceof Element)
                     this.ids[i] = ((Element) this.ids[i]).id();
             }
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/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/VertexStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java
index bd429f049c..e27fbb3802 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,41 @@ 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, (Object[]) edgeLabels);
+    }
+
+    public VertexStep(final Traversal.Admin traversal, final Class<E> 
returnClass, final Direction direction, final Object... edgeLabels) {
         super(traversal);
         this.direction = direction;
-        this.edgeLabels = edgeLabels;
         this.returnClass = returnClass;
+
+        // check each edgeLabel to ensure it is a string or a GValue with a 
GType.STRING in it. if it is just a string
+        // then convert edgeLabels to a GValue<String> or otherwise throw an 
exception
+        this.edgeLabelsGValue = Arrays.stream(edgeLabels).map(edgeLabel -> {
+            if (edgeLabel instanceof String)
+                return GValue.ofString((String) edgeLabel);
+            else if (edgeLabel instanceof GValue && ((GValue<String>) 
edgeLabel).get().getClass().equals(String.class))
+                return (GValue<String>) edgeLabel;
+            else
+                throw new IllegalArgumentException("All edge labels must be 
strings");
+        }).toArray(GValue[]::new);
+
+        // 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 +89,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 +105,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 +117,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/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/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..5ff63b3e0f 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,28 @@ 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 &&
+                            (hasContainer.getValue() instanceof String ||
+                                    (hasContainer.getValue() instanceof GValue 
&& ((GValue) hasContainer.getValue()).getType() == 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 && 
(orps.get(i).getValue() instanceof String ||
+                                    (orps.get(i).getValue() instanceof GValue 
&& ((GValue) orps.get(i).getValue()).getType() == GType.STRING)))
+                                newEdges.add(orps.get(i).getValue());
                             else {
                                 removeContainer = false;
                                 break;
@@ -157,7 +161,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(), 
edgeLabels.toArray(new Object[edgeLabels.size()]));
                 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/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/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 43f33054b5..e9c98cd2c3 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,81 +84,81 @@ 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))))},
+                {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, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {Direction.class, "x", Direction.OUT, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Direction.OUT)))},
-                {Direction.class, "x", Direction.from, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Direction.from)))},
+                {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")))},
+                {Direction.class, "x", Direction.OUT, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Direction.OUT)))},
+                {Direction.class, "x", Direction.from, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Direction.from)))},
                 {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"))))},
+                {Vertex.class, "new Vertex(1i,'person')", new 
ReferenceVertex(1, "person"), createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Direction.from)))},
+                {Vertex.class, "x", new ReferenceVertex(1, "person"), 
createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", new 
ReferenceVertex(1, "person"))))},
                 {Order.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {Order.class, "Order.desc", Order.desc, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", "nope")))},
-                {Order.class, "x", Order.desc, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Order.desc)))},
+                {Order.class, "Order.desc", Order.desc, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", "nope")))},
+                {Order.class, "x", Order.desc, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Order.desc)))},
                 {Scope.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {Scope.class, "x", Scope.local, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Scope.local)))},
+                {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")))},
+                {Scope.class, "x", Scope.local, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Scope.local)))},
                 {T.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {T.class, "x", T.label, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", T.label)))},
+                {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")))},
+                {T.class, "x", T.label, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", T.label)))},
                 {VertexProperty.Cardinality.class, "x", new 
VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {VertexProperty.Cardinality.class, "x", 
VertexProperty.Cardinality.list, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
VertexProperty.Cardinality.list)))},
+                {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")))},
+                {VertexProperty.Cardinality.class, "x", 
VertexProperty.Cardinality.list, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
VertexProperty.Cardinality.list)))},
                 {DT.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {DT.class, "x", DT.hour, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", DT.hour)))},
+                {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")))},
+                {DT.class, "x", DT.hour, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", DT.hour)))},
                 {Merge.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {Merge.class, "x", Merge.onMatch, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Merge.onMatch)))},
+                {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")))},
+                {Merge.class, "x", Merge.onMatch, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Merge.onMatch)))},
                 {Pop.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {Pop.class, "x", Pop.last, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", Pop.last)))},
+                {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")))},
+                {Pop.class, "x", Pop.last, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", Pop.last)))},
                 {Operator.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {Operator.class, "x", Operator.sum, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Operator.sum)))},
+                {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")))},
+                {Operator.class, "x", Operator.sum, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Operator.sum)))},
                 {Column.class, "x", new VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {Column.class, "x", Column.keys, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
Column.keys)))},
+                {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")))},
+                {Column.class, "x", Column.keys, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
Column.keys)))},
                 {SackFunctions.Barrier.class, "x", new 
VariableResolverException("x"), 
createAntlr(VariableResolver.NoVariableResolver.instance())},
-                {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")))},
-                {SackFunctions.Barrier.class, "x", 
SackFunctions.Barrier.normSack, createAntlr(new 
VariableResolver.DefaultVariableResolver(ElementHelper.asMap("x", 
SackFunctions.Barrier.normSack)))},
+                {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")))},
+                {SackFunctions.Barrier.class, "x", 
SackFunctions.Barrier.normSack, createAntlr(new 
VariableResolver.DirectVariableResolver(ElementHelper.asMap("x", 
SackFunctions.Barrier.normSack)))},
         });
     }
 
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/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..fcfac9b9d9
--- /dev/null
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValueTest.java
@@ -0,0 +1,316 @@
+/*
+ * 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.assertEquals;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+
+public class GValueTest {
+
+    @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().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        assertThat(gValue.isVariable(), is(true));
+    }
+
+    @Test
+    public void shouldCreateGValueFromList() {
+        final List<String> list = Arrays.asList("value1", "value2");
+        final GValue<List> 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> gValue = GValue.ofList("varName", list);
+        assertEquals(list, gValue.get());
+        assertEquals(GType.LIST, gValue.getType());
+        assertEquals("varName", gValue.getName().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        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().get());
+        assertThat(gValue.isVariable(), is(true));
+    }
+}
\ No newline at end of file
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/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


Reply via email to