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

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

commit 216b8b10c32f79ca3d875120af6308d975faed52
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        |  42 ++++++
 .../gremlin/process/traversal/step/GType.java      |  81 +++++++++++
 .../gremlin/process/traversal/step/GValue.java     | 148 +++++++++++++++++++++
 .../process/traversal/step/filter/CoinStep.java    |  26 +++-
 .../gremlin/structure/VertexProperty.java          |   3 -
 .../gremlin/jsr223/VariableResolverPluginTest.java | 117 ++++++++++++++++
 .../language/grammar/ArgumentVisitorTest.java      | 116 ++++++++--------
 .../language/grammar/GremlinQueryParserTest.java   |   8 +-
 .../tinkergraph/structure/TinkerGraphPlayTest.java |  33 +++--
 15 files changed, 691 insertions(+), 89 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 842d4daa32..6ef141e8e5 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
@@ -33,7 +33,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
@@ -53,6 +57,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}.
      */
@@ -61,6 +67,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
@@ -108,7 +123,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 d5124e20b3..536dd13e55 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.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 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.LinkedHashMap;
@@ -445,7 +447,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 f01afa8197..103ad64255 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,8 @@ 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.GType;
+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;
@@ -229,8 +231,48 @@ 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.
+         *
+         * @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.get());
+            return this.asAdmin().addStep(new CoinStep<>(this.asAdmin(), 
probability));
+        }
+
+        /**
+         * Filter the <code>E</code> object given a biased coin toss where the 
argument can be either a {@link GValue}
+         * object or a double.
+         *
+         * @param probability the probability that the object will pass 
through and must be a {@link GValue} object or a double.
+         * @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 Object probability) {
+            if (probability instanceof Number)
+                return this.coin(((Number) probability).doubleValue());
+            else if (probability instanceof GValue && ((GValue) 
probability).getType() == GType.DOUBLE)
+                return this.coin(probability);
+            else
+                throw new IllegalArgumentException("The probability must be a 
GValue<Double> or a double");
+        }
+
         @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/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..cb6930e432
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -0,0 +1,148 @@
+/*
+ * 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.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> {
+    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;
+    }
+
+    public boolean isVariable() {
+        return this.name != null;
+    }
+
+    public Optional<String> getName() {
+        return Optional.ofNullable(this.name);
+    }
+
+    public GType getType() {
+        return this.type;
+    }
+
+    public V get() {
+        return this.value;
+    }
+
+    @Override
+    public String toString() {
+        return isVariable() ?
+                String.format("%s&%s", name, value) : Objects.toString(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);
+    }
+
+    public static GValue<String> ofString(final String name, final String 
value) {
+        return new GValue<>(name, GType.STRING, value);
+    }
+
+    public static GValue<Integer> ofInteger(final String name, final Integer 
value) {
+        return new GValue<>(name, GType.INTEGER, value);
+    }
+
+    public static GValue<Boolean> ofBoolean(final String name, final Boolean 
value) {
+        return new GValue<>(name, GType.BOOLEAN, value);
+    }
+
+    public static GValue<Double> ofDouble(final String name, final Double 
value) {
+        return new GValue<>(name, GType.DOUBLE, value);
+    }
+
+    public static GValue<Double> ofDouble(final Double value) {
+        return new GValue<>(GType.DOUBLE, value);
+    }
+
+    public static GValue<BigInteger> ofBigInteger(final String name, final 
BigInteger value) {
+        return new GValue<>(name, GType.BIG_INTEGER, value);
+    }
+
+    public static GValue<BigDecimal> ofBigDecimal(final String name, final 
BigDecimal value) {
+        return new GValue<>(name, GType.BIG_DECIMAL, value);
+    }
+
+    public static GValue<Long> ofLong(final String name, final Long value) {
+        return new GValue<>(name, GType.LONG, value);
+    }
+
+    public static GValue<Map> ofMap(final String name, final Map value) {
+        return new GValue<>(name, GType.MAP, value);
+    }
+
+    public static GValue<List> ofList(final String name, final List value) {
+        return new GValue<>(name, GType.LIST, value);
+    }
+
+    public static GValue<Set> ofSet(final String name, final Set value) {
+        return new GValue<>(name, GType.SET, value);
+    }
+
+    public static GValue<Vertex> ofVertex(final String name, final Vertex 
value) {
+        return new GValue<>(name, GType.VERTEX, value);
+    }
+
+    public static GValue<Edge> ofEdge(final String name, final Edge value) {
+        return new GValue<>(name, GType.EDGE, value);
+    }
+
+    public static GValue<Path> ofPath(final String name, final Path value) {
+        return new GValue<>(name, GType.PATH, value);
+    }
+
+    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..7395dd8544 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,14 +30,25 @@ 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 = GValue.ofDouble(probability);
+    }
+
+    public CoinStep(final Traversal.Admin traversal, final GValue<Double> 
probability) {
         super(traversal);
         this.probability = probability;
     }
@@ -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/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/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 9b67393e66..8439e56878 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().getBytecode(),
@@ -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/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 3560027d2f..d853acfaee 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;
@@ -39,6 +43,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;
@@ -273,17 +278,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