protected <T> boolean match(
     int bid, SequenceMatcher.MatchedStates<T> matchedStates, boolean consume) {
   if (consume) {
     Interval<Integer> matchedInterval =
         matchedStates.getBranchStates().getMatchedInterval(bid, this);
     int cur = matchedStates.curPosition;
     if (matchedInterval == null) {
       // Haven't tried to match this node before, try now
       // Get element and return if it matched or not
       List<? extends T> nodes = matchedStates.elements();
       // TODO: Fix type checking
       Collection<Interval<Integer>> matched = pattern.match(nodes, cur);
       // TODO: Check intervals are valid?   Start at cur and ends after?
       if (matched != null && matched.size() > 0) {
         int nBranches = matched.size();
         int i = 0;
         for (Interval<Integer> interval : matched) {
           i++;
           int bid2 = matchedStates.getBranchStates().getBranchId(bid, i, nBranches);
           matchedStates.getBranchStates().setMatchedInterval(bid2, this, interval);
           // If matched, need to add next states to the queue of states to be processed
           // keep in current state until end node reached
           if (interval.getEnd() - 1 <= cur) {
             matchedStates.addStates(bid2, next);
           } else {
             matchedStates.addState(bid2, this);
           }
         }
         return true;
       } else {
         return false;
       }
     } else {
       // Previously matched this state - just need to step through until we get to end of
       // matched interval
       if (matchedInterval.getEnd() - 1 <= cur) {
         matchedStates.addStates(bid, next);
       } else {
         matchedStates.addState(bid, this);
       }
       return true;
     }
   } else {
     // Not consuming element - add this state back to queue of states to be processed
     // This state was not successfully matched
     matchedStates.addState(bid, this);
     return false;
   }
 }
 protected <T> boolean match(
     int bid,
     SequenceMatcher.MatchedStates<T> matchedStates,
     SequenceMatcher.MatchedGroup matchedGroup,
     int matchedNodes) {
   T node = matchedStates.get();
   if (matcher.matches(
       node, matchedStates.elements().get(matchedGroup.matchBegin + matchedNodes))) {
     matchedNodes++;
     matchedStates
         .getBranchStates()
         .setMatchStateInfo(
             bid,
             this,
             new Pair<SequenceMatcher.MatchedGroup, Integer>(matchedGroup, matchedNodes));
     int len = matchedGroup.matchEnd - matchedGroup.matchBegin;
     if (len == matchedNodes) {
       matchedStates.addStates(bid, next);
     } else {
       matchedStates.addState(bid, this);
     }
     return true;
   }
   return false;
 }
 protected <T> boolean match(
     int bid, SequenceMatcher.MatchedStates<T> matchedStates, boolean consume) {
   // We only mark start when about to consume elements
   if (consume) {
     // Start of group, mark start
     matchedStates.setGroupStart(bid, captureGroupId);
     return super.match(bid, matchedStates, consume);
   } else {
     // Not consuming, just add this state back to list of states to be processed
     matchedStates.addState(bid, this);
     return false;
   }
 }
 protected <T> boolean match(
     int bid, SequenceMatcher.MatchedStates<T> matchedStates, boolean consume) {
   if (consume) {
     // Get element and return if it matched or not
     T node = matchedStates.get();
     // TODO: Fix type checking
     if (pattern.match(node)) {
       // If matched, need to add next states to the queue of states to be processed
       matchedStates.addStates(bid, next);
       return true;
     } else {
       return false;
     }
   } else {
     // Not consuming element - add this state back to queue of states to be processed
     // This state was not successfully matched
     matchedStates.addState(bid, this);
     return false;
   }
 }
 protected <T> boolean match(
     int bid, SequenceMatcher.MatchedStates<T> matchedStates, boolean consume) {
   // Try to match previous node/nodes exactly
   if (consume) {
     // First element is group that is matched, second is number of nodes matched so far
     Pair<SequenceMatcher.MatchedGroup, Integer> backRefState =
         (Pair<SequenceMatcher.MatchedGroup, Integer>)
             matchedStates.getBranchStates().getMatchStateInfo(bid, this);
     if (backRefState == null) {
       // Haven't tried to match this node before, try now
       // Get element and return if it matched or not
       SequenceMatcher.MatchedGroup matchedGroup =
           matchedStates.getBranchStates().getMatchedGroup(bid, captureGroupId);
       if (matchedGroup != null) {
         // See if the first node matches
         if (matchedGroup.matchEnd > matchedGroup.matchBegin) {
           boolean matched = match(bid, matchedStates, matchedGroup, 0);
           return matched;
         } else {
           // TODO: Check handling of previous nodes that are zero elements?
           return super.match(bid, matchedStates, consume);
         }
       }
       return false;
     } else {
       SequenceMatcher.MatchedGroup matchedGroup = backRefState.first();
       int matchedNodes = backRefState.second();
       boolean matched = match(bid, matchedStates, matchedGroup, matchedNodes);
       return matched;
     }
   } else {
     // Not consuming, just add this state back to list of states to be processed
     matchedStates.addState(bid, this);
     return false;
   }
 }
 protected <T> boolean match(
     int bid, SequenceMatcher.MatchedStates<T> matchedStates, boolean consume) {
   // Get how many times this states has already been matched
   int matchedCount = matchedStates.getBranchStates().endMatchedCountInc(bid, this);
   // Get the minimum number of times we still need to match this state
   int minMatchLeft = minMatch - matchedCount;
   if (minMatchLeft < 0) {
     minMatchLeft = 0;
   }
   // Get the maximum number of times we can match this state
   int maxMatchLeft;
   if (maxMatch < 0) {
     // Indicate unlimited matching
     maxMatchLeft = maxMatch;
   } else {
     maxMatchLeft = maxMatch - matchedCount;
     if (maxMatch < 0) {
       // Already exceeded the maximum number of times we can match this state
       // indicate state not matched
       return false;
     }
   }
   boolean match = false;
   // See how many branching options there are...
   int totalBranches = 0;
   if (minMatchLeft == 0 && next != null) {
     totalBranches += next.size();
   }
   if (maxMatchLeft != 0) {
     totalBranches++;
   }
   int i = 0; // branch index
   // Check if there we have met the minimum number of matches
   // If so, go ahead and try to match next state
   //  (if we need to consume an element or end a group)
   if (minMatchLeft == 0 && next != null) {
     for (State s : next) {
       i++; // Increment branch index
       // Depending on greedy match or not, different priority to branches
       int pi = (greedyMatch && maxMatchLeft != 0) ? i + 1 : i;
       int bid2 = matchedStates.getBranchStates().getBranchId(bid, pi, totalBranches);
       matchedStates.getBranchStates().clearMatchedCount(bid2, this);
       boolean m = s.match(bid2, matchedStates, consume);
       if (m) {
         match = true;
       }
     }
   }
   // Check if we have the option of matching more
   // (maxMatchLeft < 0 indicate unlimited, maxMatchLeft > 0 indicate we are still allowed more
   // matches)
   if (maxMatchLeft != 0) {
     i++; // Increment branch index
     // Depending on greedy match or not, different priority to branches
     int pi = greedyMatch ? 1 : i;
     int bid2 = matchedStates.getBranchStates().getBranchId(bid, pi, totalBranches);
     if (consume) {
       // Consuming - try to see if repeating this pattern does anything
       boolean m = repeatStart.match(bid2, matchedStates, consume);
       if (m) {
         match = true;
         // Mark how many times we have matched this pattern
         matchedStates.getBranchStates().startMatchedCountInc(bid2, this);
       }
     } else {
       // Not consuming - don't do anything, just add this back to list of states to be processed
       matchedStates.addState(bid2, this);
     }
   }
   return match;
 }
 protected <T> boolean match(
     int bid, SequenceMatcher.MatchedStates<T> matchedStates, boolean consume) {
   // Always add this state back (effectively looping forever in this matching state)
   matchedStates.addState(bid, this);
   return false;
 }