edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C480993
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C482116
File: MutableStringOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C482116  (server)    6/30/2008 5:26 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;StringGsubWithPattern
@@ -1668,7 +1668,7 @@
                 result.Append('\\');
         }
 
-        private static void AppendReplacementExpression(GroupCollection/*!*/ groups, MutableString/*!*/ result, MutableString/*!*/ replacement) {
+        private static void AppendReplacementExpression(MutableString input, GroupCollection/*!*/ groups, MutableString/*!*/ result, MutableString/*!*/ replacement) {
             int backslashCount = 0;
             for (int i = 0; i < replacement.Length; i++) {
                 char c = replacement.GetChar(i);
@@ -1677,12 +1677,28 @@
                 else if (backslashCount == 0)
                     result.Append(c);
                 else {
+                    AppendBackslashes(backslashCount, result, 0);
                     // Odd number of \'s + digit means insert replacement expression
-                    if (Char.IsDigit(c) && ((backslashCount & 1) == 1)) {
-                        int group = (c - '0');
-                        AppendBackslashes(backslashCount, result, 0);
-                        if (groups[group].Success)
-                            result.Append(groups[group].Value);
+                    if ((backslashCount & 1) == 1) {
+                        if (Char.IsDigit(c)) {
+                            AppendGroupByIndex(groups, c - '0', backslashCount, result);
+                        } else if (c == '&') {
+                            AppendGroupByIndex(groups, groups.Count - 1, backslashCount, result);
+                        } else if (c == '`') {
+                            // Replace with everything in the input string BEFORE the match
+                            result.Append(input, 0, groups[0].Index);
+                        } else if (c == '\'') {
+                            // Replace with everything in the input string AFTER the match
+                            int start = groups[0].Index + groups[0].Length;
+                            result.Append(input, start, input.Length - start);
+                        } else if (c == '+') {
+                            // Replace last character in last successful match group
+                            AppendLastCharOfLastMatchGroup(groups, result);
+                        } else {
+                            // unknown escaped replacement char, go ahead and replace untouched
+                            result.Append('\\');
+                            result.Append(c);
+                        }
                     } else {
                         // Any other # of \'s or a non-digit character means insert literal \'s and character
                         AppendBackslashes(backslashCount, result, 1);
@@ -1691,15 +1707,30 @@
                     backslashCount = 0;
                 }
             }
+            AppendBackslashes(backslashCount, result, 1);
         }
 
-        private static void AppendReplacementExpression(MatchData/*!*/ match, MutableString/*!*/ result, MutableString/*!*/ replacement) {
-            AppendReplacementExpression(match.Groups, result, replacement);
+        private static void AppendLastCharOfLastMatchGroup(GroupCollection groups, MutableString result) {
+            int i = groups.Count - 1;
+            // move to last successful match group
+            while (i > 0) { if (groups[i].Success) break; else i--;}
+            if (i > 0 && groups[i].Value.Length > 0) {
+                result.Append(groups[i].Value.ToCharArray()[groups[i].Length - 1]);
+            }
         }
 
+        private static void AppendGroupByIndex(GroupCollection/*!*/ groups, int index, int backslashCount, MutableString/*!*/ result) {
+            if (groups[index].Success)
+                result.Append(groups[index].Value);
+        }
+
+        private static void AppendReplacementExpression(MutableString/*!*/ input, MatchData/*!*/ match, MutableString/*!*/ result, MutableString/*!*/ replacement) {
+            AppendReplacementExpression(input, match.Groups, result, replacement);
+        }
+
         // TODO: we have two overloads right now because we haven't unified Matches to return a List<MatchData> yet ...
-        private static void AppendReplacementExpression(Match/*!*/ match, MutableString/*!*/ result, MutableString/*!*/ replacement) {
-            AppendReplacementExpression(match.Groups, result, replacement);
+        private static void AppendReplacementExpression(MutableString/*!*/ input, Match/*!*/ match, MutableString/*!*/ result, MutableString/*!*/ replacement) {
+            AppendReplacementExpression(input, match.Groups, result, replacement);
         }
 
         private static MutableString ReplaceN(CodeContext/*!*/ context, MutableString/*!*/ input, MutableString/*!*/ replacement, 
@@ -1721,7 +1752,7 @@
                 result = createSubclass ? CreateSubClass(context, input) : input.GetSlice(0, 0);
 
                 result.Append(input.GetSlice(0, match.Index - offset));
-                AppendReplacementExpression(match, result, replacement);
+                AppendReplacementExpression(input, match, result, replacement);
                 offset = match.Index + match.Length;
             } else if (count == -1) {
                 // case of all
@@ -1735,7 +1766,7 @@
 
                 foreach (Match current in matches) {
                     result.Append(input.GetSlice(offset, current.Index - offset));
-                    AppendReplacementExpression(current, result, replacement);
+                    AppendReplacementExpression(input, current, result, replacement);
                     offset = current.Index + current.Length;
                     match = new MatchData(current, input);
                 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/gsub_excludes.txt;C452676
File: gsub_excludes.txt
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/gsub_excludes.txt;C452676  (server)    7/1/2008 5:04 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Specs/core/string/.spec/gsub_excludes.txt;StringGsubWithPattern
@@ -1,10 +1,3 @@
-String#gsub with pattern, replacement replaces \& and \0 with the complete match
-String#gsub with pattern, replacement replaces \` with everything before the current match
-String#gsub with pattern, replacement replaces \' with everything after the current match
-String#gsub with pattern, replacement replaces \+ with the last paren that actually matched
-String#gsub with pattern, replacement treats \+ as an empty string if there was no captures
-String#gsub with pattern, replacement maps \\ in replacement to \
-String#gsub with pattern, replacement leaves \ at the end of replacement untouched
 String#gsub with pattern and block sets $~ for access from the block
 String#gsub with pattern and block restores $~ after leaving the block
 String#gsub with pattern and block sets $~ to MatchData of last match and nil when there's none for access from outside
===================================================================
