Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/System.Management.Automation/engine/AutomationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ internal string Expand(string s)
/// Compile a piece of text into a parse tree for later execution.
/// </summary>
/// <param name="script">The text to parse</param>
/// <param name="interactiveCommand"></param>
/// <param name="addToHistory">true iff the scriptblock will be added to history</param>
/// <returns>The parse text as a parsetree node.</returns>
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);
}
Expand Down
3 changes: 3 additions & 0 deletions src/System.Management.Automation/engine/parser/tokenizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Token> TokenList;
Expand Down Expand Up @@ -687,6 +688,7 @@ internal TokenizerState StartNestedScan(UnscannedSubExprToken nestedText)
NestedTokensAdjustment = _nestedTokensAdjustment,
Script = _script,
TokenStart = _tokenStart,
FirstToken = FirstToken,
LastToken = LastToken,
SkippedCharOffsets = _skippedCharOffsets,
TokenList = TokenList,
Expand All @@ -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;
Expand Down
35 changes: 35 additions & 0 deletions test/powershell/Language/Parser/Parser.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please have a AfterAll block to dispose $ps.

}

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("(`$^,`$`$)")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little surprised this works, 2 calls to AddScript is I think like piping the first call to the second. That said, it neatly drops any results from the first call.

To be slightly more like the interactive scenario, I think you would call $ps.Invoke twice, clearing the commands between calls.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I tried that and it didn't seem to do what I wanted. To be honest, I wasn't entirely certain how I should be using the embedded PowerShell session to recreate the input. But I spent some time playing with it, tried the "script, invoke, tokens, invoke" way and seemed to get $null for everything.

$tokens = $ps.Invoke(@(), $settings)

$tokens[0] | Should -BeExactly $firstToken
$tokens[1] | Should -BeExactly $lastToken
}
}
}
19 changes: 18 additions & 1 deletion test/powershell/Language/Scripting/Requires.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,21 @@ Describe "Requires tests" -Tags "CI" {
}
}

}
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
}
}
}