Skip to content

Commit 754db66

Browse files
authored
Merge pull request microsoft#196 from MadHed/master
Handle parenthesized breakout level
2 parents 099d0b1 + 870c141 commit 754db66

19 files changed

+325
-39
lines changed

src/DiagnosticsProvider.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,52 @@ public static function checkDiagnostics($node) {
8484
}
8585
}
8686
}
87+
else if ($node instanceof Node\Statement\BreakOrContinueStatement) {
88+
if ($node->breakoutLevel === null) {
89+
return null;
90+
}
91+
92+
$breakoutLevel = $node->breakoutLevel;
93+
while ($breakoutLevel instanceof Node\Expression\ParenthesizedExpression) {
94+
$breakoutLevel = $breakoutLevel->expression;
95+
}
96+
97+
if ($breakoutLevel instanceof Node\Expression\NumericLiteral) {
98+
$literalString = $breakoutLevel->getText();
99+
if (
100+
$breakoutLevel->children->kind === TokenKind::BinaryLiteralToken
101+
&& \bindec(\substr($literalString, 2)) > 0
102+
) {
103+
return null;
104+
}
105+
else if (
106+
\in_array($breakoutLevel->children->kind, [
107+
TokenKind::DecimalLiteralToken,
108+
TokenKind::HexadecimalLiteralToken,
109+
TokenKind::OctalLiteralToken,
110+
TokenKind::IntegerLiteralToken
111+
])
112+
&& \intval($literalString, 0) > 0
113+
) {
114+
return null;
115+
}
116+
}
117+
118+
if ($breakoutLevel instanceof Token) {
119+
$start = $breakoutLevel->getStartPosition();
120+
}
121+
else {
122+
$start = $breakoutLevel->getStart();
123+
}
124+
$end = $breakoutLevel->getEndPosition();
125+
126+
return new Diagnostic(
127+
DiagnosticKind::Error,
128+
"Expected positive integer literal.",
129+
$start,
130+
$end - $start
131+
);
132+
}
87133
}
88134
return null;
89135
}

src/Node/Statement/BreakOrContinueStatement.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class BreakOrContinueStatement extends StatementNode {
1313
/** @var Token */
1414
public $breakOrContinueKeyword;
15-
/** @var Token|null */
15+
/** @var Expression|null */
1616
public $breakoutLevel;
1717
/** @var Token */
1818
public $semicolon;

src/Parser.php

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,20 +1865,10 @@ private function parseBreakOrContinueStatement($parentNode) {
18651865
$continueStatement->parent = $parentNode;
18661866
$continueStatement->breakOrContinueKeyword = $this->eat(TokenKind::ContinueKeyword, TokenKind::BreakKeyword);
18671867

1868-
// TODO this level of granularity is unnecessary - integer-literal should be sufficient
1869-
$continueStatement->breakoutLevel =
1870-
$this->eatOptional(
1871-
TokenKind::BinaryLiteralToken,
1872-
TokenKind::DecimalLiteralToken,
1873-
TokenKind::InvalidHexadecimalLiteral,
1874-
TokenKind::InvalidBinaryLiteral,
1875-
TokenKind::FloatingLiteralToken,
1876-
TokenKind::HexadecimalLiteralToken,
1877-
TokenKind::OctalLiteralToken,
1878-
TokenKind::InvalidOctalLiteralToken,
1879-
// TODO the parser should be permissive of floating literals, but rule validation should produce error
1880-
TokenKind::IntegerLiteralToken
1881-
);
1868+
if ($this->isExpressionStart($this->getCurrentToken())) {
1869+
$continueStatement->breakoutLevel = $this->parseExpression($continueStatement);
1870+
}
1871+
18821872
$continueStatement->semicolon = $this->eatSemicolonOrAbortStatement();
18831873

18841874
return $continueStatement;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
for (;;) {
4+
break (1);
5+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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+
"ForStatement": {
16+
"for": {
17+
"kind": "ForKeyword",
18+
"textLength": 3
19+
},
20+
"openParen": {
21+
"kind": "OpenParenToken",
22+
"textLength": 1
23+
},
24+
"forInitializer": null,
25+
"exprGroupSemicolon1": {
26+
"kind": "SemicolonToken",
27+
"textLength": 1
28+
},
29+
"forControl": null,
30+
"exprGroupSemicolon2": {
31+
"kind": "SemicolonToken",
32+
"textLength": 1
33+
},
34+
"forEndOfLoop": null,
35+
"closeParen": {
36+
"kind": "CloseParenToken",
37+
"textLength": 1
38+
},
39+
"colon": null,
40+
"statements": {
41+
"CompoundStatementNode": {
42+
"openBrace": {
43+
"kind": "OpenBraceToken",
44+
"textLength": 1
45+
},
46+
"statements": [
47+
{
48+
"BreakOrContinueStatement": {
49+
"breakOrContinueKeyword": {
50+
"kind": "BreakKeyword",
51+
"textLength": 5
52+
},
53+
"breakoutLevel": {
54+
"ParenthesizedExpression": {
55+
"openParen": {
56+
"kind": "OpenParenToken",
57+
"textLength": 1
58+
},
59+
"expression": {
60+
"NumericLiteral": {
61+
"children": {
62+
"kind": "IntegerLiteralToken",
63+
"textLength": 1
64+
}
65+
}
66+
},
67+
"closeParen": {
68+
"kind": "CloseParenToken",
69+
"textLength": 1
70+
}
71+
}
72+
},
73+
"semicolon": {
74+
"kind": "SemicolonToken",
75+
"textLength": 1
76+
}
77+
}
78+
}
79+
],
80+
"closeBrace": {
81+
"kind": "CloseBraceToken",
82+
"textLength": 1
83+
}
84+
}
85+
},
86+
"endFor": null,
87+
"endForSemicolon": null
88+
}
89+
}
90+
],
91+
"endOfFileToken": {
92+
"kind": "EndOfFileToken",
93+
"textLength": 0
94+
}
95+
}
96+
}

tests/cases/parser/breakStatement3.php.tree

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,12 @@
117117
"textLength": 5
118118
},
119119
"breakoutLevel": {
120-
"kind": "IntegerLiteralToken",
121-
"textLength": 4
120+
"NumericLiteral": {
121+
"children": {
122+
"kind": "IntegerLiteralToken",
123+
"textLength": 4
124+
}
125+
}
122126
},
123127
"semicolon": {
124128
"kind": "SemicolonToken",

tests/cases/parser/breakStatement4.php.tree

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,12 @@
117117
"textLength": 5
118118
},
119119
"breakoutLevel": {
120-
"kind": "IntegerLiteralToken",
121-
"textLength": 2
120+
"NumericLiteral": {
121+
"children": {
122+
"kind": "IntegerLiteralToken",
123+
"textLength": 2
124+
}
125+
}
122126
},
123127
"semicolon": {
124128
"kind": "SemicolonToken",

tests/cases/parser/breakStatement5.php.tree

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@
8484
"textLength": 5
8585
},
8686
"breakoutLevel": {
87-
"kind": "FloatingLiteralToken",
88-
"textLength": 3
87+
"NumericLiteral": {
88+
"children": {
89+
"kind": "FloatingLiteralToken",
90+
"textLength": 3
91+
}
92+
}
8993
},
9094
"semicolon": {
9195
"kind": "SemicolonToken",

tests/cases/parser/breakStatement6.php.tree

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@
8484
"textLength": 5
8585
},
8686
"breakoutLevel": {
87-
"kind": "IntegerLiteralToken",
88-
"textLength": 1
87+
"NumericLiteral": {
88+
"children": {
89+
"kind": "IntegerLiteralToken",
90+
"textLength": 1
91+
}
92+
}
8993
},
9094
"semicolon": {
9195
"kind": "SemicolonToken",

tests/cases/parser/breakStatement8.php.tree

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@
5151
"textLength": 5
5252
},
5353
"breakoutLevel": {
54-
"kind": "IntegerLiteralToken",
55-
"textLength": 3
54+
"NumericLiteral": {
55+
"children": {
56+
"kind": "IntegerLiteralToken",
57+
"textLength": 3
58+
}
59+
}
5660
},
5761
"semicolon": {
5862
"kind": "SemicolonToken",

0 commit comments

Comments
 (0)