From d7e1799279030cfe7503faaae8d5d33862ba21f3 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 18 Aug 2023 16:53:05 +0200 Subject: [PATCH] TASK: Parse negative integer literals --- .../Parser/Expression/ExpressionParser.php | 2 + .../IntegerLiteral/IntegerLiteralParser.php | 14 ++- .../Expression/ExpressionParserTest.php | 92 +++++++++++++++++++ .../IntegerLiteralParserTest.php | 80 ++++++++++++++++ 4 files changed, 186 insertions(+), 2 deletions(-) diff --git a/src/Language/Parser/Expression/ExpressionParser.php b/src/Language/Parser/Expression/ExpressionParser.php index 237ceed..0f3ca23 100644 --- a/src/Language/Parser/Expression/ExpressionParser.php +++ b/src/Language/Parser/Expression/ExpressionParser.php @@ -67,6 +67,7 @@ final class ExpressionParser Rule::KEYWORD_NULL, Rule::KEYWORD_MATCH, Rule::STRING_LITERAL_DELIMITER, + Rule::SYMBOL_DASH, Rule::INTEGER_HEXADECIMAL, Rule::INTEGER_DECIMAL, Rule::INTEGER_OCTAL, @@ -154,6 +155,7 @@ private function parseUnaryStatement(Lexer $lexer): ExpressionNode $this->parseNullLiteral($lexer), Rule::STRING_LITERAL_DELIMITER => $this->parseStringLiteral($lexer), + Rule::SYMBOL_DASH, Rule::INTEGER_HEXADECIMAL, Rule::INTEGER_DECIMAL, Rule::INTEGER_OCTAL, diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index 583d2f3..ead23b7 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -43,12 +43,22 @@ final class IntegerLiteralParser public function parse(Lexer $lexer): IntegerLiteralNode { try { + $start = null; + $value = ''; + + if ($lexer->probe(Rule::SYMBOL_DASH)) { + $start = $lexer->buffer->getStart(); + $value = $lexer->buffer->getContents(); + } + $rule = $lexer->read(...self::RULES_INTEGER_FORMATS); + $start ??= $lexer->buffer->getStart(); + $value .= $lexer->buffer->getContents(); return new IntegerLiteralNode( - rangeInSource: $lexer->buffer->getRange(), + rangeInSource: $start->toRange($lexer->buffer->getEnd()), format: $this->getIntegerFormatFromToken($rule), - value: $lexer->buffer->getContents() + value: $value ); } catch (LexerException $e) { throw IntegerLiteralCouldNotBeParsed::becauseOfLexerException($e); diff --git a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php index bf306e9..1820ccf 100644 --- a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php +++ b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php @@ -881,6 +881,29 @@ public function parsesBinaryIntegerLiteral(): void ); } + /** + * @test + */ + public function parsesNegativeBinaryIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $lexer = new Lexer('-0b1001'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 6]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 6]), + format: IntegerFormat::BINARY, + value: '-0b1001' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($lexer) + ); + } + /** * @test */ @@ -904,6 +927,29 @@ public function parsesOctalIntegerLiteral(): void ); } + /** + * @test + */ + public function parsesNegativeOctalIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $lexer = new Lexer('-0o755'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 5]), + format: IntegerFormat::OCTAL, + value: '-0o755' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($lexer) + ); + } + /** * @test */ @@ -927,6 +973,29 @@ public function parsesDecimalIntegerLiteral(): void ); } + /** + * @test + */ + public function parsesNegativeDecimalIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $lexer = new Lexer('-42'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 2]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 2]), + format: IntegerFormat::DECIMAL, + value: '-42' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($lexer) + ); + } + /** * @test */ @@ -950,6 +1019,29 @@ public function parsesHexadecimalIntegerLiteral(): void ); } + /** + * @test + */ + public function parsesNegativeHexadecimalIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $lexer = new Lexer('-0xABC'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 5]), + format: IntegerFormat::HEXADECIMAL, + value: '-0xABC' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($lexer) + ); + } + /** * @test */ diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 99f4a8e..55570ae 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -53,6 +53,26 @@ public function parsesBinaryInteger(): void ); } + /** + * @test + */ + public function parsesNegativeBinaryInteger(): void + { + $integerLiteralParser = IntegerLiteralParser::singleton(); + $lexer = new Lexer('-0b1010110101'); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 12]), + format: IntegerFormat::BINARY, + value: '-0b1010110101' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($lexer) + ); + } + /** * @test */ @@ -73,6 +93,26 @@ public function parsesOctalInteger(): void ); } + /** + * @test + */ + public function parsesNegativeOctalInteger(): void + { + $integerLiteralParser = IntegerLiteralParser::singleton(); + $lexer = new Lexer('-0o755'); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 5]), + format: IntegerFormat::OCTAL, + value: '-0o755' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($lexer) + ); + } + /** * @test */ @@ -93,6 +133,26 @@ public function parsesDecimalInteger(): void ); } + /** + * @test + */ + public function parsesNegativeDecimalInteger(): void + { + $integerLiteralParser = IntegerLiteralParser::singleton(); + $lexer = new Lexer('-1234567890'); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 10]), + format: IntegerFormat::DECIMAL, + value: '-1234567890' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($lexer) + ); + } + /** * @test */ @@ -113,6 +173,26 @@ public function parsesHexadecimalInteger(): void ); } + /** + * @test + */ + public function parsesNegativeHexadecimalInteger(): void + { + $integerLiteralParser = IntegerLiteralParser::singleton(); + $lexer = new Lexer('-0x123456789ABCDEF'); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 17]), + format: IntegerFormat::HEXADECIMAL, + value: '-0x123456789ABCDEF' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($lexer) + ); + } + /** * @test */