Skip to content

Commit b20dd31

Browse files
authored
Fix parser to continue parsing key-value pairs after an If-Statement value in a HashExpression (#7002)
After parsing `if () { }`, new lines are skipped in order to see if either `elseif` or `else` is present. When neither is present, we should resync back to the pointer before skipping those possibly available new lines, so that the new line tokens can be utilized by the subsequent parsing.
1 parent 2429b43 commit b20dd31

2 files changed

Lines changed: 107 additions & 2 deletions

File tree

src/System.Management.Automation/engine/parser/Parser.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,16 @@ private StatementAst IfStatementRule(Token ifToken)
24112411

24122412
clauses.Add(new IfClause(condition, body));
24132413

2414+
// Save a restore point here. In case there is no 'elseif' or 'else' following,
2415+
// we should resync back here to preserve the possible new lines. The new lines
2416+
// could be important for the following parsing. For example, in case we are in
2417+
// a HashExpression, a new line might be needed for parsing the key-value that
2418+
// is following the if statement:
2419+
// @{
2420+
// a = if (1) {}
2421+
// b = 10
2422+
// }
2423+
int restorePoint = _ungotToken == null ? _tokenizer.GetRestorePoint() : _ungotToken.Extent.StartOffset;
24142424
SkipNewlines();
24152425
keyword = PeekToken();
24162426

@@ -2419,8 +2429,7 @@ private StatementAst IfStatementRule(Token ifToken)
24192429
SkipToken();
24202430
continue;
24212431
}
2422-
2423-
if (keyword.Kind == TokenKind.Else)
2432+
else if (keyword.Kind == TokenKind.Else)
24242433
{
24252434
SkipToken();
24262435
SkipNewlines();
@@ -2436,6 +2445,11 @@ private StatementAst IfStatementRule(Token ifToken)
24362445
return new ErrorStatementAst(ExtentOf(ifToken, keyword), componentAsts);
24372446
}
24382447
}
2448+
else
2449+
{
2450+
// There is no 'elseif' or 'else' following, so resync back to the possible new lines.
2451+
Resync(restorePoint);
2452+
}
24392453
break;
24402454
}
24412455

test/powershell/Language/Parser/LanguageAndParser.TestFollowup.Tests.ps1

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,94 @@ Describe "Members of System.Type" -Tags "CI" {
212212
[MyType].ImplementedInterfaces | Should -Be System.Collections.IEnumerable
213213
}
214214
}
215+
216+
Describe "Hash expression with if statement as value" -Tags "CI" {
217+
BeforeAll {
218+
# With no extra new lines after if-statement
219+
$hash1 = @{
220+
a = if (1) {'a'}
221+
b = 'b'
222+
c = if (0) {2} elseif (1) {'c'}
223+
d = 'd'
224+
e = if (0) {2} elseif (0) {2} else {'e'}
225+
f = 'f'
226+
g = if (0) {2} else {'g'}
227+
h = 'h'
228+
}
229+
230+
# With extra new lines after if-statement
231+
$hash2 = @{
232+
a = if (1) {'a'}
233+
234+
b = 'b'
235+
c = if (0) {2} elseif (1) {'c'}
236+
237+
d = 'd'
238+
e = if (0) {2} elseif (0) {2} else {'e'}
239+
240+
f = 'f'
241+
g = if (0) {2} else {'g'}
242+
243+
h = 'h'
244+
}
245+
246+
# With expanded if-statement
247+
$hash3 = @{
248+
a = if (1)
249+
{
250+
'a'
251+
}
252+
b = 'b'
253+
c = if (0)
254+
{
255+
2
256+
}
257+
elseif (1)
258+
{
259+
'c'
260+
}
261+
d = 'd'
262+
e = if (0)
263+
{
264+
2
265+
}
266+
elseif (0)
267+
{
268+
2
269+
}
270+
else
271+
{
272+
'e'
273+
}
274+
f = 'f'
275+
g = if (0)
276+
{
277+
2
278+
}
279+
else
280+
{
281+
'g'
282+
}
283+
h = 'h'
284+
}
285+
286+
$testCases = @(
287+
@{ name = "No extra new lines"; hash = $hash1 }
288+
@{ name = "With extra new lines"; hash = $hash2 }
289+
@{ name = "With expanded if-statement"; hash = $hash3 }
290+
)
291+
}
292+
293+
It "Key-value pairs after an if-statement-value in a HashExpression should continue to be parsed - <name>" -TestCases $testCases {
294+
param($hash)
295+
296+
$hash['a'] | Should -BeExactly 'a'
297+
$hash['b'] | Should -BeExactly 'b'
298+
$hash['c'] | Should -BeExactly 'c'
299+
$hash['d'] | Should -BeExactly 'd'
300+
$hash['e'] | Should -BeExactly 'e'
301+
$hash['f'] | Should -BeExactly 'f'
302+
$hash['g'] | Should -BeExactly 'g'
303+
$hash['h'] | Should -BeExactly 'h'
304+
}
305+
}

0 commit comments

Comments
 (0)