String.replace do not support function as second paramater

Hi,

String.replace do not support function as second paramater,
Are there any plans to implement it

Here is my implementation (version 2 add support for replacement patterns):
I used to test it samples from MDN and:

Escape special symbols when EcmaScriptRegexpObject is created internally

        static Regex StringReplacementPlaceHolders = new Regex("(\\$[`'&])|(\\$([1-9]{1}(?![0-9])|[0-9]{2}))", RegexOptions.Compiled);

        static string FixRexExpSymbols(string pattern)
        {
            if (string.IsNullOrWhiteSpace(pattern))
            {
                return pattern ?? string.Empty;
            }

            string[] symbols = new[] { "\\", "[", "]", "^", "!", "|", "$", "?", "=", "{", "}", "+", "*", "(", ")" };
            for (int i = 0, l = symbols.Length; i < l; i++)
            {
                pattern = pattern.Replace(symbols[i], "\\" + symbols[i]);
            }
            return pattern;
        }

        public object StringReplace(ExecutionContext aCaller, object aSelf, params object[] args)
        {
            MatchEvaluator lEvaluator = null;
            string lNewValue = null; List<Match> lReplacementPlaceHolders = null;
            var lSelf = Utilities.GetObjAsString(aSelf, aCaller) ?? string.Empty;
            if (0 == args.Length)
            {
                return lSelf;
            }

            var arg_0 = Utilities.GetArg(args, 0);
            if (null == arg_0 || Undefined.Instance == arg_0)
            {
                return lSelf;
            }

            var arg_1 = Utilities.GetArg(args, 1);
            var lCallBack = arg_1 as EcmaScriptInternalFunctionObject;
            if (null == lCallBack)
                lNewValue = Utilities.GetObjAsString(arg_1, aCaller) ?? string.Empty;

            if (!string.IsNullOrWhiteSpace(lNewValue))
            {
                lReplacementPlaceHolders = ExtractMatchPlaceHolders(lNewValue);
            }

            var lPattern = arg_0 as EcmaScriptRegexpObject;
            if (lPattern == null && (lCallBack != null || lReplacementPlaceHolders != null))
            {
                lPattern = new EcmaScriptRegexpObject(aCaller.Global, FixRexExpSymbols(Utilities.GetObjAsString(arg_0, aCaller)), string.Empty);
            }

            if (lCallBack != null || lReplacementPlaceHolders != null)
            {
                if (lReplacementPlaceHolders == null)
                {
                    object[] lCallBackArgs = null; int groups = 0;
                    lEvaluator = (Match match) =>
                        {
                            if (null == lCallBackArgs)
                            {
                                groups = match.Groups.Count;
                                lCallBackArgs = new object[groups + 2];
                                lCallBackArgs[lCallBackArgs.Length - 1] = lSelf;
                            }

                            for (var i = 0; i < groups; i++)
                            {
                                if (i == 0)
                                {
                                    lCallBackArgs[lCallBackArgs.Length - 2] = match.Groups[i].Index;
                                }
                                lCallBackArgs[i] = match.Groups[i].Success ? (object)match.Groups[i].Value : Undefined.Instance;
                            }

                            var replacment = Utilities.GetObjAsString(lCallBack.CallEx(aCaller, aCaller.Global, lCallBackArgs), aCaller);

                            return replacment;
                        };
                }
                else
                {
                    var text = new StringBuilder(); var lSelfIndex = 0;
                    lEvaluator = (Match match) =>
                    {
                        text.Length = 0;
                        var index = 0; var matchIndex = 0; var matchCount = match.Groups.Count;
                        foreach (var m in lReplacementPlaceHolders)
                        {
                            text.Append(lNewValue.Substring(index, m.Index - index).Replace("$$", "$"));//and remove escape symbols
                            switch (m.Value)
                            {
                                case "$`"://Inserts the portion of the string that precedes the matched substring.
                                    text.Append(lSelf.Substring(0, match.Index));
                                    break;
                                case "$'"://Inserts the portion of the string that follows the matched substring.
                                    index = match.Index + match.Value.Length;
                                    if (index < lSelf.Length)
                                    {
                                        text.Append(lSelf.Substring(index));
                                    }
                                    break;
                                case "$&":
                                    text.Append(match.Groups[0].Value);
                                    break;
                                default:
                                    matchIndex = int.Parse(m.Value.Substring(1));
                                    if (matchIndex < matchCount)
                                    {
                                        text.Append(match.Groups[matchIndex].Value);
                                    }
                                    break;
                            }
                            index = m.Index + m.Value.Length;
                        }

                        if (index < lNewValue.Length)
                        {
                            text.Append(lNewValue.Substring(index).Replace("$$", "$"));//and remove escape symbols
                        }

                        lSelfIndex = match.Groups[0].Index + match.Groups[0].Value.Length;

                        return text.ToString();
                    };
                }

                if (lPattern.GlobalVal)
                {
                    lSelf = lPattern.Regex.Replace(lSelf, lEvaluator);
                }
                else
                {
                    lSelf = lPattern.Regex.Replace(lSelf, lEvaluator, 1);
                }
                return lSelf;
            }
            else
            {
                if (lPattern == null)
                {
                    // this will replace all occurrence
                    return lSelf.Replace(Utilities.GetObjAsString(arg_0, aCaller), lNewValue);
                }

                if (lPattern.GlobalVal)
                    return (lPattern.Regex.Replace(lSelf, lNewValue));
                else
                    return (lPattern.Regex.Replace(lSelf, lNewValue, 1));
            }
        }

        static List<Match> ExtractMatchPlaceHolders(string value)
        {
            var replacementPlaceHolders = (List<Match>)null;
            foreach (Match m in StringReplacementPlaceHolders.Matches(value))
            {
                if (m.Success)
                {
                    var i = m.Index; int count = 1; int result = 0;
                    while (i > 0)
                    {
                        --i;
                        if (value[i] != '$')
                        {
                            break;
                        }
                        ++count;
                    }

                    Math.DivRem(count, 2, out result);
                    if (result != 0)
                    {
                        if (null == replacementPlaceHolders)
                        {
                            replacementPlaceHolders = new List<Match>();
                        }
                        replacementPlaceHolders.Add(m);
                    }
                }
            }
            return replacementPlaceHolders;
        }

Thanks, logged as bugs://77216

bugs://77216 got closed with status fixed.