add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Experimental/Regex/union.rb
File: union.rb
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Experimental/Regex/union.rb;regex3
@@ -1,0 +1,8 @@
+p Regexp.union(/a/mix, /b/i, /c/)
+p Regexp.union(/a/mix, /b/i, "asdasd*")
+p Regexp.union()
+p Regexp.union(/a/mix)
+p Regexp.union("a")
+p Regexp.union("", /a/mix)
+p Regexp.union(//, /a/mix)
+p Regexp.union(nil) rescue p $!
\ No newline at end of file
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C448505
File: RubyTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C448505  (server)    5/24/2008 10:11 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;regex3
@@ -58,6 +58,7 @@
                 Regex2,
                 RegexTransform1,
                 RegexTransform2,
+                RegexEscape1,
                 
                 Scenario_RubyScopeParsing,
                 Scenario_RubyScopes1,
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/ExceptionTests.cs;C448505
File: ExceptionTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/ExceptionTests.cs;C448505  (server)    5/25/2008 10:12 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/ExceptionTests.cs;regex3
@@ -579,7 +579,6 @@
             }, @"42");
         }
 
-        [Run]
         public void ExceptionArg2() {
             AssertOutput(delegate() {
                 CompilerTest(@"
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/RegexTests.cs;C448505
File: RegexTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/RegexTests.cs;C448505  (server)    5/24/2008 10:12 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/RegexTests.cs;regex3
@@ -114,6 +114,9 @@
 
                 @"\G",
                 @"\G",
+
+                @"[a\-z]",
+                @"[a\-z]",
             };
 
             for (int i = 0; i < incorrectPatterns.Length; i += 2) {
@@ -154,6 +157,28 @@
             Assert(e == t);
             new Regex(t);
         }
+
+        public void RegexEscape1() {
+            string[] patterns = new string[] {
+                @"", 
+                @"",
+
+                @"\", 
+                @"\\",
+
+                @"(*)", 
+                @"\(\*\)",
+
+                "$ ^ | [ ] ( ) \\ . # - { } * + ? \t \v \n \r \f \a \b", 
+                @"\$ \^ \| \[ \] \( \) \\ \. \# \- \{ \} \* \+ \? \t \v \n \r \f " + "\a \b"
+            };
+
+            for (int i = 0; i < patterns.Length; i += 2) {
+                string expected = patterns[i + 1];
+                string actual = StringRegex.Escape(patterns[i]);
+                Assert(actual == expected);
+            }
+        }
     }
 }
 
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C448505
File: Initializers.Generated.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C448505  (server)    5/25/2008 11:48 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;regex3
@@ -3551,6 +3551,11 @@
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyRegex, System.Object, System.Object>(Ruby.Builtins.RegexpOps.MatchIndex),
             });
             
+            module.DefineLibraryMethod("==", 0x29, new System.Delegate[] {
+                new Microsoft.Scripting.Utils.Function<Ruby.Builtins.RubyRegex, System.Object, System.Boolean>(Ruby.Builtins.RegexpOps.Equals),
+                new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyRegex, Ruby.Builtins.RubyRegex, System.Boolean>(Ruby.Builtins.RegexpOps.Equals),
+            });
+            
             module.DefineLibraryMethod("===", 0x29, new System.Delegate[] {
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyRegex, Ruby.Builtins.MutableString, System.Boolean>(Ruby.Builtins.RegexpOps.CaseCompare),
                 new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyRegex, System.Object, System.Boolean>(Ruby.Builtins.RegexpOps.CaseCompare),
@@ -3560,6 +3565,15 @@
                 new Microsoft.Scripting.Utils.Function<Ruby.Builtins.RubyRegex, System.Boolean>(Ruby.Builtins.RegexpOps.IsCaseInsensitive),
             });
             
+            module.DefineLibraryMethod("eql?", 0x29, new System.Delegate[] {
+                new Microsoft.Scripting.Utils.Function<Ruby.Builtins.RubyRegex, System.Object, System.Boolean>(Ruby.Builtins.RegexpOps.Equals),
+                new Microsoft.Scripting.Utils.Function<Microsoft.Scripting.Runtime.CodeContext, Ruby.Builtins.RubyRegex, Ruby.Builtins.RubyRegex, System.Boolean>(Ruby.Builtins.RegexpOps.Equals),
+            });
+            
+            module.DefineLibraryMethod("hash", 0x29, new System.Delegate[] {
+                new Microsoft.Scripting.Utils.Function<Ruby.Builtins.RubyRegex, System.Int32>(Ruby.Builtins.RegexpOps.GetHash),
+            });
+            
             module.DefineLibraryMethod("inspect", 0x29, new System.Delegate[] {
                 new Microsoft.Scripting.Utils.Function<Ruby.Builtins.RubyRegex, Ruby.Builtins.MutableString>(Ruby.Builtins.RegexpOps.Inspect),
             });
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyRegexOps.cs;C448505
File: RubyRegexOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyRegexOps.cs;C448505  (server)    5/25/2008 9:51 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyRegexOps.cs;regex3
@@ -28,10 +28,6 @@
         //declared private instance methods:
         //  initialize
         //  initialize_copy
-        //declared public instance methods:
-        //  ==
-        //  eql?
-        //  hash
         
         //------------------------------------------------------------ Regexp::new
         //     Regexp.new(string [, options [, lang]])       => regexp
@@ -144,8 +140,13 @@
             // Ruby: doesn't wrap if there is a single embedded expression that evaluates to non-nil:
             // puts(/#{nil}#{/a/}#{nil}/) 
             // We don't do that.
-            
-            MutableString result = MutableString.CreateMutable();
+
+            return Append(self, MutableString.CreateMutable());
+        }
+
+        private static MutableString/*!*/ Append(RubyRegex/*!*/ self, MutableString/*!*/ result) {
+            Assert.NotNull(self, result);
+
             result.Append("(?");
             if (AppendOptionString(result, self.Options, true, false) < 3) {
                 result.Append('-');
@@ -248,6 +249,21 @@
             return Match(context, self, Protocols.CastToString(context, str), 0);
         }
 
+        [RubyMethod("hash")]
+        public static int GetHash(RubyRegex/*!*/ self) {
+            return self.GetHashCode();
+        }
+        
+        [RubyMethod("=="), RubyMethod("eql?")]
+        public static bool Equals(RubyRegex/*!*/ self, object other) {
+            return false;
+        }
+
+        [RubyMethod("=="), RubyMethod("eql?")]
+        public static bool Equals(CodeContext/*!*/ context, RubyRegex/*!*/ self, [NotNull]RubyRegex/*!*/ other) {
+            return self.Equals(other);
+        }
+
         //-------------------------------------------------------------- Regexp#=~
         //     rxp.match(str)   => matchdata or nil
         //------------------------------------------------------------------------
@@ -376,17 +392,29 @@
         [RubyMethod("union", RubyMethodAttributes.PublicSingleton)]
         public static RubyRegex/*!*/ Union(CodeContext/*!*/ context, object/*!*/ self, [NotNull]params object[]/*!*/ strings) {
 
+            if (strings.Length == 0) {
+                return new RubyRegex("(?!)", RubyRegexOptions.NONE);
+            }
+
             MutableString result = MutableString.CreateMutable();
             for (int i = 0; i < strings.Length; i++) {
-                MutableString str = Protocols.CastToString(context, strings[i]);
                 if (i > 0) {
                     result.Append('|');
                 }
-                result.Append(RubyRegex.Escape(str));
+
+                RubyRegex regex = strings[i] as RubyRegex;
+                if (regex != null) {
+                    if (strings.Length == 1) {
+                        return regex;
+                    }
+
+                    Append(regex, result);
+                } else {
+                    result.Append(RubyRegex.Escape(Protocols.CastToString(context, strings[i])));
+                }
             }
 
             return new RubyRegex(result, RubyRegexOptions.NONE);
         }
-
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.Content.cs;C448472
File: MutableString.Content.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.Content.cs;C448472  (server)    5/25/2008 12:46 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.Content.cs;regex3
@@ -61,6 +61,9 @@
             public abstract byte[]/*!*/ ToByteArray();
             public abstract GenericRegex/*!*/ ToRegularExpression(RubyRegexOptions options);
 
+            // returns self if there are no characters to be escaped:
+            public abstract Content/*!*/ EscapeRegularExpression();
+
             // read:
             public abstract bool IsBinary { get; }
             public abstract int Length { get; }
@@ -173,6 +176,11 @@
                 return new StringRegex(_data, options);
             }
 
+            public override Content/*!*/ EscapeRegularExpression() {
+                StringBuilder sb = StringRegex.EscapeToStringBuilder(_data);
+                return (sb != null) ? new StringContent(_owner, sb.ToString()) : this;
+            }
+
             private BinaryContent/*!*/ ToBinary() {
                 return ToContent(_owner._encoding.GetBytes(_data));
             }                
@@ -489,6 +497,11 @@
                 return new StringRegex(_data.ToString(), options);
             }
 
+            public override Content/*!*/ EscapeRegularExpression() {
+                StringBuilder sb = StringRegex.EscapeToStringBuilder(_data.ToString());
+                return (sb != null) ? new StringBuilderContent(_owner, sb) : this;
+            }
+
             private BinaryContent/*!*/ ToBinary() {
                 return ToContent(_owner._encoding.GetBytes(_data.ToString()));
             }
@@ -834,6 +847,10 @@
                 return new BinaryRegex(_data.ToArray(), options);
             }
 
+            public override Content/*!*/ EscapeRegularExpression() {
+                return new BinaryContent(_owner, new List<byte>(BinaryRegex.Escape(_data.ToArray())));
+            }
+
             private StringBuilderContent/*!*/ ToStringBuilder() {
                 return ToStringBuilder(0);
             }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C444052
File: MutableString.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C444052  (server)    5/25/2008 12:46 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;regex3
@@ -750,6 +750,10 @@
             _content.GetDebugView(out value, out type);
             return type;
         }
+
+        internal MutableString/*!*/ EscapeRegularExpression() {
+            return new MutableString(_content.EscapeRegularExpression(), _encoding);
+        }
         
         #endregion
 
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyRegex.cs;C448505
File: RubyRegex.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyRegex.cs;C448505  (server)    5/24/2008 10:07 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyRegex.cs;regex3
@@ -25,7 +25,7 @@
 using Ruby.Compiler;
 
 namespace Ruby.Builtins {
-    public abstract class GenericRegex {
+    public abstract class GenericRegex  {
         private readonly RubyRegexOptions _options;
 
         public abstract bool IsEmpty { get; }
@@ -36,6 +36,16 @@
         public abstract MatchCollection/*!*/ Matches(MutableString/*!*/ input, int start);
         public abstract MutableString[]/*!*/ Split(MutableString/*!*/ input, int count, int start);
 
+        public bool Equals(GenericRegex/*!*/ other) {
+            // TODO:
+            return Options == other.Options && GetPattern().Equals(other.GetPattern());
+        }
+
+        public override int GetHashCode() {
+            // TODO:
+            return (int)Options ^ GetPattern().GetHashCode();
+        }
+
         protected GenericRegex(RubyRegexOptions options) {
             _options = options;
         }
@@ -69,6 +79,10 @@
         public override MutableString[]/*!*/ Split(MutableString/*!*/ input, int count, int start) {
             throw new NotImplementedException();
         }
+
+        internal static byte[]/*!*/ Escape(byte[]/*!*/ pattern) {
+            throw new NotImplementedException();
+        }
     }
 
     public class StringRegex : GenericRegex {
@@ -122,6 +136,92 @@
             return MutableString.MakeArray(_regex.Split(input.ConvertToString(), count, start));
         }
 
+        private static int SkipNonSpecial(string/*!*/ pattern, int i, out char escaped) {
+            while (i < pattern.Length) {
+                char c = pattern[i];
+                switch (c) {
+                    case '$':
+                    case '^':
+                    case '|':
+                    case '[':
+                    case ']':
+                    case '(':
+                    case ')':
+                    case '\\':
+                    case '.':
+                    case '#':
+                    case '-':
+
+                    case '{':
+                    case '}':
+                    case '*':
+                    case '+':
+                    case '?':
+                        escaped = c;
+                        return i;
+
+                    case '\t':
+                        escaped = 't';
+                        return i;
+
+                    case '\v':
+                        escaped = 'v';
+                        return i;
+
+                    case '\n':
+                        escaped = 'n';
+                        return i;
+
+                    case '\r':
+                        escaped = 'r';
+                        return i;
+
+                    case '\f':
+                        escaped = 'f';
+                        return i;
+                }
+                i++;
+            }
+
+            escaped = '\0';
+            return -1;
+        }
+
+        internal static string/*!*/ Escape(string/*!*/ pattern) {
+            StringBuilder sb = EscapeToStringBuilder(pattern);
+            return (sb != null) ? sb.ToString() : pattern;
+        }
+
+        internal static StringBuilder EscapeToStringBuilder(string/*!*/ pattern) {
+            int first = 0;
+            char escaped;
+            int i = SkipNonSpecial(pattern, 0, out escaped);
+
+            if (i == -1) {
+                return null;
+            }
+
+            StringBuilder result = new StringBuilder(pattern.Length + 1);
+
+            do {
+                Debug.Assert(i < pattern.Length);
+                // pattern[i] needs escape
+
+                result.Append(pattern, first, i - first);
+                result.Append('\\');
+                result.Append(escaped);
+                i++;
+
+                Debug.Assert(i <= pattern.Length);
+
+                first = i;
+                i = SkipNonSpecial(pattern, i, out escaped);
+            } while (i >= 0);
+
+            result.Append(pattern, first, pattern.Length - first);
+            return result;
+        }
+
         private static int SkipWellEscaped(string/*!*/ pattern, int i) {
             while (i < pattern.Length - 1) {
                 if (pattern[i] == '\\') {
@@ -137,6 +237,7 @@
                         case '\\':
                         case '.':
                         case '#':
+                        case '-':
 
                         case '{':
                         case '}':
@@ -259,7 +360,7 @@
         }
     }
 
-    public class RubyRegex : IDuplicable {
+    public class RubyRegex : IDuplicable, IEquatable<RubyRegex> {
         private GenericRegex/*!*/ _regex;
 
         #region Construction
@@ -307,6 +408,18 @@
             return _regex.GetPattern();
         }
 
+        public bool Equals(RubyRegex other) {
+            return ReferenceEquals(this, other) || other != null && _regex.Equals(other._regex);
+        }
+
+        public override bool Equals(object other) {
+            return _regex.Equals(other as RubyRegex);
+        }
+
+        public override int GetHashCode() {
+            return _regex.GetHashCode();
+        }
+
         #region Match, ReverseMatch, Matches, Split
 
         public Match/*!*/ Match(MutableString/*!*/ input) {
@@ -363,7 +476,7 @@
 
         // TODO:
         public static MutableString/*!*/ Escape(MutableString/*!*/ str) {
-            return MutableString.Create(Regex.Escape(str.ConvertToString()));
+            return str.EscapeRegularExpression();
         }
 
         #region IDuplicable Members
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs;C447221
File: RubyUtils.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs;C447221  (server)    5/25/2008 11:57 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs;regex3
@@ -527,7 +527,16 @@
             options.LocalNames = targetScope.GetVisibleLocalNames();
 
             SourceUnit source = ec.Context.CreateSnippet(code.ConvertToString());
-            ScriptCode compiledCode = source.Compile(options, ec.RuntimeErrorSink);
+            ScriptCode compiledCode;
+            try {
+                compiledCode = source.Compile(options, ec.RuntimeErrorSink);
+            } catch (SyntaxError e) {
+                Debug.WriteLine(e.Message, "INSTANCE EVAL ERROR");
+                Debug.WriteLine(new String('-', 50), "INSTANCE EVAL ERROR");
+                Debug.WriteLine(source.GetCode(), "INSTANCE EVAL ERROR");
+                Debug.WriteLine(new String('-', 50), "INSTANCE EVAL ERROR");
+                throw;
+            }
             Debug.Assert(compiledCode != null);
 
             // TODO: this is hack - we need arbitrary signature of the Initialize method:
===================================================================
