diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index ebdae013f2f..ea36987b7d3 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -2411,6 +2411,16 @@ private StatementAst IfStatementRule(Token ifToken) clauses.Add(new IfClause(condition, body)); + // Save a restore point here. In case there is no 'elseif' or 'else' following, + // we should resync back here to preserve the possible new lines. The new lines + // could be important for the following parsing. For example, in case we are in + // a HashExpression, a new line might be needed for parsing the key-value that + // is following the if statement: + // @{ + // a = if (1) {} + // b = 10 + // } + int restorePoint = _ungotToken == null ? _tokenizer.GetRestorePoint() : _ungotToken.Extent.StartOffset; SkipNewlines(); keyword = PeekToken(); @@ -2419,8 +2429,7 @@ private StatementAst IfStatementRule(Token ifToken) SkipToken(); continue; } - - if (keyword.Kind == TokenKind.Else) + else if (keyword.Kind == TokenKind.Else) { SkipToken(); SkipNewlines(); @@ -2436,6 +2445,11 @@ private StatementAst IfStatementRule(Token ifToken) return new ErrorStatementAst(ExtentOf(ifToken, keyword), componentAsts); } } + else + { + // There is no 'elseif' or 'else' following, so resync back to the possible new lines. + Resync(restorePoint); + } break; } diff --git a/test/powershell/Language/Parser/LanguageAndParser.TestFollowup.Tests.ps1 b/test/powershell/Language/Parser/LanguageAndParser.TestFollowup.Tests.ps1 index 8860d492c24..da50b2e5541 100644 --- a/test/powershell/Language/Parser/LanguageAndParser.TestFollowup.Tests.ps1 +++ b/test/powershell/Language/Parser/LanguageAndParser.TestFollowup.Tests.ps1 @@ -212,3 +212,94 @@ Describe "Members of System.Type" -Tags "CI" { [MyType].ImplementedInterfaces | Should -Be System.Collections.IEnumerable } } + +Describe "Hash expression with if statement as value" -Tags "CI" { + BeforeAll { + # With no extra new lines after if-statement + $hash1 = @{ + a = if (1) {'a'} + b = 'b' + c = if (0) {2} elseif (1) {'c'} + d = 'd' + e = if (0) {2} elseif (0) {2} else {'e'} + f = 'f' + g = if (0) {2} else {'g'} + h = 'h' + } + + # With extra new lines after if-statement + $hash2 = @{ + a = if (1) {'a'} + + b = 'b' + c = if (0) {2} elseif (1) {'c'} + + d = 'd' + e = if (0) {2} elseif (0) {2} else {'e'} + + f = 'f' + g = if (0) {2} else {'g'} + + h = 'h' + } + + # With expanded if-statement + $hash3 = @{ + a = if (1) + { + 'a' + } + b = 'b' + c = if (0) + { + 2 + } + elseif (1) + { + 'c' + } + d = 'd' + e = if (0) + { + 2 + } + elseif (0) + { + 2 + } + else + { + 'e' + } + f = 'f' + g = if (0) + { + 2 + } + else + { + 'g' + } + h = 'h' + } + + $testCases = @( + @{ name = "No extra new lines"; hash = $hash1 } + @{ name = "With extra new lines"; hash = $hash2 } + @{ name = "With expanded if-statement"; hash = $hash3 } + ) + } + + It "Key-value pairs after an if-statement-value in a HashExpression should continue to be parsed - " -TestCases $testCases { + param($hash) + + $hash['a'] | Should -BeExactly 'a' + $hash['b'] | Should -BeExactly 'b' + $hash['c'] | Should -BeExactly 'c' + $hash['d'] | Should -BeExactly 'd' + $hash['e'] | Should -BeExactly 'e' + $hash['f'] | Should -BeExactly 'f' + $hash['g'] | Should -BeExactly 'g' + $hash['h'] | Should -BeExactly 'h' + } +}