From 24599fa413485ad65738f606bd06c97b727bc3f3 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 19 Mar 2018 20:02:22 -0700 Subject: [PATCH 01/10] [Feature] Throw better parsing error when statements should be put in named block --- .../engine/parser/Parser.cs | 13 +++++++++---- .../resources/ParserStrings.resx | 3 +++ test/powershell/Language/Parser/Parser.Tests.ps1 | 10 ++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index 3de24603421..4bf79e435bf 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1512,7 +1512,7 @@ private ITypeName CompleteArrayTypeName(ITypeName elementType, TypeName typeForA return elementType; } - private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, out IScriptExtent fullBodyExtent) + private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, out IScriptExtent fullBodyExtent, bool calledFromNamedBlockRule) { // If the caller passed in the open curly, then they expect us to consume the closing curly // and include that in the extent. @@ -1526,7 +1526,12 @@ private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, UngetToken(rCurly); endScriptBlock = bodyExtent ?? lCurly.Extent; - ReportIncompleteInput(lCurly.Extent, rCurly.Extent, () => ParserStrings.MissingEndCurlyBrace); + Expression> errorExpr = () => ParserStrings.MissingEndCurlyBrace; + if (calledFromNamedBlockRule) + { + errorExpr = () => ParserStrings.MissingEndCurlyBraceOrNamedBlock; + } + ReportIncompleteInput(lCurly.Extent, rCurly.Extent, errorExpr); } else { @@ -1592,7 +1597,7 @@ private ScriptBlockAst ScriptBlockBodyRule(Token lCurly, List statementListExtent = ExtentOf(statementListExtent, extent); } - if (CompleteScriptBlockBody(lCurly, ref statementListExtent, out scriptBlockExtent)) + if (CompleteScriptBlockBody(lCurly, ref statementListExtent, out scriptBlockExtent, calledFromNamedBlockRule: false)) { break; } @@ -1690,7 +1695,7 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List IScriptExtent scriptBlockExtent; extent = ExtentOf(startExtent, endExtent); - CompleteScriptBlockBody(lCurly, ref extent, out scriptBlockExtent); + CompleteScriptBlockBody(lCurly, ref extent, out scriptBlockExtent, calledFromNamedBlockRule: true); return new ScriptBlockAst(scriptBlockExtent, usingStatements, paramBlockAst, beginBlock, processBlock, endBlock, dynamicParamBlock); diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 5f9b75345fe..4c39e731642 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -493,6 +493,9 @@ The correct form is: foreach ($a in $b) {...} Script command clause '{0}' has already been defined. + + Missing closing '}' in script block. If you meant to continue with the script block, please note that new statements should be put in named blocks after a named block has been declared. + Missing closing '}' in statement block or type definition. diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 0edc62fda66..46c9c943b42 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -915,4 +915,14 @@ foo``u{2195}abc # Issue #2780 { ExecuteCommand "`$herestr=@`"`n'`"'`n`"@" } | Should Not Throw } + + It "Throw better error message when statement should be put in named blocks" { + try { + ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" + throw "Execution OK" + } + catch { + $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -Be "MissingEndCurlyBraceOrNamedBlock" + } + } } From 2c73857d8275e13c1babd8d66ab92881641b5c7d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 19 Mar 2018 21:47:03 -0700 Subject: [PATCH 02/10] [Feature] Address comments --- src/System.Management.Automation/engine/parser/Parser.cs | 8 +++----- .../resources/ParserStrings.resx | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index 4bf79e435bf..6ca2d9d9e5b 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1526,11 +1526,9 @@ private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, UngetToken(rCurly); endScriptBlock = bodyExtent ?? lCurly.Extent; - Expression> errorExpr = () => ParserStrings.MissingEndCurlyBrace; - if (calledFromNamedBlockRule) - { - errorExpr = () => ParserStrings.MissingEndCurlyBraceOrNamedBlock; - } + var errorExpr = calledFromNamedBlockRule + ? (Expression>)(() => ParserStrings.MissingEndCurlyBraceOrNamedBlocks) + : (Expression>)(() => ParserStrings.MissingEndCurlyBrace); ReportIncompleteInput(lCurly.Extent, rCurly.Extent, errorExpr); } else diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 4c39e731642..f7b8b6883c3 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -493,8 +493,8 @@ The correct form is: foreach ($a in $b) {...} Script command clause '{0}' has already been defined. - - Missing closing '}' in script block. If you meant to continue with the script block, please note that new statements should be put in named blocks after a named block has been declared. + + Missing closing '}' in script block. If you meant to add more statements to the script block, put the statements in one or more named blocks. Missing closing '}' in statement block or type definition. From a6b4b0eee1cf7814c8318a171c432a14c45b1b5e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 19 Mar 2018 21:56:08 -0700 Subject: [PATCH 03/10] [Feature] fix the error id in test --- test/powershell/Language/Parser/Parser.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 46c9c943b42..27635cbeb15 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -922,7 +922,7 @@ foo``u{2195}abc throw "Execution OK" } catch { - $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -Be "MissingEndCurlyBraceOrNamedBlock" + $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -Be "MissingEndCurlyBraceOrNamedBlocks" } } } From 1522393a6b49cdc408a33897b724ac3da2599a77 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 13:07:42 -0700 Subject: [PATCH 04/10] Use Pesterv4 syntax for test --- test/powershell/Language/Parser/Parser.Tests.ps1 | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 27635cbeb15..4c5bcd4aa26 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -917,12 +917,7 @@ foo``u{2195}abc } It "Throw better error message when statement should be put in named blocks" { - try { - ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" - throw "Execution OK" - } - catch { - $_.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -Be "MissingEndCurlyBraceOrNamedBlocks" - } + $err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" } | Should -Throw -PassThru + $err.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "MissingEndCurlyBraceOrNamedBlocks" } } From 5b5be3122971552d2ce208858ac84868954b841c Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 14:01:13 -0700 Subject: [PATCH 05/10] Address Steve's comment --- src/System.Management.Automation/resources/ParserStrings.resx | 2 +- test/powershell/Language/Parser/Parser.Tests.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index f7b8b6883c3..8175bc33d85 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -494,7 +494,7 @@ The correct form is: foreach ($a in $b) {...} Script command clause '{0}' has already been defined. - Missing closing '}' in script block. If you meant to add more statements to the script block, put the statements in one or more named blocks. + Missing closing '}' in script block. If you meant to add more statements to the script block, put the statements in begin, process, or end blocks. Missing closing '}' in statement block or type definition. diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 4c5bcd4aa26..53b97ea168b 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -917,7 +917,7 @@ foo``u{2195}abc } It "Throw better error message when statement should be put in named blocks" { - $err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" } | Should -Throw -PassThru + $err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" } | Should -Throw -ErrorId "IncompleteParseException" -PassThru $err.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "MissingEndCurlyBraceOrNamedBlocks" } } From f303cbe5352e269953b3b4f1b7412f067dd0f32b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 17:22:45 -0700 Subject: [PATCH 06/10] [Feature] Address Jason's feedback --- .../engine/parser/Parser.cs | 32 ++++++++++++------- .../resources/ParserStrings.resx | 4 +-- .../Language/Parser/Parser.Tests.ps1 | 9 ++++-- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index 6ca2d9d9e5b..bc58bde90d9 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1512,7 +1512,7 @@ private ITypeName CompleteArrayTypeName(ITypeName elementType, TypeName typeForA return elementType; } - private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, out IScriptExtent fullBodyExtent, bool calledFromNamedBlockRule) + private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, out IScriptExtent fullBodyExtent) { // If the caller passed in the open curly, then they expect us to consume the closing curly // and include that in the extent. @@ -1526,10 +1526,7 @@ private bool CompleteScriptBlockBody(Token lCurly, ref IScriptExtent bodyExtent, UngetToken(rCurly); endScriptBlock = bodyExtent ?? lCurly.Extent; - var errorExpr = calledFromNamedBlockRule - ? (Expression>)(() => ParserStrings.MissingEndCurlyBraceOrNamedBlocks) - : (Expression>)(() => ParserStrings.MissingEndCurlyBrace); - ReportIncompleteInput(lCurly.Extent, rCurly.Extent, errorExpr); + ReportIncompleteInput(lCurly.Extent, rCurly.Extent, () => ParserStrings.MissingEndCurlyBrace); } else { @@ -1595,7 +1592,7 @@ private ScriptBlockAst ScriptBlockBodyRule(Token lCurly, List statementListExtent = ExtentOf(statementListExtent, extent); } - if (CompleteScriptBlockBody(lCurly, ref statementListExtent, out scriptBlockExtent, calledFromNamedBlockRule: false)) + if (CompleteScriptBlockBody(lCurly, ref statementListExtent, out scriptBlockExtent)) { break; } @@ -1623,7 +1620,8 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List ? lCurly.Extent : (paramBlockAst != null) ? paramBlockAst.Extent : null; IScriptExtent endExtent = null; - IScriptExtent extent; + IScriptExtent extent = null; + IScriptExtent scriptBlockExtent = null; while (true) { @@ -1632,6 +1630,20 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List { default: UngetToken(blockNameToken); + extent = ExtentOf(startExtent, endExtent); + + // If 'lCurly' is null, then handle the next token in 'CompleteScriptBlockBody'. + if (lCurly == null) { goto finished_named_block_list; } + // Otherwise, we handle the unexpected next token here. + ReportError(blockNameToken.Extent, () => ParserStrings.MissingNamedBlocks, blockNameToken.Text); + scriptBlockExtent = extent; + goto return_script_block_ast; + + case TokenKind.RCurly: + case TokenKind.EndOfInput: + // If the next token is RCurly or , handle it in 'CompleteScriptBlockBody'. + UngetToken(blockNameToken); + extent = ExtentOf(startExtent, endExtent); goto finished_named_block_list; case TokenKind.Dynamicparam: @@ -1690,11 +1702,9 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List SkipNewlinesAndSemicolons(); } finished_named_block_list: + CompleteScriptBlockBody(lCurly, ref extent, out scriptBlockExtent); - IScriptExtent scriptBlockExtent; - extent = ExtentOf(startExtent, endExtent); - CompleteScriptBlockBody(lCurly, ref extent, out scriptBlockExtent, calledFromNamedBlockRule: true); - + return_script_block_ast: return new ScriptBlockAst(scriptBlockExtent, usingStatements, paramBlockAst, beginBlock, processBlock, endBlock, dynamicParamBlock); } diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 8175bc33d85..fc98af9421a 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -493,8 +493,8 @@ The correct form is: foreach ($a in $b) {...} Script command clause '{0}' has already been defined. - - Missing closing '}' in script block. If you meant to add more statements to the script block, put the statements in begin, process, or end blocks. + + unexpected token '{0}', expected 'begin', 'process', 'end', or 'dynamicparam'. Missing closing '}' in statement block or type definition. diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 53b97ea168b..2347bfc898e 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -917,7 +917,12 @@ foo``u{2195}abc } It "Throw better error message when statement should be put in named blocks" { - $err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" } | Should -Throw -ErrorId "IncompleteParseException" -PassThru - $err.Exception.InnerException.ErrorRecord.FullyQualifiedErrorId | Should -BeExactly "MissingEndCurlyBraceOrNamedBlocks" + $err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" } | 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" } } From b877ff978f92b6ffcb941b7d809aed9e71868449 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 18:29:42 -0700 Subject: [PATCH 07/10] [Feature] Address Jason's comment --- .../engine/parser/Parser.cs | 7 +++---- test/powershell/Language/Parser/Parser.Tests.ps1 | 10 ++++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index bc58bde90d9..1d2e3e14dcd 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1632,11 +1632,10 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List UngetToken(blockNameToken); extent = ExtentOf(startExtent, endExtent); - // If 'lCurly' is null, then handle the next token in 'CompleteScriptBlockBody'. - if (lCurly == null) { goto finished_named_block_list; } - // Otherwise, we handle the unexpected next token here. + // If 'lCurly == null", then it's a ps1/psm1 file, then the extent is the whole file. + scriptBlockExtent = lCurly != null ? extent : _tokenizer.GetScriptExtent(); + // Handle the unexpected next token. ReportError(blockNameToken.Extent, () => ParserStrings.MissingNamedBlocks, blockNameToken.Text); - scriptBlockExtent = extent; goto return_script_block_ast; case TokenKind.RCurly: diff --git a/test/powershell/Language/Parser/Parser.Tests.ps1 b/test/powershell/Language/Parser/Parser.Tests.ps1 index 2347bfc898e..d0b434af58c 100644 --- a/test/powershell/Language/Parser/Parser.Tests.ps1 +++ b/test/powershell/Language/Parser/Parser.Tests.ps1 @@ -916,8 +916,14 @@ foo``u{2195}abc { ExecuteCommand "`$herestr=@`"`n'`"'`n`"@" } | Should Not Throw } - It "Throw better error message when statement should be put in named blocks" { - $err = { ExecuteCommand "Function foo { [CmdletBinding()] param() DynamicParam {} Hi" } | Should -Throw -ErrorId "ParseException" -PassThru + It "Throw better error when statement should be put in named blocks - " -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" } From a6de6dacaab4eee4af5bfcd1d696b22cbe0c8f90 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 18:43:29 -0700 Subject: [PATCH 08/10] [Feature] Eat the unexpected token when lcurly == null --- src/System.Management.Automation/engine/parser/Parser.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index 1d2e3e14dcd..eee6fc3e184 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1629,11 +1629,12 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List switch (blockNameToken.Kind) { default: - UngetToken(blockNameToken); - extent = ExtentOf(startExtent, endExtent); + // Next token is unexpected. + // ErrorRecovery: if 'lCurly' is present, pretent we saw a closing curly, otherwise, eat the unexpected token. + if (lCurly != null) { UngetToken(blockNameToken); } // If 'lCurly == null", then it's a ps1/psm1 file, then the extent is the whole file. - scriptBlockExtent = lCurly != null ? extent : _tokenizer.GetScriptExtent(); + scriptBlockExtent = lCurly != null ? ExtentOf(startExtent, endExtent) : _tokenizer.GetScriptExtent(); // Handle the unexpected next token. ReportError(blockNameToken.Extent, () => ParserStrings.MissingNamedBlocks, blockNameToken.Text); goto return_script_block_ast; From 466680c7e00ef9c891bd1805b5ae835a086e548e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 19:49:19 -0700 Subject: [PATCH 09/10] [Feature] Fix typos in comments --- src/System.Management.Automation/engine/parser/Parser.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index eee6fc3e184..ea49baa1eb1 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1630,12 +1630,12 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List { default: // Next token is unexpected. - // ErrorRecovery: if 'lCurly' is present, pretent we saw a closing curly, otherwise, eat the unexpected token. + // ErrorRecovery: if 'lCurly' is present, pretend we saw a closing curly; otherwise, eat the unexpected token. if (lCurly != null) { UngetToken(blockNameToken); } - // If 'lCurly == null", then it's a ps1/psm1 file, then the extent is the whole file. + // If 'lCurly == null", then it's a ps1/psm1 file, and thus the extent is the whole file. scriptBlockExtent = lCurly != null ? ExtentOf(startExtent, endExtent) : _tokenizer.GetScriptExtent(); - // Handle the unexpected next token. + // Report error about the unexpected token. ReportError(blockNameToken.Extent, () => ParserStrings.MissingNamedBlocks, blockNameToken.Text); goto return_script_block_ast; From b1697c8e21a29664a1ca37969e906c3a23d40832 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 20 Mar 2018 21:55:52 -0700 Subject: [PATCH 10/10] [Feature] Address Ilya's comment --- .../engine/parser/Parser.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index ea49baa1eb1..971e4be4808 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -1631,10 +1631,17 @@ private ScriptBlockAst NamedBlockListRule(Token lCurly, List 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); } + 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(); + } - // If 'lCurly == null", then it's a ps1/psm1 file, and thus the extent is the whole file. - scriptBlockExtent = lCurly != null ? ExtentOf(startExtent, endExtent) : _tokenizer.GetScriptExtent(); // Report error about the unexpected token. ReportError(blockNameToken.Extent, () => ParserStrings.MissingNamedBlocks, blockNameToken.Text); goto return_script_block_ast;