From 3855e456805f29987ef521f832fff4be8bc9aaa0 Mon Sep 17 00:00:00 2001 From: Ilya Date: Sun, 22 Nov 2020 22:57:07 +0500 Subject: [PATCH 01/13] Opimize IEnumerable variant of replace operator --- .../engine/lang/parserutils.cs | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 217e348bfde..8c6f5cb95d5 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -965,6 +965,8 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } + MatchEvaluator cachedMatchEvaluator = null; + string cachedReplacementString = null; IEnumerator list = LanguagePrimitives.GetEnumerator(lval); if (list == null) { @@ -978,7 +980,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e lvalString = lval?.ToString() ?? string.Empty; } - return ReplaceOperatorImpl(context, lvalString, rr, substitute); + return ReplaceOperatorImpl(context, lvalString, rr, substitute, ref cachedReplacementString, ref cachedMatchEvaluator); } else { @@ -986,7 +988,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e while (ParserOps.MoveNext(context, errorPosition, list)) { string lvalString = PSObject.ToStringParser(context, ParserOps.Current(errorPosition, list)); - resultList.Add(ReplaceOperatorImpl(context, lvalString, rr, substitute)); + resultList.Add(ReplaceOperatorImpl(context, lvalString, rr, substitute, ref cachedReplacementString, ref cachedMatchEvaluator)); } return resultList.ToArray(); @@ -1002,24 +1004,44 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e /// The input string. /// A Regex instance. /// The substitute value. + /// Cached replacement string. + /// Cached MatchEvaluator. /// The result of the regex.Replace operation. - private static object ReplaceOperatorImpl(ExecutionContext context, string input, Regex regex, object substitute) + private static object ReplaceOperatorImpl( + ExecutionContext context, + string input, + Regex regex, + object substitute, + ref string cachedReplacementString, + ref MatchEvaluator cachedMatchEvaluator) { + // After first call we will have necessarily either cachedReplacementString or cachedMatchEvaluator. + if (cachedReplacementString is not null) + { + return regex.Replace(input, cachedReplacementString); + } + + if (cachedMatchEvaluator is not null) + { + return regex.Replace(input, cachedMatchEvaluator); + } + switch (substitute) { - case string replacementString: - return regex.Replace(input, replacementString); + case string replacement: + cachedReplacementString = replacement; + return regex.Replace(input, cachedReplacementString); case ScriptBlock sb: - MatchEvaluator me = GetMatchEvaluator(context, sb); - return regex.Replace(input, me); + cachedMatchEvaluator = GetMatchEvaluator(context, sb); + return regex.Replace(input, cachedMatchEvaluator); - case object val when LanguagePrimitives.TryConvertTo(val, out MatchEvaluator matchEvaluator): - return regex.Replace(input, matchEvaluator); + case object val when LanguagePrimitives.TryConvertTo(val, out cachedMatchEvaluator): + return regex.Replace(input, cachedMatchEvaluator); default: - string replacement = PSObject.ToStringParser(context, substitute); - return regex.Replace(input, replacement); + cachedReplacementString = PSObject.ToStringParser(context, substitute); + return regex.Replace(input, cachedReplacementString); } // Local helper function to avoid creating an instance of the generated delegate helper class From 4b272442a1b525fda6646d30279e27edbff728c8 Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 3 Dec 2020 22:39:05 +0500 Subject: [PATCH 02/13] Add test --- .../Language/Operators/ReplaceOperator.Tests.ps1 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 b/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 index 59d7039898a..a4b5d21c245 100644 --- a/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 +++ b/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 @@ -29,6 +29,18 @@ Describe "Replace Operator" -Tags CI { $res = "PowerPoint" -replace "Point" $res | Should -BeExactly "Power" } + + It "Replace operator can take an enumerable as first argument, a mandatory pattern, and an optional substitution" { + $res = "PowerPoint1","PowerPoint2" -replace "Point","Shell" + $res.Count | Should -Be 2 + $res[0] | Should -BeExactly "PowerShell1" + $res[1] | Should -BeExactly "PowerShell2" + + $res = "PowerPoint1","PowerPoint2" -replace "Point" + $res.Count | Should -Be 2 + $res[0] | Should -BeExactly "Power1" + $res[1] | Should -BeExactly "Power2" + } } Context "Replace operator substitutions" { From 325a6db9dd39a9c4f7bf0eb81ff34883008406a1 Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 3 Dec 2020 23:45:44 +0500 Subject: [PATCH 03/13] Refactor with OperatorReplacer struct --- .../engine/lang/parserutils.cs | 121 ++++++++++-------- 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 8c6f5cb95d5..fa99af19b4f 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -965,8 +965,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - MatchEvaluator cachedMatchEvaluator = null; - string cachedReplacementString = null; + var replacer = OperatorReplacer.Create(context); IEnumerator list = LanguagePrimitives.GetEnumerator(lval); if (list == null) { @@ -980,7 +979,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e lvalString = lval?.ToString() ?? string.Empty; } - return ReplaceOperatorImpl(context, lvalString, rr, substitute, ref cachedReplacementString, ref cachedMatchEvaluator); + return replacer.ReplaceOperator(lvalString, rr, substitute); } else { @@ -988,78 +987,88 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e while (ParserOps.MoveNext(context, errorPosition, list)) { string lvalString = PSObject.ToStringParser(context, ParserOps.Current(errorPosition, list)); - resultList.Add(ReplaceOperatorImpl(context, lvalString, rr, substitute, ref cachedReplacementString, ref cachedMatchEvaluator)); + resultList.Add(replacer.ReplaceOperator(lvalString, rr, substitute)); } return resultList.ToArray(); } } - /// - /// ReplaceOperator implementation. - /// Abstracts away conversion of the optional substitute parameter to either a string or a MatchEvaluator delegate - /// and finally returns the result of the final Regex.Replace operation. - /// - /// The execution context in which to evaluate the expression. - /// The input string. - /// A Regex instance. - /// The substitute value. - /// Cached replacement string. - /// Cached MatchEvaluator. - /// The result of the regex.Replace operation. - private static object ReplaceOperatorImpl( - ExecutionContext context, - string input, - Regex regex, - object substitute, - ref string cachedReplacementString, - ref MatchEvaluator cachedMatchEvaluator) + private struct OperatorReplacer { - // After first call we will have necessarily either cachedReplacementString or cachedMatchEvaluator. - if (cachedReplacementString is not null) + public static OperatorReplacer Create(ExecutionContext context) { - return regex.Replace(input, cachedReplacementString); + return new OperatorReplacer(context, replacementString: null, matchEvaluator: null); } - if (cachedMatchEvaluator is not null) + private readonly ExecutionContext _context; + + private string _cachedReplacementString; + + private MatchEvaluator _cachedMatchEvaluator; + + private OperatorReplacer( + ExecutionContext context, + string replacementString, + MatchEvaluator matchEvaluator) { - return regex.Replace(input, cachedMatchEvaluator); + _context = context; + _cachedReplacementString = replacementString; + _cachedMatchEvaluator = matchEvaluator; } - switch (substitute) + /// + /// ReplaceOperator implementation. + /// Abstracts away conversion of the optional substitute parameter to either a string or a MatchEvaluator delegate + /// and finally returns the result of the final Regex.Replace operation. + /// + public object ReplaceOperator(string input, Regex regex, object substitute) { - case string replacement: - cachedReplacementString = replacement; - return regex.Replace(input, cachedReplacementString); + if (_cachedReplacementString is not null) + { + return regex.Replace(input, _cachedReplacementString); + } - case ScriptBlock sb: - cachedMatchEvaluator = GetMatchEvaluator(context, sb); - return regex.Replace(input, cachedMatchEvaluator); + if (_cachedMatchEvaluator is not null) + { + return regex.Replace(input, _cachedMatchEvaluator); + } - case object val when LanguagePrimitives.TryConvertTo(val, out cachedMatchEvaluator): - return regex.Replace(input, cachedMatchEvaluator); + switch (substitute) + { + case string replacement: + _cachedReplacementString = replacement; + return regex.Replace(input, _cachedReplacementString); - default: - cachedReplacementString = PSObject.ToStringParser(context, substitute); - return regex.Replace(input, cachedReplacementString); - } + case ScriptBlock sb: + _cachedMatchEvaluator = GetMatchEvaluator(_context, sb); + return regex.Replace(input, _cachedMatchEvaluator); - // Local helper function to avoid creating an instance of the generated delegate helper class - // every time 'ReplaceOperatorImpl' is invoked. - static MatchEvaluator GetMatchEvaluator(ExecutionContext context, ScriptBlock sb) - { - return match => - { - var result = sb.DoInvokeReturnAsIs( - useLocalScope: false, /* Use current scope to be consistent with 'ForEach/Where-Object {}' and 'collection.ForEach{}/Where{}' */ - errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe, - dollarUnder: match, - input: AutomationNull.Value, - scriptThis: AutomationNull.Value, - args: Array.Empty()); + case object val when LanguagePrimitives.TryConvertTo(val, out _cachedMatchEvaluator): + return regex.Replace(input, _cachedMatchEvaluator); - return PSObject.ToStringParser(context, result); - }; + default: + _cachedReplacementString = PSObject.ToStringParser(_context, substitute); + return regex.Replace(input, _cachedReplacementString); + } + + // Local helper function to avoid creating an instance of the generated delegate helper class + // every time 'ReplaceOperatorImpl' is invoked. + static MatchEvaluator GetMatchEvaluator(ExecutionContext context, ScriptBlock sb) + { + return match => + { + var result = sb.DoInvokeReturnAsIs( + useLocalScope: false, /* Use current scope to be consistent with 'ForEach/Where-Object {}' and 'collection.ForEach{}/Where{}' */ + errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe, + dollarUnder: match, + input: AutomationNull.Value, + scriptThis: AutomationNull.Value, + args: Array.Empty()); + + return PSObject.ToStringParser(context, result); + }; + } } } From b2a17ffa543fc6ad11b2b99089ae0f0b4159c394 Mon Sep 17 00:00:00 2001 From: Ilya Date: Fri, 4 Dec 2020 00:51:38 +0500 Subject: [PATCH 04/13] Refactor with OperatorReplacer struct --- .../engine/lang/parserutils.cs | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index fa99af19b4f..51b094b2d78 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -965,7 +965,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - var replacer = OperatorReplacer.Create(context); + var replacer = OperatorReplacer.Create(context, rr, substitute); IEnumerator list = LanguagePrimitives.GetEnumerator(lval); if (list == null) { @@ -979,7 +979,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e lvalString = lval?.ToString() ?? string.Empty; } - return replacer.ReplaceOperator(lvalString, rr, substitute); + return replacer.Replace(lvalString); } else { @@ -987,7 +987,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e while (ParserOps.MoveNext(context, errorPosition, list)) { string lvalString = PSObject.ToStringParser(context, ParserOps.Current(errorPosition, list)); - resultList.Add(replacer.ReplaceOperator(lvalString, rr, substitute)); + resultList.Add(replacer.Replace(lvalString)); } return resultList.ToArray(); @@ -996,12 +996,13 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e private struct OperatorReplacer { - public static OperatorReplacer Create(ExecutionContext context) + public static OperatorReplacer Create(ExecutionContext context, Regex regex, object substitute) { - return new OperatorReplacer(context, replacementString: null, matchEvaluator: null); + return new OperatorReplacer(context, regex, substitute, replacementString: null, matchEvaluator: null); } private readonly ExecutionContext _context; + private readonly Regex _regex; private string _cachedReplacementString; @@ -1009,47 +1010,32 @@ public static OperatorReplacer Create(ExecutionContext context) private OperatorReplacer( ExecutionContext context, + Regex regex, + object substitute, string replacementString, MatchEvaluator matchEvaluator) { _context = context; + _regex = regex; _cachedReplacementString = replacementString; _cachedMatchEvaluator = matchEvaluator; - } - - /// - /// ReplaceOperator implementation. - /// Abstracts away conversion of the optional substitute parameter to either a string or a MatchEvaluator delegate - /// and finally returns the result of the final Regex.Replace operation. - /// - public object ReplaceOperator(string input, Regex regex, object substitute) - { - if (_cachedReplacementString is not null) - { - return regex.Replace(input, _cachedReplacementString); - } - - if (_cachedMatchEvaluator is not null) - { - return regex.Replace(input, _cachedMatchEvaluator); - } switch (substitute) { case string replacement: _cachedReplacementString = replacement; - return regex.Replace(input, _cachedReplacementString); + break; case ScriptBlock sb: _cachedMatchEvaluator = GetMatchEvaluator(_context, sb); - return regex.Replace(input, _cachedMatchEvaluator); + break; case object val when LanguagePrimitives.TryConvertTo(val, out _cachedMatchEvaluator): - return regex.Replace(input, _cachedMatchEvaluator); + break; default: _cachedReplacementString = PSObject.ToStringParser(_context, substitute); - return regex.Replace(input, _cachedReplacementString); + break; } // Local helper function to avoid creating an instance of the generated delegate helper class @@ -1070,6 +1056,25 @@ static MatchEvaluator GetMatchEvaluator(ExecutionContext context, ScriptBlock sb }; } } + + /// + /// ReplaceOperator implementation. + /// Abstracts away conversion of the optional substitute parameter to either a string or a MatchEvaluator delegate + /// and finally returns the result of the final Regex.Replace operation. + /// + public object Replace(string input) + { + if (_cachedReplacementString is not null) + { + return _regex.Replace(input, _cachedReplacementString); + } + else + { + // if (_cachedMatchEvaluator is not null) + return _regex.Replace(input, _cachedMatchEvaluator); + } + + } } /// From f017610c80793ab74042adf66dbf0339f153b9b2 Mon Sep 17 00:00:00 2001 From: Ilya Date: Fri, 4 Dec 2020 11:21:59 +0500 Subject: [PATCH 05/13] Address feedback 2 and add new test --- .../engine/lang/parserutils.cs | 50 +++++++++---------- .../Operators/ReplaceOperator.Tests.ps1 | 6 +++ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 51b094b2d78..82b39f8d294 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -965,7 +965,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - var replacer = OperatorReplacer.Create(context, rr, substitute); + var replacer = ReplacerOperator.Create(context, rr, substitute); IEnumerator list = LanguagePrimitives.GetEnumerator(lval); if (list == null) { @@ -994,28 +994,24 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - private struct OperatorReplacer + private struct ReplacerOperator { - public static OperatorReplacer Create(ExecutionContext context, Regex regex, object substitute) + public static ReplacerOperator Create(ExecutionContext context, Regex regex, object substitute) { - return new OperatorReplacer(context, regex, substitute, replacementString: null, matchEvaluator: null); + return new ReplacerOperator(context, regex, substitute, replacementString: null, matchEvaluator: null); } - private readonly ExecutionContext _context; private readonly Regex _regex; - private string _cachedReplacementString; - private MatchEvaluator _cachedMatchEvaluator; - private OperatorReplacer( + private ReplacerOperator( ExecutionContext context, Regex regex, object substitute, string replacementString, MatchEvaluator matchEvaluator) { - _context = context; _regex = regex; _cachedReplacementString = replacementString; _cachedMatchEvaluator = matchEvaluator; @@ -1027,34 +1023,34 @@ private OperatorReplacer( break; case ScriptBlock sb: - _cachedMatchEvaluator = GetMatchEvaluator(_context, sb); + _cachedMatchEvaluator = GetMatchEvaluator(context, sb); break; case object val when LanguagePrimitives.TryConvertTo(val, out _cachedMatchEvaluator): break; default: - _cachedReplacementString = PSObject.ToStringParser(_context, substitute); + _cachedReplacementString = PSObject.ToStringParser(context, substitute); break; } + } - // Local helper function to avoid creating an instance of the generated delegate helper class - // every time 'ReplaceOperatorImpl' is invoked. - static MatchEvaluator GetMatchEvaluator(ExecutionContext context, ScriptBlock sb) + // Local helper function to avoid creating an instance of the generated delegate helper class + // every time 'ReplaceOperatorImpl' is invoked. + private static MatchEvaluator GetMatchEvaluator(ExecutionContext context, ScriptBlock sb) + { + return match => { - return match => - { - var result = sb.DoInvokeReturnAsIs( - useLocalScope: false, /* Use current scope to be consistent with 'ForEach/Where-Object {}' and 'collection.ForEach{}/Where{}' */ - errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe, - dollarUnder: match, - input: AutomationNull.Value, - scriptThis: AutomationNull.Value, - args: Array.Empty()); - - return PSObject.ToStringParser(context, result); - }; - } + var result = sb.DoInvokeReturnAsIs( + useLocalScope: false, /* Use current scope to be consistent with 'ForEach/Where-Object {}' and 'collection.ForEach{}/Where{}' */ + errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe, + dollarUnder: match, + input: AutomationNull.Value, + scriptThis: AutomationNull.Value, + args: Array.Empty()); + + return PSObject.ToStringParser(context, result); + }; } /// diff --git a/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 b/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 index a4b5d21c245..83cc24d3863 100644 --- a/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 +++ b/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 @@ -11,6 +11,12 @@ Describe "Replace Operator" -Tags CI { $res | Should -BeExactly "image.jpg" } + It "Replace operator can convert an substitution object to string" { + $substitution = Get-Process -Name pwsh + $res = "!3!" -replace "3",$substitution + $res | Should -BeExactly "!System.Diagnostics.Process (pwsh)!" + } + It "Replace operator can be case-insensitive and case-sensitive" { $res = "book" -replace "B","C" $res | Should -BeExactly "Cook" From 86ce89e0611592a3db45c3c8d370876f32068dd5 Mon Sep 17 00:00:00 2001 From: Ilya Date: Fri, 4 Dec 2020 11:23:13 +0500 Subject: [PATCH 06/13] Fix comment --- src/System.Management.Automation/engine/lang/parserutils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 82b39f8d294..c0606315873 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -1066,7 +1066,7 @@ public object Replace(string input) } else { - // if (_cachedMatchEvaluator is not null) + // _cachedMatchEvaluator is not null when code reach here. return _regex.Replace(input, _cachedMatchEvaluator); } From be67a629645de5eb57cbff35fbb11da9c5f6ab77 Mon Sep 17 00:00:00 2001 From: Ilya Date: Fri, 4 Dec 2020 11:25:52 +0500 Subject: [PATCH 07/13] Address feedback 3 --- .../engine/lang/parserutils.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index c0606315873..ef249554508 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -1064,12 +1064,9 @@ public object Replace(string input) { return _regex.Replace(input, _cachedReplacementString); } - else - { - // _cachedMatchEvaluator is not null when code reach here. - return _regex.Replace(input, _cachedMatchEvaluator); - } + // _cachedMatchEvaluator is not null when code reach here. + return _regex.Replace(input, _cachedMatchEvaluator); } } From 686f25f9e864daefce0e657e3b26bf547fc8c806 Mon Sep 17 00:00:00 2001 From: Ilya Date: Fri, 4 Dec 2020 11:31:52 +0500 Subject: [PATCH 08/13] Replace comment with assert --- src/System.Management.Automation/engine/lang/parserutils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index ef249554508..f6f8ce1d126 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -1065,7 +1065,7 @@ public object Replace(string input) return _regex.Replace(input, _cachedReplacementString); } - // _cachedMatchEvaluator is not null when code reach here. + Dbg.Assert(_cachedMatchEvaluator is not null, "_cachedMatchEvaluator should be not null when code reach here."); return _regex.Replace(input, _cachedMatchEvaluator); } } From 58016c1315c8c2596c152946a85af9b6911735e5 Mon Sep 17 00:00:00 2001 From: Ilya Date: Sat, 5 Dec 2020 08:13:13 +0500 Subject: [PATCH 09/13] Address feedback 4 --- .../engine/lang/parserutils.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index f6f8ce1d126..1d0be18d7eb 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -998,7 +998,7 @@ private struct ReplacerOperator { public static ReplacerOperator Create(ExecutionContext context, Regex regex, object substitute) { - return new ReplacerOperator(context, regex, substitute, replacementString: null, matchEvaluator: null); + return new ReplacerOperator(context, regex, substitute); } private readonly Regex _regex; @@ -1008,13 +1008,11 @@ public static ReplacerOperator Create(ExecutionContext context, Regex regex, obj private ReplacerOperator( ExecutionContext context, Regex regex, - object substitute, - string replacementString, - MatchEvaluator matchEvaluator) + object substitute) { _regex = regex; - _cachedReplacementString = replacementString; - _cachedMatchEvaluator = matchEvaluator; + _cachedReplacementString = null; + _cachedMatchEvaluator = null; switch (substitute) { From 8560f1145da0a56f41bc35be57435bf441aa6252 Mon Sep 17 00:00:00 2001 From: Ilya Date: Wed, 9 Dec 2020 08:40:39 +0500 Subject: [PATCH 10/13] Update test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 Co-authored-by: Dongbo Wang --- test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 b/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 index 83cc24d3863..b72779f59c4 100644 --- a/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 +++ b/test/powershell/Language/Operators/ReplaceOperator.Tests.ps1 @@ -12,7 +12,7 @@ Describe "Replace Operator" -Tags CI { } It "Replace operator can convert an substitution object to string" { - $substitution = Get-Process -Name pwsh + $substitution = Get-Process -Id $pid $res = "!3!" -replace "3",$substitution $res | Should -BeExactly "!System.Diagnostics.Process (pwsh)!" } From 72a5a644fc0a6bfb4b5f98f07f58873328c863e6 Mon Sep 17 00:00:00 2001 From: Ilya Date: Wed, 9 Dec 2020 08:40:59 +0500 Subject: [PATCH 11/13] Update src/System.Management.Automation/engine/lang/parserutils.cs Co-authored-by: Dongbo Wang --- src/System.Management.Automation/engine/lang/parserutils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 1d0be18d7eb..407cac7e5ba 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -1002,8 +1002,8 @@ public static ReplacerOperator Create(ExecutionContext context, Regex regex, obj } private readonly Regex _regex; - private string _cachedReplacementString; - private MatchEvaluator _cachedMatchEvaluator; + private readonly string _cachedReplacementString; + private readonly MatchEvaluator _cachedMatchEvaluator; private ReplacerOperator( ExecutionContext context, From 388a304a67acb945e8f98dd1f72f07316c3566a2 Mon Sep 17 00:00:00 2001 From: Ilya Date: Wed, 9 Dec 2020 08:42:35 +0500 Subject: [PATCH 12/13] Rename ReplacerOperator --- .../engine/lang/parserutils.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 407cac7e5ba..4a30f854ccf 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -965,7 +965,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - var replacer = ReplacerOperator.Create(context, rr, substitute); + var replacer = ReplaceOperator.Create(context, rr, substitute); IEnumerator list = LanguagePrimitives.GetEnumerator(lval); if (list == null) { @@ -994,18 +994,18 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - private struct ReplacerOperator + private struct ReplaceOperator { - public static ReplacerOperator Create(ExecutionContext context, Regex regex, object substitute) + public static ReplaceOperator Create(ExecutionContext context, Regex regex, object substitute) { - return new ReplacerOperator(context, regex, substitute); + return new ReplaceOperator(context, regex, substitute); } private readonly Regex _regex; private readonly string _cachedReplacementString; private readonly MatchEvaluator _cachedMatchEvaluator; - private ReplacerOperator( + private ReplaceOperator( ExecutionContext context, Regex regex, object substitute) From 028fd2f537d3f1cb301d65e0ab0bf8156fda019b Mon Sep 17 00:00:00 2001 From: Ilya Date: Wed, 9 Dec 2020 23:55:35 +0500 Subject: [PATCH 13/13] Use ReplaceOperatorImpl name --- .../engine/lang/parserutils.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/lang/parserutils.cs b/src/System.Management.Automation/engine/lang/parserutils.cs index 4a30f854ccf..52c64400ccd 100644 --- a/src/System.Management.Automation/engine/lang/parserutils.cs +++ b/src/System.Management.Automation/engine/lang/parserutils.cs @@ -965,7 +965,7 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - var replacer = ReplaceOperator.Create(context, rr, substitute); + var replacer = ReplaceOperatorImpl.Create(context, rr, substitute); IEnumerator list = LanguagePrimitives.GetEnumerator(lval); if (list == null) { @@ -994,18 +994,18 @@ internal static object ReplaceOperator(ExecutionContext context, IScriptExtent e } } - private struct ReplaceOperator + private struct ReplaceOperatorImpl { - public static ReplaceOperator Create(ExecutionContext context, Regex regex, object substitute) + public static ReplaceOperatorImpl Create(ExecutionContext context, Regex regex, object substitute) { - return new ReplaceOperator(context, regex, substitute); + return new ReplaceOperatorImpl(context, regex, substitute); } private readonly Regex _regex; private readonly string _cachedReplacementString; private readonly MatchEvaluator _cachedMatchEvaluator; - private ReplaceOperator( + private ReplaceOperatorImpl( ExecutionContext context, Regex regex, object substitute)