diff options
author | Tom Tromey <tromey@gcc.gnu.org> | 2007-01-09 19:58:05 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2007-01-09 19:58:05 +0000 |
commit | 97b8365cafc3a344a22d3980b8ed885f5c6d8357 (patch) | |
tree | 996a5f57d4a68c53473382e45cb22f574cb3e4db /libjava/classpath/gnu/java/util | |
parent | c648dedbde727ca3f883bb5fd773aa4af70d3369 (diff) | |
download | gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.zip gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.tar.gz gcc-97b8365cafc3a344a22d3980b8ed885f5c6d8357.tar.bz2 |
Merged gcj-eclipse branch to trunk.
From-SVN: r120621
Diffstat (limited to 'libjava/classpath/gnu/java/util')
16 files changed, 359 insertions, 80 deletions
diff --git a/libjava/classpath/gnu/java/util/DoubleEnumeration.java b/libjava/classpath/gnu/java/util/DoubleEnumeration.java index 1fc37f8..94efb923 100644 --- a/libjava/classpath/gnu/java/util/DoubleEnumeration.java +++ b/libjava/classpath/gnu/java/util/DoubleEnumeration.java @@ -1,5 +1,5 @@ /* gnu.java.util.DoubleEnumeration - Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2001, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -63,7 +63,7 @@ import java.util.NoSuchElementException; * @author Jochen Hoenicke * @author Mark Wielaard (mark@klomp.org) */ -public class DoubleEnumeration implements Enumeration +public class DoubleEnumeration<T> implements Enumeration<T> { /** * This is true as long as one of the enumerations has more @@ -82,17 +82,17 @@ public class DoubleEnumeration implements Enumeration /** * The first enumeration. */ - private Enumeration e1; + private Enumeration<T> e1; /** * The second enumeration. */ - private Enumeration e2; + private Enumeration<T> e2; /** * Creates a new Enumeration combining the given two enumerations. * The enumerations mustn't be accessed by other classes. */ - public DoubleEnumeration(Enumeration e1, Enumeration e2) + public DoubleEnumeration(Enumeration<T> e1, Enumeration<T> e2) { this.e1 = e1; this.e2 = e2; @@ -126,7 +126,7 @@ public class DoubleEnumeration implements Enumeration * element of the second enumeration. If both enumeration don't have * any elements it throws a <code>NoSuchElementException</code>. */ - public Object nextElement() + public T nextElement() { if (!hasMoreElements()) throw new NoSuchElementException(); diff --git a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java index 5702751..a7e2322 100644 --- a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java +++ b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java @@ -72,7 +72,6 @@ import java.util.prefs.BackingStoreException; * <br /> * * @author Mario Torre <neugens@limasoftware.net> - * @version 1.0.1 */ public class GConfBasedPreferences extends AbstractPreferences @@ -136,12 +135,20 @@ public class GConfBasedPreferences absolutePath = absolutePath.substring(0, absolutePath.length() - 1); } + // strip invalid characters + // please, note that all names are unescaped into the native peer + int index = absolutePath.lastIndexOf('/'); + if (index > -1) + { + absolutePath = absolutePath.substring(0, index + 1); + absolutePath = absolutePath + GConfNativePeer.escapeString(name); + } + this.node = this.getRealRoot(isUser) + absolutePath; boolean nodeExist = backend.nodeExist(this.node); this.newNode = !nodeExist; - backend.startWatchingNode(this.node); } /** @@ -156,7 +163,15 @@ public class GConfBasedPreferences // we don't check anything here, if the node is a new node this will be // detected in the constructor, so we simply return a new reference to // the requested node. - return new GConfBasedPreferences(this, name, this.isUser); + + GConfBasedPreferences preferenceNode + = new GConfBasedPreferences(this, name, this.isUser); + + // register the node for to GConf so that it can listen + // events outside the scope of the application + backend.startWatchingNode(this.node); + + return preferenceNode; } /** @@ -365,6 +380,10 @@ public class GConfBasedPreferences { String nodeName = ""; + // strip key + // please, note that all names are unescaped into the native peer + key = GConfNativePeer.escapeString(key); + if (this.node.endsWith("/")) { nodeName = this.node + key; @@ -373,7 +392,7 @@ public class GConfBasedPreferences { nodeName = this.node + "/" + key; } - + return nodeName; } diff --git a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java index f1cb627..6049863 100644 --- a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java +++ b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java @@ -45,7 +45,6 @@ import java.util.prefs.BackingStoreException; * Native peer for GConf based preference backend. * * @author Mario Torre <neugens@limasoftware.net> - * @version 1.0.1 */ public final class GConfNativePeer { @@ -150,7 +149,7 @@ public final class GConfNativePeer */ public List getKeys(String node) throws BackingStoreException { - return gconf_client_gconf_client_all_keys(node); + return gconf_client_all_keys(node); } /** @@ -162,10 +161,26 @@ public final class GConfNativePeer */ public List getChildrenNodes(String node) throws BackingStoreException { - return gconf_client_gconf_client_all_nodes(node); + return gconf_client_all_nodes(node); } /** + * Escape the given string so the it is a valid GConf name. + */ + public static String escapeString(String plain) + { + return gconf_escape_key(plain); + } + + /** + * Unescape a string escaped with {@link #escapeString}. + */ + public static String unescapeString(String escaped) + { + return gconf_unescape_key(escaped); + } + + /** * Suggest to the backend GConf daemon to synch with the database. */ public void suggestSync() throws BackingStoreException @@ -270,8 +285,9 @@ public final class GConfNativePeer * Suggest to the GConf native peer a sync with the database. * */ - native static final protected void gconf_client_suggest_sync(); - + native static final protected void gconf_client_suggest_sync() + throws BackingStoreException; + /** * Returns a list of all nodes under the given node. * @@ -279,8 +295,9 @@ public final class GConfNativePeer * @return A list of nodes under the given source node. */ native - static final protected List gconf_client_gconf_client_all_nodes(String node); - + static final protected List gconf_client_all_nodes(String node) + throws BackingStoreException; + /** * Returns a list of all keys stored in the given node. * @@ -288,8 +305,28 @@ public final class GConfNativePeer * @return A list of all keys stored in the given node. */ native - static final protected List gconf_client_gconf_client_all_keys(String node); + static final protected List gconf_client_all_keys(String node) + throws BackingStoreException; + /** + * Escape the input String so that it's a valid element for GConf. + * + * @param plain the String to escape. + * @return An escaped String for use with GConf. + */ + native + static final protected String gconf_escape_key(String plain); + + /** + * Converts a string escaped with gconf_escape_key back into its + * original form. + * + * @param escaped key as returned by gconf_escape_key + * @return An unescaped key. + */ + native + static final protected String gconf_unescape_key(String escaped); + static { System.loadLibrary("gconfpeer"); diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexed.java b/libjava/classpath/gnu/java/util/regex/CharIndexed.java index 6cd857e..27e07b2 100644 --- a/libjava/classpath/gnu/java/util/regex/CharIndexed.java +++ b/libjava/classpath/gnu/java/util/regex/CharIndexed.java @@ -77,6 +77,13 @@ public interface CharIndexed { boolean move(int index); /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid or cursor position is at + * the end of input. + */ + boolean move1(int index); // I cannot think of a better name for this. + + /** * Returns true if the most recent move() operation placed the cursor * position at a valid position in the input. */ @@ -105,6 +112,16 @@ public interface CharIndexed { REMatch getLastMatch(); /** + * Sets the information used for hitEnd(). + */ + void setHitEnd(REMatch match); + + /** + * Returns whether the matcher has hit the end of input. + */ + boolean hitEnd(); + + /** * Returns the anchor. */ int getAnchor(); diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java index 2eb753b..8a0578e 100644 --- a/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java @@ -62,6 +62,10 @@ class CharIndexedCharSequence implements CharIndexed, Serializable { return ((anchor += index) < len); } + public boolean move1(int index) { + return ((anchor += index) <= len); + } + public CharIndexed lookBehind(int index, int length) { if (length > (anchor + index)) length = anchor + index; return new CharIndexedCharSequence(s, anchor + index - length); @@ -77,6 +81,15 @@ class CharIndexedCharSequence implements CharIndexed, Serializable { lastMatch.anchor = anchor; } public REMatch getLastMatch() { return lastMatch; } + + private int rightmostTriedPosition = 0; + public void setHitEnd(REMatch match) { + int pos = anchor + match.index; + if (pos > rightmostTriedPosition) rightmostTriedPosition = pos; + } + public boolean hitEnd() { return rightmostTriedPosition >= len; } + public int getAnchor() { return anchor; } public void setAnchor(int anchor) { this.anchor = anchor; } + } diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java index 77cd1ab..844fada 100644 --- a/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java @@ -166,6 +166,16 @@ class CharIndexedInputStream implements CharIndexed { "difficult to support getLastMatch for an input stream"); } + public void setHitEnd(REMatch match) { + throw new UnsupportedOperationException( + "difficult to support setHitEnd for an input stream"); + } + + public boolean hitEnd() { + throw new UnsupportedOperationException( + "difficult to support hitEnd for an input stream"); + } + public int getAnchor() { throw new UnsupportedOperationException( "difficult to support getAnchor for an input stream"); @@ -176,6 +186,10 @@ class CharIndexedInputStream implements CharIndexed { "difficult to support setAnchor for an input stream"); } + public boolean move1(int index) { + throw new UnsupportedOperationException( + "difficult to support move1 for an input stream"); + } } diff --git a/libjava/classpath/gnu/java/util/regex/RE.java b/libjava/classpath/gnu/java/util/regex/RE.java index 1aab3b7..09ff74b 100644 --- a/libjava/classpath/gnu/java/util/regex/RE.java +++ b/libjava/classpath/gnu/java/util/regex/RE.java @@ -130,7 +130,11 @@ public class RE extends REToken { private static final String VERSION = "1.1.5-dev"; // The localized strings are kept in a separate file - private static ResourceBundle messages = PropertyResourceBundle.getBundle("gnu/java/util/regex/MessagesBundle", Locale.getDefault()); + // Used by getLocalizedMessage(). + private static ResourceBundle messages; + + // Name of the bundle that contains the localized messages. + private static final String bundle = "gnu/java/util/regex/MessagesBundle"; // These are, respectively, the first and last tokens in our linked list // If there is only one token, firstToken == lastToken @@ -252,6 +256,13 @@ public class RE extends REToken { */ public static final int REG_ICASE_USASCII = 0x0800; + /** + * Execution flag. + * Do not move the position at which the search begins. If not set, + * the starting position will be moved until a match is found. + */ + public static final int REG_FIX_STARTING_POSITION = 0x1000; + /** Returns a string representing the version of the gnu.regexp package. */ public static final String version() { return VERSION; @@ -259,6 +270,8 @@ public class RE extends REToken { // Retrieves a message from the ResourceBundle static final String getLocalizedMessage(String key) { + if (messages == null) + messages = PropertyResourceBundle.getBundle(bundle, Locale.getDefault()); return messages.getString(key); } @@ -1643,6 +1656,7 @@ public class RE extends REToken { /* Implements abstract method REToken.match() */ boolean match(CharIndexed input, REMatch mymatch) { + input.setHitEnd(mymatch); if (firstToken == null) { return next(input, mymatch); } @@ -1720,15 +1734,23 @@ public class RE extends REToken { REMatch getMatchImpl(CharIndexed input, int anchor, int eflags, StringBuffer buffer) { boolean tryEntireMatch = ((eflags & REG_TRY_ENTIRE_MATCH) != 0); + boolean doMove = ((eflags & REG_FIX_STARTING_POSITION) == 0); RE re = (tryEntireMatch ? (RE) this.clone() : this); if (tryEntireMatch) { - re.chain(new RETokenEnd(0, null)); + RETokenEnd reEnd = new RETokenEnd(0, null); + reEnd.setFake(true); + re.chain(reEnd); } // Create a new REMatch to hold results REMatch mymatch = new REMatch(numSubs, anchor, eflags); do { + /* The following potimization is commented out because + the matching should be tried even if the length of + input is obviously too short in order that + java.util.regex.Matcher#hitEnd() may work correctly. // Optimization: check if anchor + minimumLength > length if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) { + */ if (re.match(input, mymatch)) { REMatch best = mymatch; // We assume that the match that coms first is the best. @@ -1749,13 +1771,17 @@ public class RE extends REToken { input.setLastMatch(best); return best; } - } + /* End of the optimization commented out + } + */ mymatch.clear(++anchor); // Append character to buffer if needed if (buffer != null && input.charAt(0) != CharIndexed.OUT_OF_BOUNDS) { buffer.append(input.charAt(0)); } - } while (input.move(1)); + // java.util.regex.Matcher#hitEnd() requires that the search should + // be tried at the end of input, so we use move1(1) instead of move(1) + } while (doMove && input.move1(1)); // Special handling at end of input for e.g. "$" if (minimumLength == 0) { diff --git a/libjava/classpath/gnu/java/util/regex/REMatch.java b/libjava/classpath/gnu/java/util/regex/REMatch.java index 3ff5ad7..d899482 100644 --- a/libjava/classpath/gnu/java/util/regex/REMatch.java +++ b/libjava/classpath/gnu/java/util/regex/REMatch.java @@ -307,12 +307,12 @@ public final class REMatch implements Serializable, Cloneable { } /* The following are used for debugging purpose - static String d(REMatch m) { + public static String d(REMatch m) { if (m == null) return "null"; else return "[" + m.index + "]"; } - String substringUptoIndex(CharIndexed input) { + public String substringUptoIndex(CharIndexed input) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < index; i++) { sb.append(input.charAt(i)); diff --git a/libjava/classpath/gnu/java/util/regex/RESyntax.java b/libjava/classpath/gnu/java/util/regex/RESyntax.java index b66b32f..db11e2d 100644 --- a/libjava/classpath/gnu/java/util/regex/RESyntax.java +++ b/libjava/classpath/gnu/java/util/regex/RESyntax.java @@ -54,8 +54,6 @@ import java.util.BitSet; public final class RESyntax implements Serializable { static final String DEFAULT_LINE_SEPARATOR = System.getProperty("line.separator"); - private static final String SYNTAX_IS_FINAL = RE.getLocalizedMessage("syntax.final"); - private BitSet bits; // true for the constant defined syntaxes @@ -513,7 +511,8 @@ public final class RESyntax implements Serializable { * @return a reference to this object for easy chaining. */ public RESyntax set(int index) { - if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL); + if (isFinal) + throw new IllegalAccessError(RE.getLocalizedMessage("syntax.final")); bits.set(index); return this; } @@ -525,7 +524,8 @@ public final class RESyntax implements Serializable { * @return a reference to this object for easy chaining. */ public RESyntax clear(int index) { - if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL); + if (isFinal) + throw new IllegalAccessError(RE.getLocalizedMessage("syntax.final")); bits.clear(index); return this; } @@ -548,7 +548,8 @@ public final class RESyntax implements Serializable { * @return this object for convenient chaining */ public RESyntax setLineSeparator(String aSeparator) { - if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL); + if (isFinal) + throw new IllegalAccessError(RE.getLocalizedMessage("syntax.final")); lineSeparator = aSeparator; return this; } diff --git a/libjava/classpath/gnu/java/util/regex/REToken.java b/libjava/classpath/gnu/java/util/regex/REToken.java index 155c018..9affd4e 100644 --- a/libjava/classpath/gnu/java/util/regex/REToken.java +++ b/libjava/classpath/gnu/java/util/regex/REToken.java @@ -72,6 +72,16 @@ abstract class REToken implements Serializable, Cloneable { /** Returns true if the match succeeded, false if it failed. */ boolean match(CharIndexed input, REMatch mymatch) { + return match(input, mymatch, false); + } + boolean matchFake(CharIndexed input, REMatch mymatch) { + return match(input, mymatch, true); + } + + private boolean match(CharIndexed input, REMatch mymatch, boolean fake) { + if (!fake) { + setHitEnd(input, mymatch); + } REMatch m = matchThis(input, mymatch); if (m == null) return false; if (next(input, m)) { @@ -81,6 +91,11 @@ abstract class REToken implements Serializable, Cloneable { return false; } + /** Sets whether the matching occurs at the end of input */ + void setHitEnd(CharIndexed input, REMatch mymatch) { + input.setHitEnd(mymatch); + } + /** Returns true if the match succeeded, false if it failed. * The matching is done against this REToken only. Chained * tokens are not checked. diff --git a/libjava/classpath/gnu/java/util/regex/RETokenChar.java b/libjava/classpath/gnu/java/util/regex/RETokenChar.java index 92d3efc..b70e6b1 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenChar.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenChar.java @@ -58,15 +58,20 @@ final class RETokenChar extends REToken { } REMatch matchThis(CharIndexed input, REMatch mymatch) { - int z = ch.length; if (matchOneString(input, mymatch.index)) { - mymatch.index += z; + mymatch.index += matchedLength; return mymatch; } + // java.util.regex.Matcher#hitEnd() requires that the length of + // partial match be counted. + mymatch.index += matchedLength; + input.setHitEnd(mymatch); return null; } - boolean matchOneString(CharIndexed input, int index) { + private int matchedLength; + private boolean matchOneString(CharIndexed input, int index) { + matchedLength = 0; int z = ch.length; char c; for (int i=0; i<z; i++) { @@ -74,6 +79,7 @@ final class RETokenChar extends REToken { if (! charEquals(c, ch[i])) { return false; } + ++matchedLength; } return true; } diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEnd.java b/libjava/classpath/gnu/java/util/regex/RETokenEnd.java index 00efdb6..294e320 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenEnd.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenEnd.java @@ -45,6 +45,12 @@ final class RETokenEnd extends REToken { private String newline; private boolean check_java_line_terminators; + /** + * Indicates whether this token is a real one generated at compile time, + * or a fake one temporarily added by RE#getMatchImpl. + */ + private boolean fake = false; + RETokenEnd(int subIndex,String newline) { super(subIndex); this.newline = newline; @@ -57,10 +63,19 @@ final class RETokenEnd extends REToken { this.check_java_line_terminators = b; } + void setFake(boolean fake) { + this.fake = fake; + } + int getMaximumLength() { return 0; } + boolean match(CharIndexed input, REMatch mymatch) { + if (!fake) return super.match(input, mymatch); + return super.matchFake(input, mymatch); + } + REMatch matchThis(CharIndexed input, REMatch mymatch) { char ch = input.charAt(mymatch.index); if (ch == CharIndexed.OUT_OF_BOUNDS) diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java b/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java index 57a146d..b3a28a3 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java @@ -58,6 +58,10 @@ final class RETokenEndSub extends REToken { return super.findMatch(input, mymatch); } + void setHitEnd(CharIndexed input, REMatch mymatch) { + // Do nothing + } + void dump(StringBuffer os) { // handled by RE // But add something for debugging. diff --git a/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java b/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java index a286c5b..aec2758 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java @@ -260,6 +260,14 @@ final class RETokenNamedProperty extends REToken { return new UnicodeCategoryHandler(Character.UNASSIGNED); if (name.equals("Lu")) return new UnicodeCategoryHandler(Character.UPPERCASE_LETTER); + if (name.equals("all")) + return new Handler() + { + public boolean includes(char c) + { + return true; + } + }; throw new REException("unsupported name " + name, REException.REG_ESCAPE, 0); } diff --git a/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java b/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java index bccc783..239c220 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java @@ -120,6 +120,7 @@ final class RETokenOneOf extends REToken { } boolean match(CharIndexed input, REMatch mymatch) { + setHitEnd(input, mymatch); if (matchesOneChar) return matchOneChar(input, mymatch); else return matchOneRE(input, mymatch); } diff --git a/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java b/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java index 531c4a3..7f5e562 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java @@ -38,8 +38,7 @@ exception statement from your version. */ package gnu.java.util.regex; -// import java.util.Vector; -// import java.util.Stack; +import java.util.ArrayList; final class RETokenRepeated extends REToken { private REToken token; @@ -168,19 +167,63 @@ final class RETokenRepeated extends REToken { } } + private static class FindMatchControlStack extends ArrayList { + private void push(FindMatchControl control) { + add(control); + } + private FindMatchControl pop() { + return (FindMatchControl)remove(size()-1); + } + private boolean empty() { + return isEmpty(); + } + } + + private static class FindMatchControl { + DoablesFinder finder; + FindMatchControl(DoablesFinder finder) { + this.finder = finder; + } + } + private REMatch findMatch(BacktrackStack stack) { - // Avoid using recursive calls. + return findMatch(stack, new FindMatchControlStack()); + } + + private REMatch findMatch(BacktrackStack stack, + FindMatchControlStack 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()) return null; - StackedInfo si = (StackedInfo)(stack.peek()); - CharIndexed input = si.input; - int numRepeats = si.numRepeats; - REMatch mymatch = si.match; - int[] visited = si.visited; - DoablesFinder finder = si.finder; - + 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(); @@ -192,12 +235,13 @@ final class RETokenRepeated extends REToken { m1.backtrackStack.push(new BacktrackStack.Backtrack( this, input, mymatch, stack)); } - return m1; + result = m1; + break MAIN_LOOP; } if (stingy) { continue MAIN_LOOP; } - return null; + break MAIN_LOOP; } if (finder == null) { @@ -238,7 +282,8 @@ final class RETokenRepeated extends REToken { m1.backtrackStack.push(new BacktrackStack.Backtrack( this, input, mymatch, stack)); } - return m1; + result = m1; + break MAIN_LOOP; } else { continue MAIN_LOOP; @@ -247,8 +292,82 @@ final class RETokenRepeated extends REToken { 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.empty()) 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: - do { + { boolean emptyMatchFound = false; @@ -263,61 +382,45 @@ final class RETokenRepeated extends REToken { if (!emptyMatchFound) { int n = doable.index; - if (! visitedContains(n, visited)) { - visited = addVisited(n, visited); - } - else { + if (visitedContains(n, visited)) { continue DO_ONE_DOABLE; } + visited = addVisited(n, visited); stack.push(new StackedInfo( - input, numRepeats + 1, doable, visited, null)); - REMatch m1 = findMatch(stack); - if (possessive) { - return m1; - } - if (m1 != null) { - m1.backtrackStack.push(new BacktrackStack.Backtrack( - this, input, mymatch, stack)); - return m1; - } + input, numRepeats + 1, doable, visited, null)); + taresult.visited = visited; + taresult.status = TryAnotherResult.TRY_FURTHER; + return taresult; } else { REMatch m1 = matchRest(input, doable); if (possessive) { - return m1; + 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)); - } - return m1; + } + taresult.result = m1; + taresult.status = TryAnotherResult.RESULT_FOUND; + return taresult; } } } // DO_ONE_DOABLE - } while (false); // DO_THIS only once; + } // DO_THIS - 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)); - } - return m1; - } + taresult.status = TryAnotherResult.NOTHING_FOUND; + return taresult; - } // MAIN_LOOP } boolean match(CharIndexed input, REMatch mymatch) { + setHitEnd(input, mymatch); REMatch m1 = findMatch(input, mymatch); if (m1 != null) { mymatch.assignFrom(m1); |