diff --git a/src/System.Management.Automation/engine/AutomationEngine.cs b/src/System.Management.Automation/engine/AutomationEngine.cs index 279bab545ab..58e490759a6 100644 --- a/src/System.Management.Automation/engine/AutomationEngine.cs +++ b/src/System.Management.Automation/engine/AutomationEngine.cs @@ -62,19 +62,19 @@ internal string Expand(string s) /// Compile a piece of text into a parse tree for later execution. /// /// The text to parse - /// + /// true iff the scriptblock will be added to history /// The parse text as a parsetree node. - internal ScriptBlock ParseScriptBlock(string script, bool interactiveCommand) + internal ScriptBlock ParseScriptBlock(string script, bool addToHistory) { - return ParseScriptBlock(script, null, interactiveCommand); + return ParseScriptBlock(script, null, addToHistory); } - internal ScriptBlock ParseScriptBlock(string script, string fileName, bool interactiveCommand) + internal ScriptBlock ParseScriptBlock(string script, string fileName, bool addToHistory) { ParseError[] errors; var ast = EngineParser.Parse(fileName, script, null, out errors, ParseMode.Default); - if (interactiveCommand) + if (addToHistory) { EngineParser.SetPreviousFirstLastToken(Context); } diff --git a/src/System.Management.Automation/engine/parser/tokenizer.cs b/src/System.Management.Automation/engine/parser/tokenizer.cs index 1a1045afc5a..b5d73758a33 100644 --- a/src/System.Management.Automation/engine/parser/tokenizer.cs +++ b/src/System.Management.Automation/engine/parser/tokenizer.cs @@ -492,6 +492,7 @@ internal class TokenizerState internal string Script; internal int TokenStart; internal int CurrentIndex; + internal Token FirstToken; internal Token LastToken; internal BitArray SkippedCharOffsets; internal List TokenList; @@ -687,6 +688,7 @@ internal TokenizerState StartNestedScan(UnscannedSubExprToken nestedText) NestedTokensAdjustment = _nestedTokensAdjustment, Script = _script, TokenStart = _tokenStart, + FirstToken = FirstToken, LastToken = LastToken, SkippedCharOffsets = _skippedCharOffsets, TokenList = TokenList, @@ -708,6 +710,7 @@ internal void FinishNestedScan(TokenizerState ts) _nestedTokensAdjustment = ts.NestedTokensAdjustment; _script = ts.Script; _tokenStart = ts.TokenStart; + FirstToken = ts.FirstToken; LastToken = ts.LastToken; _skippedCharOffsets = ts.SkippedCharOffsets; TokenList = ts.TokenList; diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 0edc62fda66..6307fa5c99a 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -915,4 +915,39 @@ foo``u{2195}abc # Issue #2780 { ExecuteCommand "`$herestr=@`"`n'`"'`n`"@" } | Should Not Throw } + + Context "#requires nested scan tokenizer tests" { + BeforeAll { + $settings = [System.Management.Automation.PSInvocationSettings]::new() + $settings.AddToHistory = $true + + $ps = [powershell]::Create() + } + + AfterAll { + $ps.Dispose() + } + + AfterEach { + $ps.Commands.Clear() + } + + $testCases = @( + @{ script = "#requires"; firstToken = $null; lastToken = $null }, + @{ script = "#requires -Version 5.0`n10"; firstToken = "10"; lastToken = "10" }, + @{ script = "Write-Host 'Hello'`n#requires -Version 5.0`n7"; firstToken = "Write-Host"; lastToken = "7" }, + @{ script = "Write-Host 'Hello'`n#requires -Version 5.0"; firstToken = "Write-Host"; lastToken = "Hello"} + ) + + It "Correctly resets the first and last tokens in the tokenizer after nested scan in script" -TestCases $testCases { + param($script, $firstToken, $lastToken) + + $ps.AddScript($script) + $ps.AddScript("(`$^,`$`$)") + $tokens = $ps.Invoke(@(), $settings) + + $tokens[0] | Should -BeExactly $firstToken + $tokens[1] | Should -BeExactly $lastToken + } + } } diff --git a/test/powershell/Language/Scripting/Requires.Tests.ps1 b/test/powershell/Language/Scripting/Requires.Tests.ps1 index d4a25d04a70..4354dba3cc6 100644 --- a/test/powershell/Language/Scripting/Requires.Tests.ps1 +++ b/test/powershell/Language/Scripting/Requires.Tests.ps1 @@ -27,4 +27,21 @@ Describe "Requires tests" -Tags "CI" { } } -} \ No newline at end of file + Context "Interactive requires" { + + BeforeAll { + $ps = [powershell]::Create() + } + + AfterAll { + $ps.Dispose() + } + + It "Successfully does nothing when given '#requires' interactively" { + $settings = [System.Management.Automation.PSInvocationSettings]::new() + $settings.AddToHistory = $true + + { $ps.AddScript("#requires").Invoke(@(), $settings) } | Should -Not -Throw + } + } +}