mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			640 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			640 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
/* gnu/regexp/RETokenRepeated.java
 | 
						|
   Copyright (C) 2006 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.java.util.regex;
 | 
						|
 | 
						|
import gnu.java.lang.CPStringBuilder;
 | 
						|
 | 
						|
import java.util.ArrayDeque;
 | 
						|
import java.util.Deque;
 | 
						|
 | 
						|
final class RETokenRepeated extends REToken
 | 
						|
{
 | 
						|
  private REToken token;
 | 
						|
  private int min, max;
 | 
						|
  private boolean stingy;
 | 
						|
  private boolean possessive;
 | 
						|
  private int tokenFixedLength;
 | 
						|
 | 
						|
    RETokenRepeated (int subIndex, REToken token, int min, int max)
 | 
						|
  {
 | 
						|
    super (subIndex);
 | 
						|
    this.token = token;
 | 
						|
    this.min = min;
 | 
						|
    this.max = max;
 | 
						|
    if (token.returnsFixedLengthMatches ())
 | 
						|
      {
 | 
						|
        tokenFixedLength = token.getMaximumLength ();
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        tokenFixedLength = -1;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
    /** Sets the minimal matching mode to true. */
 | 
						|
  void makeStingy ()
 | 
						|
  {
 | 
						|
    stingy = true;
 | 
						|
  }
 | 
						|
 | 
						|
    /** Queries if this token has minimal matching enabled. */
 | 
						|
  boolean isStingy ()
 | 
						|
  {
 | 
						|
    return stingy;
 | 
						|
  }
 | 
						|
 | 
						|
    /** Sets possessive matching mode to true. */
 | 
						|
  void makePossessive ()
 | 
						|
  {
 | 
						|
    possessive = true;
 | 
						|
  }
 | 
						|
 | 
						|
    /** Queries if this token has possessive matching enabled. */
 | 
						|
  boolean isPossessive ()
 | 
						|
  {
 | 
						|
    return possessive;
 | 
						|
  }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The minimum length of a repeated token is the minimum length
 | 
						|
     * of the token multiplied by the minimum number of times it must
 | 
						|
     * match.
 | 
						|
     */
 | 
						|
  int getMinimumLength ()
 | 
						|
  {
 | 
						|
    return (min * token.getMinimumLength ());
 | 
						|
  }
 | 
						|
 | 
						|
  int getMaximumLength ()
 | 
						|
  {
 | 
						|
    if (max == Integer.MAX_VALUE)
 | 
						|
      return Integer.MAX_VALUE;
 | 
						|
    int tmax = token.getMaximumLength ();
 | 
						|
    if (tmax == Integer.MAX_VALUE)
 | 
						|
      return tmax;
 | 
						|
    return (max * tmax);
 | 
						|
  }
 | 
						|
 | 
						|
  // The comment "MUST make a clone" below means that some tests
 | 
						|
  // failed without doing clone(),
 | 
						|
 | 
						|
  private static class DoablesFinder
 | 
						|
  {
 | 
						|
    private REToken tk;
 | 
						|
    private CharIndexed input;
 | 
						|
    private REMatch rematch;
 | 
						|
    private boolean findFirst;
 | 
						|
 | 
						|
    private DoablesFinder (REToken tk, CharIndexed input, REMatch mymatch)
 | 
						|
    {
 | 
						|
      this.tk = tk;
 | 
						|
      this.input = input;
 | 
						|
      this.rematch = (REMatch) mymatch.clone ();        // MUST make a clone
 | 
						|
      this.rematch.backtrackStack = new BacktrackStack ();
 | 
						|
      findFirst = true;
 | 
						|
    }
 | 
						|
 | 
						|
    private REMatch find ()
 | 
						|
    {
 | 
						|
      int origin = rematch.index;
 | 
						|
      REMatch rem;
 | 
						|
      if (findFirst)
 | 
						|
        {
 | 
						|
          rem = tk.findMatch (input, rematch);
 | 
						|
          findFirst = false;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          while (true)
 | 
						|
            {
 | 
						|
              if (rematch.backtrackStack.empty ())
 | 
						|
                {
 | 
						|
                  rem = null;
 | 
						|
                  break;
 | 
						|
                }
 | 
						|
              BacktrackStack.Backtrack bt = rematch.backtrackStack.pop ();
 | 
						|
              rem = bt.token.backtrack (bt.input, bt.match, bt.param);
 | 
						|
              if (rem != null)
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
      if (rem == null)
 | 
						|
        return null;
 | 
						|
      if (rem.index == origin)
 | 
						|
        rem.empty = true;
 | 
						|
      rematch = rem;
 | 
						|
      return (REMatch) rem.clone ();    // MUST make a clone.
 | 
						|
    }
 | 
						|
 | 
						|
    boolean noMore ()
 | 
						|
    {
 | 
						|
      return rematch.backtrackStack.empty ();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  REMatch findMatch (CharIndexed input, REMatch mymatch)
 | 
						|
  {
 | 
						|
    if (tokenFixedLength >= 0)
 | 
						|
      return findMatchFixedLength (input, mymatch);
 | 
						|
    BacktrackStack stack = new BacktrackStack ();
 | 
						|
    stack.push (new StackedInfo (input, 0, mymatch, null, null));
 | 
						|
    return findMatch (stack);
 | 
						|
  }
 | 
						|
 | 
						|
  REMatch backtrack (CharIndexed input, REMatch mymatch, Object param)
 | 
						|
  {
 | 
						|
    if (tokenFixedLength >= 0)
 | 
						|
      return backtrackFixedLength (input, mymatch, param);
 | 
						|
    return findMatch ((BacktrackStack) param);
 | 
						|
  }
 | 
						|
 | 
						|
  private static class StackedInfo extends BacktrackStack.Backtrack
 | 
						|
  {
 | 
						|
    int numRepeats;
 | 
						|
    int[] visited;
 | 
						|
    DoablesFinder finder;
 | 
						|
      StackedInfo (CharIndexed input, int numRepeats, REMatch match,
 | 
						|
                   int[]visited, DoablesFinder finder)
 | 
						|
    {
 | 
						|
      super (null, input, match, null);
 | 
						|
      this.numRepeats = numRepeats;
 | 
						|
      this.visited = visited;
 | 
						|
      this.finder = finder;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private static class FindMatchControl
 | 
						|
  {
 | 
						|
    DoablesFinder finder;
 | 
						|
      FindMatchControl (DoablesFinder finder)
 | 
						|
    {
 | 
						|
      this.finder = finder;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private REMatch findMatch (BacktrackStack stack)
 | 
						|
  {
 | 
						|
    return findMatch (stack, new ArrayDeque < FindMatchControl > ());
 | 
						|
  }
 | 
						|
 | 
						|
  private REMatch findMatch (BacktrackStack stack,
 | 
						|
                             Deque < FindMatchControl > controlStack)
 | 
						|
  {
 | 
						|
    REMatch result = null;
 | 
						|
    StackedInfo si = null;
 | 
						|
    CharIndexed input = null;
 | 
						|
    int numRepeats = 0;
 | 
						|
    REMatch mymatch = null;
 | 
						|
    int[] visited = null;
 | 
						|
    DoablesFinder finder = null;
 | 
						|
 | 
						|
    // Avoid using recursive calls because a match can be very long.
 | 
						|
 | 
						|
    // This is the first entry point of this method.
 | 
						|
    // If you want to call this method recursively and you need the
 | 
						|
    // result returned, save necessary information in a FindMatchControl
 | 
						|
    // object and push it to controlStack, then continue from this point.
 | 
						|
    // You can check the result after exiting MAIN_LOOP.
 | 
						|
  MAIN_LOOP0:
 | 
						|
    while (true)
 | 
						|
      {
 | 
						|
 | 
						|
        // This is the second entry point of this method.
 | 
						|
        // If you want to call this method recursively but you do not need the
 | 
						|
        // result returned, just continue from this point.
 | 
						|
      MAIN_LOOP:
 | 
						|
        while (true)
 | 
						|
          {
 | 
						|
 | 
						|
            if (stack.empty ())
 | 
						|
              break MAIN_LOOP;
 | 
						|
            si = (StackedInfo) (stack.peek ());
 | 
						|
            input = si.input;
 | 
						|
            numRepeats = si.numRepeats;
 | 
						|
            mymatch = si.match;
 | 
						|
            visited = si.visited;
 | 
						|
            finder = si.finder;
 | 
						|
 | 
						|
            if (mymatch.backtrackStack == null)
 | 
						|
              mymatch.backtrackStack = new BacktrackStack ();
 | 
						|
 | 
						|
            if (numRepeats >= max)
 | 
						|
              {
 | 
						|
                stack.pop ();
 | 
						|
                REMatch m1 = matchRest (input, mymatch);
 | 
						|
                if (m1 != null)
 | 
						|
                  {
 | 
						|
                    if (!stack.empty ())
 | 
						|
                      {
 | 
						|
                        m1.backtrackStack.push (new BacktrackStack.
 | 
						|
                                                Backtrack (this, input,
 | 
						|
                                                           mymatch, stack));
 | 
						|
                      }
 | 
						|
                    result = m1;
 | 
						|
                    break MAIN_LOOP;
 | 
						|
                  }
 | 
						|
                if (stingy)
 | 
						|
                  {
 | 
						|
                    continue MAIN_LOOP;
 | 
						|
                  }
 | 
						|
                break MAIN_LOOP;
 | 
						|
              }
 | 
						|
 | 
						|
            if (finder == null)
 | 
						|
              {
 | 
						|
                finder = new DoablesFinder (token, input, mymatch);
 | 
						|
                si.finder = finder;
 | 
						|
              }
 | 
						|
 | 
						|
            if (numRepeats < min)
 | 
						|
              {
 | 
						|
                while (true)
 | 
						|
                  {
 | 
						|
                    REMatch doable = finder.find ();
 | 
						|
                    if (doable == null)
 | 
						|
                      {
 | 
						|
                        if (stack.empty ())
 | 
						|
                          return null;
 | 
						|
                        stack.pop ();
 | 
						|
                        continue MAIN_LOOP;
 | 
						|
                      }
 | 
						|
                    if (finder.noMore ())
 | 
						|
                      stack.pop ();
 | 
						|
                    int newNumRepeats = (doable.empty ? min : numRepeats + 1);
 | 
						|
                    stack.
 | 
						|
                      push (new
 | 
						|
                            StackedInfo (input, newNumRepeats, doable,
 | 
						|
                                         visited, null));
 | 
						|
                    continue MAIN_LOOP;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
 | 
						|
            if (visited == null)
 | 
						|
              visited = initVisited ();
 | 
						|
 | 
						|
            if (stingy)
 | 
						|
              {
 | 
						|
                REMatch nextMatch = finder.find ();
 | 
						|
                if (nextMatch != null && !nextMatch.empty)
 | 
						|
                  {
 | 
						|
                    stack.
 | 
						|
                      push (new
 | 
						|
                            StackedInfo (input, numRepeats + 1, nextMatch,
 | 
						|
                                         visited, null));
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    stack.pop ();
 | 
						|
                  }
 | 
						|
                REMatch m1 = matchRest (input, mymatch);
 | 
						|
                if (m1 != null)
 | 
						|
                  {
 | 
						|
                    if (!stack.empty ())
 | 
						|
                      {
 | 
						|
                        m1.backtrackStack.push (new BacktrackStack.
 | 
						|
                                                Backtrack (this, input,
 | 
						|
                                                           mymatch, stack));
 | 
						|
                      }
 | 
						|
                    result = m1;
 | 
						|
                    break MAIN_LOOP;
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    continue MAIN_LOOP;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
 | 
						|
            visited = addVisited (mymatch.index, visited);
 | 
						|
 | 
						|
            TryAnotherResult taresult =
 | 
						|
              tryAnother (stack, input, mymatch, numRepeats, finder, visited);
 | 
						|
            visited = taresult.visited;
 | 
						|
            switch (taresult.status)
 | 
						|
              {
 | 
						|
              case TryAnotherResult.TRY_FURTHER:
 | 
						|
                controlStack.push (new FindMatchControl (finder));
 | 
						|
                continue MAIN_LOOP0;
 | 
						|
              case TryAnotherResult.RESULT_FOUND:
 | 
						|
                result = taresult.result;
 | 
						|
                break MAIN_LOOP;
 | 
						|
              }
 | 
						|
 | 
						|
            if (!stack.empty ())
 | 
						|
              {
 | 
						|
                stack.pop ();
 | 
						|
              }
 | 
						|
            if (possessive)
 | 
						|
              {
 | 
						|
                stack.clear ();
 | 
						|
              }
 | 
						|
            REMatch m1 = matchRest (input, mymatch);
 | 
						|
            if (m1 != null)
 | 
						|
              {
 | 
						|
                if (!stack.empty ())
 | 
						|
                  {
 | 
						|
                    m1.backtrackStack.push (new BacktrackStack.
 | 
						|
                                            Backtrack (this, input, mymatch,
 | 
						|
                                                       stack));
 | 
						|
                  }
 | 
						|
                result = m1;
 | 
						|
                break MAIN_LOOP;
 | 
						|
              }
 | 
						|
 | 
						|
          }                     // MAIN_LOOP
 | 
						|
 | 
						|
        if (controlStack.isEmpty ())
 | 
						|
          return result;
 | 
						|
        FindMatchControl control = controlStack.pop ();
 | 
						|
        if (possessive)
 | 
						|
          {
 | 
						|
            return result;
 | 
						|
          }
 | 
						|
        if (result != null)
 | 
						|
          {
 | 
						|
            result.backtrackStack.push (new BacktrackStack.
 | 
						|
                                        Backtrack (this, input, mymatch,
 | 
						|
                                                   stack));
 | 
						|
            return result;
 | 
						|
          }
 | 
						|
 | 
						|
        finder = control.finder;
 | 
						|
 | 
						|
        TryAnotherResult taresult =
 | 
						|
          tryAnother (stack, input, mymatch, numRepeats, finder, visited);
 | 
						|
        visited = taresult.visited;
 | 
						|
        switch (taresult.status)
 | 
						|
          {
 | 
						|
          case TryAnotherResult.TRY_FURTHER:
 | 
						|
            controlStack.push (new FindMatchControl (finder));
 | 
						|
            continue MAIN_LOOP0;
 | 
						|
          case TryAnotherResult.RESULT_FOUND:
 | 
						|
            return taresult.result;
 | 
						|
          }
 | 
						|
        continue MAIN_LOOP0;
 | 
						|
 | 
						|
      }                         // MAIN_LOOP0
 | 
						|
  }
 | 
						|
 | 
						|
  private static class TryAnotherResult
 | 
						|
  {
 | 
						|
    REMatch result;
 | 
						|
    int status;
 | 
						|
    static final int RESULT_FOUND = 1;
 | 
						|
    static final int TRY_FURTHER = 2;
 | 
						|
    static final int NOTHING_FOUND = 3;
 | 
						|
    int[] visited;
 | 
						|
  }
 | 
						|
 | 
						|
  private TryAnotherResult tryAnother (BacktrackStack stack,
 | 
						|
                                       CharIndexed input, REMatch mymatch,
 | 
						|
                                       int numRepeats, DoablesFinder finder,
 | 
						|
                                       int[]visited)
 | 
						|
  {
 | 
						|
 | 
						|
    TryAnotherResult taresult = new TryAnotherResult ();
 | 
						|
    taresult.visited = visited;
 | 
						|
 | 
						|
  DO_THIS:
 | 
						|
    {
 | 
						|
 | 
						|
      boolean emptyMatchFound = false;
 | 
						|
 | 
						|
    DO_ONE_DOABLE:
 | 
						|
      while (true)
 | 
						|
        {
 | 
						|
 | 
						|
          REMatch doable = finder.find ();
 | 
						|
          if (doable == null)
 | 
						|
            {
 | 
						|
              break DO_THIS;
 | 
						|
            }
 | 
						|
          if (doable.empty)
 | 
						|
            emptyMatchFound = true;
 | 
						|
 | 
						|
          if (!emptyMatchFound)
 | 
						|
            {
 | 
						|
              int n = doable.index;
 | 
						|
              if (visitedContains (n, visited))
 | 
						|
                {
 | 
						|
                  continue DO_ONE_DOABLE;
 | 
						|
                }
 | 
						|
              visited = addVisited (n, visited);
 | 
						|
              stack.
 | 
						|
                push (new
 | 
						|
                      StackedInfo (input, numRepeats + 1, doable, visited,
 | 
						|
                                   null));
 | 
						|
              taresult.visited = visited;
 | 
						|
              taresult.status = TryAnotherResult.TRY_FURTHER;
 | 
						|
              return taresult;
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              REMatch m1 = matchRest (input, doable);
 | 
						|
              if (possessive)
 | 
						|
                {
 | 
						|
                  taresult.result = m1;
 | 
						|
                  taresult.status = TryAnotherResult.RESULT_FOUND;
 | 
						|
                  return taresult;
 | 
						|
                }
 | 
						|
              if (m1 != null)
 | 
						|
                {
 | 
						|
                  if (!stack.empty ())
 | 
						|
                    {
 | 
						|
                      m1.backtrackStack.push (new BacktrackStack.
 | 
						|
                                              Backtrack (this, input, mymatch,
 | 
						|
                                                         stack));
 | 
						|
                    }
 | 
						|
                  taresult.result = m1;
 | 
						|
                  taresult.status = TryAnotherResult.RESULT_FOUND;
 | 
						|
                  return taresult;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
        }                       // DO_ONE_DOABLE
 | 
						|
 | 
						|
    }                           // DO_THIS
 | 
						|
 | 
						|
    taresult.status = TryAnotherResult.NOTHING_FOUND;
 | 
						|
    return taresult;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  boolean match (CharIndexed input, REMatch mymatch)
 | 
						|
  {
 | 
						|
    setHitEnd (input, mymatch);
 | 
						|
    REMatch m1 = findMatch (input, mymatch);
 | 
						|
    if (m1 != null)
 | 
						|
      {
 | 
						|
        mymatch.assignFrom (m1);
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Array visited is an array of character positions we have already
 | 
						|
  // visited. visited[0] is used to store the effective length of the
 | 
						|
  // array.
 | 
						|
  private static int[] initVisited ()
 | 
						|
  {
 | 
						|
    int[] visited = new int[32];
 | 
						|
    visited[0] = 0;
 | 
						|
    return visited;
 | 
						|
  }
 | 
						|
 | 
						|
  private static boolean visitedContains (int n, int[]visited)
 | 
						|
  {
 | 
						|
    // Experience tells that for a small array like this,
 | 
						|
    // simple linear search is faster than binary search.
 | 
						|
    for (int i = 1; i < visited[0]; i++)
 | 
						|
      {
 | 
						|
        if (n == visited[i])
 | 
						|
          return true;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  private static int[] addVisited (int n, int[]visited)
 | 
						|
  {
 | 
						|
    if (visitedContains (n, visited))
 | 
						|
      return visited;
 | 
						|
    if (visited[0] >= visited.length - 1)
 | 
						|
      {
 | 
						|
        int[] newvisited = new int[visited.length + 32];
 | 
						|
        System.arraycopy (visited, 0, newvisited, 0, visited.length);
 | 
						|
        visited = newvisited;
 | 
						|
      }
 | 
						|
    visited[0]++;
 | 
						|
    visited[visited[0]] = n;
 | 
						|
    return visited;
 | 
						|
  }
 | 
						|
 | 
						|
  private REMatch matchRest (CharIndexed input, final REMatch newMatch)
 | 
						|
  {
 | 
						|
    if (next (input, newMatch))
 | 
						|
      {
 | 
						|
        return newMatch;
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  private REMatch findMatchFixedLength (CharIndexed input, REMatch mymatch)
 | 
						|
  {
 | 
						|
    if (mymatch.backtrackStack == null)
 | 
						|
      mymatch.backtrackStack = new BacktrackStack ();
 | 
						|
    int numRepeats =
 | 
						|
      token.findFixedLengthMatches (input, (REMatch) mymatch.clone (), max);
 | 
						|
    if (numRepeats == Integer.MAX_VALUE)
 | 
						|
      numRepeats = min;
 | 
						|
    int count = numRepeats - min + 1;
 | 
						|
    if (count <= 0)
 | 
						|
      return null;
 | 
						|
    int index = 0;
 | 
						|
    if (!stingy)
 | 
						|
      index = mymatch.index + (tokenFixedLength * numRepeats);
 | 
						|
    else
 | 
						|
      index = mymatch.index + (tokenFixedLength * min);
 | 
						|
    return findMatchFixedLength (input, mymatch, index, count);
 | 
						|
  }
 | 
						|
 | 
						|
  private REMatch backtrackFixedLength (CharIndexed input, REMatch mymatch,
 | 
						|
                                        Object param)
 | 
						|
  {
 | 
						|
    int[] params = (int[]) param;
 | 
						|
    int index = params[0];
 | 
						|
    int count = params[1];
 | 
						|
    return findMatchFixedLength (input, mymatch, index, count);
 | 
						|
  }
 | 
						|
 | 
						|
  private REMatch findMatchFixedLength (CharIndexed input, REMatch mymatch,
 | 
						|
                                        int index, int count)
 | 
						|
  {
 | 
						|
    REMatch tryMatch = (REMatch) mymatch.clone ();
 | 
						|
    while (true)
 | 
						|
      {
 | 
						|
        tryMatch.index = index;
 | 
						|
        REMatch m = matchRest (input, tryMatch);
 | 
						|
        count--;
 | 
						|
        if (stingy)
 | 
						|
          index += tokenFixedLength;
 | 
						|
        else
 | 
						|
          index -= tokenFixedLength;
 | 
						|
        if (possessive)
 | 
						|
          return m;
 | 
						|
        if (m != null)
 | 
						|
          {
 | 
						|
            if (count > 0)
 | 
						|
              {
 | 
						|
                m.backtrackStack.push (new BacktrackStack.
 | 
						|
                                       Backtrack (this, input, mymatch,
 | 
						|
                                                  new int[]
 | 
						|
                                                  {
 | 
						|
                                                  index, count}));
 | 
						|
              }
 | 
						|
            return m;
 | 
						|
          }
 | 
						|
        if (count <= 0)
 | 
						|
          return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  void dump (CPStringBuilder os)
 | 
						|
  {
 | 
						|
    os.append ("(?:");
 | 
						|
    token.dumpAll (os);
 | 
						|
    os.append (')');
 | 
						|
    if ((max == Integer.MAX_VALUE) && (min <= 1))
 | 
						|
      os.append ((min == 0) ? '*' : '+');
 | 
						|
    else if ((min == 0) && (max == 1))
 | 
						|
      os.append ('?');
 | 
						|
    else
 | 
						|
      {
 | 
						|
        os.append ('{').append (min);
 | 
						|
        if (max > min)
 | 
						|
          {
 | 
						|
            os.append (',');
 | 
						|
            if (max != Integer.MAX_VALUE)
 | 
						|
              os.append (max);
 | 
						|
          }
 | 
						|
        os.append ('}');
 | 
						|
      }
 | 
						|
    if (stingy)
 | 
						|
      os.append ('?');
 | 
						|
  }
 | 
						|
}
 |