New test.
[mono.git] / mcs / class / System / System.Text.RegularExpressions / Regex.cs
index 1847aad6a8c5b281700977e92d8e8193615886a3..eb005b634815b0859643da20e7bf4aea9fcce327 100644 (file)
@@ -43,12 +43,12 @@ using System.Diagnostics;
 namespace System.Text.RegularExpressions {
        
        [Serializable]
-       public class Regex : ISerializable {
+       public partial class Regex : ISerializable {
 
 #if NET_2_0
                private static int cache_size = 15;
 #endif
-
+#if !TARGET_JVM
                [MonoTODO]
                public static void CompileToAssembly (RegexCompilationInfo [] regexes, AssemblyName aname)
                {
@@ -96,6 +96,7 @@ namespace System.Text.RegularExpressions {
                        asmBuilder.Save(aname.Name);
                        */
                }
+#endif
                
                public static string Escape (string str)
                {
@@ -176,20 +177,22 @@ namespace System.Text.RegularExpressions {
                }
 
 #if NET_2_0
-               [MonoTODO ("should be used somewhere ? FactoryCache ?")]
+               static FactoryCache cache = new FactoryCache (15);
                public static int CacheSize {
-                       get { return cache_size; }
+                       get { return cache.Capacity; }
                        set {
                                if (value < 0)
                                        throw new ArgumentOutOfRangeException ("CacheSize");
-                               cache_size = value;
+
+                               cache.Capacity = value; 
                        }
                }
+#else
+               static FactoryCache cache = new FactoryCache (200);
 #endif
 
                // private
 
-               private static FactoryCache cache = new FactoryCache (200);     // TODO put some meaningful number here
 
                // constructors
 
@@ -209,39 +212,61 @@ namespace System.Text.RegularExpressions {
                        this.roptions = options;
                        Init ();
                }
-
+#if !TARGET_JVM
                private void Init ()
                {
                        this.machineFactory = cache.Lookup (this.pattern, this.roptions);
 
                        if (this.machineFactory == null) {
-                               // parse and install group mapping
-
-                               Parser psr = new Parser ();
-                               RegularExpression re = psr.ParseRegularExpression (this.pattern, this.roptions);
-                               this.group_count = re.GroupCount;
-                               this.mapping = psr.GetMapping ();
-
-                               // compile
-                               
-                               ICompiler cmp;
-                               //if ((this.roptions & RegexOptions.Compiled) != 0)
-                               //      //throw new Exception ("Not implemented.");
-                               //      cmp = new CILCompiler ();
-                               //else
-                               cmp = new PatternCompiler ();
+                               InitNewRegex();
+                       } else {
+                               this.group_count = this.machineFactory.GroupCount;
+                               this.mapping = this.machineFactory.Mapping;
+                               this._groupNumberToNameMap = this.machineFactory.NamesMapping;
+                       }
+               }
+#endif
+
+               private void InitNewRegex () 
+               {
+                       this.machineFactory = CreateMachineFactory (this.pattern, this.roptions);
+                       cache.Add (this.pattern, this.roptions, this.machineFactory);
+                       this.group_count = machineFactory.GroupCount;
+                       this.mapping = machineFactory.Mapping;
+                       this._groupNumberToNameMap = this.machineFactory.NamesMapping;
+               }
 
-                               re.Compile (cmp, RightToLeft);
+               // The new rx engine has blocking bugs like
+               // https://bugzilla.novell.com/show_bug.cgi?id=470827
+               static readonly bool old_rx =
+#if !NET_2_1
+                       Environment.GetEnvironmentVariable ("MONO_NEW_RX") == null;
+#else
+                       true;
+#endif
 
-                               // install machine factory and add to pattern cache
+               private static IMachineFactory CreateMachineFactory (string pattern, RegexOptions options) 
+               {
+                       Parser psr = new Parser ();
+                       RegularExpression re = psr.ParseRegularExpression (pattern, options);
 
-                               this.machineFactory = cmp.GetMachineFactory ();
-                               this.machineFactory.Mapping = mapping;
-                               cache.Add (this.pattern, this.roptions, this.machineFactory);
+                       ICompiler cmp;
+                       if (!old_rx) {
+                               if ((options & RegexOptions.Compiled) != 0)
+                                       cmp = new CILCompiler ();
+                               else
+                                       cmp = new RxCompiler ();
                        } else {
-                               this.group_count = this.machineFactory.GroupCount;
-                               this.mapping = this.machineFactory.Mapping;
+                               cmp = new PatternCompiler ();
                        }
+
+                       re.Compile (cmp, (options & RegexOptions.RightToLeft) != 0);
+
+                       IMachineFactory machineFactory = cmp.GetMachineFactory ();
+                       machineFactory.Mapping = psr.GetMapping ();
+                       machineFactory.NamesMapping = GetGroupNamesArray (machineFactory.GroupCount, machineFactory.Mapping);
+
+                       return machineFactory;
                }
 
 #if NET_2_0
@@ -255,7 +280,7 @@ namespace System.Text.RegularExpressions {
                {
                }
 
-#if NET_1_1 && !TARGET_JVM
+#if ONLY_1_1 && !TARGET_JVM
                // fixes public API signature
                ~Regex ()
                {
@@ -291,15 +316,10 @@ namespace System.Text.RegularExpressions {
 
                public string GroupNameFromNumber (int i)
                {
-                       if (i > group_count)
+                       if (i < 0 || i > group_count)
                                return "";
-               
-                       foreach (string name in mapping.Keys) {
-                               if ((int) mapping [name] == i)
-                                       return name;
-                       }
 
-                       return "";
+                       return _groupNumberToNameMap [i];
                }
 
                public int GroupNumberFromName (string name)
@@ -366,42 +386,19 @@ namespace System.Text.RegularExpressions {
                        public void Evaluate (Match m, StringBuilder sb) { sb.Append (ev (m)); }
                }
 
-               delegate void MatchAppendEvaluator (Match match, StringBuilder sb);
-
                public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
                {
-                       Adapter a = new Adapter (evaluator);
-                       return Replace (input, new MatchAppendEvaluator (a.Evaluate), count, startat);
-               }
-
-               string Replace (string input, MatchAppendEvaluator evaluator, int count, int startat)
-               {
-                       StringBuilder result = new StringBuilder ();
-                       int ptr = startat;
-                       int counter = count;
+                       BaseMachine m = (BaseMachine)CreateMachine ();
 
-                       result.Append (input, 0, ptr);
+                       if (RightToLeft)
+                               return m.RTLReplace (this, input, evaluator, count, startat);
 
-                       Match m = Match (input, startat);
-                       while (m.Success) {
-                               if (count != -1)
-                                       if(counter -- <= 0)
-                                               break;
-                               if (m.Index < ptr)
-                                       throw new SystemException ("how");
-                               result.Append (input, ptr, m.Index - ptr);
-                               evaluator (m, result);
-
-                               ptr = m.Index + m.Length;
-                               m = m.NextMatch ();
-                       }
-                       
-                       if (ptr == 0)
-                               return input;
-                       
-                       result.Append (input, ptr, input.Length - ptr);
+                       // NOTE: If this is a cause of a lot of allocations, we can convert it to
+                       //       use a ThreadStatic allocation mitigator
+                       Adapter a = new Adapter (evaluator);
 
-                       return result.ToString ();
+                       return m.LTRReplace (this, input, new BaseMachine.MatchAppendEvaluator (a.Evaluate),
+                                                                count, startat);
                }
 
                public string Replace (string input, string replacement)
@@ -416,8 +413,7 @@ namespace System.Text.RegularExpressions {
 
                public string Replace (string input, string replacement, int count, int startat)
                {
-                       ReplacementEvaluator ev = new ReplacementEvaluator (this, replacement);
-                       return Replace (input, new MatchAppendEvaluator (ev.EvaluateAppend), count, startat);
+                       return CreateMachine ().Replace (this, input, replacement, count, startat);
                }
 
                // split methods
@@ -434,45 +430,7 @@ namespace System.Text.RegularExpressions {
 
                public string [] Split (string input, int count, int startat)
                {
-                       ArrayList splits = new ArrayList ();
-                       if (count == 0)
-                               count = Int32.MaxValue;
-
-                       int ptr = startat;
-                       Match m = null;
-                       while (--count > 0) {
-                               if (m != null)
-                                       m = m.NextMatch ();
-                               else
-                                       m = Match (input, ptr);
-
-                               if (!m.Success)
-                                       break;
-                       
-                               if (RightToLeft)
-                                       splits.Add (input.Substring (m.Index + m.Length, ptr - m.Index - m.Length));
-                               else
-                                       splits.Add (input.Substring (ptr, m.Index - ptr));
-                                       
-                               int gcount = m.Groups.Count;
-                               for (int gindex = 1; gindex < gcount; gindex++) {
-                                       Group grp = m.Groups [gindex];
-                                       splits.Add (input.Substring (grp.Index, grp.Length));
-                               }
-
-                               if (RightToLeft)
-                                       ptr = m.Index; 
-                               else
-                                       ptr = m.Index + m.Length;
-                                       
-                       }
-
-                       if (RightToLeft && ptr >= 0)
-                               splits.Add (input.Substring (0, ptr));
-                       if (!RightToLeft && ptr <= input.Length)
-                               splits.Add (input.Substring (ptr));
-
-                       return (string []) splits.ToArray (typeof (string));
+                       return CreateMachine ().Split (this, input, count, startat);
                }
 
                // This method is called at the end of the constructor of compiled
@@ -527,10 +485,20 @@ namespace System.Text.RegularExpressions {
                        return machineFactory.NewInstance ();
                }
 
+               private static string [] GetGroupNamesArray (int groupCount, IDictionary mapping) 
+               {
+                       string [] groupNumberToNameMap = new string [groupCount + 1];
+                       foreach (string name in mapping.Keys) {
+                               groupNumberToNameMap [(int) mapping [name]] = name;
+                       }
+                       return groupNumberToNameMap;
+               }
+               
                private IMachineFactory machineFactory;
                private IDictionary mapping;
                private int group_count;
                private bool refsInitialized;
+               private string [] _groupNumberToNameMap;
 
                
                // protected members
@@ -539,10 +507,17 @@ namespace System.Text.RegularExpressions {
                protected internal RegexOptions roptions;
                
                // MS undocumented members
+#if NET_2_1
+               [MonoTODO]
+               protected internal System.Collections.Generic.Dictionary<string, int> capnames;
+               [MonoTODO]
+               protected internal System.Collections.Generic.Dictionary<int, int> caps;
+#else
                [MonoTODO]
                protected internal System.Collections.Hashtable capnames;
                [MonoTODO]
                protected internal System.Collections.Hashtable caps;
+#endif
                [MonoTODO]
                protected internal int capsize;
                [MonoTODO]