Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
28 changes: 24 additions & 4 deletions 28 src/System.Management.Automation/engine/parser/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1620,15 +1620,37 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List<UsingStatementAst>
? lCurly.Extent
: (paramBlockAst != null) ? paramBlockAst.Extent : null;
IScriptExtent endExtent = null;
IScriptExtent extent;
IScriptExtent extent = null;
IScriptExtent scriptBlockExtent = null;

while (true)
{
Token blockNameToken = NextToken();
switch (blockNameToken.Kind)
{
default:
// Next token is unexpected.
// ErrorRecovery: if 'lCurly' is present, pretend we saw a closing curly; otherwise, eat the unexpected token.
if (lCurly != null)
{
UngetToken(blockNameToken);
scriptBlockExtent = ExtentOf(startExtent, endExtent);
}
else
{
// If "lCurly == null", then it's a ps1/psm1 file, and thus the extent is the whole file.
scriptBlockExtent = _tokenizer.GetScriptExtent();
}

// Report error about the unexpected token.
ReportError(blockNameToken.Extent, () => ParserStrings.MissingNamedBlocks, blockNameToken.Text);
goto return_script_block_ast;

case TokenKind.RCurly:
case TokenKind.EndOfInput:
// If the next token is RCurly or <eof>, handle it in 'CompleteScriptBlockBody'.
UngetToken(blockNameToken);
extent = ExtentOf(startExtent, endExtent);
goto finished_named_block_list;

case TokenKind.Dynamicparam:
Expand Down Expand Up @@ -1687,11 +1709,9 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List<UsingStatementAst>
SkipNewlinesAndSemicolons();
}
finished_named_block_list:

IScriptExtent scriptBlockExtent;
extent = ExtentOf(startExtent, endExtent);
CompleteScriptBlockBody(lCurly, ref extent, out scriptBlockExtent);

return_script_block_ast:
return new ScriptBlockAst(scriptBlockExtent, usingStatements, paramBlockAst, beginBlock, processBlock, endBlock,
dynamicParamBlock);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,9 @@ The correct form is: foreach ($a in $b) {...}</value>
<data name="DuplicateScriptCommandClause" xml:space="preserve">
<value>Script command clause '{0}' has already been defined.</value>
</data>
<data name="MissingNamedBlocks" xml:space="preserve">
<value>unexpected token '{0}', expected 'begin', 'process', 'end', or 'dynamicparam'.</value>
</data>
<data name="MissingEndCurlyBrace" xml:space="preserve">
<value>Missing closing '}' in statement block or type definition.</value>
</data>
Expand Down
16 changes: 16 additions & 0 deletions 16 test/powershell/Language/Parser/Parser.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -915,4 +915,20 @@ foo``u{2195}abc
# Issue #2780
{ ExecuteCommand "`$herestr=@`"`n'`"'`n`"@" } | Should Not Throw
}

It "Throw better error when statement should be put in named blocks - <name>" -TestCases @(
@{ script = "Function foo { [CmdletBinding()] param() DynamicParam {} Hi"; name = "function" }
@{ script = "{ begin {} Hi"; name = "script-block" }
@{ script = "begin {} Hi"; name = "script-file" }
) {
param($script)

$err = { ExecuteCommand $script } | Should -Throw -ErrorId "ParseException" -PassThru
$err.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "MissingNamedBlocks"
}

It "IncompleteParseException should be thrown when only ending curly is missing" {
$err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} " } | Should -Throw -ErrorId "IncompleteParseException" -PassThru
$err.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "MissingEndCurlyBrace"
}
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.