Skip to content

Commit 42ddd21

Browse files
committed
Fix handling of named label for goto.
The label is a standalone statement just like any other statement. It isn't associated with the next statement by PHP's parser. E.g. `while (false) label: echo "test\n";` echoes "test". Fixes microsoft#154
1 parent 85b40c3 commit 42ddd21

16 files changed

+413
-47
lines changed

src/Node/Statement/NamedLabelStatement.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ class NamedLabelStatement extends StatementNode {
1414
public $name;
1515
/** @var Token */
1616
public $colon;
17-
/** @var StatementNode */
17+
/**
18+
* @var null this is always null as of 0.0.23
19+
* TODO: Clean this up in the next major release.
20+
*/
1821
public $statement;
1922

2023
const CHILD_NAMES = [

src/Parser.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,8 @@ private function parseNamedLabelStatement($parentNode) {
16691669
$namedLabelStatement->parent = $parentNode;
16701670
$namedLabelStatement->name = $this->eat1(TokenKind::Name);
16711671
$namedLabelStatement->colon = $this->eat1(TokenKind::ColonToken);
1672-
$namedLabelStatement->statement = $this->parseStatement($namedLabelStatement);
1672+
// A named label is a statement on its own. E.g. `while (false) label: echo "test";`
1673+
// is parsed as `while (false) { label: } echo "test";
16731674
return $namedLabelStatement;
16741675
}
16751676

tests/cases/parser/namedLabelStatement1.php.tree

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,36 @@
2121
"kind": "ColonToken",
2222
"textLength": 1
2323
},
24-
"statement": {
25-
"CompoundStatementNode": {
26-
"openBrace": {
27-
"kind": "OpenBraceToken",
28-
"textLength": 1
29-
},
30-
"statements": [
31-
{
32-
"EmptyStatement": {
33-
"semicolon": {
34-
"kind": "SemicolonToken",
35-
"textLength": 1
36-
}
37-
}
38-
},
39-
{
40-
"EmptyStatement": {
41-
"semicolon": {
42-
"kind": "SemicolonToken",
43-
"textLength": 1
44-
}
45-
}
24+
"statement": null
25+
}
26+
},
27+
{
28+
"CompoundStatementNode": {
29+
"openBrace": {
30+
"kind": "OpenBraceToken",
31+
"textLength": 1
32+
},
33+
"statements": [
34+
{
35+
"EmptyStatement": {
36+
"semicolon": {
37+
"kind": "SemicolonToken",
38+
"textLength": 1
39+
}
40+
}
41+
},
42+
{
43+
"EmptyStatement": {
44+
"semicolon": {
45+
"kind": "SemicolonToken",
46+
"textLength": 1
4647
}
47-
],
48-
"closeBrace": {
49-
"kind": "CloseBraceToken",
50-
"textLength": 1
5148
}
5249
}
50+
],
51+
"closeBrace": {
52+
"kind": "CloseBraceToken",
53+
"textLength": 1
5354
}
5455
}
5556
}

tests/cases/parser/namedLabelStatement4.php.tree

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,27 @@
2121
"kind": "ColonToken",
2222
"textLength": 1
2323
},
24-
"statement": {
25-
"NamedLabelStatement": {
26-
"name": {
27-
"kind": "Name",
28-
"textLength": 4
29-
},
30-
"colon": {
31-
"kind": "ColonToken",
32-
"textLength": 1
33-
},
34-
"statement": {
35-
"EmptyStatement": {
36-
"semicolon": {
37-
"kind": "SemicolonToken",
38-
"textLength": 1
39-
}
40-
}
41-
}
42-
}
24+
"statement": null
25+
}
26+
},
27+
{
28+
"NamedLabelStatement": {
29+
"name": {
30+
"kind": "Name",
31+
"textLength": 4
32+
},
33+
"colon": {
34+
"kind": "ColonToken",
35+
"textLength": 1
36+
},
37+
"statement": null
38+
}
39+
},
40+
{
41+
"EmptyStatement": {
42+
"semicolon": {
43+
"kind": "SemicolonToken",
44+
"textLength": 1
4345
}
4446
}
4547
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
function test() {
3+
target:
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"SourceFileNode": {
3+
"statementList": [
4+
{
5+
"InlineHtml": {
6+
"scriptSectionEndTag": null,
7+
"text": null,
8+
"scriptSectionStartTag": {
9+
"kind": "ScriptSectionStartTag",
10+
"textLength": 6
11+
}
12+
}
13+
},
14+
{
15+
"FunctionDeclaration": {
16+
"attributes": null,
17+
"functionKeyword": {
18+
"kind": "FunctionKeyword",
19+
"textLength": 8
20+
},
21+
"byRefToken": null,
22+
"name": {
23+
"kind": "Name",
24+
"textLength": 4
25+
},
26+
"openParen": {
27+
"kind": "OpenParenToken",
28+
"textLength": 1
29+
},
30+
"parameters": null,
31+
"closeParen": {
32+
"kind": "CloseParenToken",
33+
"textLength": 1
34+
},
35+
"colonToken": null,
36+
"questionToken": null,
37+
"returnType": null,
38+
"otherReturnTypes": null,
39+
"compoundStatementOrSemicolon": {
40+
"CompoundStatementNode": {
41+
"openBrace": {
42+
"kind": "OpenBraceToken",
43+
"textLength": 1
44+
},
45+
"statements": [
46+
{
47+
"NamedLabelStatement": {
48+
"name": {
49+
"kind": "Name",
50+
"textLength": 6
51+
},
52+
"colon": {
53+
"kind": "ColonToken",
54+
"textLength": 1
55+
},
56+
"statement": null
57+
}
58+
}
59+
],
60+
"closeBrace": {
61+
"kind": "CloseBraceToken",
62+
"textLength": 1
63+
}
64+
}
65+
}
66+
}
67+
}
68+
],
69+
"endOfFileToken": {
70+
"kind": "EndOfFileToken",
71+
"textLength": 0
72+
}
73+
}
74+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
if (false)
3+
label:
4+
else
5+
echo "else\n";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
{
2+
"SourceFileNode": {
3+
"statementList": [
4+
{
5+
"InlineHtml": {
6+
"scriptSectionEndTag": null,
7+
"text": null,
8+
"scriptSectionStartTag": {
9+
"kind": "ScriptSectionStartTag",
10+
"textLength": 6
11+
}
12+
}
13+
},
14+
{
15+
"IfStatementNode": {
16+
"ifKeyword": {
17+
"kind": "IfKeyword",
18+
"textLength": 2
19+
},
20+
"openParen": {
21+
"kind": "OpenParenToken",
22+
"textLength": 1
23+
},
24+
"expression": {
25+
"ReservedWord": {
26+
"children": {
27+
"kind": "FalseReservedWord",
28+
"textLength": 5
29+
}
30+
}
31+
},
32+
"closeParen": {
33+
"kind": "CloseParenToken",
34+
"textLength": 1
35+
},
36+
"colon": null,
37+
"statements": {
38+
"NamedLabelStatement": {
39+
"name": {
40+
"kind": "Name",
41+
"textLength": 5
42+
},
43+
"colon": {
44+
"kind": "ColonToken",
45+
"textLength": 1
46+
},
47+
"statement": null
48+
}
49+
},
50+
"elseIfClauses": [],
51+
"elseClause": {
52+
"ElseClauseNode": {
53+
"elseKeyword": {
54+
"kind": "ElseKeyword",
55+
"textLength": 4
56+
},
57+
"colon": null,
58+
"statements": {
59+
"ExpressionStatement": {
60+
"expression": {
61+
"EchoExpression": {
62+
"echoKeyword": {
63+
"kind": "EchoKeyword",
64+
"textLength": 4
65+
},
66+
"expressions": {
67+
"ExpressionList": {
68+
"children": [
69+
{
70+
"StringLiteral": {
71+
"startQuote": null,
72+
"children": {
73+
"kind": "StringLiteralToken",
74+
"textLength": 8
75+
},
76+
"endQuote": null
77+
}
78+
}
79+
]
80+
}
81+
}
82+
}
83+
},
84+
"semicolon": {
85+
"kind": "SemicolonToken",
86+
"textLength": 1
87+
}
88+
}
89+
}
90+
}
91+
},
92+
"endifKeyword": null,
93+
"semicolon": null
94+
}
95+
}
96+
],
97+
"endOfFileToken": {
98+
"kind": "EndOfFileToken",
99+
"textLength": 0
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)