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

colegreer pushed a commit to branch GValueManager3.8
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/GValueManager3.8 by this push:
     new 7d1193ffaa Add contracts for predicates
7d1193ffaa is described below

commit 7d1193ffaaa00e4930f44341ac88d272f2141ac8
Author: Cole-Greer <[email protected]>
AuthorDate: Fri May 23 09:53:43 2025 -0700

    Add contracts for predicates
---
 .../gremlin/process/traversal/GValueManager.java   | 209 +++++++++++++--------
 .../tinkerpop/gremlin/process/traversal/P.java     |  69 +++----
 .../tinkerpop/gremlin/process/traversal/TextP.java |  82 ++++++++
 .../traversal/dsl/graph/GraphTraversal.java        |  33 +++-
 .../gremlin/process/traversal/step/GValue.java     |   3 +
 .../process/traversal/step/HasContainerHolder.java |  10 +-
 .../process/traversal/step/filter/IsStep.java      |   5 +-
 .../PredicateContract.java}                        |  23 +--
 .../process/traversal/util/ConnectiveP.java        |   7 +-
 .../process/traversal/util/TraversalHelper.java    |  12 +-
 .../tinkerpop/gremlin/process/traversal/PTest.java | 102 +++++++++-
 .../strategy/optimization/CountStrategyTest.java   |   5 +-
 .../gremlin-javascript/test/cucumber/gremlin.js    |   4 +-
 13 files changed, 416 insertions(+), 148 deletions(-)

diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
index e34d342eb2..27e1378e27 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.AddEdgeContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.AddVertexContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.CallContract;
@@ -26,12 +27,16 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.EdgeLabelContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.AddPropertyContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.MergeElementContract;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.PredicateContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.RangeContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.StepContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.TailContract;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 
 import java.io.Serializable;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.Map;
@@ -49,16 +54,14 @@ public final class GValueManager implements Serializable, 
Cloneable {
     private boolean locked = false;
     private final Map<String, GValue> gValueRegistry = new IdentityHashMap();
     private final Map<Step, StepContract> stepRegistry = new IdentityHashMap();
-    private final Map<Step, P> predicateRegistry = new IdentityHashMap();
 
     public GValueManager() {
-        this(Collections.EMPTY_MAP, Collections.EMPTY_MAP, 
Collections.EMPTY_MAP);
+        this(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
     }
 
-    private GValueManager(Map<String, GValue> gValueRegistry, Map<Step, 
StepContract> stepRegistry,  Map<Step, P> predicateRegistry) {
+    private GValueManager(Map<String, GValue> gValueRegistry, Map<Step, 
StepContract> stepRegistry) {
         this.gValueRegistry.putAll(gValueRegistry);
         this.stepRegistry.putAll(stepRegistry);
-        this.predicateRegistry.putAll(predicateRegistry);
     }
 
     /**
@@ -69,14 +72,6 @@ public final class GValueManager implements Serializable, 
Cloneable {
         stepRegistry.put(step, contract);
     }
 
-    /**
-     * Register a step with any {@link P} containing a {@link GValue}.
-     */
-    public void register(final Step step, final P predicate) {
-        if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
-        predicateRegistry.put(step, predicate);
-    }
-
     /**
      * Locks the current state of the manager, ensuring that no further 
modifications can be made.
      * <p/>
@@ -92,36 +87,26 @@ public final class GValueManager implements Serializable, 
Cloneable {
         // can only lock once so if already locked, just return.
         if (locked) return;
 
-        for (Map.Entry<Step, StepContract> entry : stepRegistry.entrySet()) {
-            final StepContract contract = entry.getValue();
-            if (contract instanceof RangeContract) {
-                extractGValue((RangeContract<GValue<Long>>) contract);
-            } else if (contract instanceof TailContract) {
-                extractGValue((TailContract<GValue<Long>>) contract);
-            } else if (contract instanceof MergeElementContract) {
-                extractGValue((MergeElementContract<GValue<Map<?, ?>>> ) 
contract);
-            } else if (contract instanceof ElementIdsContract) {
-                extractGValue((ElementIdsContract<GValue>) contract);
-            } else if (contract instanceof AddVertexContract) {
-                extractGValue((AddVertexContract<GValue<String>, ?, 
GValue<?>>) contract);
-            } else if (contract instanceof AddEdgeContract) {
-                extractGValue((AddEdgeContract<GValue<String>, GValue<Vertex>, 
?, GValue<?>>) contract);
-            } else if (contract instanceof AddPropertyContract) {
-                extractGValue((AddPropertyContract<?, GValue<?>>) contract);
-            } else if (contract instanceof EdgeLabelContract) {
-                extractGValue((EdgeLabelContract<GValue<String>>) contract);
-            } else if (contract instanceof CallContract) {
-                extractGValue((CallContract<GValue<Map<?, ?>>>) contract);
-            } else {
-                throw new IllegalArgumentException("Unsupported StepContract 
type: " + contract.getClass().getName());
-            }
+        for (StepContract contract : stepRegistry.values()) {
+            registerGValues(extractGValues(contract));
         }
 
-        for (Map.Entry<Step, P> entry : predicateRegistry.entrySet()) {
-            extractPredicateGValues(entry.getValue());
+        locked = true;
+    }
+
+    private void registerGValues(Collection<GValue<?>> gValues) {
+        for (GValue<?> gValue : gValues) {
+            if (gValue.getName() != null) {
+                gValueRegistry.put(gValue.getName(), gValue);
+            }
         }
+    }
 
-        locked = true;
+    private void removeGValues(Collection<GValue<?>> gValues) {
+        for (GValue<?> gValue : gValues) {
+            gValueRegistry.remove(gValue.getName(), gValue);
+            // TODO:: cascade to other steps
+        }
     }
 
     /**
@@ -136,7 +121,6 @@ public final class GValueManager implements Serializable, 
Cloneable {
         //TODO deal with conflicts
         gValueRegistry.putAll(other.gValueRegistry);
         stepRegistry.putAll(other.stepRegistry);
-        predicateRegistry.putAll(other.predicateRegistry);
     }
 
     /**
@@ -149,10 +133,6 @@ public final class GValueManager implements Serializable, 
Cloneable {
         if (stepRegistry.containsKey(sourceStep)) {
             stepRegistry.put(targetStep, stepRegistry.get(sourceStep));
         }
-
-        if (predicateRegistry.containsKey(sourceStep)) {
-            predicateRegistry.put(targetStep, 
predicateRegistry.get(sourceStep));
-        }
     }
 
     /**
@@ -173,7 +153,7 @@ public final class GValueManager implements Serializable, 
Cloneable {
      *         {@code false} otherwise
      */
     public <S> boolean isParameterized(final Step step) {
-        return this.stepRegistry.containsKey(step) || 
this.predicateRegistry.containsKey(step);
+        return this.stepRegistry.containsKey(step);
     }
 
     /**
@@ -189,7 +169,7 @@ public final class GValueManager implements Serializable, 
Cloneable {
      * Determines whether the GValueManager contains any registered GValues, 
steps, or predicates.
      */
     public boolean isEmpty() {
-        return gValueRegistry.isEmpty() && stepRegistry.isEmpty() && 
predicateRegistry.isEmpty();
+        return gValueRegistry.isEmpty() && stepRegistry.isEmpty();
     }
 
     /**
@@ -198,7 +178,6 @@ public final class GValueManager implements Serializable, 
Cloneable {
     public void reset() {
         stepRegistry.clear();
         gValueRegistry.clear();
-        predicateRegistry.clear();
     }
 
     /**
@@ -210,16 +189,42 @@ public final class GValueManager implements Serializable, 
Cloneable {
      */
     public void remove(final Step step) {
         if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
-        stepRegistry.remove(step);
-        predicateRegistry.remove(step);
+        StepContract removedContract = stepRegistry.remove(step);
+
+        if (removedContract != null) {
+            removeGValues(extractGValues(removedContract));
+        }
     }
 
-    private void extractPredicateGValues(final P predicate) {
-        if (predicate.getValue() instanceof GValue) {
-            GValue<?> gValue = (GValue<?>) predicate.getValue();
-            if (gValue.isVariable()) {
-                gValueRegistry.put(gValue.getName(), gValue);
-            }
+    private Collection<GValue<?>> extractPredicateGValues(final P predicate) {
+        return predicate.getGValueRegistry().getGValues();
+    }
+
+    private Collection<GValue<?>> extractGValues(final StepContract contract) {
+        if (contract instanceof RangeContract) {
+            return extractGValue((RangeContract<GValue<Long>>) contract);
+        } else if (contract instanceof TailContract) {
+            return extractGValue((TailContract<GValue<Long>>) contract);
+        } else if (contract instanceof MergeElementContract) {
+            return extractGValue((MergeElementContract<GValue<Map<?, ?>>> ) 
contract);
+        } else if (contract instanceof ElementIdsContract) {
+            return extractGValue((ElementIdsContract<GValue<?>>) contract);
+        } else if (contract instanceof AddVertexContract) {
+            return extractGValue((AddVertexContract<GValue<String>, ?, 
GValue<?>>) contract);
+        } else if (contract instanceof AddEdgeContract) {
+            return extractGValue((AddEdgeContract<GValue<String>, 
GValue<Vertex>, ?, GValue<?>>) contract);
+        } else if (contract instanceof AddPropertyContract) {
+            return extractGValue((AddPropertyContract<?, GValue<?>>) contract);
+        } else if (contract instanceof EdgeLabelContract) {
+            return extractGValue((EdgeLabelContract<GValue<String>>) contract);
+        } else if (contract instanceof CallContract) {
+            return extractGValue((CallContract<GValue<Map<?, ?>>>) contract);
+        } else if (contract instanceof PredicateContract) {
+            return extractGValue((PredicateContract) contract);
+        } else if (contract instanceof HasContainerHolder) {
+            return extractGValue((HasContainerHolder) contract);
+        } else {
+            throw new IllegalArgumentException("Unsupported StepContract type: 
" + contract.getClass().getName());
         }
     }
 
@@ -227,122 +232,164 @@ public final class GValueManager implements 
Serializable, Cloneable {
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final RangeContract<GValue<Long>> contract) {
+    private Collection<GValue<?>> extractGValue(final 
RangeContract<GValue<Long>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         if (contract.getHighRange().isVariable()) {
-            gValueRegistry.put(contract.getHighRange().getName(), 
contract.getHighRange());
+            results.add(contract.getHighRange());
         }
         if (contract.getLowRange().isVariable()) {
-            gValueRegistry.put(contract.getLowRange().getName(), 
contract.getLowRange());
+            results.add(contract.getLowRange());
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final TailContract<GValue<Long>> contract) {
+    private Collection<GValue<?>> extractGValue(final 
TailContract<GValue<Long>> contract) {
         if (contract.getLimit().getName() != null) {
-            gValueRegistry.put(contract.getLimit().getName(), 
contract.getLimit());
+            return Collections.singletonList(contract.getLimit());
         }
+        return Collections.emptyList();
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final MergeElementContract<GValue<Map<?,?>>> 
contract) {
+    private Collection<GValue<?>> extractGValue(final 
MergeElementContract<GValue<Map<?,?>>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         if (contract.getMergeMap() != null) {
-            gValueRegistry.put(contract.getMergeMap().getName(), 
contract.getMergeMap());
+            results.add(contract.getMergeMap());
         }
         if (contract.getOnCreateMap() != null) {
-            gValueRegistry.put(contract.getOnCreateMap().getName(), 
contract.getOnCreateMap());
+            results.add(contract.getOnCreateMap());
         }
         if (contract.getOnMatchMap() != null) {
-            gValueRegistry.put(contract.getOnMatchMap().getName(), 
contract.getOnMatchMap());
+            results.add(contract.getOnMatchMap());
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final ElementIdsContract<GValue> contract) {
+    private Collection<GValue<?>> extractGValue(final 
ElementIdsContract<GValue<?>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         for (GValue gValue: contract.getIds()) {
             if (gValue.isVariable()) {
-                gValueRegistry.put(gValue.getName(), gValue);
+                results.add(gValue);
             }
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final AddVertexContract<GValue<String>, ?, 
GValue<?>> contract) {
+    private Collection<GValue<?>> extractGValue(final 
AddVertexContract<GValue<String>, ?, GValue<?>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         if (contract.getLabel() != null) {
-            gValueRegistry.put(contract.getLabel().getName(), 
contract.getLabel());
+            results.add(contract.getLabel());
         }
         for (GValue<?> value : contract.getProperties().values()) {
-            gValueRegistry.put(value.getName(), value);
+            results.add(value);
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final AddEdgeContract<GValue<String>, 
GValue<Vertex>, ?, GValue<?>> contract) {
+    private Collection<GValue<?>> extractGValue(final 
AddEdgeContract<GValue<String>, GValue<Vertex>, ?, GValue<?>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         if (contract.getLabel() != null) {
-            gValueRegistry.put(contract.getLabel().getName(), 
contract.getLabel());
+            results.add(contract.getLabel());
         }
         if (contract.getFrom() != null) {
-            gValueRegistry.put(contract.getFrom().getName(), 
contract.getFrom());
+            results.add(contract.getFrom());
         }
         if (contract.getTo() != null) {
-            gValueRegistry.put(contract.getTo().getName(), contract.getTo());
+            results.add(contract.getTo());
         }
         if (contract.getProperties() != null) {
             for (GValue<?> value : contract.getProperties().values()) {
-                gValueRegistry.put(value.getName(), value);
+                results.add(value);
             }
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final AddPropertyContract<?, GValue<?>> 
contract) {
-        gValueRegistry.put(contract.getValue().getName(), contract.getValue());
+    private Collection<GValue<?>> extractGValue(final AddPropertyContract<?, 
GValue<?>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
+        results.add(contract.getValue());
         for (GValue<?> value : contract.getProperties().values()) {
-            gValueRegistry.put(value.getName(), value);
+            results.add(value);
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final EdgeLabelContract<GValue<String>> 
contract) {
+    private Collection<GValue<?>> extractGValue(final 
EdgeLabelContract<GValue<String>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         for (GValue gValue: contract.getEdgeLabels()) {
             if (gValue.getName() != null) {
-                gValueRegistry.put(gValue.getName(), gValue);
+                results.add(gValue);
             }
         }
+        return results;
     }
 
     /**
      * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
      * manager.
      */
-    private void extractGValue(final CallContract<GValue<Map<?,?>>> contract) {
+    private Collection<GValue<?>> extractGValue(final 
CallContract<GValue<Map<?,?>>> contract) {
+        Collection<GValue<?>> results = new ArrayList();
         if (contract.getStaticParams().getName() != null) {
-            gValueRegistry.put(contract.getStaticParams().getName(), 
contract.getStaticParams());
+            results.add(contract.getStaticParams());
+        }
+        return results;
+    }
+
+    /**
+     * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
+     * manager.
+     */
+    private Collection<GValue<?>> extractGValue(final PredicateContract 
contract) {
+        if (contract.getPredicate() != null) {
+            return contract.getPredicate().getGValueRegistry().getGValues();
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Extract {@link GValue} instances from contracts to the registry after 
{@link #lock()} has been called on the
+     * manager.
+     */
+    private Collection<GValue<?>> extractGValue(final HasContainerHolder 
contract) {
+        Collection<GValue<?>> results = new ArrayList();
+        for (P<?> predicate : contract.getPredicates()) {
+            if (predicate != null) {
+                results.addAll(predicate.getGValueRegistry().getGValues());
+            }
         }
+        return results;
     }
 
     @Override
     public GValueManager clone() {
-        return new GValueManager(gValueRegistry, stepRegistry, 
predicateRegistry);
+        return new GValueManager(gValueRegistry, stepRegistry);
     }
 }
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 24d7d538cd..6dee62840d 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
@@ -43,23 +43,27 @@ public class P<V> implements Predicate<V>, Serializable, 
Cloneable {
     protected V value;
     protected V originalValue;
 
-    public boolean parameterized;
     public GValueRegistry gValueRegistry;
 
     public P(final PBiPredicate<V, V> biPredicate, V value) {
-        parameterized = value instanceof GValue || (value instanceof List && 
((List) value).stream().anyMatch(v -> v instanceof GValue));
-        if (parameterized) {
-            if (value instanceof GValue) {
-                gValueRegistry = new GValueRegistry(this, (GValue<V>) value);
-                value = ((GValue<V>) value).get();
-            } else {
-                gValueRegistry = new GValueRegistry(this, 
GValue.ensureGValues(((List) value).toArray()));
-            }
+        if (value instanceof GValue) {
+            gValueRegistry = new GValueRegistry(this, (GValue<V>) value);
+            this.value = ((GValue<V>) value).get();
+        } else if (value instanceof List && ((List) value).stream().anyMatch(v 
-> v instanceof GValue)) {
+            gValueRegistry = new GValueRegistry(this, 
GValue.ensureGValues(((List) value).toArray()));
+            this.value = (V) 
Arrays.asList(GValue.resolveToValues(GValue.ensureGValues(((List) 
value).toArray())));
         } else {
             gValueRegistry = new GValueRegistry();
+            this.value = value;
         }
-        this.value = value;
-        this.originalValue = value;
+        this.originalValue = this.value;
+        this.biPredicate = biPredicate;
+    }
+
+    public P(final PBiPredicate<V, V> biPredicate, GValue<V> value) {
+        gValueRegistry = new GValueRegistry(this, value);
+        this.value = value.get();
+        this.originalValue = value.get();
         this.biPredicate = biPredicate;
     }
 
@@ -93,12 +97,7 @@ public class P<V> implements Predicate<V>, Serializable, 
Cloneable {
 
     @Override
     public boolean test(final V testValue) {
-        // this might be a bunch of GValue that need to be resolved. zomg
-        if (this.value instanceof List) {
-            return this.biPredicate.test(testValue, (V) ((List) 
this.value).stream().map(GValue::valueOf).collect(Collectors.toList()));
-        } else {
-            return this.biPredicate.test(testValue, (V) 
GValue.valueOf(this.value));
-        }
+        return this.biPredicate.test(testValue, this.value);
     }
 
     @Override
@@ -300,34 +299,40 @@ public class P<V> implements Predicate<V>, Serializable, 
Cloneable {
     }
 
     public boolean isParameterized() {
-        return parameterized;
+        return !gValueRegistry.isEmpty();
+    }
+
+    public GValueRegistry getGValueRegistry() {
+        return gValueRegistry;
     }
 
-    protected class GValueRegistry implements Serializable {
-        private Map<P, GValue> GValueRegistry = new IdentityHashMap<>();
+    protected class GValueRegistry<T> implements Serializable {
+        private Map<P, GValue<T>> gValueRegistry = new IdentityHashMap<>();
 
-        public GValueRegistry() {};
+        public GValueRegistry() {}
 
-        public GValueRegistry(P predicate, GValue gValue) {
-            GValueRegistry.put(predicate, gValue);
+        public GValueRegistry(P predicate, GValue<T> gValue) {
+            gValueRegistry.put(predicate, gValue);
         }
 
-        public GValueRegistry(P predicate, GValue[] gValues) {
-            for (GValue gValue : gValues) {
+        public GValueRegistry(P predicate, GValue<T>[] gValues) {
+            for (GValue<T> gValue : gValues) {
                 if (gValue.isVariable()) {
-                    GValueRegistry.put(predicate, gValue);
+                    gValueRegistry.put(predicate, gValue);
                 }
             }
         }
 
-        public GValueRegistry(GValueRegistry... registries) {
-            for (final GValueRegistry registry : registries) {
-                this.merge(registry);
-            }
+        public void addAll(final GValueRegistry other) {
+            this.gValueRegistry.putAll(other.gValueRegistry);
+        }
+
+        public boolean isEmpty(){
+            return this.gValueRegistry.isEmpty();
         }
 
-        public void merge(final GValueRegistry other) {
-            this.GValueRegistry.putAll(other.GValueRegistry);
+        public Collection<GValue<T>> getGValues() {
+            return gValueRegistry.values();
         }
     }
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
index 2e599c3e77..97e42f0b7d 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TextP.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
+import org.apache.tinkerpop.gremlin.process.traversal.step.GValue;
+
 /**
  * Predefined {@code Predicate} values that can be used as {@code String} 
filters.
  *
@@ -29,6 +31,10 @@ public class TextP extends P<String> {
         super(biPredicate, value);
     }
 
+    public TextP(final PBiPredicate<String, String> biPredicate, final 
GValue<String> value) {
+        super(biPredicate, value);
+    }
+
     @Override
     public boolean equals(final Object other) {
         return other instanceof TextP && super.equals(other);
@@ -59,6 +65,15 @@ public class TextP extends P<String> {
         return new TextP(Text.startingWith, value);
     }
 
+    /**
+     * Determines if String does start with the given value.
+     *
+     * @since 3.8.0
+     */
+    public static TextP startingWith(final GValue<String> value) {
+        return new TextP(Text.startingWith, value);
+    }
+
     /**
      * Determines if String does not start with the given value.
      *
@@ -68,6 +83,15 @@ public class TextP extends P<String> {
         return new TextP(Text.notStartingWith, value);
     }
 
+    /**
+     * Determines if String does not start with the given value.
+     *
+     * @since 3.8.0
+     */
+    public static TextP notStartingWith(final GValue<String> value) {
+        return new TextP(Text.notStartingWith, value);
+    }
+
     /**
      * Determines if String does start with the given value.
      *
@@ -77,6 +101,15 @@ public class TextP extends P<String> {
         return new TextP(Text.endingWith, value);
     }
 
+    /**
+     * Determines if String does start with the given value.
+     *
+     * @since 3.8.0
+     */
+    public static TextP endingWith(final GValue<String> value) {
+        return new TextP(Text.endingWith, value);
+    }
+
     /**
      * Determines if String does not start with the given value.
      *
@@ -86,6 +119,15 @@ public class TextP extends P<String> {
         return new TextP(Text.notEndingWith, value);
     }
 
+    /**
+     * Determines if String does not start with the given value.
+     *
+     * @since 3.8.0
+     */
+    public static TextP notEndingWith(final GValue<String> value) {
+        return new TextP(Text.notEndingWith, value);
+    }
+
     /**
      * Determines if String does contain the given value.
      *
@@ -95,6 +137,15 @@ public class TextP extends P<String> {
         return new TextP(Text.containing, value);
     }
 
+    /**
+     * Determines if String does contain the given value.
+     *
+     * @since 3.8.0
+     */
+    public static TextP containing(final GValue<String> value) {
+        return new TextP(Text.containing, value);
+    }
+
     /**
      * Determines if String does not contain the given value.
      *
@@ -103,6 +154,15 @@ public class TextP extends P<String> {
     public static TextP notContaining(final String value) {
         return new TextP(Text.notContaining, value);
     }
+
+    /**
+     * Determines if String does not contain the given value.
+     *
+     * @since 3.8.0
+     */
+    public static TextP notContaining(final GValue<String> value) {
+        return new TextP(Text.notContaining, value);
+    }
     
     /**           
      * Determines if String has a match with the given regex pattern. The 
TinkerPop reference implementation uses
@@ -116,6 +176,18 @@ public class TextP extends P<String> {
         return new TextP(new Text.RegexPredicate(value, false), value);
     }
 
+    /**
+     * Determines if String has a match with the given regex pattern. The 
TinkerPop reference implementation uses
+     * Java syntax for regex. The string is considered a match to the pattern 
if any substring matches the pattern. It
+     * is therefore important to use the appropriate boundary matchers (e.g. 
`$` for end of a line) to ensure a proper
+     * match.
+     *
+     * @since 3.8.0
+     */
+    public static TextP regex(final GValue<String> value) {
+        return new TextP(new Text.RegexPredicate(value.get(), false), value);
+    }
+
     /**           
      * Determines if String has no match with the given regex pattern and the 
reference implementation treats it as a
      * simple negation of the evaluation of the pattern match of {@link 
#regex(String)}.
@@ -125,4 +197,14 @@ public class TextP extends P<String> {
     public static TextP notRegex(final String value) {
         return new TextP(new Text.RegexPredicate(value, true), value);
     }
+
+    /**
+     * Determines if String has no match with the given regex pattern and the 
reference implementation treats it as a
+     * simple negation of the evaluation of the pattern match of {@link 
#regex(String)}.
+     *
+     * @since 3.8.0
+     */
+    public static TextP notRegex(final GValue<String> value) {
+        return new TextP(new Text.RegexPredicate(value.get(), true), value);
+    }
 }
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 f94bf9d70b..47da16bda3 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
@@ -2449,6 +2449,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> filter(final Predicate<Traverser<E>> 
predicate) {
+        if (predicate != null && predicate instanceof P && ((P<Traverser<E>>) 
predicate).isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by filter()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.filter, predicate);
         return this.asAdmin().addStep(new LambdaFilterStep<>(this.asAdmin(), 
predicate));
     }
@@ -2559,6 +2562,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> where(final String startKey, final 
P<String> predicate) {
+        if (predicate != null && predicate.isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by where()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.where, startKey, 
predicate);
         return this.asAdmin().addStep(new WherePredicateStep<>(this.asAdmin(), 
Optional.ofNullable(startKey), predicate));
     }
@@ -2574,6 +2580,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> where(final P<String> predicate) {
+        if (predicate != null && predicate.isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by where()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.where, predicate);
         return this.asAdmin().addStep(new WherePredicateStep<>(this.asAdmin(), 
Optional.empty(), predicate));
     }
@@ -3006,6 +3015,8 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
         // if calling hasKey(null), the likely use the caller is going for is 
not a "no predicate" but a eq(null)
         if (null == predicate) {
             return hasKey((String) null);
+        } else if (predicate.isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by hasKey()");
         } else {
             this.asAdmin().getBytecode().addStep(Symbols.hasKey, predicate);
             return TraversalHelper.addHasContainer(this.asAdmin(), new 
HasContainer(T.key.getAccessor(), predicate));
@@ -3080,7 +3091,7 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
         final IsStep<E> step = new IsStep<>(this.asAdmin(), predicate);
 
         if (predicate.isParameterized()) {
-            this.asAdmin().getGValueManager().register(step, predicate);
+            this.asAdmin().getGValueManager().register(step, step);
         }
 
         return this.asAdmin().addStep(step);
@@ -3100,7 +3111,7 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
         final IsStep<E> step = new IsStep<>(this.asAdmin(), predicate);
 
         if (predicate.isParameterized()) {
-            this.asAdmin().getGValueManager().register(step, predicate);
+            this.asAdmin().getGValueManager().register(step, step);
         }
 
         return this.asAdmin().addStep(step);
@@ -3515,6 +3526,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.7.1
      */
     public default <S2> GraphTraversal<S, E> all(final P<S2> predicate) {
+        if (predicate != null && predicate.isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by all()"); //TODO:: should this be supported?
+        }
         this.asAdmin().getBytecode().addStep(Symbols.all, predicate);
         return this.asAdmin().addStep(new AllStep<>(this.asAdmin(), 
predicate));
     }
@@ -3528,6 +3542,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.7.1
      */
     public default <S2> GraphTraversal<S, E> any(final P<S2> predicate) {
+        if (predicate != null && predicate.isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by any()"); //TODO:: should this be supported?
+        }
         this.asAdmin().getBytecode().addStep(Symbols.any, predicate);
         return this.asAdmin().addStep(new AnyStep<>(this.asAdmin(), 
predicate));
     }
@@ -4045,6 +4062,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      */
     public default <E2> GraphTraversal<S, E2> choose(final Predicate<E> 
choosePredicate,
                                                      final Traversal<?, E2> 
trueChoice, final Traversal<?, E2> falseChoice) {
+        if (choosePredicate instanceof P && ((P<E>) 
choosePredicate).isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by choose()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate, 
trueChoice, falseChoice);
         return this.asAdmin().addStep(new ChooseStep<E, E2, 
Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.filter(new 
PredicateTraverser<>(choosePredicate)), (Traversal.Admin<E, E2>) trueChoice, 
(Traversal.Admin<E, E2>) falseChoice));
     }
@@ -4061,6 +4081,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      */
     public default <E2> GraphTraversal<S, E2> choose(final Predicate<E> 
choosePredicate,
                                                      final Traversal<?, E2> 
trueChoice) {
+        if (choosePredicate instanceof P && ((P<E>) 
choosePredicate).isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by choose()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.choose, choosePredicate, 
trueChoice);
         return this.asAdmin().addStep(new ChooseStep<E, E2, 
Boolean>(this.asAdmin(), (Traversal.Admin<E, ?>) __.filter(new 
PredicateTraverser<>(choosePredicate)), (Traversal.Admin<E, E2>) trueChoice, 
(Traversal.Admin<E, E2>) __.identity()));
     }
@@ -4154,6 +4177,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> emit(final Predicate<Traverser<E>> 
emitPredicate) {
+        if (emitPredicate != null && emitPredicate instanceof P && 
((P<Traverser<E>>) emitPredicate).isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by emit()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.emit, emitPredicate);
         return RepeatStep.addEmitToTraversal(this, (Traversal.Admin<E, ?>) 
__.filter(emitPredicate));
     }
@@ -4192,6 +4218,9 @@ public interface GraphTraversal<S, E> extends 
Traversal<S, E> {
      * @since 3.0.0-incubating
      */
     public default GraphTraversal<S, E> until(final Predicate<Traverser<E>> 
untilPredicate) {
+        if (untilPredicate != null && untilPredicate instanceof P && 
((P<Traverser<E>>) untilPredicate).isParameterized()) {
+            throw new IllegalArgumentException("Parameterized predicates are 
not supported by until()");
+        }
         this.asAdmin().getBytecode().addStep(Symbols.until, untilPredicate);
         return RepeatStep.addUntilToTraversal(this, (Traversal.Admin<E, ?>) 
__.filter(untilPredicate));
     }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
index a65f4e8812..dbc78a6cc0 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/GValue.java
@@ -51,6 +51,9 @@ public class GValue<V> implements Serializable {
         if (name != null && name.startsWith("_")) {
             throw new IllegalArgumentException(String.format("Invalid GValue 
name [%s]. Should not start with _.", name));
         }
+        if (value instanceof GValue) {
+            throw new IllegalArgumentException("GValues cannot be nested");
+        }
         this.name = name;
         this.type = type;
         this.value = value;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
index 67c3d1e7e4..b4b08eac9e 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
@@ -18,14 +18,18 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step;
 
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.StepContract;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 
+import java.util.Collection;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public interface HasContainerHolder {
+public interface HasContainerHolder extends StepContract {
 
     public List<HasContainer> getHasContainers();
 
@@ -34,4 +38,8 @@ public interface HasContainerHolder {
     public default void removeHasContainer(final HasContainer hasContainer) {
         throw new UnsupportedOperationException("The holder does not support 
container removal: " + this.getClass().getCanonicalName());
     }
+
+    public default Collection<P<?>> getPredicates() {
+        return getHasContainers().stream().map(p -> 
p.getPredicate()).collect(Collectors.toList());
+    }
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
index a2889864a8..c27bc51248 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java
@@ -21,6 +21,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.filter;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.stepContract.PredicateContract;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -31,7 +32,7 @@ import java.util.Set;
  * @author Daniel Kuppitz (http://gremlin.guru)
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class IsStep<S> extends FilterStep<S> {
+public final class IsStep<S> extends FilterStep<S> implements 
PredicateContract {
 
     private P<S> predicate;
 
@@ -50,7 +51,7 @@ public final class IsStep<S> extends FilterStep<S> {
         return StringFactory.stepString(this, this.predicate);
     }
 
-
+    @Override
     public P<S> getPredicate() {
         return this.predicate;
     }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/stepContract/PredicateContract.java
similarity index 57%
copy from 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
copy to 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/stepContract/PredicateContract.java
index 67c3d1e7e4..b940816591 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/HasContainerHolder.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/stepContract/PredicateContract.java
@@ -16,22 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tinkerpop.gremlin.process.traversal.step;
+package org.apache.tinkerpop.gremlin.process.traversal.step.stepContract;
 
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
-
-import java.util.List;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 
 /**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * Defines the contract for steps containing a single {@link P}.
  */
-public interface HasContainerHolder {
-
-    public List<HasContainer> getHasContainers();
-
-    public void addHasContainer(final HasContainer hasContainer);
+public interface PredicateContract extends StepContract {
 
-    public default void removeHasContainer(final HasContainer hasContainer) {
-        throw new UnsupportedOperationException("The holder does not support 
container removal: " + this.getClass().getCanonicalName());
-    }
+    /**
+     * Retrieves the step's predicate.
+     *
+     * @return the predicate associated with the step
+     */
+    public P<?> getPredicate();
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
index 9520a58263..010ee2d1fa 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/ConnectiveP.java
@@ -34,12 +34,11 @@ public abstract class ConnectiveP<V> extends P<V> {
     protected List<P<V>> predicates = new ArrayList<>();
 
     public ConnectiveP(final List<P<V>> predicates) {
-        super(null, null);
+        super(null, (V) null);
 
         for (P<V> p : predicates) {
-            if (p.parameterized) {
-                this.parameterized = true;
-                this.gValueRegistry.merge(p.gValueRegistry);
+            if (p.isParameterized()) {
+                this.gValueRegistry.addAll(p.gValueRegistry);
             }
         }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index a981e1a1ce..c881cca44b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -791,8 +791,16 @@ public final class TraversalHelper {
     public static <T extends Traversal.Admin<?, ?>> T addHasContainer(final T 
traversal, final HasContainer hasContainer) {
         if (traversal.getEndStep() instanceof HasContainerHolder) {
             ((HasContainerHolder) 
traversal.getEndStep()).addHasContainer(hasContainer);
+            if (hasContainer.getPredicate().isParameterized()) {
+                traversal.getGValueManager().register(traversal.getEndStep(), 
(HasContainerHolder) traversal.getEndStep());
+            }
             return traversal;
-        } else
-            return (T) traversal.addStep(new HasStep<>(traversal, 
hasContainer));
+        } else {
+            HasStep<?> step = new HasStep<>(traversal, hasContainer);
+            if (hasContainer.getPredicate().isParameterized()) {
+                traversal.getGValueManager().register(step, step);
+            }
+            return (T) traversal.addStep(step);
+        }
     }
 }
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
index 15855e0108..322133d52b 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/PTest.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal;
 
 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.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 import org.junit.Before;
@@ -66,6 +67,12 @@ public class PTest {
                     {P.eq(Double.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, 
false},
                     {P.eq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY, 
false},
                     {P.eq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, 
false},
+                    {P.eq(GValue.of("x",0)), 0, true},
+                    {P.eq(GValue.of("x",-0)), +0, true},
+                    {P.eq(GValue.of("x",0)), 1, false},
+                    {P.eq(GValue.of("x",0)), null, false},
+                    {P.eq(GValue.of("x",null)), null, true},
+                    {P.eq(GValue.of("x",null)), 0, false},
                     {P.neq(0), 0, false},
                     {P.neq(0), -0, false},
                     {P.neq(0), +0, false},
@@ -77,31 +84,63 @@ public class PTest {
                     {P.neq(Double.POSITIVE_INFINITY), 
Double.NEGATIVE_INFINITY, true},
                     {P.neq(Float.POSITIVE_INFINITY), Float.NEGATIVE_INFINITY, 
true},
                     {P.neq(Float.POSITIVE_INFINITY), Double.NEGATIVE_INFINITY, 
true},
+                    {P.neq(GValue.of("x",0)), 0, false},
+                    {P.neq(GValue.of("x",-0)), +0, false},
+                    {P.neq(GValue.of("x",0)), 1, true},
+                    {P.neq(GValue.of("x",0)), null, true},
+                    {P.neq(GValue.of("x",null)), null, false},
+                    {P.neq(GValue.of("x",null)), 0, true},
                     {P.gt(0), -1, false},
                     {P.gt(0), 0, false},
                     {P.gt(0), 1, true},
+                    {P.gt(GValue.of("x",0)), -1, false},
+                    {P.gt(GValue.of("x",0)), 0, false},
+                    {P.gt(GValue.of("x",0)), 1, true},
                     {P.lt(0), -1, true},
                     {P.lt(0), 0, false},
                     {P.lt(0), 1, false},
+                    {P.lt(GValue.of("x",0)), -1, true},
+                    {P.lt(GValue.of("x",0)), 0, false},
+                    {P.lt(GValue.of("x",0)), 1, false},
                     {P.gte(0), -1, false},
                     {P.gte(0), 0, true},
                     {P.gte(0), 1, true},
+                    {P.gte(GValue.of("x",0)), -1, false},
+                    {P.gte(GValue.of("x",0)), 0, true},
+                    {P.gte(GValue.of("x",0)), 1, true},
                     {P.lte(0), -1, true},
                     {P.lte(0), 0, true},
                     {P.lte(0), 1, false},
+                    {P.lte(GValue.of("x",0)), -1, true},
+                    {P.lte(GValue.of("x",0)), 0, true},
+                    {P.lte(GValue.of("x",0)), 1, false},
                     {P.between(1, 10), 0, false},
                     {P.between(1, 10), 1, true},
                     {P.between(1, 10), 9, true},
                     {P.between(1, 10), 10, false},
+                    {P.between(GValue.of("x",1), GValue.of("y",10)), 0, false},
+                    {P.between(GValue.of("x",1), GValue.of("y",10)), 1, true},
+                    {P.between(GValue.of("x",1), 10), 9, true},
+                    {P.between(1, GValue.of("y",10)), 10, false},
                     {P.inside(1, 10), 0, false},
                     {P.inside(1, 10), 1, false},
                     {P.inside(1, 10), 9, true},
                     {P.inside(1, 10), 10, false},
+                    {P.inside(GValue.of("x",1), GValue.of("y",10)), 0, false},
+                    {P.inside(GValue.of("x",1), GValue.of("y",10)), 1, false},
+                    {P.inside(1, GValue.of("y",10)), 9, true},
+                    {P.inside(GValue.of("x",1), 10), 10, false},
                     {P.outside(1, 10), 0, true},
                     {P.outside(1, 10), 1, false},
                     {P.outside(1, 10), 9, false},
                     {P.outside(1, 10), 10, false},
                     {P.outside(1, Double.NaN), 0, true},
+                    {P.outside(GValue.of("x",1), GValue.of("y",10)), 0, true},
+                    {P.outside(GValue.of("x",1), GValue.of("y",10)), 1, false},
+                    {P.outside(1, GValue.of("y",10)), 9, false},
+                    {P.outside(GValue.of("x",1), 10), 10, false},
+                    {P.outside(GValue.of("x",1), GValue.of("y",Double.NaN)), 
0, true},
+
                     {P.within(), 0, false},
                     {P.within((Object) null), 0, false},
                     {P.within((Object) null), null, true},
@@ -119,6 +158,16 @@ public class PTest {
                     {P.within(Arrays.asList(1, 2, 3)), 0, false},
                     {P.within(Arrays.asList(1, 2, 3)), 1, true},
                     {P.within(Arrays.asList(1, 2, 3)), 10, false},
+                    {P.within(GValue.of("x", null)), 0, false},
+                    {P.within(GValue.of("x", null)), null, true},
+                    {P.within(GValue.of("x", (Collection) null)), 0, false},
+                    {P.within(GValue.of("x", (Collection) null)), null, true},
+                    {P.within(GValue.of("x", null), GValue.of("y", 2), 
GValue.of("z", 3)), 0, false},
+                    {P.within(GValue.of("x", null), GValue.of("y", 2), 
GValue.of("z", 3)), null, true},
+                    {P.within(GValue.of("x", null), GValue.of("y", 2), 
GValue.of("z", 3)), 2, true},
+                    {P.within(GValue.of("x", 1), GValue.of("y", 2), 
GValue.of("z", 3)), 0, false},
+                    {P.within(GValue.of("x", 1), GValue.of("y", 2), 
GValue.of("z", 3)), 1, true},
+                    {P.within(GValue.of("x", 1), GValue.of("y", 2), 
GValue.of("z", 3)), 10, false},
                     {P.without(), 0, true},
                     {P.without((Object) null), 0, true},
                     {P.without((Object) null), null, false},
@@ -136,11 +185,32 @@ public class PTest {
                     {P.without(Arrays.asList(1, 2, 3)), 0, true},
                     {P.without(Arrays.asList(1, 2, 3)), 1, false},
                     {P.without(Arrays.asList(1, 2, 3)), 10, true},
+                    {P.without(GValue.of("x", null)), 0, true},
+                    {P.without(GValue.of("x", null)), null, false},
+                    {P.without(GValue.of("x", (Collection) null)), 0, true},
+                    {P.without(GValue.of("x", (Collection) null)), null, 
false},
+                    {P.without(GValue.of("x", null), GValue.of("y", 2), 
GValue.of("z", 3)), 0, true},
+                    {P.without(GValue.of("x", null), GValue.of("y", 2), 
GValue.of("z", 3)), null, false},
+                    {P.without(GValue.of("x", null), GValue.of("y", 2), 
GValue.of("z", 3)), 2, false},
+                    {P.without(GValue.of("x", 1), GValue.of("y", 2), 
GValue.of("z", 3)), 0, true},
+                    {P.without(GValue.of("x", 1), GValue.of("y", 2), 
GValue.of("z", 3)), 1, false},
+                    {P.without(GValue.of("x", 1), GValue.of("y", 2), 
GValue.of("z", 3)), 10, true},
+                    {P.without(Arrays.asList(GValue.of("x", null), 
GValue.of("y", 2), GValue.of("z", 3))), null, false},
+                    {P.without(Arrays.asList(GValue.of("x", null), 
GValue.of("y", 2), GValue.of("z", 3))), 1, true},
+                    {P.without(Arrays.asList(GValue.of("x", null), 
GValue.of("y", 2), GValue.of("z", 3))), 2, false},
+                    {P.without(Arrays.asList(GValue.of("x", 1), GValue.of("y", 
2), GValue.of("z", 3))), 0, true},
+                    {P.without(Arrays.asList(GValue.of("x", 1), GValue.of("y", 
2), GValue.of("z", 3))), 1, false},
+                    {P.without(Arrays.asList(GValue.of("x", 1), GValue.of("y", 
2), GValue.of("z", 3))), 10, true},
                     {P.between("m", "n").and(P.neq("marko")), "marko", false},
                     {P.between("m", "n").and(P.neq("marko")), "matthias", 
true},
                     {P.between("m", "n").or(P.eq("daniel")), "marko", true},
                     {P.between("m", "n").or(P.eq("daniel")), "daniel", true},
                     {P.between("m", "n").or(P.eq("daniel")), "stephen", false},
+                    {P.between(GValue.of("x", "m"), GValue.of("y", 
"n")).and(P.neq(GValue.of("z", "marko"))), "marko", false},
+                    {P.between(GValue.of("x", "m"), GValue.of("y", 
"n")).and(P.neq(GValue.of("z", "marko"))), "matthias", true},
+                    {P.between(GValue.of("x", "m"), GValue.of("y", 
"n")).or(P.eq(GValue.of("z", "daniel"))), "marko", true},
+                    {P.between(GValue.of("x", "m"), GValue.of("y", 
"n")).or(P.eq(GValue.of("z", "daniel"))), "daniel", true},
+                    {P.between(GValue.of("x", "m"), GValue.of("y", 
"n")).or(P.eq(GValue.of("z", "daniel"))), "stephen", false},
                     {P.within().and(P.within()), 0, false},
                     {P.within().and(P.without()), 0, false},
                     {P.without().and(P.without()), 0, true},
@@ -151,10 +221,16 @@ public class PTest {
                     // text predicates
                     {TextP.containing("ark"), "marko", true},
                     {TextP.containing("ark"), "josh", false},
+                    {TextP.containing(GValue.ofString("x", "ark")), "marko", 
true},
+                    {TextP.containing(GValue.ofString("x", "ark")), "josh", 
false},
                     {TextP.startingWith("jo"), "marko", false},
                     {TextP.startingWith("jo"), "josh", true},
+                    {TextP.startingWith(GValue.ofString("x", "jo")), "marko", 
false},
+                    {TextP.startingWith(GValue.ofString("x", "jo")), "josh", 
true},
                     {TextP.endingWith("ter"), "marko", false},
                     {TextP.endingWith("ter"), "peter", true},
+                    {TextP.endingWith(GValue.ofString("x", "ter")), "marko", 
false},
+                    {TextP.endingWith(GValue.ofString("x", "ter")), "peter", 
true},
                     {TextP.containing("o"), "marko", true},
                     {TextP.containing("o"), "josh", true},
                     {TextP.containing("o").and(P.gte("j")), "marko", true},
@@ -163,20 +239,30 @@ public class PTest {
                     
{TextP.containing("o").and(P.gte("j")).and(TextP.endingWith("ko")), "josh", 
false},
                     
{TextP.containing("o").and(P.gte("j").and(TextP.endingWith("ko"))), "marko", 
true},
                     
{TextP.containing("o").and(P.gte("j").and(TextP.endingWith("ko"))), "josh", 
false},
+                    {TextP.containing(GValue.ofString("x", "o")), "marko", 
true},
+                    {TextP.containing(GValue.ofString("x", "o")), "josh", 
true},
+                    {TextP.containing(GValue.ofString("x", 
"o")).and(P.gte(GValue.ofString("y", "j"))), "marko", true},
+                    {TextP.containing(GValue.ofString("x", 
"o")).and(P.gte(GValue.ofString("y", "j"))), "josh", true},
+                    {TextP.containing(GValue.ofString("x", 
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")), 
"marko", true},
+                    {TextP.containing(GValue.ofString("x", 
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")), 
"josh", false},
+                    {TextP.containing(GValue.ofString("x", 
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")), 
"marko", true},
+                    {TextP.containing(GValue.ofString("x", 
"o")).and(P.gte(GValue.ofString("y", "j"))).and(TextP.endingWith("ko")), 
"josh", false},
 
                     // type errors
                     {P.outside(Double.NaN, Double.NaN), 0, 
GremlinTypeErrorException.class},
                     {P.inside(-1, Double.NaN), 0, 
GremlinTypeErrorException.class},
                     {P.inside(Double.NaN, 1), 0, 
GremlinTypeErrorException.class},
-                    {TextP.containing(null), "abc", 
GremlinTypeErrorException.class},
+                    {TextP.containing((String) null), "abc", 
GremlinTypeErrorException.class},
                     {TextP.containing("abc"), null, 
GremlinTypeErrorException.class},
-                    {TextP.containing(null), null, 
GremlinTypeErrorException.class},
-                    {TextP.startingWith(null), "abc", 
GremlinTypeErrorException.class},
+                    {TextP.containing((String) null), null, 
GremlinTypeErrorException.class},
+                    {TextP.startingWith((String) null), "abc", 
GremlinTypeErrorException.class},
                     {TextP.startingWith("abc"), null, 
GremlinTypeErrorException.class},
-                    {TextP.startingWith(null), null, 
GremlinTypeErrorException.class},
-                    {TextP.endingWith(null), "abc", 
GremlinTypeErrorException.class},
+                    {TextP.startingWith((String) null), null, 
GremlinTypeErrorException.class},
+                    {TextP.endingWith((String) null), "abc", 
GremlinTypeErrorException.class},
                     {TextP.endingWith("abc"), null, 
GremlinTypeErrorException.class},
-                    {TextP.endingWith(null), null, 
GremlinTypeErrorException.class},
+                    {TextP.endingWith((String) null), null, 
GremlinTypeErrorException.class},
+
+                    // regex
                     {TextP.regex("D"), "Dallas Fort Worth", true},
                     {TextP.regex("d"), "Dallas Fort Worth", false},
                     {TextP.regex("^D"), "Dallas Fort Worth", true},
@@ -196,6 +282,10 @@ public class PTest {
                     {TextP.regex("(?i)abc"), "123-ABC-456", true},
                     {TextP.regex("(?i)[a-b]{3}-[1-9]{3}-[a-z]{3}"), 
"123-ABC-456", false},
                     {TextP.regex("Tinker.*\\u00A9"), "Apache TinkerPop©", 
true},
+                    {TextP.regex(GValue.ofString("x", 
"(?i)[a-b]{3}-[1-9]{3}-[a-z]{3}")), "123-ABC-456", false},
+                    {TextP.regex(GValue.ofString("x", "Tinker.*\\u00A9")), 
"Apache TinkerPop©", true},
+                    {TextP.notRegex(GValue.ofString("x", 
"(?i)[a-b]{3}-[1-9]{3}-[a-z]{3}")), "123-ABC-456", true},
+                    {TextP.notRegex(GValue.ofString("x", "Tinker.*\\u00A9")), 
"Apache TinkerPop©", false},
             }));
         }
 
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
index ff5f800e80..163a390e1d 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
@@ -223,9 +223,8 @@ public class CountStrategyTest {
                     {__.out().count().is(gte(GValue.ofInteger("x", 2)))},
                     {__.out().count().is(inside(GValue.ofInteger("x", 2), 
GValue.ofInteger("y", 4)))},
                     {__.out().count().is(outside(GValue.ofInteger("x", 2), 
GValue.ofInteger("y", 4)))},
-                    // TODO: within/out() are broken for GValue - not 
initializing properly in the P constructor to preserve the GValue and missing 
the chance to mark as parameterized
-//                    {__.out().count().is(within(GValue.ofInteger("x", 2), 
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
-//                    {__.out().count().is(without(GValue.ofInteger("x", 2), 
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
+                    {__.out().count().is(within(GValue.ofInteger("x", 2), 
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
+                    {__.out().count().is(without(GValue.ofInteger("x", 2), 
GValue.ofInteger("y", 6), GValue.ofInteger("z", 4)))},
                     {__.map(__.count().is(GValue.of("x", 0)))},
                     {__.flatMap(__.count().is(GValue.of("x", 0)))},
                     {__.flatMap(__.count().is(GValue.of("x", 0))).as("a")},
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index ec23244172..198a4cbd72 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -467,7 +467,7 @@ const gremlins = {
     
g_withoutStrategiesXMatchPredicateStrategyX_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXa_b_cX:
 [function({g}) { return 
g.withoutStrategies(MatchPredicateStrategy).V().match(__.as("a").out("created").has("name",
 "lop").as("b"), __.as("b").in_("created").has("age", 
29).as("c")).where(__.as("c").repeat(__.out()).times(2)).select("a", "b", "c") 
}], 
     g_withStrategiesXMessagePassingReductionStrategyX_V: [function({g}) { 
return g.withStrategies(new MessagePassingReductionStrategy()).V() }], 
     g_withoutStrategiesXMessagePassingReductionStrategyX_V: [function({g}) { 
return g.withoutStrategies(MessagePassingReductionStrategy).V() }], 
-    g_V_coworker: [function({g, xx1}) { return 
g.V().hasLabel("person").filter(__.outE("created")).aggregate("p").as("p1").values("name").as("p1n").select("p").unfold().where(P.neq("p1")).as("p2").values("name").as("p2n").select("p2").out("created").choose(__.in_("created").where(P.eq("p1")),
 __.values("name"), 
__.constant(xx1)).group().by(__.select("p1n")).by(__.group().by(__.select("p2n")).by(__.unfold().fold().project("numCoCreated",
 "coCreated").by(__.count(Scope.local)).by())).unfol [...]
+    g_V_coworker: [function({g}) { return 
g.V().hasLabel("person").filter(__.outE("created")).aggregate("p").as("p1").values("name").as("p1n").select("p").unfold().where(P.neq("p1")).as("p2").values("name").as("p2n").select("p2").out("created").choose(__.in_("created").where(P.eq("p1")),
 __.values("name"), 
__.constant([])).group().by(__.select("p1n")).by(__.group().by(__.select("p2n")).by(__.unfold().fold().project("numCoCreated",
 "coCreated").by(__.count(Scope.local)).by())).unfold() }], 
     g_V_coworker_with_midV: [function({g}) { return 
g.V().hasLabel("person").filter(__.outE("created")).as("p1").V().hasLabel("person").where(P.neq("p1")).filter(__.outE("created")).as("p2").map(__.out("created").where(__.in_("created").as("p1")).values("name").fold()).group().by(__.select("p1").by("name")).by(__.group().by(__.select("p2").by("name")).by(__.project("numCoCreated",
 "coCreated").by(__.count(Scope.local)).by())).unfold() }], 
     g_withStrategiesXOptionsStrategyX_V: [function({g}) { return 
g.withStrategies(new OptionsStrategy()).V() }], 
     g_withStrategiesXOptionsStrategyXmyVar_myValueXX_V: [function({g}) { 
return g.withStrategies(new OptionsStrategy({myVar: "myValue"})).V() }], 
@@ -1679,7 +1679,7 @@ const gremlins = {
     
g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack:
 [function({g, vid1}) { return g.withSack(1.0, 
Operator.sum).V(vid1).local(__.out("knows").barrier(Barrier.normSack)).in_("knows").barrier().sack()
 }], 
     g_V_sackXassignX_byXageX_sack: [function({g}) { return 
g.V().sack(Operator.assign).by("age").sack() }], 
     
g_withSackXBigInteger_TEN_powX1000X_assignX_V_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack:
 [function({g}) { return 
g.withSack(10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 [...]
-    g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack: [function({g, xx1}) { 
return g.withSack(2).V().sack(Operator.div).by(__.constant(xx1)).sack() }], 
+    g_withSackX2X_V_sackXdivX_byXconstantX4_0XX_sack: [function({g}) { return 
g.withSack(2).V().sack(Operator.div).by(__.constant(4.0)).sack() }], 
     g_V_sackXassignX_byXageX_byXnameX_sack: [function({g}) { return 
g.V().sack(Operator.assign).by("age").by("name").sack() }], 
     g_V_sideEffectXidentityX: [function({g}) { return 
g.V().sideEffect(__.identity()) }], 
     g_V_sideEffectXidentity_valuesXnameXX: [function({g}) { return 
g.V().sideEffect(__.identity().values("name")) }], 

Reply via email to