You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2018/07/19 17:41:30 UTC

[11/50] tinkerpop git commit: Named Loops - Allows the user to name a repeat loop and to then access a named loop counter.

Named Loops - Allows the user to name a repeat loop and to then access a named loop counter.

Changes to the LoopStep to allow the loop name to be passed.
Throw IllegalArgumentException if the loop name is not defined.
Map of loop names to loop Stack held in ReferenceMap.
Documentation updated with usage.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/a80eb841
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/a80eb841
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/a80eb841

Branch: refs/heads/TINKERPOP-1996
Commit: a80eb84169048ed74c5ad27ebc4d12944fd0136a
Parents: 0b46fcd
Author: GCHQResearcher1337 <39...@users.noreply.github.com>
Authored: Fri Jul 6 15:43:06 2018 +0100
Committer: GCHQResearcher1337 <39...@users.noreply.github.com>
Committed: Fri Jul 6 15:57:51 2018 +0100

----------------------------------------------------------------------
 docs/src/reference/the-traversal.asciidoc       | 11 ++++
 .../gremlin/process/traversal/Traverser.java    | 13 +++-
 .../traversal/dsl/graph/GraphTraversal.java     | 30 ++++++++-
 .../gremlin/process/traversal/dsl/graph/__.java | 14 +++++
 .../traversal/step/branch/RepeatStep.java       | 17 ++++-
 .../process/traversal/step/map/LoopsStep.java   |  7 ++-
 .../B_LP_NL_O_P_S_SE_SL_Traverser.java          | 59 ++++++++++++++++--
 .../traverser/B_LP_NL_O_S_SE_SL_Traverser.java  | 58 +++++++++++++++--
 .../traverser/B_NL_O_S_SE_SL_Traverser.java     | 61 ++++++++++++++++--
 .../traverser/B_O_S_SE_SL_Traverser.java        | 15 ++++-
 .../LP_NL_O_OB_P_S_SE_SL_Traverser.java         | 58 +++++++++++++++--
 .../traverser/LP_NL_O_OB_S_SE_SL_Traverser.java | 60 ++++++++++++++++--
 .../traverser/NL_O_OB_S_SE_SL_Traverser.java    | 60 ++++++++++++++++--
 .../traverser/O_OB_S_SE_SL_Traverser.java       | 14 +++++
 .../traversal/traverser/ProjectedTraverser.java |  9 ++-
 .../traverser/util/AbstractTraverser.java       |  7 ++-
 .../traverser/util/EmptyTraverser.java          |  7 ++-
 .../traverser/util/LabelledCounter.java         |  7 ++-
 .../gremlin/structure/io/gryo/GryoVersion.java  |  7 ++-
 .../Process/Traversal/GraphTraversal.cs         | 18 ++++++
 .../src/Gremlin.Net/Process/Traversal/__.cs     | 16 +++++
 gremlin-test/features/branch/Repeat.feature     | 36 +++++++++++
 .../traversal/step/branch/RepeatTest.java       | 65 ++++++++++++++++++--
 23 files changed, 604 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index f845cd3..b565bae 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -2125,6 +2125,17 @@ traverser repeats. However, because the emit-predicate is declared true, those v
   Given that `loops==2`, the until-predicate fails and ripple and lop are emitted.
 Therefore, the traverser has seen the vertices: lop, vadas, josh, ripple, and lop.
 
+`repeat()`-steps may be nested inside each other or inside the `emit()` or `until()` predicates and they can also be 'named' by passing a string as the first parameter to `repeat()`. The loop counter of a named repeat step can be accessed within the looped context with `loops(loopName)` where `loopName` is the name set whe creating the `repeat()`-step.
+
+[gremlin-groovy,modern]
+----
+g.V(1).repeat(out("knows")).until(__.repeat(out("created")).emit(__.has("name", "lop"))) <1>
+g.V(6).repeat('a', both('created')).emit(repeat('b', __.both('knows')).until(or(loops().is(2), loops('b').is(loops('a')))).hasId(2)).dedup() <2>
+----
+
+<1> Starting from vertex 1, keep going taking outgoing 'knows' edges until the vertex was created by 'lop'.
+<2> Starting from vertex 6, keep taking created edges in either direction until the vertex is same distance from vertex 2 over knows edges as it is from vertex 6 over created edges.
+
 Finally, note that both `emit()` and `until()` can take a traversal and in such, situations, the predicate is
 determined by `traversal.hasNext()`. A few examples are provided below.
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
index 5fed40b..e07bec1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traverser.java
@@ -89,6 +89,15 @@ public interface Traverser<T> extends Serializable, Comparable<Traverser<T>>, Cl
     public int loops();
 
     /**
+     * Return the number of times the traverser has gone through the named looping section of a traversal.
+     *
+     * @param loopName the name applied to the loop or null for the containing loop
+     * @return The number of times the traverser has gone through a loop
+     * @throws IllegalArgumentException if the loopName is not defined
+     */
+    public int loops(final String loopName);
+
+    /**
      * A traverser may represent a grouping of traversers to allow for more efficient data propagation.
      *
      * @return the number of traversers represented in this traverser.
@@ -216,10 +225,12 @@ public interface Traverser<T> extends Serializable, Comparable<Traverser<T>>, Cl
          * Initialise a loop by setting up the looping construct.
          * The step label is important to create a stack of loop counters when within a nested context.
          * If the provided label is not the same as the current label on the stack, add a new loop counter.
+         * The loopName can be used to refer to the loops counter via the {@link LoopsStep}
          *
          * @param stepLabel the label of the step that is being set-up.
+         * @param loopName the user defined name for referencing the loop counter or null if not set
          */
-        public void initialiseLoops(final String stepLabel);
+        public void initialiseLoops(final String stepLabel, final String loopName);
 
         /**
          * Increment the number of times the traverser has gone through a looping section of traversal.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
----------------------------------------------------------------------
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 7d1e7e4..8684bfa 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
@@ -647,7 +647,20 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      */
     public default GraphTraversal<S, Integer> loops() {
         this.asAdmin().getBytecode().addStep(Symbols.loops);
-        return this.asAdmin().addStep(new LoopsStep<>(this.asAdmin()));
+        return this.asAdmin().addStep(new LoopsStep<>(this.asAdmin(), null));
+    }
+
+    /**
+     * If the {@link Traverser} supports looping then calling this method will extract the number of loops for that
+     * traverser for the named loop.
+     *
+     * @return the traversal with an appended {@link LoopsStep}
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#loops-step" target="_blank">Reference Documentation - Loops Step</a>
+     * @since 3.4.0
+     */
+    public default GraphTraversal<S, Integer> loops(String loopName) {
+        this.asAdmin().getBytecode().addStep(Symbols.loops, loopName);
+        return this.asAdmin().addStep(new LoopsStep<>(this.asAdmin(), loopName));
     }
 
     /**
@@ -2290,6 +2303,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
+     * This step is used for looping over a some traversal given some break predicate.
+     *
+     * @param repeatTraversal the traversal to repeat over
+     * @param loopName The name given to the loop
+     * @return the traversal with the appended {@link RepeatStep}
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#repeat-step" target="_blank">Reference Documentation - Repeat Step</a>
+     * @since 3.4.0
+     */
+    public default GraphTraversal<S, E> repeat(final String loopName, final Traversal<?, E> repeatTraversal) {
+        this.asAdmin().getBytecode().addStep(Symbols.repeat, loopName, repeatTraversal);
+        return RepeatStep.addRepeatToTraversal(this, loopName, (Traversal.Admin<E, E>) repeatTraversal);
+    }
+
+
+    /**
      * Emit is used in conjunction with {@link #repeat(Traversal)} to determine what objects get emit from the loop.
      *
      * @param emitTraversal the emit predicate defined as a traversal

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 2c73ce1..ae5c829 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -324,6 +324,13 @@ public class __ {
     }
 
     /**
+     * @see GraphTraversal#loops(String)
+     */
+    public static <A> GraphTraversal<A, Integer> loops(String loopName) {
+        return __.<A>start().loops(loopName);
+    }
+
+    /**
      * @see GraphTraversal#select(Pop, String)
      */
     public static <A, B> GraphTraversal<A, B> select(final Pop pop, final String selectKey) {
@@ -1030,6 +1037,13 @@ public class __ {
     }
 
     /**
+     * @see GraphTraversal#repeat(Traversal)
+     */
+    public static <A> GraphTraversal<A, A> repeat(final String loopName, final Traversal<?, A> traversal) {
+        return __.<A>start().repeat(loopName, traversal);
+    }
+
+    /**
      * @see GraphTraversal#emit(Traversal)
      */
     public static <A> GraphTraversal<A, A> emit(final Traversal<?, ?> emitTraversal) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
index ad949f8..b95f1cd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java
@@ -43,6 +43,7 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
     private Traversal.Admin<S, S> repeatTraversal = null;
     private Traversal.Admin<S, ?> untilTraversal = null;
     private Traversal.Admin<S, ?> emitTraversal = null;
+    private String loopName = null;
     public boolean untilFirst = false;
     public boolean emitFirst = false;
 
@@ -68,6 +69,11 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
         this.integrateChild(this.repeatTraversal);
     }
 
+
+    public void setLoopName(final String loopName) {
+        this.loopName = loopName;
+    }
+
     public void setUntilTraversal(final Traversal.Admin<S, ?> untilTraversal) {
         if (null != this.untilTraversal)
             throw new IllegalStateException("The repeat()-step already has its until()-modulator declared: " + this);
@@ -189,7 +195,7 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
                 return this.repeatTraversal.getEndStep();
             } else {
                 final Traverser.Admin<S> start = this.starts.next();
-                start.initialiseLoops(this.getId());
+                start.initialiseLoops(this.getId(), this.loopName);
                 if (doUntil(start, true)) {
                     start.resetLoops();
                     return IteratorUtils.of(start);
@@ -216,7 +222,7 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
             return IteratorUtils.of(start);
         } else {
             start.setStepId(this.repeatTraversal.getStartStep().getId());
-            start.initialiseLoops(start.getStepId());
+            start.initialiseLoops(start.getStepId(), this.loopName);
             if (doEmit(start, true)) {
                 final Traverser.Admin<S> emitSplit = start.split();
                 emitSplit.resetLoops();
@@ -242,6 +248,13 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav
         return traversal;
     }
 
+    public static <A, B, C extends Traversal<A, B>> C addRepeatToTraversal(final C traversal, final String loopName, final Traversal.Admin<B, B> repeatTraversal) {
+        addRepeatToTraversal(traversal, repeatTraversal);
+        final Step<?, B> step = traversal.asAdmin().getEndStep();
+        ((RepeatStep) step).setLoopName(loopName);
+        return traversal;
+    }
+
     public static <A, B, C extends Traversal<A, B>> C addUntilToTraversal(final C traversal, final Traversal.Admin<B, ?> untilPredicate) {
         final Step<?, B> step = traversal.asAdmin().getEndStep();
         if (step instanceof RepeatStep && null == ((RepeatStep) step).untilTraversal) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
index 2db9ab9..e95f26e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
@@ -26,12 +26,15 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
  */
 public final class LoopsStep<S> extends MapStep<S, Integer> {
 
-    public LoopsStep(final Traversal.Admin traversal) {
+    private String loopName;
+
+    public LoopsStep(final Traversal.Admin traversal, final String loopName) {
         super(traversal);
+        this.loopName = loopName;
     }
 
     @Override
     protected Integer map(final Traverser.Admin<S> traverser) {
-        return traverser.loops();
+        return traverser.loops(this.loopName);
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
index 380eb9f..04ba98a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java
@@ -18,14 +18,18 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.traverser;
 
+import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 
+
+import java.util.Iterator;
 import java.util.Stack;
 
 public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser<T> {
 
     protected Stack<LabelledCounter> nestedLoops;
+    protected ReferenceMap loopNames = null;
 
     protected B_LP_NL_O_P_S_SE_SL_Traverser() {
     }
@@ -33,6 +37,7 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser
     public B_LP_NL_O_P_S_SE_SL_Traverser(final T t, final Step<T, ?> step, final long initialBulk) {
         super(t, step, initialBulk);
         this.nestedLoops = new Stack<>();
+        this.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
     }
 
     /////////////////
@@ -43,9 +48,23 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel))
-            this.nestedLoops.push(new LabelledCounter(stepLabel, (short)0));
+    public int loops(final String loopName) {
+        if (loopName == null)
+            return loops();
+        else if (this.loopNames.containsKey(loopName))
+            return ((LabelledCounter) this.loopNames.get(loopName)).count();
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) {
+            LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0);
+            this.nestedLoops.push(lc);
+            if (loopName != null)
+                this.loopNames.put(loopName, lc);
+        }
     }
 
     @Override
@@ -66,6 +85,20 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -75,6 +108,20 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -93,13 +140,17 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser
 
         B_LP_NL_O_P_S_SE_SL_Traverser<?> that = (B_LP_NL_O_P_S_SE_SL_Traverser<?>) o;
 
-        return this.nestedLoops.equals(that.nestedLoops);
+        if (!this.nestedLoops.equals(that.nestedLoops)) return false;
+        return this.loopNames != null ? this.loopNames.equals(that.loopNames) : that.loopNames == null;
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + this.nestedLoops.hashCode();
+        result = 31 * result + (this.loopNames != null ? this.loopNames.hashCode() : 0);
+
         return result;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
index aa3e9b0..8ddd9fc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java
@@ -18,14 +18,17 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.traverser;
 
+import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 
+import java.util.Iterator;
 import java.util.Stack;
 
 public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T> {
 
     protected Stack<LabelledCounter> nestedLoops;
+    protected ReferenceMap loopNames = null;
 
     protected B_LP_NL_O_S_SE_SL_Traverser() {
     }
@@ -33,6 +36,7 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T>
     public B_LP_NL_O_S_SE_SL_Traverser(final T t, final Step<T, ?> step, final long initialBulk) {
         super(t, step, initialBulk);
         this.nestedLoops = new Stack<>();
+        this.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
     }
 
     /////////////////
@@ -43,9 +47,23 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T>
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel))
-            this.nestedLoops.push(new LabelledCounter(stepLabel, (short)0));
+    public int loops(final String loopName) {
+        if (loopName == null)
+            return loops();
+        else if (this.loopNames.containsKey(loopName))
+            return ((LabelledCounter) this.loopNames.get(loopName)).count();
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) {
+            LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0);
+            this.nestedLoops.push(lc);
+            if (loopName != null)
+                this.loopNames.put(loopName, lc);
+        }
     }
 
     @Override
@@ -66,6 +84,20 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T>
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -75,6 +107,20 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T>
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -93,13 +139,17 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T>
 
         B_LP_NL_O_S_SE_SL_Traverser<?> that = (B_LP_NL_O_S_SE_SL_Traverser<?>) o;
 
-        return this.nestedLoops.equals(that.nestedLoops);
+        if (!this.nestedLoops.equals(that.nestedLoops)) return false;
+        return this.loopNames != null ? this.loopNames.equals(that.loopNames) : that.loopNames == null;
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + this.nestedLoops.hashCode();
+        result = 31 * result + (this.loopNames != null ? this.loopNames.hashCode() : 0);
+
         return result;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
index 8d5d7dd..0eee799 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java
@@ -18,14 +18,18 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.traverser;
 
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 
+import java.util.Iterator;
 import java.util.Stack;
 
 public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
 
     protected Stack<LabelledCounter> nestedLoops;
+    protected ReferenceMap loopNames = null;
 
     protected B_NL_O_S_SE_SL_Traverser() {
     }
@@ -33,6 +37,7 @@ public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
     public B_NL_O_S_SE_SL_Traverser(final T t, final Step<T, ?> step, final long initialBulk) {
         super(t, step, initialBulk);
         this.nestedLoops = new Stack<>();
+        this.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
     }
 
     /////////////////
@@ -43,9 +48,23 @@ public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel))
-            this.nestedLoops.push(new LabelledCounter(stepLabel, (short)0));
+    public int loops(final String loopName) {
+        if (loopName == null)
+            return loops();
+        else if (this.loopNames.containsKey(loopName))
+            return ((LabelledCounter) this.loopNames.get(loopName)).count();
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) {
+            LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0);
+            this.nestedLoops.push(lc);
+            if (loopName != null)
+                this.loopNames.put(loopName, lc);
+        }
     }
 
     @Override
@@ -63,18 +82,48 @@ public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
     @Override
     public <R> Admin<R> split(final R r, final Step<T, R> step) {
         final B_NL_O_S_SE_SL_Traverser<R> clone = (B_NL_O_S_SE_SL_Traverser<R>) super.split(r, step);
+
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
     @Override
     public Admin<T> split() {
         final B_NL_O_S_SE_SL_Traverser<T> clone = (B_NL_O_S_SE_SL_Traverser<T>) super.split();
+
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -93,13 +142,17 @@ public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> {
 
         B_NL_O_S_SE_SL_Traverser<?> that = (B_NL_O_S_SE_SL_Traverser<?>) o;
 
-        return this.nestedLoops.equals(that.nestedLoops);
+        if (!this.nestedLoops.equals(that.nestedLoops)) return false;
+        return this.loopNames != null ? this.loopNames.equals(that.loopNames) : that.loopNames == null;
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + this.nestedLoops.hashCode();
+        result = 31 * result + (this.loopNames != null ? this.loopNames.hashCode() : 0);
+
         return result;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
index d184b7e..a6385a6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_O_S_SE_SL_Traverser.java
@@ -32,6 +32,7 @@ public class B_O_S_SE_SL_Traverser<T> extends B_O_Traverser<T> {
 
     protected Object sack = null;
     protected short loops = 0;  // an optimization hack to use a short internally to save bits :)
+    protected String loopName = null;
     protected transient TraversalSideEffects sideEffects;
 
     protected B_O_S_SE_SL_Traverser() {
@@ -64,6 +65,19 @@ public class B_O_S_SE_SL_Traverser<T> extends B_O_Traverser<T> {
     }
 
     @Override
+    public int loops(final String loopName) {
+        if (loopName == null || this.loopName != null && this.loopName.equals(loopName))
+            return this.loops;
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel , final String loopName){
+        this.loopName = loopName;
+    }
+
+    @Override
     public void incrLoops() {
         this.loops++;
     }
@@ -80,7 +94,6 @@ public class B_O_S_SE_SL_Traverser<T> extends B_O_Traverser<T> {
         return this.sideEffects;
     }
 
-
     @Override
     public void setSideEffects(final TraversalSideEffects sideEffects) {
         this.sideEffects = sideEffects;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
index 7fcaa2a..c7b42c6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java
@@ -19,14 +19,17 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.traverser;
 
+import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 
+import java.util.Iterator;
 import java.util.Stack;
 
 public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Traverser<T> {
 
     protected Stack<LabelledCounter> nestedLoops;
+    protected ReferenceMap loopNames = null;
 
     protected LP_NL_O_OB_P_S_SE_SL_Traverser() {
     }
@@ -34,6 +37,7 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Travers
     public LP_NL_O_OB_P_S_SE_SL_Traverser(final T t, final Step<T, ?> step) {
         super(t, step);
         this.nestedLoops = new Stack<>();
+        this.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
     }
 
     /////////////////
@@ -44,9 +48,23 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Travers
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel))
-            this.nestedLoops.push(new LabelledCounter(stepLabel, (short)0));
+    public int loops(final String loopName) {
+        if (loopName == null)
+            return loops();
+        else if (this.loopNames.containsKey(loopName))
+            return ((LabelledCounter) this.loopNames.get(loopName)).count();
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) {
+            LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0);
+            this.nestedLoops.push(lc);
+            if (loopName != null)
+                this.loopNames.put(loopName, lc);
+        }
     }
 
     @Override
@@ -67,6 +85,20 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Travers
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -76,6 +108,20 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Travers
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -94,13 +140,17 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Travers
 
         LP_NL_O_OB_P_S_SE_SL_Traverser<?> that = (LP_NL_O_OB_P_S_SE_SL_Traverser<?>) o;
 
-        return this.nestedLoops.equals(that.nestedLoops);
+        if (!this.nestedLoops.equals(that.nestedLoops)) return false;
+        return this.loopNames != null ? this.loopNames.equals(that.loopNames) : that.loopNames == null;
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + this.nestedLoops.hashCode();
+        result = 31 * result + (this.loopNames != null ? this.loopNames.hashCode() : 0);
+
         return result;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
index 92eb991..7e61841 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java
@@ -19,14 +19,17 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.traverser;
 
+import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 
+import java.util.Iterator;
 import java.util.Stack;
 
 public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends LP_O_OB_S_SE_SL_Traverser<T> {
 
     protected Stack<LabelledCounter> nestedLoops;
+    protected ReferenceMap loopNames = null;
 
     protected LP_NL_O_OB_S_SE_SL_Traverser() {
     }
@@ -34,19 +37,34 @@ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends LP_O_OB_S_SE_SL_Traverser<T
     public LP_NL_O_OB_S_SE_SL_Traverser(final T t, final Step<T, ?> step) {
         super(t, step);
         this.nestedLoops = new Stack<>();
+        this.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
     }
 
     /////////////////
 
     @Override
     public int loops() {
-        return this.nestedLoops.size() > 0 ? this.nestedLoops.peek().count() : 0;
+        return this.nestedLoops.peek().count();
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel))
-            this.nestedLoops.push(new LabelledCounter(stepLabel, (short)0));
+    public int loops(final String loopName) {
+        if (loopName == null)
+            return loops();
+        else if (this.loopNames.containsKey(loopName))
+            return ((LabelledCounter) this.loopNames.get(loopName)).count();
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) {
+            LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0);
+            this.nestedLoops.push(lc);
+            if (loopName != null)
+                this.loopNames.put(loopName, lc);
+        }
     }
 
     @Override
@@ -67,6 +85,20 @@ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends LP_O_OB_S_SE_SL_Traverser<T
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -76,6 +108,20 @@ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends LP_O_OB_S_SE_SL_Traverser<T
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -94,13 +140,17 @@ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends LP_O_OB_S_SE_SL_Traverser<T
 
         LP_NL_O_OB_S_SE_SL_Traverser<?> that = (LP_NL_O_OB_S_SE_SL_Traverser<?>) o;
 
-        return this.nestedLoops.equals(that.nestedLoops);
+        if (!this.nestedLoops.equals(that.nestedLoops)) return false;
+        return this.loopNames != null ? this.loopNames.equals(that.loopNames) : that.loopNames == null;
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + this.nestedLoops.hashCode();
+        result = 31 * result + (this.loopNames != null ? this.loopNames.hashCode() : 0);
+
         return result;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
index 31e93fe..9bbd94a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java
@@ -19,21 +19,25 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.traverser;
 
+import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 
+import java.util.Iterator;
 import java.util.Stack;
 
 public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> {
 
     protected Stack<LabelledCounter> nestedLoops;
-
+    protected ReferenceMap loopNames;
 
     protected NL_O_OB_S_SE_SL_Traverser() {
     }
 
     public NL_O_OB_S_SE_SL_Traverser(final T t, final Step<T, ?> step) {
         super(t, step);
+        this.nestedLoops = new Stack<>();
+        this.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
     }
 
     /////////////////
@@ -44,9 +48,23 @@ public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> {
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel))
-            this.nestedLoops.push(new LabelledCounter(stepLabel, (short)0));
+    public int loops(final String loopName) {
+        if (loopName == null)
+            return loops();
+        else if (this.loopNames.containsKey(loopName))
+            return ((LabelledCounter) this.loopNames.get(loopName)).count();
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) {
+            LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0);
+            this.nestedLoops.push(lc);
+            if (loopName != null)
+                this.loopNames.put(loopName, lc);
+        }
     }
 
     @Override
@@ -67,6 +85,20 @@ public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> {
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -76,6 +108,20 @@ public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> {
         clone.nestedLoops = new Stack<>();
         for(LabelledCounter lc : this.nestedLoops)
             clone.nestedLoops.push((LabelledCounter) lc.clone());
+
+        if (this.loopNames != null) {
+            clone.loopNames = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+            Iterator loopNamesIterator = this.loopNames.entrySet().iterator();
+            while (loopNamesIterator.hasNext()) {
+                ReferenceMap.Entry pair = (ReferenceMap.Entry) loopNamesIterator.next();
+
+                int idx = this.nestedLoops.indexOf(pair.getValue());
+                if (idx != -1)
+                    clone.loopNames.put(pair.getKey(), clone.nestedLoops.get(idx));
+            }
+        }
+
         return clone;
     }
 
@@ -94,13 +140,17 @@ public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> {
 
         NL_O_OB_S_SE_SL_Traverser<?> that = (NL_O_OB_S_SE_SL_Traverser<?>) o;
 
-        return this.nestedLoops.equals(that.nestedLoops);
+        if (!this.nestedLoops.equals(that.nestedLoops)) return false;
+        return this.loopNames != null ? this.loopNames.equals(that.loopNames) : that.loopNames == null;
     }
 
     @Override
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + this.nestedLoops.hashCode();
+        result = 31 * result + (this.loopNames != null ? this.loopNames.hashCode() : 0);
+
         return result;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
index e35716d..6001a7b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/O_OB_S_SE_SL_Traverser.java
@@ -30,6 +30,7 @@ public class O_OB_S_SE_SL_Traverser<T> extends O_Traverser<T> {
 
     protected Object sack = null;
     protected short loops = 0;  // an optimization hack to use a short internally to save bits :)
+    protected String loopName = null;
     protected transient TraversalSideEffects sideEffects;
     protected String future = HALT;
     protected long bulk = 1L;
@@ -74,6 +75,19 @@ public class O_OB_S_SE_SL_Traverser<T> extends O_Traverser<T> {
     }
 
     @Override
+    public int loops(final String loopName) {
+        if (loopName == null || this.loopName != null && this.loopName.equals(loopName))
+            return this.loops;
+        else
+            throw new IllegalArgumentException("Loop name not defined: " + loopName);
+    }
+
+    @Override
+    public void initialiseLoops(final String stepLabel , final String loopName){
+        this.loopName = loopName;
+    }
+
+    @Override
     public void incrLoops() {
         this.loops++;
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
index b624eef..ad3712b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
@@ -91,8 +91,8 @@ public final class ProjectedTraverser<T, P> implements Traverser.Admin<T> {
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
-        this.baseTraverser.initialiseLoops(stepLabel);
+    public void initialiseLoops(final String stepLabel, final String loopName) {
+        this.baseTraverser.initialiseLoops(stepLabel, loopName);
     }
 
     @Override
@@ -172,6 +172,11 @@ public final class ProjectedTraverser<T, P> implements Traverser.Admin<T> {
     }
 
     @Override
+    public int loops(String loopName) {
+        return this.baseTraverser.loops(loopName);
+    }
+
+    @Override
     public long bulk() {
         return this.baseTraverser.bulk();
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
index 9d52fea..658ba4b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/AbstractTraverser.java
@@ -100,7 +100,7 @@ public abstract class AbstractTraverser<T> implements Traverser<T>, Traverser.Ad
 
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
+    public void initialiseLoops(final String stepLabel, final String loopName) {
 
     }
 
@@ -180,6 +180,11 @@ public abstract class AbstractTraverser<T> implements Traverser<T>, Traverser.Ad
     }
 
     @Override
+    public int loops(final String loopName) {
+        throw new UnsupportedOperationException("This traverser does not support named loops: " + this.getClass().getCanonicalName());
+    }
+
+    @Override
     public long bulk() {
         return 1l;
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
index 4f4ca0a..3aeafbd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/EmptyTraverser.java
@@ -70,7 +70,7 @@ public final class EmptyTraverser<T> implements Traverser<T>, Traverser.Admin<T>
     }
 
     @Override
-    public void initialiseLoops(final String stepLabel) {
+    public void initialiseLoops(final String stepLabel, final String loopNam) {
 
     }
 
@@ -155,6 +155,11 @@ public final class EmptyTraverser<T> implements Traverser<T>, Traverser.Admin<T>
     }
 
     @Override
+    public int loops(final String loopName) {
+        return 0;
+    }
+
+    @Override
     public long bulk() {
         return 0l;
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
index 0e2130a..8be43e3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/util/LabelledCounter.java
@@ -29,15 +29,18 @@ import java.io.Serializable;
 public class LabelledCounter implements Serializable, Cloneable {
 
     private final String label;
+    private final MutableShort count = new MutableShort();
 
-    private final MutableShort count;
+    protected LabelledCounter() {
+        label = "";
+    }
 
     public LabelledCounter(final String label, final short initialCount) {
         if (label == null) {
             throw new NullPointerException("Label is null");
         }
         this.label = label;
-        this.count = new MutableShort(initialCount);
+        this.count.setValue(initialCount);
     }
 
     public boolean hasLabel(final String label){

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index fb2cffa..6935549 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -117,6 +117,7 @@ import org.apache.tinkerpop.shaded.kryo.serializers.JavaSerializer;
 import org.javatuples.Pair;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter;
 import org.apache.commons.lang.mutable.MutableShort;
+import org.apache.commons.collections.map.ReferenceMap;
 import java.util.Stack;
 
 import java.math.BigDecimal;
@@ -393,7 +394,8 @@ public enum GryoVersion {
             add(GryoTypeReg.of(LP_NL_O_OB_P_S_SE_SL_Traverser.class, 179));
             add(GryoTypeReg.of(LabelledCounter.class, 180));
             add(GryoTypeReg.of(MutableShort.class, 181));
-            add(GryoTypeReg.of(Stack.class, 182));                         // ***LAST ID***
+            add(GryoTypeReg.of(Stack.class, 182));
+            add(GryoTypeReg.of(ReferenceMap.class, 183));                        // ***LAST ID***
 
 
             // placeholder serializers for classes that don't live here in core. this will allow them to be used if
@@ -583,7 +585,8 @@ public enum GryoVersion {
             add(GryoTypeReg.of(LP_NL_O_OB_P_S_SE_SL_Traverser.class, 179));
             add(GryoTypeReg.of(LabelledCounter.class, 180));
             add(GryoTypeReg.of(MutableShort.class, 181));
-            add(GryoTypeReg.of(Stack.class, 182));                         // ***LAST ID***
+            add(GryoTypeReg.of(Stack.class, 182));
+            add(GryoTypeReg.of(ReferenceMap.class, 183));                        // ***LAST ID***
         }};
     }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index 537cdbe..4979067 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -914,6 +914,15 @@ namespace Gremlin.Net.Process.Traversal
         }
 
         /// <summary>
+        ///     Adds the loops step to this <see cref="GraphTraversal{SType, EType}" />.
+        /// </summary>
+        public GraphTraversal<S, int> Loops (string loopName)
+        {
+            Bytecode.AddStep("loops", loopName);
+            return Wrap<S, int>(this);
+        }
+
+        /// <summary>
         ///     Adds the map step to this <see cref="GraphTraversal{SType, EType}" />.
         /// </summary>
         public GraphTraversal<S, E2> Map<E2> (IFunction function)
@@ -1249,6 +1258,15 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Adds the repeat step to this <see cref="GraphTraversal{SType, EType}" />.
         /// </summary>
+        public GraphTraversal<S, E> Repeat (string loopName, ITraversal repeatTraversal)
+        {
+            Bytecode.AddStep("repeat", loopName, repeatTraversal);
+            return Wrap<S, E>(this);
+        }
+
+        /// <summary>
+        ///     Adds the repeat step to this <see cref="GraphTraversal{SType, EType}" />.
+        /// </summary>
         public GraphTraversal<S, E> Repeat (ITraversal repeatTraversal)
         {
             Bytecode.AddStep("repeat", repeatTraversal);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index 27a0004..3681ce6 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -697,6 +697,14 @@ namespace Gremlin.Net.Process.Traversal
         }
 
         /// <summary>
+        ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the loops step to that traversal.
+        /// </summary>
+        public static GraphTraversal<object, int> Loops(string loopName)
+        {
+            return new GraphTraversal<object, int>().Loops(loopName);            
+        }
+
+        /// <summary>
         ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the map step to that traversal.
         /// </summary>
         public static GraphTraversal<object, E2> Map<E2>(IFunction function)
@@ -933,6 +941,14 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the repeat step to that traversal.
         /// </summary>
+        public static GraphTraversal<object, object> Repeat(string loopName, ITraversal traversal)
+        {
+            return new GraphTraversal<object, object>().Repeat(loopName, traversal);            
+        }
+
+        /// <summary>
+        ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the repeat step to that traversal.
+        /// </summary>
         public static GraphTraversal<object, object> Repeat(ITraversal traversal)
         {
             return new GraphTraversal<object, object>().Repeat(traversal);            

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-test/features/branch/Repeat.feature
----------------------------------------------------------------------
diff --git a/gremlin-test/features/branch/Repeat.feature b/gremlin-test/features/branch/Repeat.feature
index 695ca1f..b5dc6ce 100644
--- a/gremlin-test/features/branch/Repeat.feature
+++ b/gremlin-test/features/branch/Repeat.feature
@@ -293,6 +293,18 @@ Scenario: g_V_untilXconstantXtrueXX_repeatXrepeatXout_createdXX_untilXhasXname_r
     | java |
     | java |
 
+Scenario: g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang
+  Given the modern graph
+  And the traversal of
+    """
+    g.V().emit().repeat("a", __.out("knows").filter(__.loops("a").is(0))).values("lang")
+    """
+  When iterated to list
+  Then the result should be unordered
+    | result |
+    | java |
+    | java |
+
 Scenario: g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values
     Given the modern graph
     And using the parameter v3Id defined as "v[lop].id"
@@ -318,3 +330,27 @@ Scenario: g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_
       Then the result should be unordered
         | result |
         | tinkergraph |
+
+Scenario: g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang
+  Given the modern graph
+  And the traversal of
+    """
+    g.V().repeat("a", __.out("knows").repeat("b", __.out("created").filter(__.loops("a").is(0))).emit()).emit().values("lang")
+    """
+  When iterated to list
+  Then the result should be unordered
+    | result |
+    | java |
+    | java |
+
+Scenario: g_VX6X_repeatXa_bothXcreatedXX_emitXrepeatXb_bothXknowsXX_untilXorXloops_isX2X_loopsXbX_isXloopsXaXXXX_hasXname_vadasXX_dedup_name
+  Given the modern graph
+  And using the parameter v6Id defined as "v[peter].id"
+  And the traversal of
+    """
+    g.V(v6Id).repeat("a", __.both("created")).emit(__.repeat("b", __.both("knows")).until(__.or(__.loops().is(2), __.loops("b").is(__.loops("a")))).has("name", "vadas")).dedup().values("name")
+    """
+  When iterated to list
+  Then the result should be unordered
+    | result |
+    | josh |

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a80eb841/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java
index b454c8c..a43534c 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatTest.java
@@ -114,6 +114,14 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, String> get_g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name(final Object v1Id);
 
+    // NAMED LOOP
+
+    public abstract Traversal<Vertex, String> get_g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang();
+
+    public abstract Traversal<Vertex, String> get_g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang();
+
+    public abstract Traversal<Vertex, String> get_g_VX6X_repeatXa_bothXcreatedXX_emitXrepeatXb_bothXknowsXX_untilXorXloops_isX2X_loopsXbX_isXloopsXaXXXX_hasXname_vadasXX_dedup_name(final Object v6Id);
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_repeatXoutX_timesX2X_emit_path() {
@@ -388,7 +396,6 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest {
     @LoadGraphWith(MODERN)
     public void g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values() {
         final Traversal<Vertex, String> traversal = get_g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values(convertToVertexId("lop"));
-
         printTraversalForm(traversal);
         for (String res :   new String[]{"josh","lop", "ripple"})
         {
@@ -396,7 +403,6 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest {
             String lang = traversal.next();
             assertEquals(lang, res);
         }
-
         assertFalse(traversal.hasNext());
     }
 
@@ -404,12 +410,48 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest {
     @LoadGraphWith(CREW)
     public void g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name() {
         final Traversal<Vertex, String> traversal = get_g_VX1X_repeatXrepeatXunionXout_uses_out_traversesXX_whereXloops_isX0X_timesX1X_timeX2X_name(convertToVertexId("marko"));
-
         printTraversalForm(traversal);
         assertTrue(traversal.hasNext());
         String name = traversal.next();
         assertEquals(name, "tinkergraph");
+        assertFalse(traversal.hasNext());
+    }
+
+    @LoadGraphWith(MODERN)
+    public void g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang() {
+        final Traversal<Vertex, String> traversal = get_g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang();
+        printTraversalForm(traversal);
+        assertTrue(traversal.hasNext());
+        String lang = traversal.next();
+        assertEquals(lang, "java");
+        assertTrue(traversal.hasNext());
+        lang = traversal.next();
+        assertEquals(lang, "java");
+        assertFalse(traversal.hasNext());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang() {
+        final Traversal<Vertex, String> traversal = get_g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang();
+        printTraversalForm(traversal);
+        assertTrue(traversal.hasNext());
+        String lang = traversal.next();
+        assertEquals(lang, "java");
+        assertTrue(traversal.hasNext());
+        lang = traversal.next();
+        assertEquals(lang, "java");
+        assertFalse(traversal.hasNext());
+    }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_VX6X_repeatXa_bothXcreatedXX_emitXrepeatXb_bothXknowsXX_untilXorXloops_isX2X_loopsXbX_isXloopsXaXXXX_hasXname_vadasXX_dedup_name() {
+        final Traversal<Vertex, String> traversal = get_g_VX6X_repeatXa_bothXcreatedXX_emitXrepeatXb_bothXknowsXX_untilXorXloops_isX2X_loopsXbX_isXloopsXaXXXX_hasXname_vadasXX_dedup_name(convertToVertexId("peter"));
+        printTraversalForm(traversal);
+        assertTrue(traversal.hasNext());
+        String name = traversal.next();
+        assertEquals(name, "josh");
         assertFalse(traversal.hasNext());
     }
 
@@ -513,7 +555,22 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest {
 
         @Override
         public Traversal<Vertex, String> get_g_VX3X_repeatXbothX_createdXX_untilXloops_is_40XXemit_repeatXin_knowsXX_emit_loopsXisX1Xdedup_values(final Object v3Id) {
-            return g.V(v3Id).repeat( __.both("created")).until(loops().is(40)).emit(__.repeat(__.in("knows")).emit(loops().is(1))).dedup().values("name");
+            return g.V(v3Id).repeat(__.both("created")).until(loops().is(40)).emit(__.repeat(__.in("knows")).emit(loops().is(1))).dedup().values("name");
+        }
+
+        @Override
+        public Traversal<Vertex, String> get_g_V_repeatXa_outXknows_repeatXb_outXcreatedX_filterXloops_isX0XX_emit_lang() {
+            return g.V().repeat("a", out("knows").repeat("b", out("created").filter(loops("a").is(0))).emit()).emit().values("lang");
+        }
+
+        @Override
+        public Traversal<Vertex, String> get_g_V_emit_repeatXa_outXknows_filterXloops_isX0XX_lang() {
+            return g.V().emit().repeat("a", out("knows").filter(loops("a").is(0))).values("lang");
+        }
+
+        @Override
+        public Traversal<Vertex, String> get_g_VX6X_repeatXa_bothXcreatedXX_emitXrepeatXb_bothXknowsXX_untilXorXloops_isX2X_loopsXbX_isXloopsXaXXXX_hasXname_vadasXX_dedup_name(final Object v6Id) {
+            return g.V(v6Id).repeat("a", both("created")).emit(__.repeat("b", __.both("knows")).until(__.or(loops().is(2), loops("b").is(loops("a")))).has("name", "vadas")).dedup().values("name");
         }
 
         @Override