From 6f9946ede1fa736ca5de9242e4af6cf3c76c0ead Mon Sep 17 00:00:00 2001 From: Stephan Unverwerth Date: Tue, 26 Sep 2017 21:28:37 +0200 Subject: [PATCH 1/2] Handle parenthesized breakout level --- src/DiagnosticsProvider.php | 39 ++++++++ .../Statement/BreakOrContinueStatement.php | 2 +- src/Parser.php | 18 +--- tests/cases/parser/breakStatement10.php | 5 + tests/cases/parser/breakStatement10.php.tree | 96 +++++++++++++++++++ tests/cases/parser/breakStatement3.php.tree | 8 +- tests/cases/parser/breakStatement4.php.tree | 8 +- tests/cases/parser/breakStatement5.php.tree | 8 +- tests/cases/parser/breakStatement6.php.tree | 8 +- tests/cases/parser/breakStatement8.php.tree | 8 +- tests/cases/parser/breakStatement9.php.tree | 8 +- tests/cases/parser/continueStatement10.php | 5 + .../cases/parser/continueStatement10.php.tree | 96 +++++++++++++++++++ .../cases/parser/continueStatement3.php.tree | 8 +- .../cases/parser/continueStatement4.php.tree | 8 +- .../cases/parser/continueStatement5.php.tree | 8 +- .../cases/parser/continueStatement6.php.tree | 8 +- .../cases/parser/continueStatement8.php.tree | 8 +- .../cases/parser/continueStatement9.php.tree | 8 +- 19 files changed, 318 insertions(+), 39 deletions(-) create mode 100644 tests/cases/parser/breakStatement10.php create mode 100644 tests/cases/parser/breakStatement10.php.tree create mode 100644 tests/cases/parser/continueStatement10.php create mode 100644 tests/cases/parser/continueStatement10.php.tree diff --git a/src/DiagnosticsProvider.php b/src/DiagnosticsProvider.php index e918fe69..ccf03343 100644 --- a/src/DiagnosticsProvider.php +++ b/src/DiagnosticsProvider.php @@ -84,6 +84,45 @@ public static function checkDiagnostics($node) { } } } + else if ($node instanceof Node\Statement\BreakOrContinueStatement) { + if ($node->breakoutLevel === null) { + return null; + } + + $breakoutLevel = $node->breakoutLevel; + while ($breakoutLevel instanceof Node\Expression\ParenthesizedExpression) { + $breakoutLevel = $breakoutLevel->expression; + } + + if ( + $breakoutLevel instanceof Node\Expression\NumericLiteral + && \in_array($breakoutLevel->children->kind, [ + TokenKind::BinaryLiteralToken, + TokenKind::DecimalLiteralToken, + TokenKind::HexadecimalLiteralToken, + TokenKind::OctalLiteralToken, + TokenKind::IntegerLiteralToken + ]) + && \intval($breakoutLevel->getText()) > 0 + ) { + return null; + } + + if ($breakoutLevel instanceof Token) { + $start = $breakoutLevel->getStartPosition(); + } + else { + $start = $breakoutLevel->getStart(); + } + $end = $breakoutLevel->getEndPosition(); + + return new Diagnostic( + DiagnosticKind::Error, + "Expected positive integer literal.", + $start, + $end - $start + ); + } } return null; } diff --git a/src/Node/Statement/BreakOrContinueStatement.php b/src/Node/Statement/BreakOrContinueStatement.php index bc4a65af..aa283de2 100644 --- a/src/Node/Statement/BreakOrContinueStatement.php +++ b/src/Node/Statement/BreakOrContinueStatement.php @@ -12,7 +12,7 @@ class BreakOrContinueStatement extends StatementNode { /** @var Token */ public $breakOrContinueKeyword; - /** @var Token|null */ + /** @var Expression|null */ public $breakoutLevel; /** @var Token */ public $semicolon; diff --git a/src/Parser.php b/src/Parser.php index 6e4782af..87a7a13f 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -1865,20 +1865,10 @@ private function parseBreakOrContinueStatement($parentNode) { $continueStatement->parent = $parentNode; $continueStatement->breakOrContinueKeyword = $this->eat(TokenKind::ContinueKeyword, TokenKind::BreakKeyword); - // TODO this level of granularity is unnecessary - integer-literal should be sufficient - $continueStatement->breakoutLevel = - $this->eatOptional( - TokenKind::BinaryLiteralToken, - TokenKind::DecimalLiteralToken, - TokenKind::InvalidHexadecimalLiteral, - TokenKind::InvalidBinaryLiteral, - TokenKind::FloatingLiteralToken, - TokenKind::HexadecimalLiteralToken, - TokenKind::OctalLiteralToken, - TokenKind::InvalidOctalLiteralToken, - // TODO the parser should be permissive of floating literals, but rule validation should produce error - TokenKind::IntegerLiteralToken - ); + if ($this->isExpressionStart($this->getCurrentToken())) { + $continueStatement->breakoutLevel = $this->parseExpression($continueStatement); + } + $continueStatement->semicolon = $this->eatSemicolonOrAbortStatement(); return $continueStatement; diff --git a/tests/cases/parser/breakStatement10.php b/tests/cases/parser/breakStatement10.php new file mode 100644 index 00000000..abb34ee6 --- /dev/null +++ b/tests/cases/parser/breakStatement10.php @@ -0,0 +1,5 @@ + Date: Tue, 26 Sep 2017 22:05:10 +0200 Subject: [PATCH 2/2] Fix breakout level number parsing --- src/DiagnosticsProvider.php | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/DiagnosticsProvider.php b/src/DiagnosticsProvider.php index ccf03343..735c1812 100644 --- a/src/DiagnosticsProvider.php +++ b/src/DiagnosticsProvider.php @@ -94,18 +94,25 @@ public static function checkDiagnostics($node) { $breakoutLevel = $breakoutLevel->expression; } - if ( - $breakoutLevel instanceof Node\Expression\NumericLiteral - && \in_array($breakoutLevel->children->kind, [ - TokenKind::BinaryLiteralToken, - TokenKind::DecimalLiteralToken, - TokenKind::HexadecimalLiteralToken, - TokenKind::OctalLiteralToken, - TokenKind::IntegerLiteralToken - ]) - && \intval($breakoutLevel->getText()) > 0 - ) { - return null; + if ($breakoutLevel instanceof Node\Expression\NumericLiteral) { + $literalString = $breakoutLevel->getText(); + if ( + $breakoutLevel->children->kind === TokenKind::BinaryLiteralToken + && \bindec(\substr($literalString, 2)) > 0 + ) { + return null; + } + else if ( + \in_array($breakoutLevel->children->kind, [ + TokenKind::DecimalLiteralToken, + TokenKind::HexadecimalLiteralToken, + TokenKind::OctalLiteralToken, + TokenKind::IntegerLiteralToken + ]) + && \intval($literalString, 0) > 0 + ) { + return null; + } } if ($breakoutLevel instanceof Token) {