From ca51f994c6701cfdc00bb9d2676e1fd003bc3b9e Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 25 Jul 2023 13:04:24 +0200 Subject: [PATCH 01/64] !!!TASK: Give ImportNode only the source path, not the entire source --- .../Loader/ModuleFile/ModuleFileLoader.php | 2 +- src/Parser/Ast/ImportNode.php | 8 ++--- src/Parser/Source/Path.php | 5 +++ src/Parser/Tokenizer/Scanner.php | 8 ++--- src/Parser/Tokenizer/Token.php | 10 +++--- .../Module/Loader/Fixtures/DummyLoader.php | 2 +- test/Unit/Parser/Source/PathTest.php | 36 +++++++++++++++++++ 7 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/Module/Loader/ModuleFile/ModuleFileLoader.php b/src/Module/Loader/ModuleFile/ModuleFileLoader.php index 7581f0b3..f937c0e4 100644 --- a/src/Module/Loader/ModuleFile/ModuleFileLoader.php +++ b/src/Module/Loader/ModuleFile/ModuleFileLoader.php @@ -41,7 +41,7 @@ final class ModuleFileLoader implements LoaderInterface { public function resolveTypeOfImport(ImportNode $importNode): TypeInterface { - $pathToImportFrom = $importNode->source->path->resolveRelationTo( + $pathToImportFrom = $importNode->sourcePath->resolveRelationTo( Path::fromString($importNode->path) ); $source = Source::fromFile($pathToImportFrom->value); diff --git a/src/Parser/Ast/ImportNode.php b/src/Parser/Ast/ImportNode.php index 32446b37..295dd440 100644 --- a/src/Parser/Ast/ImportNode.php +++ b/src/Parser/Ast/ImportNode.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Parser\Ast; use PackageFactory\ComponentEngine\Parser\Ast\IdentifierNode; -use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -31,7 +31,7 @@ final class ImportNode implements \JsonSerializable { private function __construct( - public readonly Source $source, + public readonly Path $sourcePath, public readonly string $path, public readonly IdentifierNode $name ) { @@ -46,7 +46,7 @@ public static function fromTokens(\Iterator $tokens): \Iterator Scanner::skipSpaceAndComments($tokens); Scanner::assertType($tokens, TokenType::KEYWORD_FROM); - $source = Scanner::source($tokens); + $sourcePath = Scanner::sourcePath($tokens); Scanner::skipOne($tokens); Scanner::skipSpaceAndComments($tokens); @@ -64,7 +64,7 @@ public static function fromTokens(\Iterator $tokens): \Iterator while (true) { $identifier = IdentifierNode::fromTokens($tokens); - yield new self($source, $path, $identifier); + yield new self($sourcePath, $path, $identifier); Scanner::skipSpaceAndComments($tokens); if (Scanner::type($tokens) === TokenType::COMMA) { diff --git a/src/Parser/Source/Path.php b/src/Parser/Source/Path.php index 4880e0e5..a3217a9d 100644 --- a/src/Parser/Source/Path.php +++ b/src/Parser/Source/Path.php @@ -113,6 +113,11 @@ public function resolveRelationTo(Path $other): self } } + public function equals(Path $other): bool + { + return $this->value === $other->value; + } + public function __toString(): string { return $this->value; diff --git a/src/Parser/Tokenizer/Scanner.php b/src/Parser/Tokenizer/Scanner.php index 5aa89761..c6cc21bf 100644 --- a/src/Parser/Tokenizer/Scanner.php +++ b/src/Parser/Tokenizer/Scanner.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Parser\Tokenizer; -use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Source\Path; final class Scanner { @@ -149,12 +149,12 @@ public static function type(\Iterator $tokens): TokenType /** * @param \Iterator $tokens - * @return Source + * @return Path */ - public static function source(\Iterator $tokens): Source + public static function sourcePath(\Iterator $tokens): Path { self::assertValid($tokens); - return $tokens->current()->source; + return $tokens->current()->sourcePath; } /** diff --git a/src/Parser/Tokenizer/Token.php b/src/Parser/Tokenizer/Token.php index 7e4cbf45..6eaf6768 100644 --- a/src/Parser/Tokenizer/Token.php +++ b/src/Parser/Tokenizer/Token.php @@ -23,8 +23,8 @@ namespace PackageFactory\ComponentEngine\Parser\Tokenizer; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; -use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Source\Fragment; +use PackageFactory\ComponentEngine\Parser\Source\Path; final class Token { @@ -32,7 +32,7 @@ private function __construct( public readonly TokenType $type, public readonly string $value, public readonly Boundaries $boundaries, - public readonly Source $source + public readonly Path $sourcePath ) { } @@ -44,7 +44,7 @@ public static function fromFragment( $type, $fragment->value, Boundaries::fromPositions($fragment->start, $fragment->end), - $fragment->source + $fragment->source->path ); } @@ -57,7 +57,7 @@ public static function emptyFromDelimitingFragments( $type, '', Boundaries::fromPositions($startFragment->start, $endFragment->end), - $startFragment->source + $startFragment->source->path ); } @@ -66,7 +66,7 @@ public function equals(Token $other): bool return ($this->type === $other->type && $this->value === $other->value && $this->boundaries->equals($other->boundaries) - && $this->source->equals($other->source) + && $this->sourcePath->equals($other->sourcePath) ); } diff --git a/test/Unit/Module/Loader/Fixtures/DummyLoader.php b/test/Unit/Module/Loader/Fixtures/DummyLoader.php index f74a6a80..2a687a67 100644 --- a/test/Unit/Module/Loader/Fixtures/DummyLoader.php +++ b/test/Unit/Module/Loader/Fixtures/DummyLoader.php @@ -43,7 +43,7 @@ public function resolveTypeOfImport(ImportNode $importNode): TypeInterface } throw new \Exception( - '[DummyLoader] Cannot import "' . $importNode->name->value . '" from "' . $importNode->source->path->value . '"' + '[DummyLoader] Cannot import "' . $importNode->name->value . '" from "' . $importNode->sourcePath->value . '"' ); } diff --git a/test/Unit/Parser/Source/PathTest.php b/test/Unit/Parser/Source/PathTest.php index 0c94b311..f426ceba 100644 --- a/test/Unit/Parser/Source/PathTest.php +++ b/test/Unit/Parser/Source/PathTest.php @@ -94,4 +94,40 @@ public function resolvesRelationToOtherPath(string $pathAsString, string $otherP $path->resolveRelationTo($otherPath)->value ); } + + /** + * @test + */ + public function equalsOtherPathIfValuesAreIdentical(): void + { + $path = Path::fromString('/some/where/in/the/filesystem'); + $otherPath = Path::fromString('/some/where/in/the/filesystem'); + + $this->assertTrue($path->equals($otherPath)); + $this->assertTrue($otherPath->equals($path)); + } + + /** + * @test + */ + public function doesNotEqualOtherPathIfValuesAreNotIdentical(): void + { + $path = Path::fromString('/some/where/in/the/filesystem'); + $otherPath = Path::fromString('/else/where/in/the/filesystem'); + + $this->assertFalse($path->equals($otherPath)); + $this->assertFalse($otherPath->equals($path)); + } + + /** + * @test + */ + public function memoryPathsEqualEachOther(): void + { + $path = Path::createMemory(); + $otherPath = Path::createMemory(); + + $this->assertTrue($path->equals($otherPath)); + $this->assertTrue($otherPath->equals($path)); + } } From 1406f9ee3ffce47eba200883d4ec15d9c26caf35 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 25 Jul 2023 13:51:37 +0200 Subject: [PATCH 02/64] TASK: Implement `BooleanLiteralParser` --- .../AST/BooleanLiteral/BooleanLiteralNode.php | 34 +++++++++ .../BooleanLiteral/BooleanLiteralParser.php | 54 ++++++++++++++ src/Language/Shared/Location/Location.php | 35 +++++++++ .../BooleanLiteralParserTest.php | 71 +++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 src/Language/AST/BooleanLiteral/BooleanLiteralNode.php create mode 100644 src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php create mode 100644 src/Language/Shared/Location/Location.php create mode 100644 test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php diff --git a/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php b/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php new file mode 100644 index 00000000..22fba3e1 --- /dev/null +++ b/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php @@ -0,0 +1,34 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\BooleanLiteral; + +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; + +final class BooleanLiteralNode +{ + public function __construct( + public readonly Location $location, + public readonly bool $value + ) { + } +} diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php new file mode 100644 index 00000000..62ae1779 --- /dev/null +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -0,0 +1,54 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral; + +use PackageFactory\ComponentEngine\Language\AST\BooleanLiteral\BooleanLiteralNode; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class BooleanLiteralParser +{ + /** + * @param \Iterator $tokens + * @return BooleanLiteralNode + */ + public function parse(\Iterator $tokens): BooleanLiteralNode + { + Scanner::assertType($tokens, TokenType::KEYWORD_TRUE, TokenType::KEYWORD_FALSE); + + $token = $tokens->current(); + $value = $token->type === TokenType::KEYWORD_TRUE; + + Scanner::skipOne($tokens); + + return new BooleanLiteralNode( + location: new Location( + sourcePath: $token->sourcePath, + boundaries: $token->boundaries + ), + value: $value + ); + } +} diff --git a/src/Language/Shared/Location/Location.php b/src/Language/Shared/Location/Location.php new file mode 100644 index 00000000..073808cd --- /dev/null +++ b/src/Language/Shared/Location/Location.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Shared\Location; + +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Path; + +final class Location +{ + public function __construct( + public readonly Path $sourcePath, + public readonly Boundaries $boundaries + ) { + } +} diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php new file mode 100644 index 00000000..c3392fc0 --- /dev/null +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -0,0 +1,71 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\BooleanLiteral; + +use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class BooleanLiteralParserTest extends TestCase +{ + /** + * @test + */ + public function producesAstNodeForTrueIfGivenOneTrueToken(): void + { + $booleanLiteralParser = new BooleanLiteralParser(); + + $tokens = Tokenizer::fromSource(Source::fromString('true'))->getIterator(); + $booleanLiteralNode = $booleanLiteralParser->parse($tokens); + + $this->assertEquals(true, $booleanLiteralNode->value); + $this->assertEquals(':memory:', $booleanLiteralNode->location->sourcePath); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->index); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->rowIndex); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->columnIndex); + $this->assertEquals(3, $booleanLiteralNode->location->boundaries->end->index); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->end->rowIndex); + $this->assertEquals(3, $booleanLiteralNode->location->boundaries->end->columnIndex); + } + + /** + * @test + */ + public function producesAstNodeForFalseIfGivenOneFalseToken(): void + { + $booleanLiteralParser = new BooleanLiteralParser(); + + $tokens = Tokenizer::fromSource(Source::fromString('false'))->getIterator(); + $booleanLiteralNode = $booleanLiteralParser->parse($tokens); + + $this->assertEquals(false, $booleanLiteralNode->value); + $this->assertEquals(':memory:', $booleanLiteralNode->location->sourcePath); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->index); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->rowIndex); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->columnIndex); + $this->assertEquals(4, $booleanLiteralNode->location->boundaries->end->index); + $this->assertEquals(0, $booleanLiteralNode->location->boundaries->end->rowIndex); + $this->assertEquals(4, $booleanLiteralNode->location->boundaries->end->columnIndex); + } +} From 4c4ffa6f1ce50f11c4e6235d7259fbf3177150db Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 25 Jul 2023 14:32:56 +0200 Subject: [PATCH 03/64] TASK: Implement `NullLiteralParser` --- .../AST/NullLiteral/NullLiteralNode.php | 33 ++++++++++++ .../Parser/NullLiteral/NullLiteralParser.php | 52 +++++++++++++++++++ .../NullLiteral/NullLiteralParserTest.php | 50 ++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/Language/AST/NullLiteral/NullLiteralNode.php create mode 100644 src/Language/Parser/NullLiteral/NullLiteralParser.php create mode 100644 test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php diff --git a/src/Language/AST/NullLiteral/NullLiteralNode.php b/src/Language/AST/NullLiteral/NullLiteralNode.php new file mode 100644 index 00000000..b7bdfa12 --- /dev/null +++ b/src/Language/AST/NullLiteral/NullLiteralNode.php @@ -0,0 +1,33 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\NullLiteral; + +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; + +final class NullLiteralNode +{ + public function __construct( + public readonly Location $location + ) { + } +} diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php new file mode 100644 index 00000000..5e72ff42 --- /dev/null +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -0,0 +1,52 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\NullLiteral; + +use PackageFactory\ComponentEngine\Language\AST\NullLiteral\NullLiteralNode; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class NullLiteralParser +{ + /** + * @param \Iterator $tokens + * @return NullLiteralNode + */ + public function parse(\Iterator $tokens): NullLiteralNode + { + Scanner::assertType($tokens, TokenType::KEYWORD_NULL); + + $token = $tokens->current(); + + Scanner::skipOne($tokens); + + return new NullLiteralNode( + location: new Location( + sourcePath: $token->sourcePath, + boundaries: $token->boundaries + ) + ); + } +} diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php new file mode 100644 index 00000000..f3255220 --- /dev/null +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -0,0 +1,50 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\NullLiteral; + +use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class NullLiteralParserTest extends TestCase +{ + /** + * @test + */ + public function producesAstNodeForNullIfGivenOneNullToken(): void + { + $nullLiteralParser = new NullLiteralParser(); + + $tokens = Tokenizer::fromSource(Source::fromString('null'))->getIterator(); + $nullLiteralNode = $nullLiteralParser->parse($tokens); + + $this->assertEquals(':memory:', $nullLiteralNode->location->sourcePath); + $this->assertEquals(0, $nullLiteralNode->location->boundaries->start->index); + $this->assertEquals(0, $nullLiteralNode->location->boundaries->start->rowIndex); + $this->assertEquals(0, $nullLiteralNode->location->boundaries->start->columnIndex); + $this->assertEquals(3, $nullLiteralNode->location->boundaries->end->index); + $this->assertEquals(0, $nullLiteralNode->location->boundaries->end->rowIndex); + $this->assertEquals(3, $nullLiteralNode->location->boundaries->end->columnIndex); + } +} From c9064d050345e9eac74182cde03e9f5ead58d08d Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 26 Jul 2023 14:24:46 +0200 Subject: [PATCH 04/64] TASK: Implement `IntegerLiteralParser` --- .../AST/IntegerLiteral/IntegerFormat.php | 45 ++++++++++++++++ .../AST/IntegerLiteral/IntegerLiteralNode.php | 35 ++++++++++++ .../IntegerLiteral/IntegerLiteralParser.php | 53 +++++++++++++++++++ .../IntegerLiteralParserTest.php | 51 ++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 src/Language/AST/IntegerLiteral/IntegerFormat.php create mode 100644 src/Language/AST/IntegerLiteral/IntegerLiteralNode.php create mode 100644 src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php create mode 100644 test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php diff --git a/src/Language/AST/IntegerLiteral/IntegerFormat.php b/src/Language/AST/IntegerLiteral/IntegerFormat.php new file mode 100644 index 00000000..e1699062 --- /dev/null +++ b/src/Language/AST/IntegerLiteral/IntegerFormat.php @@ -0,0 +1,45 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\IntegerLiteral; + +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +enum IntegerFormat: string +{ + case BINARY = 'BINARY'; + case OCTAL = 'OCTAL'; + case DECIMAL = 'DECIMAL'; + case HEXADECIMAL = 'HEXADECIMAL'; + + public static function fromTokenType(TokenType $tokenType): self + { + return match ($tokenType) { + TokenType::NUMBER_BINARY => self::BINARY, + TokenType::NUMBER_OCTAL => self::OCTAL, + TokenType::NUMBER_DECIMAL => self::DECIMAL, + TokenType::NUMBER_HEXADECIMAL => self::HEXADECIMAL, + + default => throw new \Exception('@TODO: Unknown Integer Format: ' . $tokenType->value) + }; + } +} diff --git a/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php b/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php new file mode 100644 index 00000000..06fb9975 --- /dev/null +++ b/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\IntegerLiteral; + +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; + +final class IntegerLiteralNode +{ + public function __construct( + public readonly Location $location, + public readonly IntegerFormat $format, + public readonly string $value + ) { + } +} diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php new file mode 100644 index 00000000..421c2503 --- /dev/null +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral; + +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class IntegerLiteralParser +{ + /** + * @param \Iterator $tokens + * @return IntegerLiteralNode + */ + public function parse(\Iterator $tokens): IntegerLiteralNode + { + $token = $tokens->current(); + + Scanner::skipOne($tokens); + + return new IntegerLiteralNode( + location: new Location( + sourcePath: $token->sourcePath, + boundaries: $token->boundaries + ), + format: IntegerFormat::fromTokenType($token->type), + value: $token->value + ); + } +} diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php new file mode 100644 index 00000000..976de20a --- /dev/null +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\IntegerLiteral; + +use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class IntegerLiteralParserTest extends TestCase +{ + /** + * @test + */ + public function producesIntegerLiteralNodeForDecimals(): void + { + $integerLiteralParser = new IntegerLiteralParser(); + + $tokens = Tokenizer::fromSource(Source::fromString('1234567890'))->getIterator(); + $integerLiteralNode = $integerLiteralParser->parse($tokens); + + $this->assertEquals('1234567890', $integerLiteralNode->value); + $this->assertEquals(':memory:', $integerLiteralNode->location->sourcePath); + $this->assertEquals(0, $integerLiteralNode->location->boundaries->start->index); + $this->assertEquals(0, $integerLiteralNode->location->boundaries->start->rowIndex); + $this->assertEquals(0, $integerLiteralNode->location->boundaries->start->columnIndex); + $this->assertEquals(9, $integerLiteralNode->location->boundaries->end->index); + $this->assertEquals(0, $integerLiteralNode->location->boundaries->end->rowIndex); + $this->assertEquals(9, $integerLiteralNode->location->boundaries->end->columnIndex); + } +} From eb29f484cd93401cdb65cf70ebb4d5f308ceebb4 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 26 Jul 2023 14:52:47 +0200 Subject: [PATCH 05/64] TASK: Implement `StringLiteralParser` --- .../AST/StringLiteral/StringLiteralNode.php | 34 ++++++++++++ .../StringLiteral/StringLiteralParser.php | 53 +++++++++++++++++++ .../StringLiteral/StringLiteralParserTest.php | 51 ++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 src/Language/AST/StringLiteral/StringLiteralNode.php create mode 100644 src/Language/Parser/StringLiteral/StringLiteralParser.php create mode 100644 test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php diff --git a/src/Language/AST/StringLiteral/StringLiteralNode.php b/src/Language/AST/StringLiteral/StringLiteralNode.php new file mode 100644 index 00000000..3ff07033 --- /dev/null +++ b/src/Language/AST/StringLiteral/StringLiteralNode.php @@ -0,0 +1,34 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\StringLiteral; + +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; + +final class StringLiteralNode +{ + public function __construct( + public readonly Location $location, + public readonly string $value + ) { + } +} diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php new file mode 100644 index 00000000..1c8e2bd4 --- /dev/null +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\StringLiteral; + +use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class StringLiteralParser +{ + /** + * @param \Iterator $tokens + * @return StringLiteralNode + */ + public function parse(\Iterator $tokens): StringLiteralNode + { + Scanner::assertType($tokens, TokenType::STRING_QUOTED); + + $token = $tokens->current(); + + Scanner::skipOne($tokens); + + return new StringLiteralNode( + location: new Location( + sourcePath: $token->sourcePath, + boundaries: $token->boundaries + ), + value: $token->value + ); + } +} diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php new file mode 100644 index 00000000..787ae4f1 --- /dev/null +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\StringLiteral; + +use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class StringLiteralParserTest extends TestCase +{ + /** + * @test + */ + public function producesStringLiteralNodeForLiteralString(): void + { + $stringLiteralParser = new StringLiteralParser(); + + $tokens = Tokenizer::fromSource(Source::fromString('"Hello World"'))->getIterator(); + $stringLiteralNode = $stringLiteralParser->parse($tokens); + + $this->assertEquals('Hello World', $stringLiteralNode->value); + $this->assertEquals(':memory:', $stringLiteralNode->location->sourcePath); + $this->assertEquals(1, $stringLiteralNode->location->boundaries->start->index); + $this->assertEquals(0, $stringLiteralNode->location->boundaries->start->rowIndex); + $this->assertEquals(1, $stringLiteralNode->location->boundaries->start->columnIndex); + $this->assertEquals(11, $stringLiteralNode->location->boundaries->end->index); + $this->assertEquals(0, $stringLiteralNode->location->boundaries->end->rowIndex); + $this->assertEquals(11, $stringLiteralNode->location->boundaries->end->columnIndex); + } +} From 8a20958347398ea885fe8e9e81db7f8dd936be27 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 12:10:36 +0200 Subject: [PATCH 06/64] TASK: Implement `EnumDeclarationParser` --- .../EnumDeclaration/EnumDeclarationNode.php | 35 + .../EnumMemberDeclarationNode.php | 38 + .../EnumMemberDeclarationNodes.php | 42 ++ .../AST/EnumDeclaration/EnumMemberName.php | 36 + src/Language/AST/EnumDeclaration/EnumName.php | 36 + .../EnumDeclaration/EnumDeclarationParser.php | 151 ++++ .../EnumDeclarationParserTest.php | 709 ++++++++++++++++++ 7 files changed, 1047 insertions(+) create mode 100644 src/Language/AST/EnumDeclaration/EnumDeclarationNode.php create mode 100644 src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php create mode 100644 src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php create mode 100644 src/Language/AST/EnumDeclaration/EnumMemberName.php create mode 100644 src/Language/AST/EnumDeclaration/EnumName.php create mode 100644 src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php create mode 100644 test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php diff --git a/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php new file mode 100644 index 00000000..5239d44b --- /dev/null +++ b/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; + +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; + +final class EnumDeclarationNode +{ + public function __construct( + public readonly Location $location, + public readonly EnumName $enumName, + public readonly EnumMemberDeclarationNodes $memberDeclarations + ) { + } +} diff --git a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php new file mode 100644 index 00000000..25bf4b65 --- /dev/null +++ b/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; + +final class EnumMemberDeclarationNode +{ + public function __construct( + public readonly Location $location, + public readonly EnumMemberName $name, + public readonly null|StringLiteralNode|IntegerLiteralNode $value + ) { + } +} diff --git a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php b/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php new file mode 100644 index 00000000..7055e406 --- /dev/null +++ b/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php @@ -0,0 +1,42 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; + +final class EnumMemberDeclarationNodes +{ + /** + * @var array + */ + public readonly array $items; + + public function __construct( + EnumMemberDeclarationNode ...$items + ) { + $itemsAsHashMap = []; + foreach ($items as $item) { + $itemsAsHashMap[$item->name->value] = $item; + } + + $this->items = $itemsAsHashMap; + } +} diff --git a/src/Language/AST/EnumDeclaration/EnumMemberName.php b/src/Language/AST/EnumDeclaration/EnumMemberName.php new file mode 100644 index 00000000..18e5e0bb --- /dev/null +++ b/src/Language/AST/EnumDeclaration/EnumMemberName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; + +final class EnumMemberName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/EnumDeclaration/EnumName.php b/src/Language/AST/EnumDeclaration/EnumName.php new file mode 100644 index 00000000..cc004127 --- /dev/null +++ b/src/Language/AST/EnumDeclaration/EnumName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; + +final class EnumName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php new file mode 100644 index 00000000..4ba6ea60 --- /dev/null +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -0,0 +1,151 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumName; +use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class EnumDeclarationParser +{ + /** + * @param \Iterator $tokens + * @return EnumDeclarationNode + */ + public function parse(\Iterator $tokens): EnumDeclarationNode + { + Scanner::assertType($tokens, TokenType::KEYWORD_ENUM); + + $enumKeyWordToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + Scanner::assertType($tokens, TokenType::STRING); + + $enumKeyNameToken = $tokens->current(); + $enumName = EnumName::from($enumKeyNameToken->value); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + + $enumMemberDeclarations = $this->parseEnumMemberDeclarations($tokens); + + Scanner::skipSpace($tokens); + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + + $closingBracketToken = $tokens->current(); + + Scanner::skipOne($tokens); + + return new EnumDeclarationNode( + location: new Location( + sourcePath: $enumKeyWordToken->sourcePath, + boundaries: Boundaries::fromPositions( + $enumKeyWordToken->boundaries->start, + $closingBracketToken->boundaries->end + ) + ), + enumName: $enumName, + memberDeclarations: $enumMemberDeclarations + ); + } + + /** + * @param \Iterator $tokens + * @return EnumMemberDeclarationNodes + */ + private function parseEnumMemberDeclarations(\Iterator $tokens): EnumMemberDeclarationNodes + { + $items = []; + while (true) { + Scanner::skipSpaceAndComments($tokens); + + switch (Scanner::type($tokens)) { + case TokenType::STRING: + $items[] = $this->parseEnumMemberDeclarationNode($tokens); + break; + case TokenType::BRACKET_CURLY_CLOSE: + break 2; + default: + Scanner::assertType($tokens, TokenType::STRING, TokenType::BRACKET_CURLY_CLOSE); + } + } + + return new EnumMemberDeclarationNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return EnumMemberDeclarationNode + */ + private function parseEnumMemberDeclarationNode(\Iterator $tokens): EnumMemberDeclarationNode + { + Scanner::skipSpaceAndComments($tokens); + Scanner::assertType($tokens, TokenType::STRING); + + $enumMemberNameToken = $finalToken = $tokens->current(); + $enumMemberName = EnumMemberName::from($enumMemberNameToken->value); + + Scanner::skipOne($tokens); + + $value = null; + if (Scanner::type($tokens) === TokenType::BRACKET_ROUND_OPEN) { + Scanner::skipOne($tokens); + $valueToken = $tokens->current(); + $value = match ($valueToken->type) { + TokenType::STRING_QUOTED => + (new StringLiteralParser())->parse($tokens), + TokenType::NUMBER_DECIMAL => + (new IntegerLiteralParser())->parse($tokens), + default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) + }; + Scanner::assertType($tokens, TokenType::BRACKET_ROUND_CLOSE); + $finalToken = $tokens->current(); + + Scanner::skipOne($tokens); + } + + return new EnumMemberDeclarationNode( + location: new Location( + sourcePath: $enumMemberNameToken->sourcePath, + boundaries: Boundaries::fromPositions( + $enumMemberNameToken->boundaries->start, + $finalToken->boundaries->end + ) + ), + name: $enumMemberName, + value: $value + ); + } +} diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php new file mode 100644 index 00000000..d608177c --- /dev/null +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -0,0 +1,709 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\EnumDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumName; +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class EnumDeclarationParserTest extends TestCase +{ + /** + * @test + */ + public function oneValuelessMember(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(15, 0, 15) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(13, 0, 13) + ) + ), + name: EnumMemberName::from('BAR'), + value: null + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function threeValuelessMembers(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR BAZ QUX }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(23, 0, 23) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(13, 0, 13) + ) + ), + name: EnumMemberName::from('BAR'), + value: null + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(15, 0, 15), + Position::create(17, 0, 17) + ) + ), + name: EnumMemberName::from('BAZ'), + value: null + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(19, 0, 19), + Position::create(21, 0, 21) + ) + ), + name: EnumMemberName::from('QUX'), + value: null + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function oneStringValueMember(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR("BAR") }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(22, 0, 22) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(20, 0, 20) + ) + ), + name: EnumMemberName::from('BAR'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(16, 0, 16), + Position::create(18, 0, 18) + ) + ), + value: 'BAR' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function sevenStringValueMembers(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $enumAsString = <<getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(149, 8, 0) + ) + ), + enumName: EnumName::from('Weekday'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(19, 1, 4), + Position::create(31, 1, 16) + ) + ), + name: EnumMemberName::from('MONDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(27, 1, 12), + Position::create(29, 1, 14) + ) + ), + value: 'mon' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(37, 2, 4), + Position::create(50, 2, 17) + ) + ), + name: EnumMemberName::from('TUESDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(46, 2, 13), + Position::create(48, 2, 15) + ) + ), + value: 'tue' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(56, 3, 4), + Position::create(71, 3, 19) + ) + ), + name: EnumMemberName::from('WEDNESDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(67, 3, 15), + Position::create(69, 3, 17) + ) + ), + value: 'wed' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(77, 4, 4), + Position::create(91, 4, 18) + ) + ), + name: EnumMemberName::from('THURSDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(87, 4, 14), + Position::create(89, 4, 16) + ) + ), + value: 'thu' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(97, 5, 4), + Position::create(109, 5, 16) + ) + ), + name: EnumMemberName::from('FRIDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(105, 5, 12), + Position::create(107, 5, 14) + ) + ), + value: 'fri' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(115, 6, 4), + Position::create(129, 6, 18) + ) + ), + name: EnumMemberName::from('SATURDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(125, 6, 14), + Position::create(127, 6, 16) + ) + ), + value: 'sat' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(135, 7, 4), + Position::create(147, 7, 16) + ) + ), + name: EnumMemberName::from('SUNDAY'), + value: new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(143, 7, 12), + Position::create(145, 7, 14) + ) + ), + value: 'sun' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function oneIntegerValueMember(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(42) }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(19, 0, 19) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(17, 0, 17) + ) + ), + name: EnumMemberName::from('BAR'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(15, 0, 15), + Position::create(16, 0, 16) + ) + ), + format: IntegerFormat::DECIMAL, + value: '42' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function twelveIntegerValueMembers(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $enumAsString = <<getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(186, 13, 0) + ) + ), + enumName: EnumName::from('Month'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(17, 1, 4), + Position::create(26, 1, 13) + ) + ), + name: EnumMemberName::from('JANUARY'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(25, 1, 12), + Position::create(25, 1, 12) + ) + ), + format: IntegerFormat::DECIMAL, + value: '1' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(32, 2, 4), + Position::create(42, 2, 14) + ) + ), + name: EnumMemberName::from('FEBRUARY'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(41, 2, 13), + Position::create(41, 2, 13) + ) + ), + format: IntegerFormat::DECIMAL, + value: '2' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(48, 3, 4), + Position::create(55, 3, 11) + ) + ), + name: EnumMemberName::from('MARCH'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(54, 3, 10), + Position::create(54, 3, 10) + ) + ), + format: IntegerFormat::DECIMAL, + value: '3' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(61, 4, 4), + Position::create(68, 4, 11) + ) + ), + name: EnumMemberName::from('APRIL'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(67, 4, 10), + Position::create(67, 4, 10) + ) + ), + format: IntegerFormat::DECIMAL, + value: '4' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(74, 5, 4), + Position::create(79, 5, 9) + ) + ), + name: EnumMemberName::from('MAY'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(78, 5, 8), + Position::create(78, 5, 8) + ) + ), + format: IntegerFormat::DECIMAL, + value: '5' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(85, 6, 4), + Position::create(91, 6, 10) + ) + ), + name: EnumMemberName::from('JUNE'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(90, 6, 9), + Position::create(90, 6, 9) + ) + ), + format: IntegerFormat::DECIMAL, + value: '6' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(97, 7, 4), + Position::create(103, 7, 10) + ) + ), + name: EnumMemberName::from('JULY'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(102, 7, 9), + Position::create(102, 7, 9) + ) + ), + format: IntegerFormat::DECIMAL, + value: '7' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(109, 8, 4), + Position::create(117, 8, 12) + ) + ), + name: EnumMemberName::from('AUGUST'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(116, 8, 11), + Position::create(116, 8, 11) + ) + ), + format: IntegerFormat::DECIMAL, + value: '8' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(123, 9, 4), + Position::create(134, 9, 15) + ) + ), + name: EnumMemberName::from('SEPTEMBER'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(133, 9, 14), + Position::create(133, 9, 14) + ) + ), + format: IntegerFormat::DECIMAL, + value: '9' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(140, 10, 4), + Position::create(150, 10, 14) + ) + ), + name: EnumMemberName::from('OCTOBER'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(148, 10, 12), + Position::create(149, 10, 13) + ) + ), + format: IntegerFormat::DECIMAL, + value: '10' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(156, 11, 4), + Position::create(167, 11, 15) + ) + ), + name: EnumMemberName::from('NOVEMBER'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(165, 11, 13), + Position::create(166, 11, 14) + ) + ), + format: IntegerFormat::DECIMAL, + value: '11' + ) + ), + new EnumMemberDeclarationNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(173, 12, 4), + Position::create(184, 12, 15) + ) + ), + name: EnumMemberName::from('DECEMBER'), + value: new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(182, 12, 13), + Position::create(183, 12, 14) + ) + ), + format: IntegerFormat::DECIMAL, + value: '12' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } +} From d442e4b957db4bd1f3ca980ce797e96fa8106dc0 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 12:22:42 +0200 Subject: [PATCH 07/64] TASK: Refactor BooleanLiteralParserTest to use single assertions --- .../BooleanLiteralParserTest.php | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index c3392fc0..237e8520 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -22,7 +22,12 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\BooleanLiteral; +use PackageFactory\ComponentEngine\Language\AST\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; use PHPUnit\Framework\TestCase; @@ -35,18 +40,23 @@ final class BooleanLiteralParserTest extends TestCase public function producesAstNodeForTrueIfGivenOneTrueToken(): void { $booleanLiteralParser = new BooleanLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('true'))->getIterator(); - $booleanLiteralNode = $booleanLiteralParser->parse($tokens); - $this->assertEquals(true, $booleanLiteralNode->value); - $this->assertEquals(':memory:', $booleanLiteralNode->location->sourcePath); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->index); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->rowIndex); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->columnIndex); - $this->assertEquals(3, $booleanLiteralNode->location->boundaries->end->index); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->end->rowIndex); - $this->assertEquals(3, $booleanLiteralNode->location->boundaries->end->columnIndex); + $expectedBooleanLiteralNode = new BooleanLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(3, 0, 3) + ) + ), + value: true + ); + + $this->assertEquals( + $expectedBooleanLiteralNode, + $booleanLiteralParser->parse($tokens) + ); } /** @@ -55,17 +65,22 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void public function producesAstNodeForFalseIfGivenOneFalseToken(): void { $booleanLiteralParser = new BooleanLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('false'))->getIterator(); - $booleanLiteralNode = $booleanLiteralParser->parse($tokens); - $this->assertEquals(false, $booleanLiteralNode->value); - $this->assertEquals(':memory:', $booleanLiteralNode->location->sourcePath); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->index); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->rowIndex); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->start->columnIndex); - $this->assertEquals(4, $booleanLiteralNode->location->boundaries->end->index); - $this->assertEquals(0, $booleanLiteralNode->location->boundaries->end->rowIndex); - $this->assertEquals(4, $booleanLiteralNode->location->boundaries->end->columnIndex); + $expectedBooleanLiteralNode = new BooleanLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(4, 0, 4) + ) + ), + value: false + ); + + $this->assertEquals( + $expectedBooleanLiteralNode, + $booleanLiteralParser->parse($tokens) + ); } } From 62100712fea2e62e638263b4512b8e7494b1e204 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 12:33:23 +0200 Subject: [PATCH 08/64] TASK: Refactor IntegerLiteralParserTest to use single assertion --- .../IntegerLiteralParserTest.php | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 976de20a..b4fc21f7 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -22,7 +22,13 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\IntegerLiteral; +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; use PHPUnit\Framework\TestCase; @@ -35,17 +41,23 @@ final class IntegerLiteralParserTest extends TestCase public function producesIntegerLiteralNodeForDecimals(): void { $integerLiteralParser = new IntegerLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('1234567890'))->getIterator(); - $integerLiteralNode = $integerLiteralParser->parse($tokens); - $this->assertEquals('1234567890', $integerLiteralNode->value); - $this->assertEquals(':memory:', $integerLiteralNode->location->sourcePath); - $this->assertEquals(0, $integerLiteralNode->location->boundaries->start->index); - $this->assertEquals(0, $integerLiteralNode->location->boundaries->start->rowIndex); - $this->assertEquals(0, $integerLiteralNode->location->boundaries->start->columnIndex); - $this->assertEquals(9, $integerLiteralNode->location->boundaries->end->index); - $this->assertEquals(0, $integerLiteralNode->location->boundaries->end->rowIndex); - $this->assertEquals(9, $integerLiteralNode->location->boundaries->end->columnIndex); + $expectedIntegerLiteralNode = new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(9, 0, 9) + ) + ), + format: IntegerFormat::DECIMAL, + value: '1234567890' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($tokens) + ); } } From 583baef0c2077ef9a28c53c2335f56d1ce46c215 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 12:38:30 +0200 Subject: [PATCH 09/64] TASK: Add cases for all integer formats to IntegerLiteralParserTest --- .../IntegerLiteralParserTest.php | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index b4fc21f7..67832c33 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -38,7 +38,59 @@ final class IntegerLiteralParserTest extends TestCase /** * @test */ - public function producesIntegerLiteralNodeForDecimals(): void + public function binaryInteger(): void + { + $integerLiteralParser = new IntegerLiteralParser(); + $tokens = Tokenizer::fromSource(Source::fromString('0b1010110101'))->getIterator(); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(11, 0, 11) + ) + ), + format: IntegerFormat::BINARY, + value: '0b1010110101' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function octalInteger(): void + { + $integerLiteralParser = new IntegerLiteralParser(); + $tokens = Tokenizer::fromSource(Source::fromString('0o755'))->getIterator(); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(4, 0, 4) + ) + ), + format: IntegerFormat::OCTAL, + value: '0o755' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function decimalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); $tokens = Tokenizer::fromSource(Source::fromString('1234567890'))->getIterator(); @@ -60,4 +112,30 @@ public function producesIntegerLiteralNodeForDecimals(): void $integerLiteralParser->parse($tokens) ); } + + /** + * @test + */ + public function hexadecimalInteger(): void + { + $integerLiteralParser = new IntegerLiteralParser(); + $tokens = Tokenizer::fromSource(Source::fromString('0x123456789ABCDEF'))->getIterator(); + + $expectedIntegerLiteralNode = new IntegerLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(16, 0, 16) + ) + ), + format: IntegerFormat::HEXADECIMAL, + value: '0x123456789ABCDEF' + ); + + $this->assertEquals( + $expectedIntegerLiteralNode, + $integerLiteralParser->parse($tokens) + ); + } } From 0cf8fa8127a04ae766c1601d38e8b6aa67be5511 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 12:44:32 +0200 Subject: [PATCH 10/64] TASK: Refactor NullLiteralParserTest to use single assertion --- .../NullLiteral/NullLiteralParserTest.php | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index f3255220..524c81b1 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -22,7 +22,12 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\NullLiteral; +use PackageFactory\ComponentEngine\Language\AST\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; use PHPUnit\Framework\TestCase; @@ -35,16 +40,21 @@ final class NullLiteralParserTest extends TestCase public function producesAstNodeForNullIfGivenOneNullToken(): void { $nullLiteralParser = new NullLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('null'))->getIterator(); - $nullLiteralNode = $nullLiteralParser->parse($tokens); - $this->assertEquals(':memory:', $nullLiteralNode->location->sourcePath); - $this->assertEquals(0, $nullLiteralNode->location->boundaries->start->index); - $this->assertEquals(0, $nullLiteralNode->location->boundaries->start->rowIndex); - $this->assertEquals(0, $nullLiteralNode->location->boundaries->start->columnIndex); - $this->assertEquals(3, $nullLiteralNode->location->boundaries->end->index); - $this->assertEquals(0, $nullLiteralNode->location->boundaries->end->rowIndex); - $this->assertEquals(3, $nullLiteralNode->location->boundaries->end->columnIndex); + $expectedNullLiteralNode = new NullLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(3, 0, 3) + ) + ) + ); + + $this->assertEquals( + $expectedNullLiteralNode, + $nullLiteralParser->parse($tokens) + ); } } From 28ec204348ca70f3dd962dcb84f58b758ad6c512 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 12:48:50 +0200 Subject: [PATCH 11/64] TASK: Refactor StringLiteralParserTest to use single assertion --- .../StringLiteral/StringLiteralParserTest.php | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 787ae4f1..218d32f8 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -22,7 +22,12 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\StringLiteral; +use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; +use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; use PHPUnit\Framework\TestCase; @@ -35,17 +40,22 @@ final class StringLiteralParserTest extends TestCase public function producesStringLiteralNodeForLiteralString(): void { $stringLiteralParser = new StringLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('"Hello World"'))->getIterator(); - $stringLiteralNode = $stringLiteralParser->parse($tokens); - $this->assertEquals('Hello World', $stringLiteralNode->value); - $this->assertEquals(':memory:', $stringLiteralNode->location->sourcePath); - $this->assertEquals(1, $stringLiteralNode->location->boundaries->start->index); - $this->assertEquals(0, $stringLiteralNode->location->boundaries->start->rowIndex); - $this->assertEquals(1, $stringLiteralNode->location->boundaries->start->columnIndex); - $this->assertEquals(11, $stringLiteralNode->location->boundaries->end->index); - $this->assertEquals(0, $stringLiteralNode->location->boundaries->end->rowIndex); - $this->assertEquals(11, $stringLiteralNode->location->boundaries->end->columnIndex); + $expectedStringLiteralNode = new StringLiteralNode( + location: new Location( + sourcePath: Path::fromString(':memory:'), + boundaries: Boundaries::fromPositions( + Position::create(1, 0, 1), + Position::create(11, 0, 11) + ) + ), + value: 'Hello World' + ); + + $this->assertEquals( + $expectedStringLiteralNode, + $stringLiteralParser->parse($tokens) + ); } } From 14cc6d6f63a27c3ea9ea633a6437a48845d29c19 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 13:20:10 +0200 Subject: [PATCH 12/64] TASK: Rename Location to NodeAttributes --- .../AST/BooleanLiteral/BooleanLiteralNode.php | 4 +- .../EnumDeclaration/EnumDeclarationNode.php | 4 +- .../EnumMemberDeclarationNode.php | 4 +- .../AST/IntegerLiteral/IntegerLiteralNode.php | 4 +- .../AST/NullLiteral/NullLiteralNode.php | 4 +- .../AST/StringLiteral/StringLiteralNode.php | 4 +- .../BooleanLiteral/BooleanLiteralParser.php | 8 +- .../EnumDeclaration/EnumDeclarationParser.php | 14 +- .../IntegerLiteral/IntegerLiteralParser.php | 9 +- .../Parser/NullLiteral/NullLiteralParser.php | 8 +- .../StringLiteral/StringLiteralParser.php | 8 +- .../NodeAttributes.php} | 8 +- .../BooleanLiteralParserTest.php | 22 +- .../EnumDeclarationParserTest.php | 314 +++++++++--------- .../IntegerLiteralParserTest.php | 26 +- .../NullLiteral/NullLiteralParserTest.php | 8 +- .../StringLiteral/StringLiteralParserTest.php | 8 +- 17 files changed, 228 insertions(+), 229 deletions(-) rename src/Language/Shared/{Location/Location.php => NodeAttributes/NodeAttributes.php} (84%) diff --git a/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php b/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php index 22fba3e1..2b5ee4cc 100644 --- a/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php +++ b/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php @@ -22,12 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\BooleanLiteral; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class BooleanLiteralNode { public function __construct( - public readonly Location $location, + public readonly NodeAttributes $attributes, public readonly bool $value ) { } diff --git a/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php index 5239d44b..ba8c689d 100644 --- a/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php @@ -22,12 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class EnumDeclarationNode { public function __construct( - public readonly Location $location, + public readonly NodeAttributes $attributes, public readonly EnumName $enumName, public readonly EnumMemberDeclarationNodes $memberDeclarations ) { diff --git a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php index 25bf4b65..ab49b50f 100644 --- a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php +++ b/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php @@ -25,12 +25,12 @@ use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class EnumMemberDeclarationNode { public function __construct( - public readonly Location $location, + public readonly NodeAttributes $attributes, public readonly EnumMemberName $name, public readonly null|StringLiteralNode|IntegerLiteralNode $value ) { diff --git a/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php b/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php index 06fb9975..e8af71b0 100644 --- a/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php +++ b/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php @@ -22,12 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\IntegerLiteral; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class IntegerLiteralNode { public function __construct( - public readonly Location $location, + public readonly NodeAttributes $attributes, public readonly IntegerFormat $format, public readonly string $value ) { diff --git a/src/Language/AST/NullLiteral/NullLiteralNode.php b/src/Language/AST/NullLiteral/NullLiteralNode.php index b7bdfa12..f6cd5807 100644 --- a/src/Language/AST/NullLiteral/NullLiteralNode.php +++ b/src/Language/AST/NullLiteral/NullLiteralNode.php @@ -22,12 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\NullLiteral; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class NullLiteralNode { public function __construct( - public readonly Location $location + public readonly NodeAttributes $attributes ) { } } diff --git a/src/Language/AST/StringLiteral/StringLiteralNode.php b/src/Language/AST/StringLiteral/StringLiteralNode.php index 3ff07033..880eae05 100644 --- a/src/Language/AST/StringLiteral/StringLiteralNode.php +++ b/src/Language/AST/StringLiteral/StringLiteralNode.php @@ -22,12 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\StringLiteral; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class StringLiteralNode { public function __construct( - public readonly Location $location, + public readonly NodeAttributes $attributes, public readonly string $value ) { } diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index 62ae1779..f1203f54 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral; use PackageFactory\ComponentEngine\Language\AST\BooleanLiteral\BooleanLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -44,9 +44,9 @@ public function parse(\Iterator $tokens): BooleanLiteralNode Scanner::skipOne($tokens); return new BooleanLiteralNode( - location: new Location( - sourcePath: $token->sourcePath, - boundaries: $token->boundaries + attributes: new NodeAttributes( + pathToSource: $token->sourcePath, + rangeInSource: $token->boundaries ), value: $value ); diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 4ba6ea60..53512673 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -29,7 +29,7 @@ use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumName; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -69,9 +69,9 @@ public function parse(\Iterator $tokens): EnumDeclarationNode Scanner::skipOne($tokens); return new EnumDeclarationNode( - location: new Location( - sourcePath: $enumKeyWordToken->sourcePath, - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: $enumKeyWordToken->sourcePath, + rangeInSource: Boundaries::fromPositions( $enumKeyWordToken->boundaries->start, $closingBracketToken->boundaries->end ) @@ -137,9 +137,9 @@ private function parseEnumMemberDeclarationNode(\Iterator $tokens): EnumMemberDe } return new EnumMemberDeclarationNode( - location: new Location( - sourcePath: $enumMemberNameToken->sourcePath, - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: $enumMemberNameToken->sourcePath, + rangeInSource: Boundaries::fromPositions( $enumMemberNameToken->boundaries->start, $finalToken->boundaries->end ) diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index 421c2503..10e7ca33 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -24,10 +24,9 @@ use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; -use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; final class IntegerLiteralParser { @@ -42,9 +41,9 @@ public function parse(\Iterator $tokens): IntegerLiteralNode Scanner::skipOne($tokens); return new IntegerLiteralNode( - location: new Location( - sourcePath: $token->sourcePath, - boundaries: $token->boundaries + attributes: new NodeAttributes( + pathToSource: $token->sourcePath, + rangeInSource: $token->boundaries ), format: IntegerFormat::fromTokenType($token->type), value: $token->value diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index 5e72ff42..a9054e15 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\NullLiteral; use PackageFactory\ComponentEngine\Language\AST\NullLiteral\NullLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -43,9 +43,9 @@ public function parse(\Iterator $tokens): NullLiteralNode Scanner::skipOne($tokens); return new NullLiteralNode( - location: new Location( - sourcePath: $token->sourcePath, - boundaries: $token->boundaries + attributes: new NodeAttributes( + pathToSource: $token->sourcePath, + rangeInSource: $token->boundaries ) ); } diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index 1c8e2bd4..f8fd071d 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\StringLiteral; use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -43,9 +43,9 @@ public function parse(\Iterator $tokens): StringLiteralNode Scanner::skipOne($tokens); return new StringLiteralNode( - location: new Location( - sourcePath: $token->sourcePath, - boundaries: $token->boundaries + attributes: new NodeAttributes( + pathToSource: $token->sourcePath, + rangeInSource: $token->boundaries ), value: $token->value ); diff --git a/src/Language/Shared/Location/Location.php b/src/Language/Shared/NodeAttributes/NodeAttributes.php similarity index 84% rename from src/Language/Shared/Location/Location.php rename to src/Language/Shared/NodeAttributes/NodeAttributes.php index 073808cd..3662a115 100644 --- a/src/Language/Shared/Location/Location.php +++ b/src/Language/Shared/NodeAttributes/NodeAttributes.php @@ -20,16 +20,16 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\Shared\Location; +namespace PackageFactory\ComponentEngine\Language\Shared\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; -final class Location +final class NodeAttributes { public function __construct( - public readonly Path $sourcePath, - public readonly Boundaries $boundaries + public readonly Path $pathToSource, + public readonly Boundaries $rangeInSource ) { } } diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 237e8520..04f7662c 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; @@ -43,14 +43,14 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void $tokens = Tokenizer::fromSource(Source::fromString('true'))->getIterator(); $expectedBooleanLiteralNode = new BooleanLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(3, 0, 3) ) - ), - value: true + ), + value: true ); $this->assertEquals( @@ -68,14 +68,14 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void $tokens = Tokenizer::fromSource(Source::fromString('false'))->getIterator(); $expectedBooleanLiteralNode = new BooleanLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(4, 0, 4) ) - ), - value: false + ), + value: false ); $this->assertEquals( diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index d608177c..ab7751ea 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -31,7 +31,7 @@ use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; @@ -50,9 +50,9 @@ public function oneValuelessMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(15, 0, 15) ) @@ -60,9 +60,9 @@ public function oneValuelessMember(): void enumName: EnumName::from('Foo'), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(11, 0, 11), Position::create(13, 0, 13) ) @@ -88,9 +88,9 @@ public function threeValuelessMembers(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR BAZ QUX }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(23, 0, 23) ) @@ -98,9 +98,9 @@ public function threeValuelessMembers(): void enumName: EnumName::from('Foo'), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(11, 0, 11), Position::create(13, 0, 13) ) @@ -109,9 +109,9 @@ enumName: EnumName::from('Foo'), value: null ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(15, 0, 15), Position::create(17, 0, 17) ) @@ -120,9 +120,9 @@ enumName: EnumName::from('Foo'), value: null ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(19, 0, 19), Position::create(21, 0, 21) ) @@ -148,9 +148,9 @@ public function oneStringValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR("BAR") }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -158,18 +158,18 @@ public function oneStringValueMember(): void enumName: EnumName::from('Foo'), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(11, 0, 11), Position::create(20, 0, 20) ) ), name: EnumMemberName::from('BAR'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(16, 0, 16), Position::create(18, 0, 18) ) @@ -206,9 +206,9 @@ enum Weekday { $tokens = Tokenizer::fromSource(Source::fromString($enumAsString))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(149, 8, 0) ) @@ -216,18 +216,18 @@ enum Weekday { enumName: EnumName::from('Weekday'), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(19, 1, 4), Position::create(31, 1, 16) ) ), name: EnumMemberName::from('MONDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(27, 1, 12), Position::create(29, 1, 14) ) @@ -236,18 +236,18 @@ enumName: EnumName::from('Weekday'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(37, 2, 4), Position::create(50, 2, 17) ) ), name: EnumMemberName::from('TUESDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(46, 2, 13), Position::create(48, 2, 15) ) @@ -256,18 +256,18 @@ enumName: EnumName::from('Weekday'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(56, 3, 4), Position::create(71, 3, 19) ) ), name: EnumMemberName::from('WEDNESDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(67, 3, 15), Position::create(69, 3, 17) ) @@ -276,18 +276,18 @@ enumName: EnumName::from('Weekday'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(77, 4, 4), Position::create(91, 4, 18) ) ), name: EnumMemberName::from('THURSDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(87, 4, 14), Position::create(89, 4, 16) ) @@ -296,18 +296,18 @@ enumName: EnumName::from('Weekday'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(97, 5, 4), Position::create(109, 5, 16) ) ), name: EnumMemberName::from('FRIDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(105, 5, 12), Position::create(107, 5, 14) ) @@ -316,18 +316,18 @@ enumName: EnumName::from('Weekday'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(115, 6, 4), Position::create(129, 6, 18) ) ), name: EnumMemberName::from('SATURDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(125, 6, 14), Position::create(127, 6, 16) ) @@ -336,18 +336,18 @@ enumName: EnumName::from('Weekday'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(135, 7, 4), Position::create(147, 7, 16) ) ), name: EnumMemberName::from('SUNDAY'), value: new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(143, 7, 12), Position::create(145, 7, 14) ) @@ -373,9 +373,9 @@ public function oneIntegerValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(42) }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(19, 0, 19) ) @@ -383,18 +383,18 @@ public function oneIntegerValueMember(): void enumName: EnumName::from('Foo'), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(11, 0, 11), Position::create(17, 0, 17) ) ), name: EnumMemberName::from('BAR'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(15, 0, 15), Position::create(16, 0, 16) ) @@ -437,9 +437,9 @@ enum Month { $tokens = Tokenizer::fromSource(Source::fromString($enumAsString))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(186, 13, 0) ) @@ -447,18 +447,18 @@ enum Month { enumName: EnumName::from('Month'), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(17, 1, 4), Position::create(26, 1, 13) ) ), name: EnumMemberName::from('JANUARY'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(25, 1, 12), Position::create(25, 1, 12) ) @@ -468,18 +468,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(32, 2, 4), Position::create(42, 2, 14) ) ), name: EnumMemberName::from('FEBRUARY'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(41, 2, 13), Position::create(41, 2, 13) ) @@ -489,18 +489,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(48, 3, 4), Position::create(55, 3, 11) ) ), name: EnumMemberName::from('MARCH'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(54, 3, 10), Position::create(54, 3, 10) ) @@ -510,18 +510,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(61, 4, 4), Position::create(68, 4, 11) ) ), name: EnumMemberName::from('APRIL'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(67, 4, 10), Position::create(67, 4, 10) ) @@ -531,18 +531,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(74, 5, 4), Position::create(79, 5, 9) ) ), name: EnumMemberName::from('MAY'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(78, 5, 8), Position::create(78, 5, 8) ) @@ -552,18 +552,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(85, 6, 4), Position::create(91, 6, 10) ) ), name: EnumMemberName::from('JUNE'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(90, 6, 9), Position::create(90, 6, 9) ) @@ -573,18 +573,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(97, 7, 4), Position::create(103, 7, 10) ) ), name: EnumMemberName::from('JULY'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(102, 7, 9), Position::create(102, 7, 9) ) @@ -594,18 +594,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(109, 8, 4), Position::create(117, 8, 12) ) ), name: EnumMemberName::from('AUGUST'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(116, 8, 11), Position::create(116, 8, 11) ) @@ -615,18 +615,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(123, 9, 4), Position::create(134, 9, 15) ) ), name: EnumMemberName::from('SEPTEMBER'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(133, 9, 14), Position::create(133, 9, 14) ) @@ -636,18 +636,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(140, 10, 4), Position::create(150, 10, 14) ) ), name: EnumMemberName::from('OCTOBER'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(148, 10, 12), Position::create(149, 10, 13) ) @@ -657,18 +657,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(156, 11, 4), Position::create(167, 11, 15) ) ), name: EnumMemberName::from('NOVEMBER'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(165, 11, 13), Position::create(166, 11, 14) ) @@ -678,18 +678,18 @@ enumName: EnumName::from('Month'), ) ), new EnumMemberDeclarationNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(173, 12, 4), Position::create(184, 12, 15) ) ), name: EnumMemberName::from('DECEMBER'), value: new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(182, 12, 13), Position::create(183, 12, 14) ) diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 67832c33..21b81d51 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -25,7 +25,7 @@ use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; @@ -44,9 +44,9 @@ public function binaryInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('0b1010110101'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(11, 0, 11) ) @@ -70,9 +70,9 @@ public function octalInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('0o755'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(4, 0, 4) ) @@ -96,9 +96,9 @@ public function decimalInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('1234567890'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(9, 0, 9) ) @@ -122,9 +122,9 @@ public function hexadecimalInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('0x123456789ABCDEF'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(16, 0, 16) ) diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 524c81b1..97f1ebe2 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; @@ -43,9 +43,9 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void $tokens = Tokenizer::fromSource(Source::fromString('null'))->getIterator(); $expectedNullLiteralNode = new NullLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(0, 0, 0), Position::create(3, 0, 3) ) diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 218d32f8..21950241 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\Location\Location; +use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; @@ -43,9 +43,9 @@ public function producesStringLiteralNodeForLiteralString(): void $tokens = Tokenizer::fromSource(Source::fromString('"Hello World"'))->getIterator(); $expectedStringLiteralNode = new StringLiteralNode( - location: new Location( - sourcePath: Path::fromString(':memory:'), - boundaries: Boundaries::fromPositions( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( Position::create(1, 0, 1), Position::create(11, 0, 11) ) From 7dd44fc2b6ce0a058382bb6b4a78d2a869923d2e Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 13:28:48 +0200 Subject: [PATCH 13/64] TASK: Move all members of AST namespace to AST\Node --- .../BooleanLiteral/BooleanLiteralNode.php | 2 +- .../EnumDeclaration/EnumDeclarationNode.php | 2 +- .../EnumMemberDeclarationNode.php | 7 +++---- .../EnumMemberDeclarationNodes.php | 2 +- .../EnumDeclaration/EnumMemberName.php | 2 +- .../AST/{ => Node}/EnumDeclaration/EnumName.php | 2 +- .../{ => Node}/IntegerLiteral/IntegerFormat.php | 2 +- .../IntegerLiteral/IntegerLiteralNode.php | 2 +- .../{ => Node}/NullLiteral/NullLiteralNode.php | 2 +- .../StringLiteral/StringLiteralNode.php | 2 +- .../BooleanLiteral/BooleanLiteralParser.php | 2 +- .../EnumDeclaration/EnumDeclarationParser.php | 10 +++++----- .../IntegerLiteral/IntegerLiteralParser.php | 4 ++-- .../Parser/NullLiteral/NullLiteralParser.php | 2 +- .../Parser/StringLiteral/StringLiteralParser.php | 2 +- .../BooleanLiteral/BooleanLiteralParserTest.php | 2 +- .../EnumDeclarationParserTest.php | 16 ++++++++-------- .../IntegerLiteral/IntegerLiteralParserTest.php | 4 ++-- .../Parser/NullLiteral/NullLiteralParserTest.php | 2 +- .../StringLiteral/StringLiteralParserTest.php | 2 +- 20 files changed, 35 insertions(+), 36 deletions(-) rename src/Language/AST/{ => Node}/BooleanLiteral/BooleanLiteralNode.php (93%) rename src/Language/AST/{ => Node}/EnumDeclaration/EnumDeclarationNode.php (93%) rename src/Language/AST/{ => Node}/EnumDeclaration/EnumMemberDeclarationNode.php (79%) rename src/Language/AST/{ => Node}/EnumDeclaration/EnumMemberDeclarationNodes.php (94%) rename src/Language/AST/{ => Node}/EnumDeclaration/EnumMemberName.php (93%) rename src/Language/AST/{ => Node}/EnumDeclaration/EnumName.php (93%) rename src/Language/AST/{ => Node}/IntegerLiteral/IntegerFormat.php (95%) rename src/Language/AST/{ => Node}/IntegerLiteral/IntegerLiteralNode.php (93%) rename src/Language/AST/{ => Node}/NullLiteral/NullLiteralNode.php (93%) rename src/Language/AST/{ => Node}/StringLiteral/StringLiteralNode.php (93%) diff --git a/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php similarity index 93% rename from src/Language/AST/BooleanLiteral/BooleanLiteralNode.php rename to src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php index 2b5ee4cc..597d16e4 100644 --- a/src/Language/AST/BooleanLiteral/BooleanLiteralNode.php +++ b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\BooleanLiteral; +namespace PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; diff --git a/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php similarity index 93% rename from src/Language/AST/EnumDeclaration/EnumDeclarationNode.php rename to src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php index ba8c689d..1a751509 100644 --- a/src/Language/AST/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; diff --git a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php similarity index 79% rename from src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php rename to src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php index ab49b50f..84bf1002 100644 --- a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php @@ -20,11 +20,10 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; final class EnumMemberDeclarationNode diff --git a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php similarity index 94% rename from src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php rename to src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php index 7055e406..e4e9771d 100644 --- a/src/Language/AST/EnumDeclaration/EnumMemberDeclarationNodes.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; final class EnumMemberDeclarationNodes { diff --git a/src/Language/AST/EnumDeclaration/EnumMemberName.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberName.php similarity index 93% rename from src/Language/AST/EnumDeclaration/EnumMemberName.php rename to src/Language/AST/Node/EnumDeclaration/EnumMemberName.php index 18e5e0bb..20355f35 100644 --- a/src/Language/AST/EnumDeclaration/EnumMemberName.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberName.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; final class EnumMemberName { diff --git a/src/Language/AST/EnumDeclaration/EnumName.php b/src/Language/AST/Node/EnumDeclaration/EnumName.php similarity index 93% rename from src/Language/AST/EnumDeclaration/EnumName.php rename to src/Language/AST/Node/EnumDeclaration/EnumName.php index cc004127..58dc6c10 100644 --- a/src/Language/AST/EnumDeclaration/EnumName.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumName.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; final class EnumName { diff --git a/src/Language/AST/IntegerLiteral/IntegerFormat.php b/src/Language/AST/Node/IntegerLiteral/IntegerFormat.php similarity index 95% rename from src/Language/AST/IntegerLiteral/IntegerFormat.php rename to src/Language/AST/Node/IntegerLiteral/IntegerFormat.php index e1699062..c4733b89 100644 --- a/src/Language/AST/IntegerLiteral/IntegerFormat.php +++ b/src/Language/AST/Node/IntegerLiteral/IntegerFormat.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\IntegerLiteral; +namespace PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; diff --git a/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php similarity index 93% rename from src/Language/AST/IntegerLiteral/IntegerLiteralNode.php rename to src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php index e8af71b0..880958a8 100644 --- a/src/Language/AST/IntegerLiteral/IntegerLiteralNode.php +++ b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\IntegerLiteral; +namespace PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; diff --git a/src/Language/AST/NullLiteral/NullLiteralNode.php b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php similarity index 93% rename from src/Language/AST/NullLiteral/NullLiteralNode.php rename to src/Language/AST/Node/NullLiteral/NullLiteralNode.php index f6cd5807..77d51613 100644 --- a/src/Language/AST/NullLiteral/NullLiteralNode.php +++ b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\NullLiteral; +namespace PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; diff --git a/src/Language/AST/StringLiteral/StringLiteralNode.php b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php similarity index 93% rename from src/Language/AST/StringLiteral/StringLiteralNode.php rename to src/Language/AST/Node/StringLiteral/StringLiteralNode.php index 880eae05..a4f1b9ec 100644 --- a/src/Language/AST/StringLiteral/StringLiteralNode.php +++ b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\StringLiteral; +namespace PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index f1203f54..24d0e04a 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral; -use PackageFactory\ComponentEngine\Language\AST\BooleanLiteral\BooleanLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 53512673..b84c814c 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -22,11 +22,11 @@ namespace PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumDeclarationNode; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNode; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNodes; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumName; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index 10e7ca33..e66908eb 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -22,8 +22,8 @@ namespace PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index a9054e15..135e37b6 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\NullLiteral; -use PackageFactory\ComponentEngine\Language\AST\NullLiteral\NullLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index f8fd071d..98dae5e3 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\StringLiteral; -use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 04f7662c..62f65c76 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\BooleanLiteral; -use PackageFactory\ComponentEngine\Language\AST\BooleanLiteral\BooleanLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index ab7751ea..9079befb 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -22,14 +22,14 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\EnumDeclaration; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumDeclarationNode; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNode; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberDeclarationNodes; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumMemberName; -use PackageFactory\ComponentEngine\Language\AST\EnumDeclaration\EnumName; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumName; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 21b81d51..c45b1d53 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -22,8 +22,8 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\IntegerLiteral; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerFormat; -use PackageFactory\ComponentEngine\Language\AST\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 97f1ebe2..683667c4 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\NullLiteral; -use PackageFactory\ComponentEngine\Language\AST\NullLiteral\NullLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 21950241..e88765fa 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\StringLiteral; -use PackageFactory\ComponentEngine\Language\AST\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; From 9bf87f061ab040268eb9742663abb67b5afe4436 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 13:32:39 +0200 Subject: [PATCH 14/64] TASK: Move NodeAttributes class to AST namespace --- src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php | 2 +- src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php | 2 +- .../AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php | 2 +- src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php | 2 +- src/Language/AST/Node/NullLiteral/NullLiteralNode.php | 2 +- src/Language/AST/Node/StringLiteral/StringLiteralNode.php | 2 +- src/Language/{Shared => AST}/NodeAttributes/NodeAttributes.php | 2 +- src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php | 2 +- src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php | 2 +- src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php | 2 +- src/Language/Parser/NullLiteral/NullLiteralParser.php | 2 +- src/Language/Parser/StringLiteral/StringLiteralParser.php | 2 +- .../Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php | 2 +- .../Parser/EnumDeclaration/EnumDeclarationParserTest.php | 2 +- .../Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php | 2 +- test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php | 2 +- .../Language/Parser/StringLiteral/StringLiteralParserTest.php | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) rename src/Language/{Shared => AST}/NodeAttributes/NodeAttributes.php (93%) diff --git a/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php index 597d16e4..4af78499 100644 --- a/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php +++ b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class BooleanLiteralNode { diff --git a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php index 1a751509..e7bc7b52 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class EnumDeclarationNode { diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php index 84bf1002..ed52797c 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class EnumMemberDeclarationNode { diff --git a/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php index 880958a8..be4865cd 100644 --- a/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php +++ b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class IntegerLiteralNode { diff --git a/src/Language/AST/Node/NullLiteral/NullLiteralNode.php b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php index 77d51613..eb634ea1 100644 --- a/src/Language/AST/Node/NullLiteral/NullLiteralNode.php +++ b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class NullLiteralNode { diff --git a/src/Language/AST/Node/StringLiteral/StringLiteralNode.php b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php index a4f1b9ec..6404805b 100644 --- a/src/Language/AST/Node/StringLiteral/StringLiteralNode.php +++ b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class StringLiteralNode { diff --git a/src/Language/Shared/NodeAttributes/NodeAttributes.php b/src/Language/AST/NodeAttributes/NodeAttributes.php similarity index 93% rename from src/Language/Shared/NodeAttributes/NodeAttributes.php rename to src/Language/AST/NodeAttributes/NodeAttributes.php index 3662a115..74eac4ee 100644 --- a/src/Language/Shared/NodeAttributes/NodeAttributes.php +++ b/src/Language/AST/NodeAttributes/NodeAttributes.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\Shared\NodeAttributes; +namespace PackageFactory\ComponentEngine\Language\AST\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index 24d0e04a..4c4558aa 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index b84c814c..e540bb4c 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -29,7 +29,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumName; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index e66908eb..6968fc0c 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index 135e37b6..1e84dbe3 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\NullLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index 98dae5e3..72db0c07 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -23,7 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\StringLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 62f65c76..52060649 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 9079befb..620210c0 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -31,7 +31,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index c45b1d53..87296d38 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -25,7 +25,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 683667c4..49b2d122 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index e88765fa..5a1b3700 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -24,7 +24,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Language\Shared\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Boundaries; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; From bc87d1326552d05d79904267fdee61621fb6284f Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 13:50:13 +0200 Subject: [PATCH 15/64] TASK: Add abstract Node class for all AST nodes to inherit from --- .../BooleanLiteral/BooleanLiteralNode.php | 4 ++- .../EnumDeclaration/EnumDeclarationNode.php | 3 +- .../EnumMemberDeclarationNode.php | 3 +- .../IntegerLiteral/IntegerLiteralNode.php | 3 +- src/Language/AST/Node/Node.php | 33 +++++++++++++++++++ .../AST/Node/NullLiteral/NullLiteralNode.php | 3 +- .../Node/StringLiteral/StringLiteralNode.php | 3 +- 7 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 src/Language/AST/Node/Node.php diff --git a/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php index 4af78499..2e17fa05 100644 --- a/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php +++ b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php @@ -22,13 +22,15 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -final class BooleanLiteralNode +final class BooleanLiteralNode extends Node { public function __construct( public readonly NodeAttributes $attributes, public readonly bool $value ) { + // parent::__construct($attributes); } } diff --git a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php index e7bc7b52..c27ccb45 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php @@ -22,9 +22,10 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -final class EnumDeclarationNode +final class EnumDeclarationNode extends Node { public function __construct( public readonly NodeAttributes $attributes, diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php index ed52797c..5de2a456 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php @@ -23,10 +23,11 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -final class EnumMemberDeclarationNode +final class EnumMemberDeclarationNode extends Node { public function __construct( public readonly NodeAttributes $attributes, diff --git a/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php index be4865cd..6ee74007 100644 --- a/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php +++ b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php @@ -22,9 +22,10 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -final class IntegerLiteralNode +final class IntegerLiteralNode extends Node { public function __construct( public readonly NodeAttributes $attributes, diff --git a/src/Language/AST/Node/Node.php b/src/Language/AST/Node/Node.php new file mode 100644 index 00000000..a49380eb --- /dev/null +++ b/src/Language/AST/Node/Node.php @@ -0,0 +1,33 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node; + +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +abstract class Node +{ + protected function __construct( + public readonly NodeAttributes $attributes + ) { + } +} diff --git a/src/Language/AST/Node/NullLiteral/NullLiteralNode.php b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php index eb634ea1..d85ec9c4 100644 --- a/src/Language/AST/Node/NullLiteral/NullLiteralNode.php +++ b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php @@ -22,9 +22,10 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -final class NullLiteralNode +final class NullLiteralNode extends Node { public function __construct( public readonly NodeAttributes $attributes diff --git a/src/Language/AST/Node/StringLiteral/StringLiteralNode.php b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php index 6404805b..4a199ae9 100644 --- a/src/Language/AST/Node/StringLiteral/StringLiteralNode.php +++ b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php @@ -22,9 +22,10 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -final class StringLiteralNode +final class StringLiteralNode extends Node { public function __construct( public readonly NodeAttributes $attributes, From a3924814ca4c70c9dd0d42bde2e053d18dcbdee7 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:00:39 +0200 Subject: [PATCH 16/64] TASK: Add cases for all integer formats to EnumDeclarationParserTest --- .../EnumDeclaration/EnumDeclarationParser.php | 5 +- .../EnumDeclarationParserTest.php | 146 +++++++++++++++++- 2 files changed, 149 insertions(+), 2 deletions(-) diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index e540bb4c..5488215b 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -126,7 +126,10 @@ private function parseEnumMemberDeclarationNode(\Iterator $tokens): EnumMemberDe $value = match ($valueToken->type) { TokenType::STRING_QUOTED => (new StringLiteralParser())->parse($tokens), - TokenType::NUMBER_DECIMAL => + TokenType::NUMBER_BINARY, + TokenType::NUMBER_OCTAL, + TokenType::NUMBER_DECIMAL, + TokenType::NUMBER_HEXADECIMAL => (new IntegerLiteralParser())->parse($tokens), default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) }; diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 620210c0..875c1697 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -367,7 +367,103 @@ enumName: EnumName::from('Weekday'), /** * @test */ - public function oneIntegerValueMember(): void + public function oneBinaryIntegerValueMember(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0b101) }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(22, 0, 22) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(20, 0, 20) + ) + ), + name: EnumMemberName::from('BAR'), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(15, 0, 15), + Position::create(19, 0, 19) + ) + ), + format: IntegerFormat::BINARY, + value: '0b101' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function oneOctalIntegerValueMember(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0o644) }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(22, 0, 22) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(20, 0, 20) + ) + ), + name: EnumMemberName::from('BAR'), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(15, 0, 15), + Position::create(19, 0, 19) + ) + ), + format: IntegerFormat::OCTAL, + value: '0o644' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function oneDecimalIntegerValueMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(42) }'))->getIterator(); @@ -412,6 +508,54 @@ enumName: EnumName::from('Foo'), ); } + /** + * @test + */ + public function oneHexadecimalIntegerValueMember(): void + { + $enumDeclarationParser = new EnumDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0xABC) }'))->getIterator(); + + $expectedEnumDeclarationNode = new EnumDeclarationNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(0, 0, 0), + Position::create(22, 0, 22) + ) + ), + enumName: EnumName::from('Foo'), + memberDeclarations: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(11, 0, 11), + Position::create(20, 0, 20) + ) + ), + name: EnumMemberName::from('BAR'), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Boundaries::fromPositions( + Position::create(15, 0, 15), + Position::create(19, 0, 19) + ) + ), + format: IntegerFormat::HEXADECIMAL, + value: '0xABC' + ) + ) + ) + ); + + $this->assertEquals( + $expectedEnumDeclarationNode, + $enumDeclarationParser->parse($tokens) + ); + } + /** * @test */ From c0c564ed341a7d842243a3c4ba17adc438e5ca74 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:08:02 +0200 Subject: [PATCH 17/64] TASK: Rename Boundaries::fromPositions -> Boundaries::from --- .../EnumDeclaration/EnumDeclarationParser.php | 4 +- src/Parser/Source/Boundaries.php | 2 +- src/Parser/Tokenizer/Token.php | 4 +- .../BooleanLiteralParserTest.php | 4 +- .../EnumDeclarationParserTest.php | 122 +++++++++--------- .../IntegerLiteralParserTest.php | 8 +- .../NullLiteral/NullLiteralParserTest.php | 2 +- .../StringLiteral/StringLiteralParserTest.php | 2 +- 8 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 5488215b..938e7697 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -71,7 +71,7 @@ public function parse(\Iterator $tokens): EnumDeclarationNode return new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: $enumKeyWordToken->sourcePath, - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( $enumKeyWordToken->boundaries->start, $closingBracketToken->boundaries->end ) @@ -142,7 +142,7 @@ private function parseEnumMemberDeclarationNode(\Iterator $tokens): EnumMemberDe return new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: $enumMemberNameToken->sourcePath, - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( $enumMemberNameToken->boundaries->start, $finalToken->boundaries->end ) diff --git a/src/Parser/Source/Boundaries.php b/src/Parser/Source/Boundaries.php index 5a5919c8..cfc84520 100644 --- a/src/Parser/Source/Boundaries.php +++ b/src/Parser/Source/Boundaries.php @@ -30,7 +30,7 @@ private function __construct( ) { } - public static function fromPositions(Position $start, Position $end): self + public static function from(Position $start, Position $end): self { return new self($start, $end); } diff --git a/src/Parser/Tokenizer/Token.php b/src/Parser/Tokenizer/Token.php index 6eaf6768..73856887 100644 --- a/src/Parser/Tokenizer/Token.php +++ b/src/Parser/Tokenizer/Token.php @@ -43,7 +43,7 @@ public static function fromFragment( return new Token( $type, $fragment->value, - Boundaries::fromPositions($fragment->start, $fragment->end), + Boundaries::from($fragment->start, $fragment->end), $fragment->source->path ); } @@ -56,7 +56,7 @@ public static function emptyFromDelimitingFragments( return new Token( $type, '', - Boundaries::fromPositions($startFragment->start, $endFragment->end), + Boundaries::from($startFragment->start, $endFragment->end), $startFragment->source->path ); } diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 52060649..5d6949b2 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -45,7 +45,7 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void $expectedBooleanLiteralNode = new BooleanLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(3, 0, 3) ) @@ -70,7 +70,7 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void $expectedBooleanLiteralNode = new BooleanLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(4, 0, 4) ) diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 875c1697..8a89368c 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -52,7 +52,7 @@ public function oneValuelessMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(15, 0, 15) ) @@ -62,7 +62,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(13, 0, 13) ) @@ -90,7 +90,7 @@ public function threeValuelessMembers(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(23, 0, 23) ) @@ -100,7 +100,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(13, 0, 13) ) @@ -111,7 +111,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(15, 0, 15), Position::create(17, 0, 17) ) @@ -122,7 +122,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(19, 0, 19), Position::create(21, 0, 21) ) @@ -150,7 +150,7 @@ public function oneStringValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -160,7 +160,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -169,7 +169,7 @@ enumName: EnumName::from('Foo'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(16, 0, 16), Position::create(18, 0, 18) ) @@ -208,7 +208,7 @@ enum Weekday { $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(149, 8, 0) ) @@ -218,7 +218,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(19, 1, 4), Position::create(31, 1, 16) ) @@ -227,7 +227,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(27, 1, 12), Position::create(29, 1, 14) ) @@ -238,7 +238,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(37, 2, 4), Position::create(50, 2, 17) ) @@ -247,7 +247,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(46, 2, 13), Position::create(48, 2, 15) ) @@ -258,7 +258,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(56, 3, 4), Position::create(71, 3, 19) ) @@ -267,7 +267,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(67, 3, 15), Position::create(69, 3, 17) ) @@ -278,7 +278,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(77, 4, 4), Position::create(91, 4, 18) ) @@ -287,7 +287,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(87, 4, 14), Position::create(89, 4, 16) ) @@ -298,7 +298,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(97, 5, 4), Position::create(109, 5, 16) ) @@ -307,7 +307,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(105, 5, 12), Position::create(107, 5, 14) ) @@ -318,7 +318,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(115, 6, 4), Position::create(129, 6, 18) ) @@ -327,7 +327,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(125, 6, 14), Position::create(127, 6, 16) ) @@ -338,7 +338,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(135, 7, 4), Position::create(147, 7, 16) ) @@ -347,7 +347,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(143, 7, 12), Position::create(145, 7, 14) ) @@ -375,7 +375,7 @@ public function oneBinaryIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -385,7 +385,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -394,7 +394,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(15, 0, 15), Position::create(19, 0, 19) ) @@ -423,7 +423,7 @@ public function oneOctalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -433,7 +433,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -442,7 +442,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(15, 0, 15), Position::create(19, 0, 19) ) @@ -471,7 +471,7 @@ public function oneDecimalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(19, 0, 19) ) @@ -481,7 +481,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(17, 0, 17) ) @@ -490,7 +490,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(15, 0, 15), Position::create(16, 0, 16) ) @@ -519,7 +519,7 @@ public function oneHexadecimalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -529,7 +529,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -538,7 +538,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(15, 0, 15), Position::create(19, 0, 19) ) @@ -583,7 +583,7 @@ enum Month { $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(186, 13, 0) ) @@ -593,7 +593,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(17, 1, 4), Position::create(26, 1, 13) ) @@ -602,7 +602,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(25, 1, 12), Position::create(25, 1, 12) ) @@ -614,7 +614,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(32, 2, 4), Position::create(42, 2, 14) ) @@ -623,7 +623,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(41, 2, 13), Position::create(41, 2, 13) ) @@ -635,7 +635,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(48, 3, 4), Position::create(55, 3, 11) ) @@ -644,7 +644,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(54, 3, 10), Position::create(54, 3, 10) ) @@ -656,7 +656,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(61, 4, 4), Position::create(68, 4, 11) ) @@ -665,7 +665,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(67, 4, 10), Position::create(67, 4, 10) ) @@ -677,7 +677,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(74, 5, 4), Position::create(79, 5, 9) ) @@ -686,7 +686,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(78, 5, 8), Position::create(78, 5, 8) ) @@ -698,7 +698,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(85, 6, 4), Position::create(91, 6, 10) ) @@ -707,7 +707,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(90, 6, 9), Position::create(90, 6, 9) ) @@ -719,7 +719,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(97, 7, 4), Position::create(103, 7, 10) ) @@ -728,7 +728,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(102, 7, 9), Position::create(102, 7, 9) ) @@ -740,7 +740,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(109, 8, 4), Position::create(117, 8, 12) ) @@ -749,7 +749,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(116, 8, 11), Position::create(116, 8, 11) ) @@ -761,7 +761,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(123, 9, 4), Position::create(134, 9, 15) ) @@ -770,7 +770,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(133, 9, 14), Position::create(133, 9, 14) ) @@ -782,7 +782,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(140, 10, 4), Position::create(150, 10, 14) ) @@ -791,7 +791,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(148, 10, 12), Position::create(149, 10, 13) ) @@ -803,7 +803,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(156, 11, 4), Position::create(167, 11, 15) ) @@ -812,7 +812,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(165, 11, 13), Position::create(166, 11, 14) ) @@ -824,7 +824,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(173, 12, 4), Position::create(184, 12, 15) ) @@ -833,7 +833,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(182, 12, 13), Position::create(183, 12, 14) ) diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 87296d38..3cba6a92 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -46,7 +46,7 @@ public function binaryInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(11, 0, 11) ) @@ -72,7 +72,7 @@ public function octalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(4, 0, 4) ) @@ -98,7 +98,7 @@ public function decimalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(9, 0, 9) ) @@ -124,7 +124,7 @@ public function hexadecimalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(16, 0, 16) ) diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 49b2d122..14b6e917 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -45,7 +45,7 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void $expectedNullLiteralNode = new NullLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(0, 0, 0), Position::create(3, 0, 3) ) diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 5a1b3700..82e907d4 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -45,7 +45,7 @@ public function producesStringLiteralNodeForLiteralString(): void $expectedStringLiteralNode = new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::fromPositions( + rangeInSource: Boundaries::from( Position::create(1, 0, 1), Position::create(11, 0, 11) ) From b56aae8c2e2e718eb54a9a90d0f51fda5a1d16e0 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:11:55 +0200 Subject: [PATCH 18/64] TASK: Rename Boundaries -> Range --- .../AST/NodeAttributes/NodeAttributes.php | 4 +- .../EnumDeclaration/EnumDeclarationParser.php | 6 +- .../Source/{Boundaries.php => Range.php} | 6 +- src/Parser/Tokenizer/Token.php | 8 +- .../BooleanLiteralParserTest.php | 6 +- .../EnumDeclarationParserTest.php | 124 +++++++++--------- .../IntegerLiteralParserTest.php | 10 +- .../NullLiteral/NullLiteralParserTest.php | 4 +- .../StringLiteral/StringLiteralParserTest.php | 4 +- 9 files changed, 86 insertions(+), 86 deletions(-) rename src/Parser/Source/{Boundaries.php => Range.php} (90%) diff --git a/src/Language/AST/NodeAttributes/NodeAttributes.php b/src/Language/AST/NodeAttributes/NodeAttributes.php index 74eac4ee..7c446efc 100644 --- a/src/Language/AST/NodeAttributes/NodeAttributes.php +++ b/src/Language/AST/NodeAttributes/NodeAttributes.php @@ -22,14 +22,14 @@ namespace PackageFactory\ComponentEngine\Language\AST\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Path; final class NodeAttributes { public function __construct( public readonly Path $pathToSource, - public readonly Boundaries $rangeInSource + public readonly Range $rangeInSource ) { } } diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 938e7697..d0e4068c 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -30,7 +30,7 @@ use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -71,7 +71,7 @@ public function parse(\Iterator $tokens): EnumDeclarationNode return new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: $enumKeyWordToken->sourcePath, - rangeInSource: Boundaries::from( + rangeInSource: Range::from( $enumKeyWordToken->boundaries->start, $closingBracketToken->boundaries->end ) @@ -142,7 +142,7 @@ private function parseEnumMemberDeclarationNode(\Iterator $tokens): EnumMemberDe return new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: $enumMemberNameToken->sourcePath, - rangeInSource: Boundaries::from( + rangeInSource: Range::from( $enumMemberNameToken->boundaries->start, $finalToken->boundaries->end ) diff --git a/src/Parser/Source/Boundaries.php b/src/Parser/Source/Range.php similarity index 90% rename from src/Parser/Source/Boundaries.php rename to src/Parser/Source/Range.php index cfc84520..56ea705c 100644 --- a/src/Parser/Source/Boundaries.php +++ b/src/Parser/Source/Range.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Parser\Source; -final class Boundaries implements \JsonSerializable +final class Range implements \JsonSerializable { private function __construct( public readonly Position $start, @@ -35,12 +35,12 @@ public static function from(Position $start, Position $end): self return new self($start, $end); } - public function expandedTo(Boundaries $other): self + public function expandedTo(Range $other): self { return new self($this->start, $other->end); } - public function equals(Boundaries $other): bool + public function equals(Range $other): bool { return ($this->start->equals($other->start) && $this->end->equals($other->end)); diff --git a/src/Parser/Tokenizer/Token.php b/src/Parser/Tokenizer/Token.php index 73856887..ef66cb85 100644 --- a/src/Parser/Tokenizer/Token.php +++ b/src/Parser/Tokenizer/Token.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Parser\Tokenizer; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Fragment; use PackageFactory\ComponentEngine\Parser\Source\Path; @@ -31,7 +31,7 @@ final class Token private function __construct( public readonly TokenType $type, public readonly string $value, - public readonly Boundaries $boundaries, + public readonly Range $boundaries, public readonly Path $sourcePath ) { } @@ -43,7 +43,7 @@ public static function fromFragment( return new Token( $type, $fragment->value, - Boundaries::from($fragment->start, $fragment->end), + Range::from($fragment->start, $fragment->end), $fragment->source->path ); } @@ -56,7 +56,7 @@ public static function emptyFromDelimitingFragments( return new Token( $type, '', - Boundaries::from($startFragment->start, $endFragment->end), + Range::from($startFragment->start, $endFragment->end), $startFragment->source->path ); } diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 5d6949b2..747ac170 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -25,7 +25,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -45,7 +45,7 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void $expectedBooleanLiteralNode = new BooleanLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(3, 0, 3) ) @@ -70,7 +70,7 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void $expectedBooleanLiteralNode = new BooleanLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(4, 0, 4) ) diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 8a89368c..f6e5151a 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -32,7 +32,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -52,7 +52,7 @@ public function oneValuelessMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(15, 0, 15) ) @@ -62,7 +62,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(13, 0, 13) ) @@ -90,7 +90,7 @@ public function threeValuelessMembers(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(23, 0, 23) ) @@ -100,7 +100,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(13, 0, 13) ) @@ -111,7 +111,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(15, 0, 15), Position::create(17, 0, 17) ) @@ -122,7 +122,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(19, 0, 19), Position::create(21, 0, 21) ) @@ -150,7 +150,7 @@ public function oneStringValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -160,7 +160,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -169,7 +169,7 @@ enumName: EnumName::from('Foo'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(16, 0, 16), Position::create(18, 0, 18) ) @@ -208,7 +208,7 @@ enum Weekday { $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(149, 8, 0) ) @@ -218,7 +218,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(19, 1, 4), Position::create(31, 1, 16) ) @@ -227,7 +227,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(27, 1, 12), Position::create(29, 1, 14) ) @@ -238,7 +238,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(37, 2, 4), Position::create(50, 2, 17) ) @@ -247,7 +247,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(46, 2, 13), Position::create(48, 2, 15) ) @@ -258,7 +258,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(56, 3, 4), Position::create(71, 3, 19) ) @@ -267,7 +267,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(67, 3, 15), Position::create(69, 3, 17) ) @@ -278,7 +278,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(77, 4, 4), Position::create(91, 4, 18) ) @@ -287,7 +287,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(87, 4, 14), Position::create(89, 4, 16) ) @@ -298,7 +298,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(97, 5, 4), Position::create(109, 5, 16) ) @@ -307,7 +307,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(105, 5, 12), Position::create(107, 5, 14) ) @@ -318,7 +318,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(115, 6, 4), Position::create(129, 6, 18) ) @@ -327,7 +327,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(125, 6, 14), Position::create(127, 6, 16) ) @@ -338,7 +338,7 @@ enumName: EnumName::from('Weekday'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(135, 7, 4), Position::create(147, 7, 16) ) @@ -347,7 +347,7 @@ enumName: EnumName::from('Weekday'), value: new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(143, 7, 12), Position::create(145, 7, 14) ) @@ -375,7 +375,7 @@ public function oneBinaryIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -385,7 +385,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -394,7 +394,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(15, 0, 15), Position::create(19, 0, 19) ) @@ -423,7 +423,7 @@ public function oneOctalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -433,7 +433,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -442,7 +442,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(15, 0, 15), Position::create(19, 0, 19) ) @@ -471,7 +471,7 @@ public function oneDecimalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(19, 0, 19) ) @@ -481,7 +481,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(17, 0, 17) ) @@ -490,7 +490,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(15, 0, 15), Position::create(16, 0, 16) ) @@ -519,7 +519,7 @@ public function oneHexadecimalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(22, 0, 22) ) @@ -529,7 +529,7 @@ enumName: EnumName::from('Foo'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(11, 0, 11), Position::create(20, 0, 20) ) @@ -538,7 +538,7 @@ enumName: EnumName::from('Foo'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(15, 0, 15), Position::create(19, 0, 19) ) @@ -583,7 +583,7 @@ enum Month { $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(186, 13, 0) ) @@ -593,7 +593,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(17, 1, 4), Position::create(26, 1, 13) ) @@ -602,7 +602,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(25, 1, 12), Position::create(25, 1, 12) ) @@ -614,7 +614,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(32, 2, 4), Position::create(42, 2, 14) ) @@ -623,7 +623,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(41, 2, 13), Position::create(41, 2, 13) ) @@ -635,7 +635,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(48, 3, 4), Position::create(55, 3, 11) ) @@ -644,7 +644,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(54, 3, 10), Position::create(54, 3, 10) ) @@ -656,7 +656,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(61, 4, 4), Position::create(68, 4, 11) ) @@ -665,7 +665,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(67, 4, 10), Position::create(67, 4, 10) ) @@ -677,7 +677,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(74, 5, 4), Position::create(79, 5, 9) ) @@ -686,7 +686,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(78, 5, 8), Position::create(78, 5, 8) ) @@ -698,7 +698,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(85, 6, 4), Position::create(91, 6, 10) ) @@ -707,7 +707,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(90, 6, 9), Position::create(90, 6, 9) ) @@ -719,7 +719,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(97, 7, 4), Position::create(103, 7, 10) ) @@ -728,7 +728,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(102, 7, 9), Position::create(102, 7, 9) ) @@ -740,7 +740,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(109, 8, 4), Position::create(117, 8, 12) ) @@ -749,7 +749,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(116, 8, 11), Position::create(116, 8, 11) ) @@ -761,7 +761,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(123, 9, 4), Position::create(134, 9, 15) ) @@ -770,7 +770,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(133, 9, 14), Position::create(133, 9, 14) ) @@ -782,7 +782,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(140, 10, 4), Position::create(150, 10, 14) ) @@ -791,7 +791,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(148, 10, 12), Position::create(149, 10, 13) ) @@ -803,7 +803,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(156, 11, 4), Position::create(167, 11, 15) ) @@ -812,7 +812,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(165, 11, 13), Position::create(166, 11, 14) ) @@ -824,7 +824,7 @@ enumName: EnumName::from('Month'), new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(173, 12, 4), Position::create(184, 12, 15) ) @@ -833,7 +833,7 @@ enumName: EnumName::from('Month'), value: new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(182, 12, 13), Position::create(183, 12, 14) ) diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 3cba6a92..1e85ec1c 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -26,7 +26,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -46,7 +46,7 @@ public function binaryInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(11, 0, 11) ) @@ -72,7 +72,7 @@ public function octalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(4, 0, 4) ) @@ -98,7 +98,7 @@ public function decimalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(9, 0, 9) ) @@ -124,7 +124,7 @@ public function hexadecimalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(16, 0, 16) ) diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 14b6e917..074185b8 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -25,7 +25,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -45,7 +45,7 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void $expectedNullLiteralNode = new NullLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(0, 0, 0), Position::create(3, 0, 3) ) diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 82e907d4..c2274e60 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -25,7 +25,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Boundaries; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -45,7 +45,7 @@ public function producesStringLiteralNodeForLiteralString(): void $expectedStringLiteralNode = new StringLiteralNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), - rangeInSource: Boundaries::from( + rangeInSource: Range::from( Position::create(1, 0, 1), Position::create(11, 0, 11) ) From f34588cf78d4cecbdad31667b2a10d55cb0aab25 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:14:05 +0200 Subject: [PATCH 19/64] TASK: Rename Position::create -> Position::from --- src/Parser/Source/Position.php | 2 +- src/Parser/Source/Source.php | 4 +- .../BooleanLiteralParserTest.php | 8 +- .../EnumDeclarationParserTest.php | 244 +++++++++--------- .../IntegerLiteralParserTest.php | 16 +- .../NullLiteral/NullLiteralParserTest.php | 4 +- .../StringLiteral/StringLiteralParserTest.php | 4 +- 7 files changed, 141 insertions(+), 141 deletions(-) diff --git a/src/Parser/Source/Position.php b/src/Parser/Source/Position.php index aa6561c0..0a0e6bfe 100644 --- a/src/Parser/Source/Position.php +++ b/src/Parser/Source/Position.php @@ -31,7 +31,7 @@ private function __construct( ) { } - public static function create( + public static function from( int $index, int $rowIndex, int $columnIndex diff --git a/src/Parser/Source/Source.php b/src/Parser/Source/Source.php index 5b46cb33..7dd1c30f 100644 --- a/src/Parser/Source/Source.php +++ b/src/Parser/Source/Source.php @@ -66,8 +66,8 @@ public function getIterator(): \Iterator yield Fragment::create( $character, - Position::create($index, $rowIndex, $columnIndex), - Position::create($index, $rowIndex, $columnIndex), + Position::from($index, $rowIndex, $columnIndex), + Position::from($index, $rowIndex, $columnIndex), $this ); diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 747ac170..59b55a11 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -46,8 +46,8 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(3, 0, 3) + Position::from(0, 0, 0), + Position::from(3, 0, 3) ) ), value: true @@ -71,8 +71,8 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(4, 0, 4) + Position::from(0, 0, 0), + Position::from(4, 0, 4) ) ), value: false diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index f6e5151a..dd0325d8 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -53,8 +53,8 @@ public function oneValuelessMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(15, 0, 15) + Position::from(0, 0, 0), + Position::from(15, 0, 15) ) ), enumName: EnumName::from('Foo'), @@ -63,8 +63,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(13, 0, 13) + Position::from(11, 0, 11), + Position::from(13, 0, 13) ) ), name: EnumMemberName::from('BAR'), @@ -91,8 +91,8 @@ public function threeValuelessMembers(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(23, 0, 23) + Position::from(0, 0, 0), + Position::from(23, 0, 23) ) ), enumName: EnumName::from('Foo'), @@ -101,8 +101,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(13, 0, 13) + Position::from(11, 0, 11), + Position::from(13, 0, 13) ) ), name: EnumMemberName::from('BAR'), @@ -112,8 +112,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(15, 0, 15), - Position::create(17, 0, 17) + Position::from(15, 0, 15), + Position::from(17, 0, 17) ) ), name: EnumMemberName::from('BAZ'), @@ -123,8 +123,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(19, 0, 19), - Position::create(21, 0, 21) + Position::from(19, 0, 19), + Position::from(21, 0, 21) ) ), name: EnumMemberName::from('QUX'), @@ -151,8 +151,8 @@ public function oneStringValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(22, 0, 22) + Position::from(0, 0, 0), + Position::from(22, 0, 22) ) ), enumName: EnumName::from('Foo'), @@ -161,8 +161,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(20, 0, 20) + Position::from(11, 0, 11), + Position::from(20, 0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -170,8 +170,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(16, 0, 16), - Position::create(18, 0, 18) + Position::from(16, 0, 16), + Position::from(18, 0, 18) ) ), value: 'BAR' @@ -209,8 +209,8 @@ enum Weekday { attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(149, 8, 0) + Position::from(0, 0, 0), + Position::from(149, 8, 0) ) ), enumName: EnumName::from('Weekday'), @@ -219,8 +219,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(19, 1, 4), - Position::create(31, 1, 16) + Position::from(19, 1, 4), + Position::from(31, 1, 16) ) ), name: EnumMemberName::from('MONDAY'), @@ -228,8 +228,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(27, 1, 12), - Position::create(29, 1, 14) + Position::from(27, 1, 12), + Position::from(29, 1, 14) ) ), value: 'mon' @@ -239,8 +239,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(37, 2, 4), - Position::create(50, 2, 17) + Position::from(37, 2, 4), + Position::from(50, 2, 17) ) ), name: EnumMemberName::from('TUESDAY'), @@ -248,8 +248,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(46, 2, 13), - Position::create(48, 2, 15) + Position::from(46, 2, 13), + Position::from(48, 2, 15) ) ), value: 'tue' @@ -259,8 +259,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(56, 3, 4), - Position::create(71, 3, 19) + Position::from(56, 3, 4), + Position::from(71, 3, 19) ) ), name: EnumMemberName::from('WEDNESDAY'), @@ -268,8 +268,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(67, 3, 15), - Position::create(69, 3, 17) + Position::from(67, 3, 15), + Position::from(69, 3, 17) ) ), value: 'wed' @@ -279,8 +279,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(77, 4, 4), - Position::create(91, 4, 18) + Position::from(77, 4, 4), + Position::from(91, 4, 18) ) ), name: EnumMemberName::from('THURSDAY'), @@ -288,8 +288,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(87, 4, 14), - Position::create(89, 4, 16) + Position::from(87, 4, 14), + Position::from(89, 4, 16) ) ), value: 'thu' @@ -299,8 +299,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(97, 5, 4), - Position::create(109, 5, 16) + Position::from(97, 5, 4), + Position::from(109, 5, 16) ) ), name: EnumMemberName::from('FRIDAY'), @@ -308,8 +308,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(105, 5, 12), - Position::create(107, 5, 14) + Position::from(105, 5, 12), + Position::from(107, 5, 14) ) ), value: 'fri' @@ -319,8 +319,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(115, 6, 4), - Position::create(129, 6, 18) + Position::from(115, 6, 4), + Position::from(129, 6, 18) ) ), name: EnumMemberName::from('SATURDAY'), @@ -328,8 +328,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(125, 6, 14), - Position::create(127, 6, 16) + Position::from(125, 6, 14), + Position::from(127, 6, 16) ) ), value: 'sat' @@ -339,8 +339,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(135, 7, 4), - Position::create(147, 7, 16) + Position::from(135, 7, 4), + Position::from(147, 7, 16) ) ), name: EnumMemberName::from('SUNDAY'), @@ -348,8 +348,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(143, 7, 12), - Position::create(145, 7, 14) + Position::from(143, 7, 12), + Position::from(145, 7, 14) ) ), value: 'sun' @@ -376,8 +376,8 @@ public function oneBinaryIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(22, 0, 22) + Position::from(0, 0, 0), + Position::from(22, 0, 22) ) ), enumName: EnumName::from('Foo'), @@ -386,8 +386,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(20, 0, 20) + Position::from(11, 0, 11), + Position::from(20, 0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -395,8 +395,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(15, 0, 15), - Position::create(19, 0, 19) + Position::from(15, 0, 15), + Position::from(19, 0, 19) ) ), format: IntegerFormat::BINARY, @@ -424,8 +424,8 @@ public function oneOctalIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(22, 0, 22) + Position::from(0, 0, 0), + Position::from(22, 0, 22) ) ), enumName: EnumName::from('Foo'), @@ -434,8 +434,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(20, 0, 20) + Position::from(11, 0, 11), + Position::from(20, 0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -443,8 +443,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(15, 0, 15), - Position::create(19, 0, 19) + Position::from(15, 0, 15), + Position::from(19, 0, 19) ) ), format: IntegerFormat::OCTAL, @@ -472,8 +472,8 @@ public function oneDecimalIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(19, 0, 19) + Position::from(0, 0, 0), + Position::from(19, 0, 19) ) ), enumName: EnumName::from('Foo'), @@ -482,8 +482,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(17, 0, 17) + Position::from(11, 0, 11), + Position::from(17, 0, 17) ) ), name: EnumMemberName::from('BAR'), @@ -491,8 +491,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(15, 0, 15), - Position::create(16, 0, 16) + Position::from(15, 0, 15), + Position::from(16, 0, 16) ) ), format: IntegerFormat::DECIMAL, @@ -520,8 +520,8 @@ public function oneHexadecimalIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(22, 0, 22) + Position::from(0, 0, 0), + Position::from(22, 0, 22) ) ), enumName: EnumName::from('Foo'), @@ -530,8 +530,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(11, 0, 11), - Position::create(20, 0, 20) + Position::from(11, 0, 11), + Position::from(20, 0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -539,8 +539,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(15, 0, 15), - Position::create(19, 0, 19) + Position::from(15, 0, 15), + Position::from(19, 0, 19) ) ), format: IntegerFormat::HEXADECIMAL, @@ -584,8 +584,8 @@ enum Month { attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(186, 13, 0) + Position::from(0, 0, 0), + Position::from(186, 13, 0) ) ), enumName: EnumName::from('Month'), @@ -594,8 +594,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(17, 1, 4), - Position::create(26, 1, 13) + Position::from(17, 1, 4), + Position::from(26, 1, 13) ) ), name: EnumMemberName::from('JANUARY'), @@ -603,8 +603,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(25, 1, 12), - Position::create(25, 1, 12) + Position::from(25, 1, 12), + Position::from(25, 1, 12) ) ), format: IntegerFormat::DECIMAL, @@ -615,8 +615,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(32, 2, 4), - Position::create(42, 2, 14) + Position::from(32, 2, 4), + Position::from(42, 2, 14) ) ), name: EnumMemberName::from('FEBRUARY'), @@ -624,8 +624,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(41, 2, 13), - Position::create(41, 2, 13) + Position::from(41, 2, 13), + Position::from(41, 2, 13) ) ), format: IntegerFormat::DECIMAL, @@ -636,8 +636,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(48, 3, 4), - Position::create(55, 3, 11) + Position::from(48, 3, 4), + Position::from(55, 3, 11) ) ), name: EnumMemberName::from('MARCH'), @@ -645,8 +645,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(54, 3, 10), - Position::create(54, 3, 10) + Position::from(54, 3, 10), + Position::from(54, 3, 10) ) ), format: IntegerFormat::DECIMAL, @@ -657,8 +657,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(61, 4, 4), - Position::create(68, 4, 11) + Position::from(61, 4, 4), + Position::from(68, 4, 11) ) ), name: EnumMemberName::from('APRIL'), @@ -666,8 +666,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(67, 4, 10), - Position::create(67, 4, 10) + Position::from(67, 4, 10), + Position::from(67, 4, 10) ) ), format: IntegerFormat::DECIMAL, @@ -678,8 +678,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(74, 5, 4), - Position::create(79, 5, 9) + Position::from(74, 5, 4), + Position::from(79, 5, 9) ) ), name: EnumMemberName::from('MAY'), @@ -687,8 +687,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(78, 5, 8), - Position::create(78, 5, 8) + Position::from(78, 5, 8), + Position::from(78, 5, 8) ) ), format: IntegerFormat::DECIMAL, @@ -699,8 +699,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(85, 6, 4), - Position::create(91, 6, 10) + Position::from(85, 6, 4), + Position::from(91, 6, 10) ) ), name: EnumMemberName::from('JUNE'), @@ -708,8 +708,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(90, 6, 9), - Position::create(90, 6, 9) + Position::from(90, 6, 9), + Position::from(90, 6, 9) ) ), format: IntegerFormat::DECIMAL, @@ -720,8 +720,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(97, 7, 4), - Position::create(103, 7, 10) + Position::from(97, 7, 4), + Position::from(103, 7, 10) ) ), name: EnumMemberName::from('JULY'), @@ -729,8 +729,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(102, 7, 9), - Position::create(102, 7, 9) + Position::from(102, 7, 9), + Position::from(102, 7, 9) ) ), format: IntegerFormat::DECIMAL, @@ -741,8 +741,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(109, 8, 4), - Position::create(117, 8, 12) + Position::from(109, 8, 4), + Position::from(117, 8, 12) ) ), name: EnumMemberName::from('AUGUST'), @@ -750,8 +750,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(116, 8, 11), - Position::create(116, 8, 11) + Position::from(116, 8, 11), + Position::from(116, 8, 11) ) ), format: IntegerFormat::DECIMAL, @@ -762,8 +762,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(123, 9, 4), - Position::create(134, 9, 15) + Position::from(123, 9, 4), + Position::from(134, 9, 15) ) ), name: EnumMemberName::from('SEPTEMBER'), @@ -771,8 +771,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(133, 9, 14), - Position::create(133, 9, 14) + Position::from(133, 9, 14), + Position::from(133, 9, 14) ) ), format: IntegerFormat::DECIMAL, @@ -783,8 +783,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(140, 10, 4), - Position::create(150, 10, 14) + Position::from(140, 10, 4), + Position::from(150, 10, 14) ) ), name: EnumMemberName::from('OCTOBER'), @@ -792,8 +792,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(148, 10, 12), - Position::create(149, 10, 13) + Position::from(148, 10, 12), + Position::from(149, 10, 13) ) ), format: IntegerFormat::DECIMAL, @@ -804,8 +804,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(156, 11, 4), - Position::create(167, 11, 15) + Position::from(156, 11, 4), + Position::from(167, 11, 15) ) ), name: EnumMemberName::from('NOVEMBER'), @@ -813,8 +813,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(165, 11, 13), - Position::create(166, 11, 14) + Position::from(165, 11, 13), + Position::from(166, 11, 14) ) ), format: IntegerFormat::DECIMAL, @@ -825,8 +825,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(173, 12, 4), - Position::create(184, 12, 15) + Position::from(173, 12, 4), + Position::from(184, 12, 15) ) ), name: EnumMemberName::from('DECEMBER'), @@ -834,8 +834,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(182, 12, 13), - Position::create(183, 12, 14) + Position::from(182, 12, 13), + Position::from(183, 12, 14) ) ), format: IntegerFormat::DECIMAL, diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 1e85ec1c..8c3f7f9e 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -47,8 +47,8 @@ public function binaryInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(11, 0, 11) + Position::from(0, 0, 0), + Position::from(11, 0, 11) ) ), format: IntegerFormat::BINARY, @@ -73,8 +73,8 @@ public function octalInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(4, 0, 4) + Position::from(0, 0, 0), + Position::from(4, 0, 4) ) ), format: IntegerFormat::OCTAL, @@ -99,8 +99,8 @@ public function decimalInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(9, 0, 9) + Position::from(0, 0, 0), + Position::from(9, 0, 9) ) ), format: IntegerFormat::DECIMAL, @@ -125,8 +125,8 @@ public function hexadecimalInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(16, 0, 16) + Position::from(0, 0, 0), + Position::from(16, 0, 16) ) ), format: IntegerFormat::HEXADECIMAL, diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 074185b8..0814f481 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -46,8 +46,8 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(0, 0, 0), - Position::create(3, 0, 3) + Position::from(0, 0, 0), + Position::from(3, 0, 3) ) ) ); diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index c2274e60..83dfc638 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -46,8 +46,8 @@ public function producesStringLiteralNodeForLiteralString(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::create(1, 0, 1), - Position::create(11, 0, 11) + Position::from(1, 0, 1), + Position::from(11, 0, 11) ) ), value: 'Hello World' From d20042aab782c1f599ac0714144f18667a666ca0 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:21:19 +0200 Subject: [PATCH 20/64] TASK: Remove dead equals method from Token class --- src/Parser/Tokenizer/Token.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Parser/Tokenizer/Token.php b/src/Parser/Tokenizer/Token.php index ef66cb85..8fa8e49b 100644 --- a/src/Parser/Tokenizer/Token.php +++ b/src/Parser/Tokenizer/Token.php @@ -61,15 +61,6 @@ public static function emptyFromDelimitingFragments( ); } - public function equals(Token $other): bool - { - return ($this->type === $other->type - && $this->value === $other->value - && $this->boundaries->equals($other->boundaries) - && $this->sourcePath->equals($other->sourcePath) - ); - } - public function __toString(): string { return $this->value; From 149d6a4e964281515926f0251702c52d12ed7c1e Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:21:58 +0200 Subject: [PATCH 21/64] TASK: Remove dead code from Range class --- src/Parser/Source/Range.php | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/Parser/Source/Range.php b/src/Parser/Source/Range.php index 56ea705c..42e1e940 100644 --- a/src/Parser/Source/Range.php +++ b/src/Parser/Source/Range.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Parser\Source; -final class Range implements \JsonSerializable +final class Range { private function __construct( public readonly Position $start, @@ -34,23 +34,4 @@ public static function from(Position $start, Position $end): self { return new self($start, $end); } - - public function expandedTo(Range $other): self - { - return new self($this->start, $other->end); - } - - public function equals(Range $other): bool - { - return ($this->start->equals($other->start) - && $this->end->equals($other->end)); - } - - public function jsonSerialize(): mixed - { - return [ - 'start' => $this->start, - 'end' => $this->end, - ]; - } } From 319be866c1a670207054ebef7db088c5cfef7a0a Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:22:31 +0200 Subject: [PATCH 22/64] TASK: Remove dead code from Position class --- src/Parser/Source/Position.php | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/src/Parser/Source/Position.php b/src/Parser/Source/Position.php index 0a0e6bfe..7ea1d7ae 100644 --- a/src/Parser/Source/Position.php +++ b/src/Parser/Source/Position.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Parser\Source; -final class Position implements \JsonSerializable +final class Position { private function __construct( public readonly int $index, @@ -42,34 +42,4 @@ public static function from( columnIndex: $columnIndex ); } - - public function equals(Position $other): bool - { - return $this->index === $other->index; - } - - public function gt(Position $other): bool - { - return $this->index > $other->index; - } - - public function gte(Position $other): bool - { - return $this->gt($other) || $this->equals($other); - } - - public function lt(Position $other): bool - { - return $this->index < $other->index; - } - - public function lte(Position $other): bool - { - return $this->lt($other) || $this->equals($other); - } - - public function jsonSerialize(): mixed - { - return $this->index; - } } From b67b004b9d587be8f721af71c2e9e751725d9cd6 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 14:37:49 +0200 Subject: [PATCH 23/64] TASK: Reduce Position class to contain only lineNumber and columnNumber --- src/Parser/Source/Position.php | 19 +- src/Parser/Source/Source.php | 14 +- src/Parser/Tokenizer/Scanner.php | 4 +- .../BooleanLiteralParserTest.php | 8 +- .../EnumDeclarationParserTest.php | 244 +++++++++--------- .../IntegerLiteralParserTest.php | 16 +- .../NullLiteral/NullLiteralParserTest.php | 4 +- .../StringLiteral/StringLiteralParserTest.php | 4 +- 8 files changed, 150 insertions(+), 163 deletions(-) diff --git a/src/Parser/Source/Position.php b/src/Parser/Source/Position.php index 7ea1d7ae..67c5aeda 100644 --- a/src/Parser/Source/Position.php +++ b/src/Parser/Source/Position.php @@ -24,22 +24,9 @@ final class Position { - private function __construct( - public readonly int $index, - public readonly int $rowIndex, - public readonly int $columnIndex + public function __construct( + public readonly int $lineNumber, + public readonly int $columnNumber ) { } - - public static function from( - int $index, - int $rowIndex, - int $columnIndex - ): Position { - return new Position( - index: $index, - rowIndex: $rowIndex, - columnIndex: $columnIndex - ); - } } diff --git a/src/Parser/Source/Source.php b/src/Parser/Source/Source.php index 7dd1c30f..ba143ca7 100644 --- a/src/Parser/Source/Source.php +++ b/src/Parser/Source/Source.php @@ -57,8 +57,8 @@ public function equals(Source $other): bool */ public function getIterator(): \Iterator { - $rowIndex = 0; - $columnIndex = 0; + $lineNumber = 0; + $columnNumber = 0; $length = strlen($this->contents); for ($index = 0; $index < $length; $index++) { @@ -66,16 +66,16 @@ public function getIterator(): \Iterator yield Fragment::create( $character, - Position::from($index, $rowIndex, $columnIndex), - Position::from($index, $rowIndex, $columnIndex), + new Position($lineNumber, $columnNumber), + new Position($lineNumber, $columnNumber), $this ); if ($character === "\n") { - $rowIndex++; - $columnIndex = 0; + $lineNumber++; + $columnNumber = 0; } else { - $columnIndex++; + $columnNumber++; } } } diff --git a/src/Parser/Tokenizer/Scanner.php b/src/Parser/Tokenizer/Scanner.php index c6cc21bf..97fff1cb 100644 --- a/src/Parser/Tokenizer/Scanner.php +++ b/src/Parser/Tokenizer/Scanner.php @@ -57,9 +57,9 @@ public static function assertType(\Iterator $tokens, TokenType ...$types): void "@TODO: Unexpected token: " . $actualType->value . " at " - . ($tokens->current()->boundaries->start->rowIndex + 1) + . ($tokens->current()->boundaries->start->lineNumber + 1) . ":" - . ($tokens->current()->boundaries->start->columnIndex + 1) + . ($tokens->current()->boundaries->start->columnNumber + 1) ); } diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 59b55a11..a2f94e85 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -46,8 +46,8 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(3, 0, 3) + new Position(0, 0), + new Position(0, 3) ) ), value: true @@ -71,8 +71,8 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(4, 0, 4) + new Position(0, 0), + new Position(0, 4) ) ), value: false diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index dd0325d8..c74fe319 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -53,8 +53,8 @@ public function oneValuelessMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(15, 0, 15) + new Position(0, 0), + new Position(0, 15) ) ), enumName: EnumName::from('Foo'), @@ -63,8 +63,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(13, 0, 13) + new Position(0, 11), + new Position(0, 13) ) ), name: EnumMemberName::from('BAR'), @@ -91,8 +91,8 @@ public function threeValuelessMembers(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(23, 0, 23) + new Position(0, 0), + new Position(0, 23) ) ), enumName: EnumName::from('Foo'), @@ -101,8 +101,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(13, 0, 13) + new Position(0, 11), + new Position(0, 13) ) ), name: EnumMemberName::from('BAR'), @@ -112,8 +112,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(15, 0, 15), - Position::from(17, 0, 17) + new Position(0, 15), + new Position(0, 17) ) ), name: EnumMemberName::from('BAZ'), @@ -123,8 +123,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(19, 0, 19), - Position::from(21, 0, 21) + new Position(0, 19), + new Position(0, 21) ) ), name: EnumMemberName::from('QUX'), @@ -151,8 +151,8 @@ public function oneStringValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(22, 0, 22) + new Position(0, 0), + new Position(0, 22) ) ), enumName: EnumName::from('Foo'), @@ -161,8 +161,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(20, 0, 20) + new Position(0, 11), + new Position(0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -170,8 +170,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(16, 0, 16), - Position::from(18, 0, 18) + new Position(0, 16), + new Position(0, 18) ) ), value: 'BAR' @@ -209,8 +209,8 @@ enum Weekday { attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(149, 8, 0) + new Position(0, 0), + new Position(8, 0) ) ), enumName: EnumName::from('Weekday'), @@ -219,8 +219,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(19, 1, 4), - Position::from(31, 1, 16) + new Position(1, 4), + new Position(1, 16) ) ), name: EnumMemberName::from('MONDAY'), @@ -228,8 +228,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(27, 1, 12), - Position::from(29, 1, 14) + new Position(1, 12), + new Position(1, 14) ) ), value: 'mon' @@ -239,8 +239,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(37, 2, 4), - Position::from(50, 2, 17) + new Position(2, 4), + new Position(2, 17) ) ), name: EnumMemberName::from('TUESDAY'), @@ -248,8 +248,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(46, 2, 13), - Position::from(48, 2, 15) + new Position(2, 13), + new Position(2, 15) ) ), value: 'tue' @@ -259,8 +259,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(56, 3, 4), - Position::from(71, 3, 19) + new Position(3, 4), + new Position(3, 19) ) ), name: EnumMemberName::from('WEDNESDAY'), @@ -268,8 +268,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(67, 3, 15), - Position::from(69, 3, 17) + new Position(3, 15), + new Position(3, 17) ) ), value: 'wed' @@ -279,8 +279,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(77, 4, 4), - Position::from(91, 4, 18) + new Position(4, 4), + new Position(4, 18) ) ), name: EnumMemberName::from('THURSDAY'), @@ -288,8 +288,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(87, 4, 14), - Position::from(89, 4, 16) + new Position(4, 14), + new Position(4, 16) ) ), value: 'thu' @@ -299,8 +299,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(97, 5, 4), - Position::from(109, 5, 16) + new Position(5, 4), + new Position(5, 16) ) ), name: EnumMemberName::from('FRIDAY'), @@ -308,8 +308,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(105, 5, 12), - Position::from(107, 5, 14) + new Position(5, 12), + new Position(5, 14) ) ), value: 'fri' @@ -319,8 +319,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(115, 6, 4), - Position::from(129, 6, 18) + new Position(6, 4), + new Position(6, 18) ) ), name: EnumMemberName::from('SATURDAY'), @@ -328,8 +328,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(125, 6, 14), - Position::from(127, 6, 16) + new Position(6, 14), + new Position(6, 16) ) ), value: 'sat' @@ -339,8 +339,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(135, 7, 4), - Position::from(147, 7, 16) + new Position(7, 4), + new Position(7, 16) ) ), name: EnumMemberName::from('SUNDAY'), @@ -348,8 +348,8 @@ enumName: EnumName::from('Weekday'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(143, 7, 12), - Position::from(145, 7, 14) + new Position(7, 12), + new Position(7, 14) ) ), value: 'sun' @@ -376,8 +376,8 @@ public function oneBinaryIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(22, 0, 22) + new Position(0, 0), + new Position(0, 22) ) ), enumName: EnumName::from('Foo'), @@ -386,8 +386,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(20, 0, 20) + new Position(0, 11), + new Position(0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -395,8 +395,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(15, 0, 15), - Position::from(19, 0, 19) + new Position(0, 15), + new Position(0, 19) ) ), format: IntegerFormat::BINARY, @@ -424,8 +424,8 @@ public function oneOctalIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(22, 0, 22) + new Position(0, 0), + new Position(0, 22) ) ), enumName: EnumName::from('Foo'), @@ -434,8 +434,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(20, 0, 20) + new Position(0, 11), + new Position(0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -443,8 +443,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(15, 0, 15), - Position::from(19, 0, 19) + new Position(0, 15), + new Position(0, 19) ) ), format: IntegerFormat::OCTAL, @@ -472,8 +472,8 @@ public function oneDecimalIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(19, 0, 19) + new Position(0, 0), + new Position(0, 19) ) ), enumName: EnumName::from('Foo'), @@ -482,8 +482,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(17, 0, 17) + new Position(0, 11), + new Position(0, 17) ) ), name: EnumMemberName::from('BAR'), @@ -491,8 +491,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(15, 0, 15), - Position::from(16, 0, 16) + new Position(0, 15), + new Position(0, 16) ) ), format: IntegerFormat::DECIMAL, @@ -520,8 +520,8 @@ public function oneHexadecimalIntegerValueMember(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(22, 0, 22) + new Position(0, 0), + new Position(0, 22) ) ), enumName: EnumName::from('Foo'), @@ -530,8 +530,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(11, 0, 11), - Position::from(20, 0, 20) + new Position(0, 11), + new Position(0, 20) ) ), name: EnumMemberName::from('BAR'), @@ -539,8 +539,8 @@ enumName: EnumName::from('Foo'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(15, 0, 15), - Position::from(19, 0, 19) + new Position(0, 15), + new Position(0, 19) ) ), format: IntegerFormat::HEXADECIMAL, @@ -584,8 +584,8 @@ enum Month { attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(186, 13, 0) + new Position(0, 0), + new Position(13, 0) ) ), enumName: EnumName::from('Month'), @@ -594,8 +594,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(17, 1, 4), - Position::from(26, 1, 13) + new Position(1, 4), + new Position(1, 13) ) ), name: EnumMemberName::from('JANUARY'), @@ -603,8 +603,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(25, 1, 12), - Position::from(25, 1, 12) + new Position(1, 12), + new Position(1, 12) ) ), format: IntegerFormat::DECIMAL, @@ -615,8 +615,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(32, 2, 4), - Position::from(42, 2, 14) + new Position(2, 4), + new Position(2, 14) ) ), name: EnumMemberName::from('FEBRUARY'), @@ -624,8 +624,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(41, 2, 13), - Position::from(41, 2, 13) + new Position(2, 13), + new Position(2, 13) ) ), format: IntegerFormat::DECIMAL, @@ -636,8 +636,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(48, 3, 4), - Position::from(55, 3, 11) + new Position(3, 4), + new Position(3, 11) ) ), name: EnumMemberName::from('MARCH'), @@ -645,8 +645,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(54, 3, 10), - Position::from(54, 3, 10) + new Position(3, 10), + new Position(3, 10) ) ), format: IntegerFormat::DECIMAL, @@ -657,8 +657,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(61, 4, 4), - Position::from(68, 4, 11) + new Position(4, 4), + new Position(4, 11) ) ), name: EnumMemberName::from('APRIL'), @@ -666,8 +666,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(67, 4, 10), - Position::from(67, 4, 10) + new Position(4, 10), + new Position(4, 10) ) ), format: IntegerFormat::DECIMAL, @@ -678,8 +678,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(74, 5, 4), - Position::from(79, 5, 9) + new Position(5, 4), + new Position(5, 9) ) ), name: EnumMemberName::from('MAY'), @@ -687,8 +687,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(78, 5, 8), - Position::from(78, 5, 8) + new Position(5, 8), + new Position(5, 8) ) ), format: IntegerFormat::DECIMAL, @@ -699,8 +699,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(85, 6, 4), - Position::from(91, 6, 10) + new Position(6, 4), + new Position(6, 10) ) ), name: EnumMemberName::from('JUNE'), @@ -708,8 +708,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(90, 6, 9), - Position::from(90, 6, 9) + new Position(6, 9), + new Position(6, 9) ) ), format: IntegerFormat::DECIMAL, @@ -720,8 +720,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(97, 7, 4), - Position::from(103, 7, 10) + new Position(7, 4), + new Position(7, 10) ) ), name: EnumMemberName::from('JULY'), @@ -729,8 +729,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(102, 7, 9), - Position::from(102, 7, 9) + new Position(7, 9), + new Position(7, 9) ) ), format: IntegerFormat::DECIMAL, @@ -741,8 +741,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(109, 8, 4), - Position::from(117, 8, 12) + new Position(8, 4), + new Position(8, 12) ) ), name: EnumMemberName::from('AUGUST'), @@ -750,8 +750,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(116, 8, 11), - Position::from(116, 8, 11) + new Position(8, 11), + new Position(8, 11) ) ), format: IntegerFormat::DECIMAL, @@ -762,8 +762,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(123, 9, 4), - Position::from(134, 9, 15) + new Position(9, 4), + new Position(9, 15) ) ), name: EnumMemberName::from('SEPTEMBER'), @@ -771,8 +771,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(133, 9, 14), - Position::from(133, 9, 14) + new Position(9, 14), + new Position(9, 14) ) ), format: IntegerFormat::DECIMAL, @@ -783,8 +783,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(140, 10, 4), - Position::from(150, 10, 14) + new Position(10, 4), + new Position(10, 14) ) ), name: EnumMemberName::from('OCTOBER'), @@ -792,8 +792,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(148, 10, 12), - Position::from(149, 10, 13) + new Position(10, 12), + new Position(10, 13) ) ), format: IntegerFormat::DECIMAL, @@ -804,8 +804,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(156, 11, 4), - Position::from(167, 11, 15) + new Position(11, 4), + new Position(11, 15) ) ), name: EnumMemberName::from('NOVEMBER'), @@ -813,8 +813,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(165, 11, 13), - Position::from(166, 11, 14) + new Position(11, 13), + new Position(11, 14) ) ), format: IntegerFormat::DECIMAL, @@ -825,8 +825,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(173, 12, 4), - Position::from(184, 12, 15) + new Position(12, 4), + new Position(12, 15) ) ), name: EnumMemberName::from('DECEMBER'), @@ -834,8 +834,8 @@ enumName: EnumName::from('Month'), attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(182, 12, 13), - Position::from(183, 12, 14) + new Position(12, 13), + new Position(12, 14) ) ), format: IntegerFormat::DECIMAL, diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index 8c3f7f9e..b618c4ef 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -47,8 +47,8 @@ public function binaryInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(11, 0, 11) + new Position(0, 0), + new Position(0, 11) ) ), format: IntegerFormat::BINARY, @@ -73,8 +73,8 @@ public function octalInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(4, 0, 4) + new Position(0, 0), + new Position(0, 4) ) ), format: IntegerFormat::OCTAL, @@ -99,8 +99,8 @@ public function decimalInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(9, 0, 9) + new Position(0, 0), + new Position(0, 9) ) ), format: IntegerFormat::DECIMAL, @@ -125,8 +125,8 @@ public function hexadecimalInteger(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(16, 0, 16) + new Position(0, 0), + new Position(0, 16) ) ), format: IntegerFormat::HEXADECIMAL, diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 0814f481..1a696bcc 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -46,8 +46,8 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(0, 0, 0), - Position::from(3, 0, 3) + new Position(0, 0), + new Position(0, 3) ) ) ); diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 83dfc638..2be362b8 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -46,8 +46,8 @@ public function producesStringLiteralNodeForLiteralString(): void attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - Position::from(1, 0, 1), - Position::from(11, 0, 11) + new Position(0, 1), + new Position(0, 11) ) ), value: 'Hello World' From ea11e11d9adc63db393df483fb1185ee75ab240b Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 15:18:58 +0200 Subject: [PATCH 24/64] TASK: Split parse method of EnumDeclarationParser --- .../EnumDeclaration/EnumDeclarationParser.php | 89 ++++++++++++++----- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index d0e4068c..96a122c2 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -43,30 +43,13 @@ final class EnumDeclarationParser */ public function parse(\Iterator $tokens): EnumDeclarationNode { - Scanner::assertType($tokens, TokenType::KEYWORD_ENUM); - - $enumKeyWordToken = $tokens->current(); + $enumKeyWordToken = $this->extractEnumKeywordToken($tokens); + $enumName = $this->parseEnumName($tokens); - Scanner::skipOne($tokens); - Scanner::skipSpaceAndComments($tokens); - Scanner::assertType($tokens, TokenType::STRING); - - $enumKeyNameToken = $tokens->current(); - $enumName = EnumName::from($enumKeyNameToken->value); - - Scanner::skipOne($tokens); - Scanner::skipSpace($tokens); - Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); - Scanner::skipOne($tokens); + $this->skipOpeningBracketToken($tokens); $enumMemberDeclarations = $this->parseEnumMemberDeclarations($tokens); - - Scanner::skipSpace($tokens); - Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); - - $closingBracketToken = $tokens->current(); - - Scanner::skipOne($tokens); + $closingBracketToken = $this->extractClosingBracketToken($tokens); return new EnumDeclarationNode( attributes: new NodeAttributes( @@ -81,6 +64,49 @@ enumName: $enumName, ); } + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractEnumKeywordToken(\Iterator $tokens): Token + { + Scanner::assertType($tokens, TokenType::KEYWORD_ENUM); + + $enumKeyWordToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $enumKeyWordToken; + } + + /** + * @param \Iterator $tokens + * @return EnumName + */ + private function parseEnumName(\Iterator $tokens): EnumName + { + Scanner::assertType($tokens, TokenType::STRING); + + $enumKeyNameToken = $tokens->current(); + $enumName = EnumName::from($enumKeyNameToken->value); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $enumName; + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipOpeningBracketToken(\Iterator $tokens): void + { + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + } + /** * @param \Iterator $tokens * @return EnumMemberDeclarationNodes @@ -93,7 +119,7 @@ private function parseEnumMemberDeclarations(\Iterator $tokens): EnumMemberDecla switch (Scanner::type($tokens)) { case TokenType::STRING: - $items[] = $this->parseEnumMemberDeclarationNode($tokens); + $items[] = $this->parseEnumMemberDeclaration($tokens); break; case TokenType::BRACKET_CURLY_CLOSE: break 2; @@ -105,13 +131,28 @@ private function parseEnumMemberDeclarations(\Iterator $tokens): EnumMemberDecla return new EnumMemberDeclarationNodes(...$items); } + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractClosingBracketToken(\Iterator $tokens): Token + { + Scanner::skipSpace($tokens); + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + + $closingBracketToken = $tokens->current(); + + Scanner::skipOne($tokens); + + return $closingBracketToken; + } + /** * @param \Iterator $tokens * @return EnumMemberDeclarationNode */ - private function parseEnumMemberDeclarationNode(\Iterator $tokens): EnumMemberDeclarationNode + private function parseEnumMemberDeclaration(\Iterator $tokens): EnumMemberDeclarationNode { - Scanner::skipSpaceAndComments($tokens); Scanner::assertType($tokens, TokenType::STRING); $enumMemberNameToken = $finalToken = $tokens->current(); From d0e38e4416a45f97c75163abd1885d73971b54b5 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 27 Jul 2023 15:33:47 +0200 Subject: [PATCH 25/64] TASK: Turn name of EnumDeclarationNode into an AST Node as well This also turns the EnumName class into a domain concern. --- .../EnumName}/EnumName.php | 2 +- .../EnumDeclaration/EnumDeclarationNode.php | 2 +- .../AST/Node/EnumDeclaration/EnumNameNode.php | 36 +++++++ .../EnumDeclaration/EnumDeclarationParser.php | 21 ++-- .../EnumDeclarationParserTest.php | 102 ++++++++++++++++-- 5 files changed, 144 insertions(+), 19 deletions(-) rename src/{Language/AST/Node/EnumDeclaration => Domain/EnumName}/EnumName.php (93%) create mode 100644 src/Language/AST/Node/EnumDeclaration/EnumNameNode.php diff --git a/src/Language/AST/Node/EnumDeclaration/EnumName.php b/src/Domain/EnumName/EnumName.php similarity index 93% rename from src/Language/AST/Node/EnumDeclaration/EnumName.php rename to src/Domain/EnumName/EnumName.php index 58dc6c10..d3f0d8ee 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumName.php +++ b/src/Domain/EnumName/EnumName.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Domain\EnumName; final class EnumName { diff --git a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php index c27ccb45..ffe26188 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php @@ -29,7 +29,7 @@ final class EnumDeclarationNode extends Node { public function __construct( public readonly NodeAttributes $attributes, - public readonly EnumName $enumName, + public readonly EnumNameNode $name, public readonly EnumMemberDeclarationNodes $memberDeclarations ) { } diff --git a/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php b/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php new file mode 100644 index 00000000..adc24bc5 --- /dev/null +++ b/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; + +use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class EnumNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly EnumName $value + ) { + } +} diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 96a122c2..aeeebe7f 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -22,11 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration; +use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberName; -use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; @@ -44,7 +45,7 @@ final class EnumDeclarationParser public function parse(\Iterator $tokens): EnumDeclarationNode { $enumKeyWordToken = $this->extractEnumKeywordToken($tokens); - $enumName = $this->parseEnumName($tokens); + $enumNameNode = $this->parseEnumName($tokens); $this->skipOpeningBracketToken($tokens); @@ -59,7 +60,7 @@ public function parse(\Iterator $tokens): EnumDeclarationNode $closingBracketToken->boundaries->end ) ), - enumName: $enumName, + name: $enumNameNode, memberDeclarations: $enumMemberDeclarations ); } @@ -82,19 +83,25 @@ private function extractEnumKeywordToken(\Iterator $tokens): Token /** * @param \Iterator $tokens - * @return EnumName + * @return EnumNameNode */ - private function parseEnumName(\Iterator $tokens): EnumName + private function parseEnumName(\Iterator $tokens): EnumNameNode { Scanner::assertType($tokens, TokenType::STRING); $enumKeyNameToken = $tokens->current(); - $enumName = EnumName::from($enumKeyNameToken->value); + $enumNameNode = new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: $enumKeyNameToken->sourcePath, + rangeInSource: $enumKeyNameToken->boundaries + ), + value: EnumName::from($enumKeyNameToken->value) + ); Scanner::skipOne($tokens); Scanner::skipSpace($tokens); - return $enumName; + return $enumNameNode; } /** diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index c74fe319..f8016ecb 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -22,11 +22,12 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\EnumDeclaration; +use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberName; -use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; @@ -57,7 +58,16 @@ public function oneValuelessMember(): void new Position(0, 15) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -95,7 +105,16 @@ public function threeValuelessMembers(): void new Position(0, 23) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -155,7 +174,16 @@ public function oneStringValueMember(): void new Position(0, 22) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -213,7 +241,16 @@ enum Weekday { new Position(8, 0) ) ), - enumName: EnumName::from('Weekday'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 11) + ) + ), + value: EnumName::from('Weekday') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -380,7 +417,16 @@ public function oneBinaryIntegerValueMember(): void new Position(0, 22) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -428,7 +474,16 @@ public function oneOctalIntegerValueMember(): void new Position(0, 22) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -476,7 +531,16 @@ public function oneDecimalIntegerValueMember(): void new Position(0, 19) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -524,7 +588,16 @@ public function oneHexadecimalIntegerValueMember(): void new Position(0, 22) ) ), - enumName: EnumName::from('Foo'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: EnumName::from('Foo') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( @@ -588,7 +661,16 @@ enum Month { new Position(13, 0) ) ), - enumName: EnumName::from('Month'), + name: new EnumNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 9) + ) + ), + value: EnumName::from('Month') + ), memberDeclarations: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( From 910a54a7cd44b2b8fdde431c29f6927480b12d6e Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 11:35:00 +0200 Subject: [PATCH 26/64] TASK: Turn name and value of EnumMemberDeclarationNode into an AST Nodes as well Similar to EnumName, EnumMemberName is now a domain concern as well. --- .../EnumMemberName}/EnumMemberName.php | 2 +- .../EnumMemberDeclarationNode.php | 6 +- .../EnumMemberDeclarationNodes.php | 2 +- .../EnumDeclaration/EnumMemberNameNode.php | 36 + .../EnumDeclaration/EnumMemberValueNode.php | 37 + .../EnumDeclaration/EnumDeclarationParser.php | 96 ++- .../EnumDeclarationParserTest.php | 752 ++++++++++++++---- 7 files changed, 758 insertions(+), 173 deletions(-) rename src/{Language/AST/Node/EnumDeclaration => Domain/EnumMemberName}/EnumMemberName.php (93%) create mode 100644 src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php create mode 100644 src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberName.php b/src/Domain/EnumMemberName/EnumMemberName.php similarity index 93% rename from src/Language/AST/Node/EnumDeclaration/EnumMemberName.php rename to src/Domain/EnumMemberName/EnumMemberName.php index 20355f35..39040656 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberName.php +++ b/src/Domain/EnumMemberName/EnumMemberName.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; +namespace PackageFactory\ComponentEngine\Domain\EnumMemberName; final class EnumMemberName { diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php index 5de2a456..e4e001e5 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php @@ -22,17 +22,15 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; -use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class EnumMemberDeclarationNode extends Node { public function __construct( public readonly NodeAttributes $attributes, - public readonly EnumMemberName $name, - public readonly null|StringLiteralNode|IntegerLiteralNode $value + public readonly EnumMemberNameNode $name, + public readonly ?EnumMemberValueNode $value ) { } } diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php index e4e9771d..51797009 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php @@ -34,7 +34,7 @@ public function __construct( ) { $itemsAsHashMap = []; foreach ($items as $item) { - $itemsAsHashMap[$item->name->value] = $item; + $itemsAsHashMap[$item->name->value->value] = $item; } $this->items = $itemsAsHashMap; diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php new file mode 100644 index 00000000..3447a39b --- /dev/null +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; + +use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class EnumMemberNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly EnumMemberName $value + ) { + } +} diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php new file mode 100644 index 00000000..5d0796ff --- /dev/null +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class EnumMemberValueNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly StringLiteralNode|IntegerLiteralNode $value + ) { + } +} diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index aeeebe7f..bc057d45 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -22,12 +22,16 @@ namespace PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration; +use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; -use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberValueNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; @@ -159,43 +163,83 @@ private function extractClosingBracketToken(\Iterator $tokens): Token * @return EnumMemberDeclarationNode */ private function parseEnumMemberDeclaration(\Iterator $tokens): EnumMemberDeclarationNode + { + $enumMemberName = $this->parseEnumMemberName($tokens); + $value = $this->parseEnumMemberValue($tokens); + + return new EnumMemberDeclarationNode( + attributes: new NodeAttributes( + pathToSource: $enumMemberName->attributes->pathToSource, + rangeInSource: Range::from( + $enumMemberName->attributes->rangeInSource->start, + $value?->attributes->rangeInSource->end + ?? $enumMemberName->attributes->rangeInSource->end + ) + ), + name: $enumMemberName, + value: $value + ); + } + + /** + * @param \Iterator $tokens + * @return EnumMemberNameNode + */ + private function parseEnumMemberName(\Iterator $tokens): EnumMemberNameNode { Scanner::assertType($tokens, TokenType::STRING); - $enumMemberNameToken = $finalToken = $tokens->current(); - $enumMemberName = EnumMemberName::from($enumMemberNameToken->value); + $enumMemberNameToken = $tokens->current(); + $enumMemberNameNode = new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: $enumMemberNameToken->sourcePath, + rangeInSource: $enumMemberNameToken->boundaries + ), + value: EnumMemberName::from($enumMemberNameToken->value) + ); Scanner::skipOne($tokens); - $value = null; - if (Scanner::type($tokens) === TokenType::BRACKET_ROUND_OPEN) { - Scanner::skipOne($tokens); - $valueToken = $tokens->current(); - $value = match ($valueToken->type) { - TokenType::STRING_QUOTED => - (new StringLiteralParser())->parse($tokens), - TokenType::NUMBER_BINARY, - TokenType::NUMBER_OCTAL, - TokenType::NUMBER_DECIMAL, - TokenType::NUMBER_HEXADECIMAL => - (new IntegerLiteralParser())->parse($tokens), - default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) - }; - Scanner::assertType($tokens, TokenType::BRACKET_ROUND_CLOSE); - $finalToken = $tokens->current(); - - Scanner::skipOne($tokens); + return $enumMemberNameNode; + } + + /** + * @param \Iterator $tokens + * @return null|EnumMemberValueNode + */ + private function parseEnumMemberValue(\Iterator $tokens): ?EnumMemberValueNode + { + if (Scanner::type($tokens) !== TokenType::BRACKET_ROUND_OPEN) { + return null; } - return new EnumMemberDeclarationNode( + $openingBracketToken = $tokens->current(); + Scanner::skipOne($tokens); + + $valueToken = $tokens->current(); + $value = match ($valueToken->type) { + TokenType::STRING_QUOTED => + (new StringLiteralParser())->parse($tokens), + TokenType::NUMBER_BINARY, + TokenType::NUMBER_OCTAL, + TokenType::NUMBER_DECIMAL, + TokenType::NUMBER_HEXADECIMAL => + (new IntegerLiteralParser())->parse($tokens), + default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) + }; + + Scanner::assertType($tokens, TokenType::BRACKET_ROUND_CLOSE); + $closingBracketToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: $enumMemberNameToken->sourcePath, + pathToSource: $valueToken->sourcePath, rangeInSource: Range::from( - $enumMemberNameToken->boundaries->start, - $finalToken->boundaries->end + $openingBracketToken->boundaries->start, + $closingBracketToken->boundaries->end ) ), - name: $enumMemberName, value: $value ); } diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index f8016ecb..22c03b07 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -22,11 +22,13 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\EnumDeclaration; +use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; -use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberName; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberValueNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; @@ -77,7 +79,16 @@ public function oneValuelessMember(): void new Position(0, 13) ) ), - name: EnumMemberName::from('BAR'), + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ) + ), + value: EnumMemberName::from('BAR') + ), value: null ) ) @@ -124,7 +135,16 @@ public function threeValuelessMembers(): void new Position(0, 13) ) ), - name: EnumMemberName::from('BAR'), + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ) + ), + value: EnumMemberName::from('BAR') + ), value: null ), new EnumMemberDeclarationNode( @@ -135,7 +155,16 @@ public function threeValuelessMembers(): void new Position(0, 17) ) ), - name: EnumMemberName::from('BAZ'), + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) + ) + ), + value: EnumMemberName::from('BAZ') + ), value: null ), new EnumMemberDeclarationNode( @@ -146,7 +175,16 @@ public function threeValuelessMembers(): void new Position(0, 21) ) ), - name: EnumMemberName::from('QUX'), + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 19), + new Position(0, 21) + ) + ), + value: EnumMemberName::from('QUX') + ), value: null ) ) @@ -193,16 +231,34 @@ public function oneStringValueMember(): void new Position(0, 20) ) ), - name: EnumMemberName::from('BAR'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(0, 16), - new Position(0, 18) + new Position(0, 11), + new Position(0, 13) ) ), - value: 'BAR' + value: EnumMemberName::from('BAR') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) + ) + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 16), + new Position(0, 18) + ) + ), + value: 'BAR' + ) ) ) ) @@ -260,16 +316,34 @@ enum Weekday { new Position(1, 16) ) ), - name: EnumMemberName::from('MONDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 9) + ) + ), + value: EnumMemberName::from('MONDAY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(1, 12), - new Position(1, 14) + new Position(1, 10), + new Position(1, 16) ) ), - value: 'mon' + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(1, 12), + new Position(1, 14) + ) + ), + value: 'mon' + ) ) ), new EnumMemberDeclarationNode( @@ -280,16 +354,34 @@ enum Weekday { new Position(2, 17) ) ), - name: EnumMemberName::from('TUESDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 10) + ) + ), + value: EnumMemberName::from('TUESDAY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(2, 13), - new Position(2, 15) + new Position(2, 11), + new Position(2, 17) ) ), - value: 'tue' + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(2, 13), + new Position(2, 15) + ) + ), + value: 'tue' + ) ) ), new EnumMemberDeclarationNode( @@ -300,16 +392,34 @@ enum Weekday { new Position(3, 19) ) ), - name: EnumMemberName::from('WEDNESDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 12) + ) + ), + value: EnumMemberName::from('WEDNESDAY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(3, 15), - new Position(3, 17) + new Position(3, 13), + new Position(3, 19) ) ), - value: 'wed' + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(3, 15), + new Position(3, 17) + ) + ), + value: 'wed' + ) ) ), new EnumMemberDeclarationNode( @@ -320,16 +430,34 @@ enum Weekday { new Position(4, 18) ) ), - name: EnumMemberName::from('THURSDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(4, 14), - new Position(4, 16) + new Position(4, 4), + new Position(4, 11) ) ), - value: 'thu' + value: EnumMemberName::from('THURSDAY') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(4, 12), + new Position(4, 18) + ) + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(4, 14), + new Position(4, 16) + ) + ), + value: 'thu' + ) ) ), new EnumMemberDeclarationNode( @@ -340,16 +468,34 @@ enum Weekday { new Position(5, 16) ) ), - name: EnumMemberName::from('FRIDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(5, 12), - new Position(5, 14) + new Position(5, 4), + new Position(5, 9) ) ), - value: 'fri' + value: EnumMemberName::from('FRIDAY') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(5, 10), + new Position(5, 16) + ) + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(5, 12), + new Position(5, 14) + ) + ), + value: 'fri' + ) ) ), new EnumMemberDeclarationNode( @@ -360,16 +506,34 @@ enum Weekday { new Position(6, 18) ) ), - name: EnumMemberName::from('SATURDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 11) + ) + ), + value: EnumMemberName::from('SATURDAY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(6, 14), - new Position(6, 16) + new Position(6, 12), + new Position(6, 18) ) ), - value: 'sat' + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(6, 14), + new Position(6, 16) + ) + ), + value: 'sat' + ) ) ), new EnumMemberDeclarationNode( @@ -380,16 +544,34 @@ enum Weekday { new Position(7, 16) ) ), - name: EnumMemberName::from('SUNDAY'), - value: new StringLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(7, 4), + new Position(7, 9) + ) + ), + value: EnumMemberName::from('SUNDAY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(7, 12), - new Position(7, 14) + new Position(7, 10), + new Position(7, 16) ) ), - value: 'sun' + value: new StringLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(7, 12), + new Position(7, 14) + ) + ), + value: 'sun' + ) ) ) ) @@ -436,17 +618,35 @@ public function oneBinaryIntegerValueMember(): void new Position(0, 20) ) ), - name: EnumMemberName::from('BAR'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) + new Position(0, 11), + new Position(0, 13) ) ), - format: IntegerFormat::BINARY, - value: '0b101' + value: EnumMemberName::from('BAR') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) + ) + ), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 19) + ) + ), + format: IntegerFormat::BINARY, + value: '0b101' + ) ) ) ) @@ -493,17 +693,35 @@ public function oneOctalIntegerValueMember(): void new Position(0, 20) ) ), - name: EnumMemberName::from('BAR'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) + new Position(0, 11), + new Position(0, 13) + ) + ), + value: EnumMemberName::from('BAR') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ) ), - format: IntegerFormat::OCTAL, - value: '0o644' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 19) + ) + ), + format: IntegerFormat::OCTAL, + value: '0o644' + ) ) ) ) @@ -550,17 +768,35 @@ public function oneDecimalIntegerValueMember(): void new Position(0, 17) ) ), - name: EnumMemberName::from('BAR'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 16) + new Position(0, 11), + new Position(0, 13) ) ), - format: IntegerFormat::DECIMAL, - value: '42' + value: EnumMemberName::from('BAR') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 17) + ) + ), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 16) + ) + ), + format: IntegerFormat::DECIMAL, + value: '42' + ) ) ) ) @@ -607,17 +843,35 @@ public function oneHexadecimalIntegerValueMember(): void new Position(0, 20) ) ), - name: EnumMemberName::from('BAR'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) + new Position(0, 11), + new Position(0, 13) + ) + ), + value: EnumMemberName::from('BAR') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ) ), - format: IntegerFormat::HEXADECIMAL, - value: '0xABC' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 19) + ) + ), + format: IntegerFormat::HEXADECIMAL, + value: '0xABC' + ) ) ) ) @@ -680,17 +934,35 @@ enum Month { new Position(1, 13) ) ), - name: EnumMemberName::from('JANUARY'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 10) + ) + ), + value: EnumMemberName::from('JANUARY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(1, 12), - new Position(1, 12) + new Position(1, 11), + new Position(1, 13) ) ), - format: IntegerFormat::DECIMAL, - value: '1' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(1, 12), + new Position(1, 12) + ) + ), + format: IntegerFormat::DECIMAL, + value: '1' + ) ) ), new EnumMemberDeclarationNode( @@ -701,17 +973,35 @@ enum Month { new Position(2, 14) ) ), - name: EnumMemberName::from('FEBRUARY'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 11) + ) + ), + value: EnumMemberName::from('FEBRUARY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(2, 13), - new Position(2, 13) + new Position(2, 12), + new Position(2, 14) ) ), - format: IntegerFormat::DECIMAL, - value: '2' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(2, 13), + new Position(2, 13) + ) + ), + format: IntegerFormat::DECIMAL, + value: '2' + ) ) ), new EnumMemberDeclarationNode( @@ -722,17 +1012,35 @@ enum Month { new Position(3, 11) ) ), - name: EnumMemberName::from('MARCH'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 10) + new Position(3, 4), + new Position(3, 8) ) ), - format: IntegerFormat::DECIMAL, - value: '3' + value: EnumMemberName::from('MARCH') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(3, 9), + new Position(3, 11) + ) + ), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(3, 10), + new Position(3, 10) + ) + ), + format: IntegerFormat::DECIMAL, + value: '3' + ) ) ), new EnumMemberDeclarationNode( @@ -743,17 +1051,35 @@ enum Month { new Position(4, 11) ) ), - name: EnumMemberName::from('APRIL'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(4, 10), - new Position(4, 10) + new Position(4, 4), + new Position(4, 8) ) ), - format: IntegerFormat::DECIMAL, - value: '4' + value: EnumMemberName::from('APRIL') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(4, 9), + new Position(4, 11) + ) + ), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(4, 10), + new Position(4, 10) + ) + ), + format: IntegerFormat::DECIMAL, + value: '4' + ) ) ), new EnumMemberDeclarationNode( @@ -764,17 +1090,35 @@ enum Month { new Position(5, 9) ) ), - name: EnumMemberName::from('MAY'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(5, 4), + new Position(5, 6) + ) + ), + value: EnumMemberName::from('MAY') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(5, 8), - new Position(5, 8) + new Position(5, 7), + new Position(5, 9) ) ), - format: IntegerFormat::DECIMAL, - value: '5' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(5, 8), + new Position(5, 8) + ) + ), + format: IntegerFormat::DECIMAL, + value: '5' + ) ) ), new EnumMemberDeclarationNode( @@ -785,17 +1129,35 @@ enum Month { new Position(6, 10) ) ), - name: EnumMemberName::from('JUNE'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(6, 9), - new Position(6, 9) + new Position(6, 4), + new Position(6, 7) ) ), - format: IntegerFormat::DECIMAL, - value: '6' + value: EnumMemberName::from('JUNE') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(6, 8), + new Position(6, 10) + ) + ), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(6, 9), + new Position(6, 9) + ) + ), + format: IntegerFormat::DECIMAL, + value: '6' + ) ) ), new EnumMemberDeclarationNode( @@ -806,17 +1168,35 @@ enum Month { new Position(7, 10) ) ), - name: EnumMemberName::from('JULY'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(7, 9), - new Position(7, 9) + new Position(7, 4), + new Position(7, 7) + ) + ), + value: EnumMemberName::from('JULY') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(7, 8), + new Position(7, 10) ) ), - format: IntegerFormat::DECIMAL, - value: '7' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(7, 9), + new Position(7, 9) + ) + ), + format: IntegerFormat::DECIMAL, + value: '7' + ) ) ), new EnumMemberDeclarationNode( @@ -827,17 +1207,35 @@ enum Month { new Position(8, 12) ) ), - name: EnumMemberName::from('AUGUST'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(8, 4), + new Position(8, 9) + ) + ), + value: EnumMemberName::from('AUGUST') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(8, 11), - new Position(8, 11) + new Position(8, 10), + new Position(8, 12) ) ), - format: IntegerFormat::DECIMAL, - value: '8' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(8, 11), + new Position(8, 11) + ) + ), + format: IntegerFormat::DECIMAL, + value: '8' + ) ) ), new EnumMemberDeclarationNode( @@ -848,17 +1246,35 @@ enum Month { new Position(9, 15) ) ), - name: EnumMemberName::from('SEPTEMBER'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(9, 14), - new Position(9, 14) + new Position(9, 4), + new Position(9, 12) ) ), - format: IntegerFormat::DECIMAL, - value: '9' + value: EnumMemberName::from('SEPTEMBER') + ), + value: new EnumMemberValueNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(9, 13), + new Position(9, 15) + ) + ), + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(9, 14), + new Position(9, 14) + ) + ), + format: IntegerFormat::DECIMAL, + value: '9' + ) ) ), new EnumMemberDeclarationNode( @@ -869,17 +1285,35 @@ enum Month { new Position(10, 14) ) ), - name: EnumMemberName::from('OCTOBER'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(10, 4), + new Position(10, 10) + ) + ), + value: EnumMemberName::from('OCTOBER') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(10, 12), - new Position(10, 13) + new Position(10, 11), + new Position(10, 14) ) ), - format: IntegerFormat::DECIMAL, - value: '10' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(10, 12), + new Position(10, 13) + ) + ), + format: IntegerFormat::DECIMAL, + value: '10' + ) ) ), new EnumMemberDeclarationNode( @@ -890,17 +1324,35 @@ enum Month { new Position(11, 15) ) ), - name: EnumMemberName::from('NOVEMBER'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(11, 4), + new Position(11, 11) + ) + ), + value: EnumMemberName::from('NOVEMBER') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(11, 13), - new Position(11, 14) + new Position(11, 12), + new Position(11, 15) ) ), - format: IntegerFormat::DECIMAL, - value: '11' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(11, 13), + new Position(11, 14) + ) + ), + format: IntegerFormat::DECIMAL, + value: '11' + ) ) ), new EnumMemberDeclarationNode( @@ -911,17 +1363,35 @@ enum Month { new Position(12, 15) ) ), - name: EnumMemberName::from('DECEMBER'), - value: new IntegerLiteralNode( + name: new EnumMemberNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(12, 4), + new Position(12, 11) + ) + ), + value: EnumMemberName::from('DECEMBER') + ), + value: new EnumMemberValueNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( - new Position(12, 13), - new Position(12, 14) + new Position(12, 12), + new Position(12, 15) ) ), - format: IntegerFormat::DECIMAL, - value: '12' + value: new IntegerLiteralNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(12, 13), + new Position(12, 14) + ) + ), + format: IntegerFormat::DECIMAL, + value: '12' + ) ) ) ) From af729d596fa65e0cf94d02c073c2d337c76b76f5 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 11:40:17 +0200 Subject: [PATCH 27/64] TASK: Instantiate subsequent parsers in constructor of EnumDeclarationParser --- .../EnumDeclaration/EnumDeclarationParser.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index bc057d45..e3db7465 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -30,8 +30,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberValueNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; -use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; @@ -42,6 +40,15 @@ final class EnumDeclarationParser { + private readonly StringLiteralParser $stringLiteralParser; + private readonly IntegerLiteralParser $integerLiteralParser; + + public function __construct() + { + $this->stringLiteralParser = new StringLiteralParser(); + $this->integerLiteralParser = new IntegerLiteralParser(); + } + /** * @param \Iterator $tokens * @return EnumDeclarationNode @@ -219,12 +226,12 @@ private function parseEnumMemberValue(\Iterator $tokens): ?EnumMemberValueNode $valueToken = $tokens->current(); $value = match ($valueToken->type) { TokenType::STRING_QUOTED => - (new StringLiteralParser())->parse($tokens), + $this->stringLiteralParser->parse($tokens), TokenType::NUMBER_BINARY, TokenType::NUMBER_OCTAL, TokenType::NUMBER_DECIMAL, TokenType::NUMBER_HEXADECIMAL => - (new IntegerLiteralParser())->parse($tokens), + $this->integerLiteralParser->parse($tokens), default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) }; From 4f4f73744f6d843357a3e6d23be1405a17586b7b Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 11:43:25 +0200 Subject: [PATCH 28/64] TASK: Rename property memberDeclarations to members in EnumDeclarationNode --- .../EnumDeclaration/EnumDeclarationNode.php | 2 +- .../EnumDeclaration/EnumDeclarationParser.php | 2 +- .../EnumDeclarationParserTest.php | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php index ffe26188..3482e001 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php @@ -30,7 +30,7 @@ final class EnumDeclarationNode extends Node public function __construct( public readonly NodeAttributes $attributes, public readonly EnumNameNode $name, - public readonly EnumMemberDeclarationNodes $memberDeclarations + public readonly EnumMemberDeclarationNodes $members ) { } } diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index e3db7465..82ee2f12 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -72,7 +72,7 @@ public function parse(\Iterator $tokens): EnumDeclarationNode ) ), name: $enumNameNode, - memberDeclarations: $enumMemberDeclarations + members: $enumMemberDeclarations ); } diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 22c03b07..34395732 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -70,7 +70,7 @@ public function oneValuelessMember(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -126,7 +126,7 @@ public function threeValuelessMembers(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -222,7 +222,7 @@ public function oneStringValueMember(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -307,7 +307,7 @@ enum Weekday { ), value: EnumName::from('Weekday') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -609,7 +609,7 @@ public function oneBinaryIntegerValueMember(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -684,7 +684,7 @@ public function oneOctalIntegerValueMember(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -759,7 +759,7 @@ public function oneDecimalIntegerValueMember(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -834,7 +834,7 @@ public function oneHexadecimalIntegerValueMember(): void ), value: EnumName::from('Foo') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), @@ -925,7 +925,7 @@ enum Month { ), value: EnumName::from('Month') ), - memberDeclarations: new EnumMemberDeclarationNodes( + members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( pathToSource: Path::fromString(':memory:'), From c5d13c1b966624f8b8f63ef97585a6f9b26fff49 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 13:20:11 +0200 Subject: [PATCH 29/64] TASK: Implement TypeReferenceParser --- src/Domain/TypeName/TypeName.php | 36 +++++ src/Language/AST/ASTException.php | 36 +++++ .../InvalidTypeReferenceNode.php | 44 +++++ .../Node/TypeReference/TypeReferenceNode.php | 44 +++++ src/Language/Parser/ParserException.php | 43 +++++ .../TypeReferenceCouldNotBeParsed.php | 45 ++++++ .../TypeReference/TypeReferenceParser.php | 87 ++++++++++ src/Parser/Source/Position.php | 5 + .../TypeReference/TypeReferenceNodeTest.php | 133 ++++++++++++++++ .../TypeReference/TypeReferenceParserTest.php | 150 ++++++++++++++++++ test/Unit/Parser/Source/PositionTest.php | 38 +++++ 11 files changed, 661 insertions(+) create mode 100644 src/Domain/TypeName/TypeName.php create mode 100644 src/Language/AST/ASTException.php create mode 100644 src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php create mode 100644 src/Language/AST/Node/TypeReference/TypeReferenceNode.php create mode 100644 src/Language/Parser/ParserException.php create mode 100644 src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php create mode 100644 src/Language/Parser/TypeReference/TypeReferenceParser.php create mode 100644 test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php create mode 100644 test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php create mode 100644 test/Unit/Parser/Source/PositionTest.php diff --git a/src/Domain/TypeName/TypeName.php b/src/Domain/TypeName/TypeName.php new file mode 100644 index 00000000..29e603ce --- /dev/null +++ b/src/Domain/TypeName/TypeName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\TypeName; + +final class TypeName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/ASTException.php b/src/Language/AST/ASTException.php new file mode 100644 index 00000000..929a45a7 --- /dev/null +++ b/src/Language/AST/ASTException.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST; + +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +abstract class ASTException extends \Exception +{ + protected function __construct( + int $code, + string $message, + public readonly NodeAttributes $attributesOfAffectedNode + ) { + parent::__construct($message, $code); + } +} diff --git a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php new file mode 100644 index 00000000..e0069d1c --- /dev/null +++ b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php @@ -0,0 +1,44 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\ASTException; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class InvalidTypeReferenceNode extends ASTException +{ + public static function becauseItWasOptionalAndArrayAtTheSameTime( + TypeName $affectedTypeName, + NodeAttributes $attributesOfAffectedNode + ): self { + return new self( + code: 1690538480, + message: sprintf( + 'The reference to type "%s" must not be optional and array at the same time.', + $affectedTypeName->value + ), + attributesOfAffectedNode: $attributesOfAffectedNode + ); + } +} diff --git a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php new file mode 100644 index 00000000..99566976 --- /dev/null +++ b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php @@ -0,0 +1,44 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TypeReferenceNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly TypeName $name, + public readonly bool $isArray, + public readonly bool $isOptional + ) { + if ($isArray === true && $isOptional === true) { + throw InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( + affectedTypeName: $name, + attributesOfAffectedNode: $attributes + ); + } + } +} diff --git a/src/Language/Parser/ParserException.php b/src/Language/Parser/ParserException.php new file mode 100644 index 00000000..c6242ac7 --- /dev/null +++ b/src/Language/Parser/ParserException.php @@ -0,0 +1,43 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser; + +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; + +abstract class ParserException extends \Exception +{ + protected function __construct( + int $code, + string $message, + public readonly Token $affectedToken, + ?\Exception $cause = null + ) { + $message = sprintf( + '[%s] %s', + $affectedToken->boundaries->start->toDebugString(), + $message + ); + + parent::__construct($message, $code, $cause); + } +} diff --git a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php new file mode 100644 index 00000000..a937e6cb --- /dev/null +++ b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php @@ -0,0 +1,45 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference; + +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; + +final class TypeReferenceCouldNotBeParsed extends ParserException +{ + public static function becauseOfInvalidTypeReferenceNode( + InvalidTypeReferenceNode $cause, + Token $affectedToken + ): self { + return new self( + code: 1690542466, + message: sprintf( + 'TypeReferenceNode could not be parsed, because the result would be invalid: %s', + $cause->getMessage() + ), + affectedToken: $affectedToken, + cause: $cause + ); + } +} diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php new file mode 100644 index 00000000..dc4db16c --- /dev/null +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -0,0 +1,87 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class TypeReferenceParser +{ + /** + * @param \Iterator $tokens + * @return TypeReferenceNode + */ + public function parse(\Iterator $tokens): TypeReferenceNode + { + $isOptional = false; + if (Scanner::type($tokens) === TokenType::QUESTIONMARK) { + $startingToken = $tokens->current(); + $isOptional = true; + Scanner::skipOne($tokens); + } + + Scanner::assertType($tokens, TokenType::STRING); + + $typeNameToken = $finalToken = $tokens->current(); + $startingToken = $startingToken ?? $typeNameToken; + + Scanner::skipOne($tokens); + + $isArray = false; + if (!Scanner::isEnd($tokens) && Scanner::type($tokens) === TokenType::BRACKET_SQUARE_OPEN) { + Scanner::skipOne($tokens); + Scanner::assertType($tokens, TokenType::BRACKET_SQUARE_CLOSE); + + $finalToken = $tokens->current(); + $isArray = true; + + Scanner::skipOne($tokens); + } + + try { + return new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: $startingToken->sourcePath, + rangeInSource: Range::from( + $startingToken->boundaries->start, + $finalToken->boundaries->end + ) + ), + name: TypeName::from($typeNameToken->value), + isArray: $isArray, + isOptional: $isOptional + ); + } catch (InvalidTypeReferenceNode $e) { + throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( + cause: $e, + affectedToken: $startingToken + ); + } + } +} diff --git a/src/Parser/Source/Position.php b/src/Parser/Source/Position.php index 67c5aeda..42affcdc 100644 --- a/src/Parser/Source/Position.php +++ b/src/Parser/Source/Position.php @@ -29,4 +29,9 @@ public function __construct( public readonly int $columnNumber ) { } + + public function toDebugString(): string + { + return sprintf('line %s, column %s', $this->lineNumber, $this->columnNumber); + } } diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php new file mode 100644 index 00000000..8f8766f3 --- /dev/null +++ b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php @@ -0,0 +1,133 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PHPUnit\Framework\TestCase; + +final class TypeReferenceNodeTest extends TestCase +{ + /** + * @test + */ + public function validSimpleTypeReferenceIsValid(): void + { + $typeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) + ), + name: TypeName::from('Foo'), + isArray: false, + isOptional: false + ); + + $this->assertEquals('Foo', $typeReferenceNode->name->value); + $this->assertFalse($typeReferenceNode->isArray); + $this->assertFalse($typeReferenceNode->isOptional); + } + + /** + * @test + */ + public function validArrayTypeReferenceIsValid(): void + { + $typeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) + ), + name: TypeName::from('Foo'), + isArray: true, + isOptional: false + ); + + $this->assertEquals('Foo', $typeReferenceNode->name->value); + $this->assertTrue($typeReferenceNode->isArray); + $this->assertFalse($typeReferenceNode->isOptional); + } + + /** + * @test + */ + public function validOptionalTypeReferenceIsValid(): void + { + $typeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) + ), + name: TypeName::from('Foo'), + isArray: false, + isOptional: true + ); + + $this->assertEquals('Foo', $typeReferenceNode->name->value); + $this->assertFalse($typeReferenceNode->isArray); + $this->assertTrue($typeReferenceNode->isOptional); + } + + /** + * @test + */ + public function typeReferenceCannotBeArrayAndOptionalSimultaneously(): void + { + $attributes = new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) + ); + $name = TypeName::from('Foo'); + + $this->expectExceptionObject( + InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( + affectedTypeName: $name, + attributesOfAffectedNode: $attributes + ) + ); + + new TypeReferenceNode( + attributes: $attributes, + name: $name, + isArray: true, + isOptional: true + ); + } +} diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php new file mode 100644 index 00000000..7535f3fc --- /dev/null +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -0,0 +1,150 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceCouldNotBeParsed; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class TypeReferenceParserTest extends TestCase +{ + /** + * @test + */ + public function producesAstNodeForSimpleTypeReference(): void + { + $typeReferenceParser = new TypeReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Foo'))->getIterator(); + + $expectedTypeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + name: TypeName::from('Foo'), + isArray: false, + isOptional: false + ); + + $this->assertEquals( + $expectedTypeReferenceNode, + $typeReferenceParser->parse($tokens) + ); + } + + /** + * @test + */ + public function producesAstNodeForArrayTypeReference(): void + { + $typeReferenceParser = new TypeReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Foo[]'))->getIterator(); + + $expectedTypeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) + ) + ), + name: TypeName::from('Foo'), + isArray: true, + isOptional: false + ); + + $this->assertEquals( + $expectedTypeReferenceNode, + $typeReferenceParser->parse($tokens) + ); + } + + /** + * @test + */ + public function producesAstNodeForOptionalTypeReference(): void + { + $typeReferenceParser = new TypeReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('?Foo'))->getIterator(); + + $expectedTypeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 3) + ) + ), + name: TypeName::from('Foo'), + isArray: false, + isOptional: true + ); + + $this->assertEquals( + $expectedTypeReferenceNode, + $typeReferenceParser->parse($tokens) + ); + } + + /** + * @test + */ + public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void + { + $typeReferenceParser = new TypeReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('?Foo[]'))->getIterator(); + $startingToken = $tokens->current(); + + $this->expectException(ParserException::class); + $this->expectExceptionObject( + TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( + cause: InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( + affectedTypeName: TypeName::from('Foo'), + attributesOfAffectedNode: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) + ) + ), + ), + affectedToken: $startingToken + ) + ); + + $typeReferenceParser->parse($tokens); + } +} diff --git a/test/Unit/Parser/Source/PositionTest.php b/test/Unit/Parser/Source/PositionTest.php new file mode 100644 index 00000000..1edadb08 --- /dev/null +++ b/test/Unit/Parser/Source/PositionTest.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Parser\Source; + +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PHPUnit\Framework\TestCase; + +final class PositionTest extends TestCase +{ + /** + * @test + */ + public function providesDebugStringRepresentingItself(): void + { + $position = new Position(42, 102); + $this->assertEquals('line 42, column 102', $position->toDebugString()); + } +} From c28ce282e139a8b122be08e3880a436a4cb695ff Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 13:53:08 +0200 Subject: [PATCH 30/64] TASK: Wrap type name in additional AST node within TypeReferenceNode This is in preparation to allow for union type references. --- .../AST/Node/TypeReference/TypeNameNode.php | 36 +++++++++++ .../Node/TypeReference/TypeReferenceNode.php | 5 +- .../TypeReference/TypeReferenceParser.php | 9 ++- .../TypeReference/TypeReferenceNodeTest.php | 63 ++++++++++--------- .../TypeReference/TypeReferenceParserTest.php | 34 +++++++++- 5 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 src/Language/AST/Node/TypeReference/TypeNameNode.php diff --git a/src/Language/AST/Node/TypeReference/TypeNameNode.php b/src/Language/AST/Node/TypeReference/TypeNameNode.php new file mode 100644 index 00000000..92c9f89f --- /dev/null +++ b/src/Language/AST/Node/TypeReference/TypeNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TypeNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly TypeName $value + ) { + } +} diff --git a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php index 99566976..c3055af0 100644 --- a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php @@ -22,7 +22,6 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; -use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; @@ -30,13 +29,13 @@ final class TypeReferenceNode extends Node { public function __construct( public readonly NodeAttributes $attributes, - public readonly TypeName $name, + public readonly TypeNameNode $name, public readonly bool $isArray, public readonly bool $isOptional ) { if ($isArray === true && $isOptional === true) { throw InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( - affectedTypeName: $name, + affectedTypeName: $name->value, attributesOfAffectedNode: $attributes ); } diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index dc4db16c..062dbed9 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -73,7 +74,13 @@ public function parse(\Iterator $tokens): TypeReferenceNode $finalToken->boundaries->end ) ), - name: TypeName::from($typeNameToken->value), + name: new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: $typeNameToken->sourcePath, + rangeInSource: $typeNameToken->boundaries + ), + value: TypeName::from($typeNameToken->value) + ), isArray: $isArray, isOptional: $isOptional ); diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php index 8f8766f3..940ead75 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Path; @@ -33,20 +34,30 @@ final class TypeReferenceNodeTest extends TestCase { + private NodeAttributes $dummyAttributes; + + public function setUp(): void + { + $this->dummyAttributes = new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) + ); + } + /** * @test */ public function validSimpleTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 0) - ) + attributes: $this->dummyAttributes, + name: new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') ), - name: TypeName::from('Foo'), isArray: false, isOptional: false ); @@ -62,14 +73,11 @@ public function validSimpleTypeReferenceIsValid(): void public function validArrayTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 0) - ) + attributes: $this->dummyAttributes, + name: new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') ), - name: TypeName::from('Foo'), isArray: true, isOptional: false ); @@ -85,14 +93,11 @@ public function validArrayTypeReferenceIsValid(): void public function validOptionalTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 0) - ) + attributes: $this->dummyAttributes, + name: new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') ), - name: TypeName::from('Foo'), isArray: false, isOptional: true ); @@ -107,25 +112,21 @@ public function validOptionalTypeReferenceIsValid(): void */ public function typeReferenceCannotBeArrayAndOptionalSimultaneously(): void { - $attributes = new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 0) - ) - ); $name = TypeName::from('Foo'); $this->expectExceptionObject( InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( affectedTypeName: $name, - attributesOfAffectedNode: $attributes + attributesOfAffectedNode: $this->dummyAttributes ) ); new TypeReferenceNode( - attributes: $attributes, - name: $name, + attributes: $this->dummyAttributes, + name: new TypeNameNode( + attributes: $this->dummyAttributes, + value: $name + ), isArray: true, isOptional: true ); diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index 7535f3fc..ad094484 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; @@ -54,7 +55,16 @@ public function producesAstNodeForSimpleTypeReference(): void new Position(0, 2) ) ), - name: TypeName::from('Foo'), + name: new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: TypeName::from('Foo') + ), isArray: false, isOptional: false ); @@ -81,7 +91,16 @@ public function producesAstNodeForArrayTypeReference(): void new Position(0, 4) ) ), - name: TypeName::from('Foo'), + name: new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: TypeName::from('Foo') + ), isArray: true, isOptional: false ); @@ -108,7 +127,16 @@ public function producesAstNodeForOptionalTypeReference(): void new Position(0, 3) ) ), - name: TypeName::from('Foo'), + name: new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) + ) + ), + value: TypeName::from('Foo') + ), isArray: false, isOptional: true ); From f192958f9122808954340777a037882bd104e722 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 14:52:13 +0200 Subject: [PATCH 31/64] TASK: Allow for type references to refer to multiple types in principle This is in preparation to allow for union type references. --- src/Domain/TypeName/TypeNames.php | 47 ++++++++++ .../InvalidTypeReferenceNode.php | 8 +- .../AST/Node/TypeReference/TypeNameNodes.php | 59 ++++++++++++ .../Node/TypeReference/TypeReferenceNode.php | 4 +- .../TypeReference/TypeReferenceParser.php | 15 +-- test/Unit/Domain/TypeName/TypeNamesTest.php | 47 ++++++++++ .../Language/AST/Helpers/DummyAttributes.php | 47 ++++++++++ .../Node/TypeReference/TypeNameNodesTest.php | 91 +++++++++++++++++++ .../TypeReference/TypeReferenceNodeTest.php | 63 +++++++------ .../TypeReference/TypeReferenceParserTest.php | 64 +++++++------ 10 files changed, 373 insertions(+), 72 deletions(-) create mode 100644 src/Domain/TypeName/TypeNames.php create mode 100644 src/Language/AST/Node/TypeReference/TypeNameNodes.php create mode 100644 test/Unit/Domain/TypeName/TypeNamesTest.php create mode 100644 test/Unit/Language/AST/Helpers/DummyAttributes.php create mode 100644 test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php diff --git a/src/Domain/TypeName/TypeNames.php b/src/Domain/TypeName/TypeNames.php new file mode 100644 index 00000000..b85d5a64 --- /dev/null +++ b/src/Domain/TypeName/TypeNames.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\TypeName; + +final class TypeNames +{ + /** + * @var TypeName[] + */ + public readonly array $items; + + public function __construct(TypeName ...$items) + { + $this->items = $items; + } + + public function toDebugString(): string + { + return join( + '|', + array_map( + static fn (TypeName $typeName) => $typeName->value, + $this->items + ) + ); + } +} diff --git a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php index e0069d1c..a41ec56d 100644 --- a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php @@ -22,21 +22,21 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; -use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; use PackageFactory\ComponentEngine\Language\AST\ASTException; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; final class InvalidTypeReferenceNode extends ASTException { public static function becauseItWasOptionalAndArrayAtTheSameTime( - TypeName $affectedTypeName, + TypeNames $affectedTypeNames, NodeAttributes $attributesOfAffectedNode ): self { return new self( code: 1690538480, message: sprintf( - 'The reference to type "%s" must not be optional and array at the same time.', - $affectedTypeName->value + 'The type reference to "%s" must not be optional and array at the same time.', + $affectedTypeNames->toDebugString() ), attributesOfAffectedNode: $attributesOfAffectedNode ); diff --git a/src/Language/AST/Node/TypeReference/TypeNameNodes.php b/src/Language/AST/Node/TypeReference/TypeNameNodes.php new file mode 100644 index 00000000..4737d73c --- /dev/null +++ b/src/Language/AST/Node/TypeReference/TypeNameNodes.php @@ -0,0 +1,59 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; + +final class TypeNameNodes +{ + /** + * @var TypeNameNode[] + */ + public readonly array $items; + + private ?TypeNames $cachedTypeNames = null; + + public function __construct(TypeNameNode ...$items) + { + $this->items = $items; + } + + public function getSize(): int + { + return count($this->items); + } + + public function toTypeNames(): TypeNames + { + if ($this->cachedTypeNames === null) { + $typeNamesAsArray = array_map( + static fn (TypeNameNode $typeNameNode) => $typeNameNode->value, + $this->items + ); + + $this->cachedTypeNames = new TypeNames(...$typeNamesAsArray); + } + + return $this->cachedTypeNames; + } +} diff --git a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php index c3055af0..5dbcb9bf 100644 --- a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php @@ -29,13 +29,13 @@ final class TypeReferenceNode extends Node { public function __construct( public readonly NodeAttributes $attributes, - public readonly TypeNameNode $name, + public readonly TypeNameNodes $names, public readonly bool $isArray, public readonly bool $isOptional ) { if ($isArray === true && $isOptional === true) { throw InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( - affectedTypeName: $name->value, + affectedTypeNames: $names->toTypeNames(), attributesOfAffectedNode: $attributes ); } diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index 062dbed9..5764e447 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -25,6 +25,7 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -74,12 +75,14 @@ public function parse(\Iterator $tokens): TypeReferenceNode $finalToken->boundaries->end ) ), - name: new TypeNameNode( - attributes: new NodeAttributes( - pathToSource: $typeNameToken->sourcePath, - rangeInSource: $typeNameToken->boundaries - ), - value: TypeName::from($typeNameToken->value) + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: $typeNameToken->sourcePath, + rangeInSource: $typeNameToken->boundaries + ), + value: TypeName::from($typeNameToken->value) + ) ), isArray: $isArray, isOptional: $isOptional diff --git a/test/Unit/Domain/TypeName/TypeNamesTest.php b/test/Unit/Domain/TypeName/TypeNamesTest.php new file mode 100644 index 00000000..d027374f --- /dev/null +++ b/test/Unit/Domain/TypeName/TypeNamesTest.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Domain\TypeName; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; +use PHPUnit\Framework\TestCase; + +final class TypeNamesTest extends TestCase +{ + /** + * @test + */ + public function providesDebugString(): void + { + $typeNames = new TypeNames( + TypeName::from('Foo'), + TypeName::from('Bar'), + TypeName::from('Baz') + ); + + $this->assertEquals( + 'Foo|Bar|Baz', + $typeNames->toDebugString() + ); + } +} diff --git a/test/Unit/Language/AST/Helpers/DummyAttributes.php b/test/Unit/Language/AST/Helpers/DummyAttributes.php new file mode 100644 index 00000000..bb3f30b3 --- /dev/null +++ b/test/Unit/Language/AST/Helpers/DummyAttributes.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers; + +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +trait DummyAttributes +{ + protected NodeAttributes $dummyAttributes; + + /** + * @before + */ + public function setUpDummyAttributes(): void + { + $this->dummyAttributes = new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) + ); + } +} diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php new file mode 100644 index 00000000..9ba15be8 --- /dev/null +++ b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php @@ -0,0 +1,91 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; +use PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers\DummyAttributes; +use PHPUnit\Framework\TestCase; + +final class TypeNameNodesTest extends TestCase +{ + use DummyAttributes; + + protected function createTypeNameNode(string $typeName): TypeNameNode + { + return new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from($typeName) + ); + } + + /** + * @test + */ + public function providesItsOwnSize(): void + { + $typeNameNodes = new TypeNameNodes( + $this->createTypeNameNode('Foo') + ); + + $this->assertEquals(1, $typeNameNodes->getSize()); + + $typeNameNodes = new TypeNameNodes( + $this->createTypeNameNode('Foo'), + $this->createTypeNameNode('Bar') + ); + + $this->assertEquals(2, $typeNameNodes->getSize()); + + $typeNameNodes = new TypeNameNodes( + $this->createTypeNameNode('Foo'), + $this->createTypeNameNode('Bar'), + $this->createTypeNameNode('Baz') + ); + + $this->assertEquals(3, $typeNameNodes->getSize()); + } + + /** + * @test + */ + public function convertsToTypeNames(): void + { + $typeNameNodes = new TypeNameNodes( + $this->createTypeNameNode('Foo'), + $this->createTypeNameNode('Bar'), + $this->createTypeNameNode('Baz') + ); + + $this->assertEquals( + new TypeNames( + TypeName::from('Foo'), + TypeName::from('Bar'), + TypeName::from('Baz') + ), + $typeNameNodes->toTypeNames() + ); + } +} diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php index 940ead75..0dd690b3 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php @@ -23,29 +23,17 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Node\TypeReference; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Path; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers\DummyAttributes; use PHPUnit\Framework\TestCase; final class TypeReferenceNodeTest extends TestCase { - private NodeAttributes $dummyAttributes; - - public function setUp(): void - { - $this->dummyAttributes = new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 0) - ) - ); - } + use DummyAttributes; /** * @test @@ -54,15 +42,18 @@ public function validSimpleTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( attributes: $this->dummyAttributes, - name: new TypeNameNode( - attributes: $this->dummyAttributes, - value: TypeName::from('Foo') + names: new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') + ) ), isArray: false, isOptional: false ); - $this->assertEquals('Foo', $typeReferenceNode->name->value); + $this->assertEquals(1, $typeReferenceNode->names->getSize()); + $this->assertEquals('Foo', $typeReferenceNode->names->items[0]->value->value); $this->assertFalse($typeReferenceNode->isArray); $this->assertFalse($typeReferenceNode->isOptional); } @@ -74,15 +65,18 @@ public function validArrayTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( attributes: $this->dummyAttributes, - name: new TypeNameNode( - attributes: $this->dummyAttributes, - value: TypeName::from('Foo') + names: new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') + ) ), isArray: true, isOptional: false ); - $this->assertEquals('Foo', $typeReferenceNode->name->value); + $this->assertEquals(1, $typeReferenceNode->names->getSize()); + $this->assertEquals('Foo', $typeReferenceNode->names->items[0]->value->value); $this->assertTrue($typeReferenceNode->isArray); $this->assertFalse($typeReferenceNode->isOptional); } @@ -94,15 +88,18 @@ public function validOptionalTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( attributes: $this->dummyAttributes, - name: new TypeNameNode( - attributes: $this->dummyAttributes, - value: TypeName::from('Foo') + names: new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') + ) ), isArray: false, isOptional: true ); - $this->assertEquals('Foo', $typeReferenceNode->name->value); + $this->assertEquals(1, $typeReferenceNode->names->getSize()); + $this->assertEquals('Foo', $typeReferenceNode->names->items[0]->value->value); $this->assertFalse($typeReferenceNode->isArray); $this->assertTrue($typeReferenceNode->isOptional); } @@ -116,16 +113,18 @@ public function typeReferenceCannotBeArrayAndOptionalSimultaneously(): void $this->expectExceptionObject( InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( - affectedTypeName: $name, + affectedTypeNames: new TypeNames($name), attributesOfAffectedNode: $this->dummyAttributes ) ); new TypeReferenceNode( attributes: $this->dummyAttributes, - name: new TypeNameNode( - attributes: $this->dummyAttributes, - value: $name + names: new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: $name + ) ), isArray: true, isOptional: true diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index ad094484..007cb95c 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -23,8 +23,10 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\TypeReference; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; @@ -55,15 +57,17 @@ public function producesAstNodeForSimpleTypeReference(): void new Position(0, 2) ) ), - name: new TypeNameNode( - attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) - ), - value: TypeName::from('Foo') + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: TypeName::from('Foo') + ) ), isArray: false, isOptional: false @@ -91,15 +95,17 @@ public function producesAstNodeForArrayTypeReference(): void new Position(0, 4) ) ), - name: new TypeNameNode( - attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) - ), - value: TypeName::from('Foo') + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: TypeName::from('Foo') + ) ), isArray: true, isOptional: false @@ -127,15 +133,17 @@ public function producesAstNodeForOptionalTypeReference(): void new Position(0, 3) ) ), - name: new TypeNameNode( - attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ) - ), - value: TypeName::from('Foo') + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) + ) + ), + value: TypeName::from('Foo') + ) ), isArray: false, isOptional: true @@ -160,7 +168,7 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void $this->expectExceptionObject( TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( cause: InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( - affectedTypeName: TypeName::from('Foo'), + affectedTypeNames: new TypeNames(TypeName::from('Foo')), attributesOfAffectedNode: new NodeAttributes( pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( From 312dfc3b7631e17da6e2b60abf79bb88ade9fffb Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 28 Jul 2023 15:58:15 +0200 Subject: [PATCH 32/64] TASK: Add constraints for union type references --- src/Language/AST/ASTException.php | 2 +- .../TypeReference/InvalidTypeNameNodes.php | 46 ++++++++ .../InvalidTypeReferenceNode.php | 28 +++++ .../AST/Node/TypeReference/TypeNameNodes.php | 15 +++ .../Node/TypeReference/TypeReferenceNode.php | 14 +++ .../Node/TypeReference/TypeNameNodesTest.php | 47 ++++++++ .../TypeReference/TypeReferenceNodeTest.php | 105 +++++++++++++++++- 7 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php diff --git a/src/Language/AST/ASTException.php b/src/Language/AST/ASTException.php index 929a45a7..6de58c30 100644 --- a/src/Language/AST/ASTException.php +++ b/src/Language/AST/ASTException.php @@ -29,7 +29,7 @@ abstract class ASTException extends \Exception protected function __construct( int $code, string $message, - public readonly NodeAttributes $attributesOfAffectedNode + public readonly ?NodeAttributes $attributesOfAffectedNode = null ) { parent::__construct($message, $code); } diff --git a/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php b/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php new file mode 100644 index 00000000..975dcc3d --- /dev/null +++ b/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; + +use PackageFactory\ComponentEngine\Language\AST\ASTException; + +final class InvalidTypeNameNodes extends ASTException +{ + public static function becauseTheyWereEmpty(): self + { + return new self( + code: 1690549442, + message: 'A type reference must refer to at least one type name.' + ); + } + + public static function becauseTheyContainDuplicates( + TypeNameNode $duplicateTypeNameNode + ): self { + return new self( + code: 1690551330, + message: 'A type reference must not contain duplicates.', + attributesOfAffectedNode: $duplicateTypeNameNode->attributes + ); + } +} diff --git a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php index a41ec56d..d712ae87 100644 --- a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php @@ -41,4 +41,32 @@ public static function becauseItWasOptionalAndArrayAtTheSameTime( attributesOfAffectedNode: $attributesOfAffectedNode ); } + + public static function becauseItWasUnionAndArrayAtTheSameTime( + TypeNames $affectedTypeNames, + NodeAttributes $attributesOfAffectedNode + ): self { + return new self( + code: 1690552344, + message: sprintf( + 'The type reference to "%s" must not be union and array at the same time.', + $affectedTypeNames->toDebugString() + ), + attributesOfAffectedNode: $attributesOfAffectedNode + ); + } + + public static function becauseItWasUnionAndOptionalAtTheSameTime( + TypeNames $affectedTypeNames, + NodeAttributes $attributesOfAffectedNode + ): self { + return new self( + code: 1690552586, + message: sprintf( + 'The type reference to "%s" must not be union and optional at the same time.', + $affectedTypeNames->toDebugString() + ), + attributesOfAffectedNode: $attributesOfAffectedNode + ); + } } diff --git a/src/Language/AST/Node/TypeReference/TypeNameNodes.php b/src/Language/AST/Node/TypeReference/TypeNameNodes.php index 4737d73c..6e0ad7e5 100644 --- a/src/Language/AST/Node/TypeReference/TypeNameNodes.php +++ b/src/Language/AST/Node/TypeReference/TypeNameNodes.php @@ -35,6 +35,21 @@ final class TypeNameNodes public function __construct(TypeNameNode ...$items) { + if (count($items) === 0) { + throw InvalidTypeNameNodes::becauseTheyWereEmpty(); + } + + $typeNames = []; + foreach ($items as $item) { + if (isset($typeNames[$item->value->value])) { + throw InvalidTypeNameNodes::becauseTheyContainDuplicates( + duplicateTypeNameNode: $item + ); + } + + $typeNames[$item->value->value] = true; + } + $this->items = $items; } diff --git a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php index 5dbcb9bf..390c3d50 100644 --- a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php @@ -39,5 +39,19 @@ public function __construct( attributesOfAffectedNode: $attributes ); } + + if ($names->getSize() > 1 && $isArray === true) { + throw InvalidTypeReferenceNode::becauseItWasUnionAndArrayAtTheSameTime( + affectedTypeNames: $names->toTypeNames(), + attributesOfAffectedNode: $attributes + ); + } + + if ($names->getSize() > 1 && $isOptional === true) { + throw InvalidTypeReferenceNode::becauseItWasUnionAndOptionalAtTheSameTime( + affectedTypeNames: $names->toTypeNames(), + attributesOfAffectedNode: $attributes + ); + } } } diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php index 9ba15be8..e307b7e9 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php @@ -24,8 +24,13 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers\DummyAttributes; use PHPUnit\Framework\TestCase; @@ -41,6 +46,48 @@ protected function createTypeNameNode(string $typeName): TypeNameNode ); } + /** + * @test + */ + public function mustNotBeEmpty(): void + { + $this->expectExceptionObject( + InvalidTypeNameNodes::becauseTheyWereEmpty() + ); + + new TypeNameNodes(); + } + + /** + * @test + */ + public function mustNotContainDuplicates(): void + { + $duplicate = new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(1, 1), + new Position(1, 1) + ) + ), + value: TypeName::from('Foo') + ); + + $this->expectExceptionObject( + InvalidTypeNameNodes::becauseTheyContainDuplicates( + duplicateTypeNameNode: $duplicate + ) + ); + + new TypeNameNodes( + $this->createTypeNameNode('Foo'), + $this->createTypeNameNode('Bar'), + $duplicate, + $this->createTypeNameNode('Baz'), + ); + } + /** * @test */ diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php index 0dd690b3..5d4c7a0e 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php @@ -107,7 +107,40 @@ public function validOptionalTypeReferenceIsValid(): void /** * @test */ - public function typeReferenceCannotBeArrayAndOptionalSimultaneously(): void + public function validUnionTypeReferenceIsValid(): void + { + $typeReferenceNode = new TypeReferenceNode( + attributes: $this->dummyAttributes, + names: new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') + ), + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Bar') + ), + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Baz') + ) + ), + isArray: false, + isOptional: false + ); + + $this->assertEquals(3, $typeReferenceNode->names->getSize()); + $this->assertEquals('Foo', $typeReferenceNode->names->items[0]->value->value); + $this->assertEquals('Bar', $typeReferenceNode->names->items[1]->value->value); + $this->assertEquals('Baz', $typeReferenceNode->names->items[2]->value->value); + $this->assertFalse($typeReferenceNode->isArray); + $this->assertFalse($typeReferenceNode->isOptional); + } + + /** + * @test + */ + public function mustNotBeArrayAndOptionalSimultaneously(): void { $name = TypeName::from('Foo'); @@ -130,4 +163,74 @@ public function typeReferenceCannotBeArrayAndOptionalSimultaneously(): void isOptional: true ); } + + /** + * @test + */ + public function mustNotBeUnionAndArraySimultaneously(): void + { + $typeNameNodes = new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') + ), + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Bar') + ), + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Baz') + ) + ); + + $this->expectExceptionObject( + InvalidTypeReferenceNode::becauseItWasUnionAndArrayAtTheSameTime( + affectedTypeNames: $typeNameNodes->toTypeNames(), + attributesOfAffectedNode: $this->dummyAttributes + ) + ); + + new TypeReferenceNode( + attributes: $this->dummyAttributes, + names: $typeNameNodes, + isArray: true, + isOptional: false + ); + } + + /** + * @test + */ + public function mustNotBeUnionAndOptionalSimultaneously(): void + { + $typeNameNodes = new TypeNameNodes( + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Foo') + ), + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Bar') + ), + new TypeNameNode( + attributes: $this->dummyAttributes, + value: TypeName::from('Baz') + ) + ); + + $this->expectExceptionObject( + InvalidTypeReferenceNode::becauseItWasUnionAndOptionalAtTheSameTime( + affectedTypeNames: $typeNameNodes->toTypeNames(), + attributesOfAffectedNode: $this->dummyAttributes + ) + ); + + new TypeReferenceNode( + attributes: $this->dummyAttributes, + names: $typeNameNodes, + isArray: false, + isOptional: true + ); + } } From ef6a7325458199a6e5c99196614196321a4b15f6 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 31 Jul 2023 19:00:55 +0200 Subject: [PATCH 33/64] FEATURE: Parse references to union types --- .../AST/Node/TypeReference/TypeNameNodes.php | 5 + .../TypeReference/TypeReferenceParser.php | 113 +++++++++++++----- src/Parser/Tokenizer/TokenType.php | 1 + src/Parser/Tokenizer/Tokenizer.php | 1 + .../Node/TypeReference/TypeNameNodesTest.php | 24 ++++ .../TypeReference/TypeReferenceParserTest.php | 58 +++++++++ 6 files changed, 170 insertions(+), 32 deletions(-) diff --git a/src/Language/AST/Node/TypeReference/TypeNameNodes.php b/src/Language/AST/Node/TypeReference/TypeNameNodes.php index 6e0ad7e5..59db01f8 100644 --- a/src/Language/AST/Node/TypeReference/TypeNameNodes.php +++ b/src/Language/AST/Node/TypeReference/TypeNameNodes.php @@ -58,6 +58,11 @@ public function getSize(): int return count($this->items); } + public function getLast(): TypeNameNode + { + return $this->items[$this->getSize() - 1]; + } + public function toTypeNames(): TypeNames { if ($this->cachedTypeNames === null) { diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index 5764e447..d02a91db 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -41,30 +41,14 @@ final class TypeReferenceParser */ public function parse(\Iterator $tokens): TypeReferenceNode { - $isOptional = false; - if (Scanner::type($tokens) === TokenType::QUESTIONMARK) { - $startingToken = $tokens->current(); - $isOptional = true; - Scanner::skipOne($tokens); - } - - Scanner::assertType($tokens, TokenType::STRING); + $startingToken = $tokens->current(); + $questionmarkToken = $this->extractQuestionmarkToken($tokens); + $isOptional = !is_null($questionmarkToken); - $typeNameToken = $finalToken = $tokens->current(); - $startingToken = $startingToken ?? $typeNameToken; + $typeNameNodes = $this->parseTypeNames($tokens); - Scanner::skipOne($tokens); - - $isArray = false; - if (!Scanner::isEnd($tokens) && Scanner::type($tokens) === TokenType::BRACKET_SQUARE_OPEN) { - Scanner::skipOne($tokens); - Scanner::assertType($tokens, TokenType::BRACKET_SQUARE_CLOSE); - - $finalToken = $tokens->current(); - $isArray = true; - - Scanner::skipOne($tokens); - } + $closingArrayToken = $this->extractClosingArrayToken($tokens); + $isArray = !is_null($closingArrayToken); try { return new TypeReferenceNode( @@ -72,18 +56,11 @@ public function parse(\Iterator $tokens): TypeReferenceNode pathToSource: $startingToken->sourcePath, rangeInSource: Range::from( $startingToken->boundaries->start, - $finalToken->boundaries->end - ) - ), - names: new TypeNameNodes( - new TypeNameNode( - attributes: new NodeAttributes( - pathToSource: $typeNameToken->sourcePath, - rangeInSource: $typeNameToken->boundaries - ), - value: TypeName::from($typeNameToken->value) + $closingArrayToken?->boundaries->end + ?? $typeNameNodes->getLast()->attributes->rangeInSource->end ) ), + names: $typeNameNodes, isArray: $isArray, isOptional: $isOptional ); @@ -94,4 +71,76 @@ public function parse(\Iterator $tokens): TypeReferenceNode ); } } + + /** + * @param \Iterator $tokens + * @return Token + */ + public function extractQuestionmarkToken(\Iterator $tokens): ?Token + { + if (Scanner::type($tokens) === TokenType::QUESTIONMARK) { + $questionmarkToken = $tokens->current(); + Scanner::skipOne($tokens); + + return $questionmarkToken; + } + + return null; + } + + /** + * @param \Iterator $tokens + * @return TypeNameNodes + */ + public function parseTypeNames(\Iterator $tokens): TypeNameNodes + { + $items = []; + while (true) { + Scanner::assertType($tokens, TokenType::STRING); + + $typeNameToken = $tokens->current(); + $items[] = new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: $typeNameToken->sourcePath, + rangeInSource: $typeNameToken->boundaries + ), + value: TypeName::from($typeNameToken->value) + ); + + Scanner::skipOne($tokens); + + if (Scanner::isEnd($tokens)) { + break; + } + + if (Scanner::type($tokens) === TokenType::PIPE) { + Scanner::skipOne($tokens); + continue; + } + + break; + } + + return new TypeNameNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return Token + */ + public function extractClosingArrayToken(\Iterator $tokens): ?Token + { + if (!Scanner::isEnd($tokens) && Scanner::type($tokens) === TokenType::BRACKET_SQUARE_OPEN) { + Scanner::skipOne($tokens); + Scanner::assertType($tokens, TokenType::BRACKET_SQUARE_CLOSE); + + $closingArrayToken = $tokens->current(); + + Scanner::skipOne($tokens); + + return $closingArrayToken; + } + + return null; + } } diff --git a/src/Parser/Tokenizer/TokenType.php b/src/Parser/Tokenizer/TokenType.php index 12d76b29..694170b0 100644 --- a/src/Parser/Tokenizer/TokenType.php +++ b/src/Parser/Tokenizer/TokenType.php @@ -86,6 +86,7 @@ enum TokenType: string case EQUALS = 'EQUALS'; case SLASH_FORWARD = 'SLASH_FORWARD'; case DOLLAR = 'DOLLAR'; + case PIPE = 'PIPE'; case OPTCHAIN = 'OPTCHAIN'; case NULLISH_COALESCE = 'NULLISH_COALESCE'; diff --git a/src/Parser/Tokenizer/Tokenizer.php b/src/Parser/Tokenizer/Tokenizer.php index c08eaa15..dc3008ce 100644 --- a/src/Parser/Tokenizer/Tokenizer.php +++ b/src/Parser/Tokenizer/Tokenizer.php @@ -277,6 +277,7 @@ public static function symbol(\Iterator $fragments, ?Buffer $buffer = null): \It '=' => $buffer->flush(TokenType::EQUALS), '?' => $buffer->flush(TokenType::QUESTIONMARK), '$' => $buffer->flush(TokenType::DOLLAR), + '|' => $buffer->flush(TokenType::PIPE), default => self::flushRemainder($buffer) }; } diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php index e307b7e9..4d949713 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php @@ -115,6 +115,30 @@ public function providesItsOwnSize(): void $this->assertEquals(3, $typeNameNodes->getSize()); } + /** + * @test + */ + public function providesItsLastItemIfTheresOnlyOne(): void + { + $foo = $this->createTypeNameNode('Foo'); + $typeNameNodes = new TypeNameNodes($foo); + + $this->assertSame($foo, $typeNameNodes->getLast()); + } + + /** + * @test + */ + public function providesItsLastItemIfTheresMultiple(): void + { + $foo = $this->createTypeNameNode('Foo'); + $bar = $this->createTypeNameNode('Bar'); + $baz = $this->createTypeNameNode('Baz'); + $typeNameNodes = new TypeNameNodes($foo, $bar, $baz); + + $this->assertSame($baz, $typeNameNodes->getLast()); + } + /** * @test */ diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index 007cb95c..c8b8a0aa 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -155,6 +155,64 @@ public function producesAstNodeForOptionalTypeReference(): void ); } + /** + * @test + */ + public function producesAstNodeForUnionTypeReference(): void + { + $typeReferenceParser = new TypeReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Foo|Bar|Baz'))->getIterator(); + + $expectedTypeReferenceNode = new TypeReferenceNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: TypeName::from('Foo') + ), + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 6) + ) + ), + value: TypeName::from('Bar') + ), + new TypeNameNode( + attributes: new NodeAttributes( + pathToSource: Path::fromString(':memory:'), + rangeInSource: Range::from( + new Position(0, 8), + new Position(0, 10) + ) + ), + value: TypeName::from('Baz') + ) + ), + isArray: false, + isOptional: false + ); + + $this->assertEquals( + $expectedTypeReferenceNode, + $typeReferenceParser->parse($tokens) + ); + } + /** * @test */ From d47936baa3eb0fdcded4500280f38f68352c0e2f Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 31 Jul 2023 19:09:58 +0200 Subject: [PATCH 34/64] TASK: Remove pathToSource property from NodeAttributes --- .../AST/NodeAttributes/NodeAttributes.php | 2 - .../BooleanLiteral/BooleanLiteralParser.php | 1 - .../EnumDeclaration/EnumDeclarationParser.php | 5 - .../IntegerLiteral/IntegerLiteralParser.php | 1 - .../Parser/NullLiteral/NullLiteralParser.php | 1 - .../StringLiteral/StringLiteralParser.php | 1 - .../TypeReference/TypeReferenceParser.php | 2 - .../Language/AST/Helpers/DummyAttributes.php | 2 - .../Node/TypeReference/TypeNameNodesTest.php | 2 - .../BooleanLiteralParserTest.php | 3 - .../EnumDeclarationParserTest.php | 123 ------------------ .../IntegerLiteralParserTest.php | 5 - .../NullLiteral/NullLiteralParserTest.php | 2 - .../StringLiteral/StringLiteralParserTest.php | 2 - .../TypeReference/TypeReferenceParserTest.php | 12 -- 15 files changed, 164 deletions(-) diff --git a/src/Language/AST/NodeAttributes/NodeAttributes.php b/src/Language/AST/NodeAttributes/NodeAttributes.php index 7c446efc..7347e1ab 100644 --- a/src/Language/AST/NodeAttributes/NodeAttributes.php +++ b/src/Language/AST/NodeAttributes/NodeAttributes.php @@ -23,12 +23,10 @@ namespace PackageFactory\ComponentEngine\Language\AST\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; final class NodeAttributes { public function __construct( - public readonly Path $pathToSource, public readonly Range $rangeInSource ) { } diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index 4c4558aa..81b9dbda 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -45,7 +45,6 @@ public function parse(\Iterator $tokens): BooleanLiteralNode return new BooleanLiteralNode( attributes: new NodeAttributes( - pathToSource: $token->sourcePath, rangeInSource: $token->boundaries ), value: $value diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 82ee2f12..74f271cd 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -65,7 +65,6 @@ public function parse(\Iterator $tokens): EnumDeclarationNode return new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: $enumKeyWordToken->sourcePath, rangeInSource: Range::from( $enumKeyWordToken->boundaries->start, $closingBracketToken->boundaries->end @@ -103,7 +102,6 @@ private function parseEnumName(\Iterator $tokens): EnumNameNode $enumKeyNameToken = $tokens->current(); $enumNameNode = new EnumNameNode( attributes: new NodeAttributes( - pathToSource: $enumKeyNameToken->sourcePath, rangeInSource: $enumKeyNameToken->boundaries ), value: EnumName::from($enumKeyNameToken->value) @@ -176,7 +174,6 @@ private function parseEnumMemberDeclaration(\Iterator $tokens): EnumMemberDeclar return new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: $enumMemberName->attributes->pathToSource, rangeInSource: Range::from( $enumMemberName->attributes->rangeInSource->start, $value?->attributes->rangeInSource->end @@ -199,7 +196,6 @@ private function parseEnumMemberName(\Iterator $tokens): EnumMemberNameNode $enumMemberNameToken = $tokens->current(); $enumMemberNameNode = new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: $enumMemberNameToken->sourcePath, rangeInSource: $enumMemberNameToken->boundaries ), value: EnumMemberName::from($enumMemberNameToken->value) @@ -241,7 +237,6 @@ private function parseEnumMemberValue(\Iterator $tokens): ?EnumMemberValueNode return new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: $valueToken->sourcePath, rangeInSource: Range::from( $openingBracketToken->boundaries->start, $closingBracketToken->boundaries->end diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index 6968fc0c..774465d9 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -42,7 +42,6 @@ public function parse(\Iterator $tokens): IntegerLiteralNode return new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: $token->sourcePath, rangeInSource: $token->boundaries ), format: IntegerFormat::fromTokenType($token->type), diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index 1e84dbe3..4cbcccee 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -44,7 +44,6 @@ public function parse(\Iterator $tokens): NullLiteralNode return new NullLiteralNode( attributes: new NodeAttributes( - pathToSource: $token->sourcePath, rangeInSource: $token->boundaries ) ); diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index 72db0c07..5f891039 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -44,7 +44,6 @@ public function parse(\Iterator $tokens): StringLiteralNode return new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: $token->sourcePath, rangeInSource: $token->boundaries ), value: $token->value diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index d02a91db..e89cfcd1 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -53,7 +53,6 @@ public function parse(\Iterator $tokens): TypeReferenceNode try { return new TypeReferenceNode( attributes: new NodeAttributes( - pathToSource: $startingToken->sourcePath, rangeInSource: Range::from( $startingToken->boundaries->start, $closingArrayToken?->boundaries->end @@ -101,7 +100,6 @@ public function parseTypeNames(\Iterator $tokens): TypeNameNodes $typeNameToken = $tokens->current(); $items[] = new TypeNameNode( attributes: new NodeAttributes( - pathToSource: $typeNameToken->sourcePath, rangeInSource: $typeNameToken->boundaries ), value: TypeName::from($typeNameToken->value) diff --git a/test/Unit/Language/AST/Helpers/DummyAttributes.php b/test/Unit/Language/AST/Helpers/DummyAttributes.php index bb3f30b3..4376f2c9 100644 --- a/test/Unit/Language/AST/Helpers/DummyAttributes.php +++ b/test/Unit/Language/AST/Helpers/DummyAttributes.php @@ -23,7 +23,6 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -37,7 +36,6 @@ trait DummyAttributes public function setUpDummyAttributes(): void { $this->dummyAttributes = new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 0) diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php index 4d949713..b79f9d2e 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php @@ -28,7 +28,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers\DummyAttributes; @@ -65,7 +64,6 @@ public function mustNotContainDuplicates(): void { $duplicate = new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 1), new Position(1, 1) diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index a2f94e85..0a862e43 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -26,7 +26,6 @@ use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; @@ -44,7 +43,6 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void $expectedBooleanLiteralNode = new BooleanLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 3) @@ -69,7 +67,6 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void $expectedBooleanLiteralNode = new BooleanLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 4) diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 34395732..343a170d 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -36,7 +36,6 @@ use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; @@ -54,7 +53,6 @@ public function oneValuelessMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 15) @@ -62,7 +60,6 @@ public function oneValuelessMember(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -73,7 +70,6 @@ public function oneValuelessMember(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -81,7 +77,6 @@ public function oneValuelessMember(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -110,7 +105,6 @@ public function threeValuelessMembers(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 23) @@ -118,7 +112,6 @@ public function threeValuelessMembers(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -129,7 +122,6 @@ public function threeValuelessMembers(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -137,7 +129,6 @@ public function threeValuelessMembers(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -149,7 +140,6 @@ public function threeValuelessMembers(): void ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 15), new Position(0, 17) @@ -157,7 +147,6 @@ public function threeValuelessMembers(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 15), new Position(0, 17) @@ -169,7 +158,6 @@ public function threeValuelessMembers(): void ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 19), new Position(0, 21) @@ -177,7 +165,6 @@ public function threeValuelessMembers(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 19), new Position(0, 21) @@ -206,7 +193,6 @@ public function oneStringValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 22) @@ -214,7 +200,6 @@ public function oneStringValueMember(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -225,7 +210,6 @@ public function oneStringValueMember(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 20) @@ -233,7 +217,6 @@ public function oneStringValueMember(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -243,7 +226,6 @@ public function oneStringValueMember(): void ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 14), new Position(0, 20) @@ -251,7 +233,6 @@ public function oneStringValueMember(): void ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 16), new Position(0, 18) @@ -291,7 +272,6 @@ enum Weekday { $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(8, 0) @@ -299,7 +279,6 @@ enum Weekday { ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 11) @@ -310,7 +289,6 @@ enum Weekday { members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 4), new Position(1, 16) @@ -318,7 +296,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 4), new Position(1, 9) @@ -328,7 +305,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 10), new Position(1, 16) @@ -336,7 +312,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 12), new Position(1, 14) @@ -348,7 +323,6 @@ enum Weekday { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 4), new Position(2, 17) @@ -356,7 +330,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 4), new Position(2, 10) @@ -366,7 +339,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 11), new Position(2, 17) @@ -374,7 +346,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 13), new Position(2, 15) @@ -386,7 +357,6 @@ enum Weekday { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 4), new Position(3, 19) @@ -394,7 +364,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 4), new Position(3, 12) @@ -404,7 +373,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 13), new Position(3, 19) @@ -412,7 +380,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 15), new Position(3, 17) @@ -424,7 +391,6 @@ enum Weekday { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 4), new Position(4, 18) @@ -432,7 +398,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 4), new Position(4, 11) @@ -442,7 +407,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 12), new Position(4, 18) @@ -450,7 +414,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 14), new Position(4, 16) @@ -462,7 +425,6 @@ enum Weekday { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 4), new Position(5, 16) @@ -470,7 +432,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 4), new Position(5, 9) @@ -480,7 +441,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 10), new Position(5, 16) @@ -488,7 +448,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 12), new Position(5, 14) @@ -500,7 +459,6 @@ enum Weekday { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 4), new Position(6, 18) @@ -508,7 +466,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 4), new Position(6, 11) @@ -518,7 +475,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 12), new Position(6, 18) @@ -526,7 +482,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 14), new Position(6, 16) @@ -538,7 +493,6 @@ enum Weekday { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 4), new Position(7, 16) @@ -546,7 +500,6 @@ enum Weekday { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 4), new Position(7, 9) @@ -556,7 +509,6 @@ enum Weekday { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 10), new Position(7, 16) @@ -564,7 +516,6 @@ enum Weekday { ), value: new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 12), new Position(7, 14) @@ -593,7 +544,6 @@ public function oneBinaryIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 22) @@ -601,7 +551,6 @@ public function oneBinaryIntegerValueMember(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -612,7 +561,6 @@ public function oneBinaryIntegerValueMember(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 20) @@ -620,7 +568,6 @@ public function oneBinaryIntegerValueMember(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -630,7 +577,6 @@ public function oneBinaryIntegerValueMember(): void ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 14), new Position(0, 20) @@ -638,7 +584,6 @@ public function oneBinaryIntegerValueMember(): void ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 15), new Position(0, 19) @@ -668,7 +613,6 @@ public function oneOctalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 22) @@ -676,7 +620,6 @@ public function oneOctalIntegerValueMember(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -687,7 +630,6 @@ public function oneOctalIntegerValueMember(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 20) @@ -695,7 +637,6 @@ public function oneOctalIntegerValueMember(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -705,7 +646,6 @@ public function oneOctalIntegerValueMember(): void ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 14), new Position(0, 20) @@ -713,7 +653,6 @@ public function oneOctalIntegerValueMember(): void ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 15), new Position(0, 19) @@ -743,7 +682,6 @@ public function oneDecimalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 19) @@ -751,7 +689,6 @@ public function oneDecimalIntegerValueMember(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -762,7 +699,6 @@ public function oneDecimalIntegerValueMember(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 17) @@ -770,7 +706,6 @@ public function oneDecimalIntegerValueMember(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -780,7 +715,6 @@ public function oneDecimalIntegerValueMember(): void ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 14), new Position(0, 17) @@ -788,7 +722,6 @@ public function oneDecimalIntegerValueMember(): void ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 15), new Position(0, 16) @@ -818,7 +751,6 @@ public function oneHexadecimalIntegerValueMember(): void $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 22) @@ -826,7 +758,6 @@ public function oneHexadecimalIntegerValueMember(): void ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 7) @@ -837,7 +768,6 @@ public function oneHexadecimalIntegerValueMember(): void members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 20) @@ -845,7 +775,6 @@ public function oneHexadecimalIntegerValueMember(): void ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) @@ -855,7 +784,6 @@ public function oneHexadecimalIntegerValueMember(): void ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 14), new Position(0, 20) @@ -863,7 +791,6 @@ public function oneHexadecimalIntegerValueMember(): void ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 15), new Position(0, 19) @@ -909,7 +836,6 @@ enum Month { $expectedEnumDeclarationNode = new EnumDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(13, 0) @@ -917,7 +843,6 @@ enum Month { ), name: new EnumNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 5), new Position(0, 9) @@ -928,7 +853,6 @@ enum Month { members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 4), new Position(1, 13) @@ -936,7 +860,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 4), new Position(1, 10) @@ -946,7 +869,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 11), new Position(1, 13) @@ -954,7 +876,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(1, 12), new Position(1, 12) @@ -967,7 +888,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 4), new Position(2, 14) @@ -975,7 +895,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 4), new Position(2, 11) @@ -985,7 +904,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 12), new Position(2, 14) @@ -993,7 +911,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(2, 13), new Position(2, 13) @@ -1006,7 +923,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 4), new Position(3, 11) @@ -1014,7 +930,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 4), new Position(3, 8) @@ -1024,7 +939,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 9), new Position(3, 11) @@ -1032,7 +946,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(3, 10), new Position(3, 10) @@ -1045,7 +958,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 4), new Position(4, 11) @@ -1053,7 +965,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 4), new Position(4, 8) @@ -1063,7 +974,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 9), new Position(4, 11) @@ -1071,7 +981,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(4, 10), new Position(4, 10) @@ -1084,7 +993,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 4), new Position(5, 9) @@ -1092,7 +1000,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 4), new Position(5, 6) @@ -1102,7 +1009,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 7), new Position(5, 9) @@ -1110,7 +1016,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(5, 8), new Position(5, 8) @@ -1123,7 +1028,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 4), new Position(6, 10) @@ -1131,7 +1035,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 4), new Position(6, 7) @@ -1141,7 +1044,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 8), new Position(6, 10) @@ -1149,7 +1051,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(6, 9), new Position(6, 9) @@ -1162,7 +1063,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 4), new Position(7, 10) @@ -1170,7 +1070,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 4), new Position(7, 7) @@ -1180,7 +1079,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 8), new Position(7, 10) @@ -1188,7 +1086,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(7, 9), new Position(7, 9) @@ -1201,7 +1098,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(8, 4), new Position(8, 12) @@ -1209,7 +1105,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(8, 4), new Position(8, 9) @@ -1219,7 +1114,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(8, 10), new Position(8, 12) @@ -1227,7 +1121,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(8, 11), new Position(8, 11) @@ -1240,7 +1133,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(9, 4), new Position(9, 15) @@ -1248,7 +1140,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(9, 4), new Position(9, 12) @@ -1258,7 +1149,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(9, 13), new Position(9, 15) @@ -1266,7 +1156,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(9, 14), new Position(9, 14) @@ -1279,7 +1168,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(10, 4), new Position(10, 14) @@ -1287,7 +1175,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(10, 4), new Position(10, 10) @@ -1297,7 +1184,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(10, 11), new Position(10, 14) @@ -1305,7 +1191,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(10, 12), new Position(10, 13) @@ -1318,7 +1203,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(11, 4), new Position(11, 15) @@ -1326,7 +1210,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(11, 4), new Position(11, 11) @@ -1336,7 +1219,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(11, 12), new Position(11, 15) @@ -1344,7 +1226,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(11, 13), new Position(11, 14) @@ -1357,7 +1238,6 @@ enum Month { ), new EnumMemberDeclarationNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(12, 4), new Position(12, 15) @@ -1365,7 +1245,6 @@ enum Month { ), name: new EnumMemberNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(12, 4), new Position(12, 11) @@ -1375,7 +1254,6 @@ enum Month { ), value: new EnumMemberValueNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(12, 12), new Position(12, 15) @@ -1383,7 +1261,6 @@ enum Month { ), value: new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(12, 13), new Position(12, 14) diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index b618c4ef..c01a87a0 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -27,7 +27,6 @@ use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; @@ -45,7 +44,6 @@ public function binaryInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 11) @@ -71,7 +69,6 @@ public function octalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 4) @@ -97,7 +94,6 @@ public function decimalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 9) @@ -123,7 +119,6 @@ public function hexadecimalInteger(): void $expectedIntegerLiteralNode = new IntegerLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 16) diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 1a696bcc..2d90535c 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -26,7 +26,6 @@ use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; @@ -44,7 +43,6 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void $expectedNullLiteralNode = new NullLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 3) diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 2be362b8..2d88c6c1 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -26,7 +26,6 @@ use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; @@ -44,7 +43,6 @@ public function producesStringLiteralNodeForLiteralString(): void $expectedStringLiteralNode = new StringLiteralNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 1), new Position(0, 11) diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index c8b8a0aa..88fea008 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -33,7 +33,6 @@ use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceCouldNotBeParsed; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Path; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; @@ -51,7 +50,6 @@ public function producesAstNodeForSimpleTypeReference(): void $expectedTypeReferenceNode = new TypeReferenceNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 2) @@ -60,7 +58,6 @@ public function producesAstNodeForSimpleTypeReference(): void names: new TypeNameNodes( new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 2) @@ -89,7 +86,6 @@ public function producesAstNodeForArrayTypeReference(): void $expectedTypeReferenceNode = new TypeReferenceNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 4) @@ -98,7 +94,6 @@ public function producesAstNodeForArrayTypeReference(): void names: new TypeNameNodes( new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 2) @@ -127,7 +122,6 @@ public function producesAstNodeForOptionalTypeReference(): void $expectedTypeReferenceNode = new TypeReferenceNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 3) @@ -136,7 +130,6 @@ public function producesAstNodeForOptionalTypeReference(): void names: new TypeNameNodes( new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 1), new Position(0, 3) @@ -165,7 +158,6 @@ public function producesAstNodeForUnionTypeReference(): void $expectedTypeReferenceNode = new TypeReferenceNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 10) @@ -174,7 +166,6 @@ public function producesAstNodeForUnionTypeReference(): void names: new TypeNameNodes( new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 2) @@ -184,7 +175,6 @@ public function producesAstNodeForUnionTypeReference(): void ), new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 4), new Position(0, 6) @@ -194,7 +184,6 @@ public function producesAstNodeForUnionTypeReference(): void ), new TypeNameNode( attributes: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 8), new Position(0, 10) @@ -228,7 +217,6 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void cause: InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( affectedTypeNames: new TypeNames(TypeName::from('Foo')), attributesOfAffectedNode: new NodeAttributes( - pathToSource: Path::fromString(':memory:'), rangeInSource: Range::from( new Position(0, 0), new Position(0, 4) From 2e86dca0ee92ef9411223210ff888751b27e136b Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 31 Jul 2023 21:42:34 +0200 Subject: [PATCH 35/64] TASK: Let ParserException carry only the affected range in source ...rather than the entire affected token. --- src/Language/Parser/ParserException.php | 6 +++--- .../TypeReferenceCouldNotBeParsed.php | 6 +++--- .../Parser/TypeReference/TypeReferenceParser.php | 14 ++++++++------ .../TypeReference/TypeReferenceParserTest.php | 6 ++++-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Language/Parser/ParserException.php b/src/Language/Parser/ParserException.php index c6242ac7..4ecba210 100644 --- a/src/Language/Parser/ParserException.php +++ b/src/Language/Parser/ParserException.php @@ -22,19 +22,19 @@ namespace PackageFactory\ComponentEngine\Language\Parser; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Source\Range; abstract class ParserException extends \Exception { protected function __construct( int $code, string $message, - public readonly Token $affectedToken, + public readonly Range $affectedRangeInSource, ?\Exception $cause = null ) { $message = sprintf( '[%s] %s', - $affectedToken->boundaries->start->toDebugString(), + $affectedRangeInSource->start->toDebugString(), $message ); diff --git a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php index a937e6cb..9b396bba 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php +++ b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php @@ -24,13 +24,13 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\ParserException; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TypeReferenceCouldNotBeParsed extends ParserException { public static function becauseOfInvalidTypeReferenceNode( InvalidTypeReferenceNode $cause, - Token $affectedToken + Range $affectedRangeInSource ): self { return new self( code: 1690542466, @@ -38,7 +38,7 @@ public static function becauseOfInvalidTypeReferenceNode( 'TypeReferenceNode could not be parsed, because the result would be invalid: %s', $cause->getMessage() ), - affectedToken: $affectedToken, + affectedRangeInSource: $affectedRangeInSource, cause: $cause ); } diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index e89cfcd1..99f0303a 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -50,14 +50,16 @@ public function parse(\Iterator $tokens): TypeReferenceNode $closingArrayToken = $this->extractClosingArrayToken($tokens); $isArray = !is_null($closingArrayToken); + $rangeInSource = Range::from( + $startingToken->boundaries->start, + $closingArrayToken?->boundaries->end + ?? $typeNameNodes->getLast()->attributes->rangeInSource->end + ); + try { return new TypeReferenceNode( attributes: new NodeAttributes( - rangeInSource: Range::from( - $startingToken->boundaries->start, - $closingArrayToken?->boundaries->end - ?? $typeNameNodes->getLast()->attributes->rangeInSource->end - ) + rangeInSource: $rangeInSource ), names: $typeNameNodes, isArray: $isArray, @@ -66,7 +68,7 @@ public function parse(\Iterator $tokens): TypeReferenceNode } catch (InvalidTypeReferenceNode $e) { throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( cause: $e, - affectedToken: $startingToken + affectedRangeInSource: $rangeInSource ); } } diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index 88fea008..8cb64784 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -209,7 +209,6 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void { $typeReferenceParser = new TypeReferenceParser(); $tokens = Tokenizer::fromSource(Source::fromString('?Foo[]'))->getIterator(); - $startingToken = $tokens->current(); $this->expectException(ParserException::class); $this->expectExceptionObject( @@ -223,7 +222,10 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void ) ), ), - affectedToken: $startingToken + affectedRangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) + ) ) ); From 2ab3f7253e58b4a9e50955897fa7a7232a276440 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 31 Jul 2023 22:10:00 +0200 Subject: [PATCH 36/64] TASK: Refactor TypeReferenceParser --- src/Language/Parser/ParserException.php | 8 +-- .../TypeReferenceCouldNotBeParsed.php | 21 ++++++-- .../TypeReference/TypeReferenceParser.php | 51 +++++++++++-------- .../TypeReference/TypeReferenceParserTest.php | 33 ++++++++++-- 4 files changed, 76 insertions(+), 37 deletions(-) diff --git a/src/Language/Parser/ParserException.php b/src/Language/Parser/ParserException.php index 4ecba210..d98f0cb0 100644 --- a/src/Language/Parser/ParserException.php +++ b/src/Language/Parser/ParserException.php @@ -29,15 +29,9 @@ abstract class ParserException extends \Exception protected function __construct( int $code, string $message, - public readonly Range $affectedRangeInSource, + public readonly ?Range $affectedRangeInSource = null, ?\Exception $cause = null ) { - $message = sprintf( - '[%s] %s', - $affectedRangeInSource->start->toDebugString(), - $message - ); - parent::__construct($message, $code, $cause); } } diff --git a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php index 9b396bba..84cc8d2f 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php +++ b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php @@ -22,15 +22,14 @@ namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\ParserException; -use PackageFactory\ComponentEngine\Parser\Source\Range; final class TypeReferenceCouldNotBeParsed extends ParserException { public static function becauseOfInvalidTypeReferenceNode( - InvalidTypeReferenceNode $cause, - Range $affectedRangeInSource + InvalidTypeReferenceNode $cause ): self { return new self( code: 1690542466, @@ -38,7 +37,21 @@ public static function becauseOfInvalidTypeReferenceNode( 'TypeReferenceNode could not be parsed, because the result would be invalid: %s', $cause->getMessage() ), - affectedRangeInSource: $affectedRangeInSource, + affectedRangeInSource: $cause->attributesOfAffectedNode?->rangeInSource ?? null, + cause: $cause + ); + } + + public static function becauseOfInvalidTypeTypeNameNodes( + InvalidTypeNameNodes $cause + ): self { + return new self( + code: 1690833898, + message: sprintf( + 'TypeReferenceNode could not be parsed, because the list of type names was invalid: %s', + $cause->getMessage() + ), + affectedRangeInSource: $cause->attributesOfAffectedNode?->rangeInSource ?? null, cause: $cause ); } diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index 99f0303a..a0f3bf4d 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; @@ -66,10 +67,7 @@ public function parse(\Iterator $tokens): TypeReferenceNode isOptional: $isOptional ); } catch (InvalidTypeReferenceNode $e) { - throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( - cause: $e, - affectedRangeInSource: $rangeInSource - ); + throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode($e); } } @@ -97,31 +95,40 @@ public function parseTypeNames(\Iterator $tokens): TypeNameNodes { $items = []; while (true) { - Scanner::assertType($tokens, TokenType::STRING); - - $typeNameToken = $tokens->current(); - $items[] = new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: $typeNameToken->boundaries - ), - value: TypeName::from($typeNameToken->value) - ); + $items[] = $this->parseTypeName($tokens); - Scanner::skipOne($tokens); - - if (Scanner::isEnd($tokens)) { + if (Scanner::isEnd($tokens) || Scanner::type($tokens) !== TokenType::PIPE) { break; } - if (Scanner::type($tokens) === TokenType::PIPE) { - Scanner::skipOne($tokens); - continue; - } + Scanner::skipOne($tokens); + } - break; + try { + return new TypeNameNodes(...$items); + } catch (InvalidTypeNameNodes $e) { + throw TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeTypeNameNodes($e); } + } + + /** + * @param \Iterator $tokens + * @return TypeNameNode + */ + public function parseTypeName(\Iterator $tokens): TypeNameNode + { + Scanner::assertType($tokens, TokenType::STRING); + + $typeNameToken = $tokens->current(); - return new TypeNameNodes(...$items); + Scanner::skipOne($tokens); + + return new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: $typeNameToken->boundaries + ), + value: TypeName::from($typeNameToken->value) + ); } /** diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index 8cb64784..b4aa1db7 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; @@ -221,10 +222,34 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void new Position(0, 4) ) ), - ), - affectedRangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) + ) + ) + ); + + $typeReferenceParser->parse($tokens); + } + + /** + * @test + */ + public function throwsParserExceptionWhenDuplicatesOccur(): void + { + $typeReferenceParser = new TypeReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Foo|Bar|Foo|Baz'))->getIterator(); + + $this->expectException(ParserException::class); + $this->expectExceptionObject( + TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeTypeNameNodes( + cause: InvalidTypeNameNodes::becauseTheyContainDuplicates( + duplicateTypeNameNode: new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 9), + new Position(0, 11) + ) + ), + value: TypeName::from('Foo') + ) ) ) ); From 8c85541f8744cb70e1891f3291bb896aa20bcd56 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 31 Jul 2023 22:42:54 +0200 Subject: [PATCH 37/64] TASK: Implement PropertyDeclarationParser --- src/Domain/PropertyName/PropertyName.php | 36 +++ .../PropertyDeclarationNode.php | 37 +++ .../PropertyDeclaration/PropertyNameNode.php | 36 +++ .../PropertyDeclarationParser.php | 78 +++++ .../PropertyDeclarationParserTest.php | 271 ++++++++++++++++++ 5 files changed, 458 insertions(+) create mode 100644 src/Domain/PropertyName/PropertyName.php create mode 100644 src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php create mode 100644 src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php create mode 100644 src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php create mode 100644 test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php diff --git a/src/Domain/PropertyName/PropertyName.php b/src/Domain/PropertyName/PropertyName.php new file mode 100644 index 00000000..1aeef046 --- /dev/null +++ b/src/Domain/PropertyName/PropertyName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\PropertyName; + +final class PropertyName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php b/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php new file mode 100644 index 00000000..70edbf8f --- /dev/null +++ b/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class PropertyDeclarationNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly PropertyNameNode $name, + public readonly TypeReferenceNode $type + ) { + } +} diff --git a/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php b/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php new file mode 100644 index 00000000..5bc7e7ad --- /dev/null +++ b/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class PropertyNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly PropertyName $value + ) { + } +} diff --git a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php new file mode 100644 index 00000000..5699ba35 --- /dev/null +++ b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php @@ -0,0 +1,78 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class PropertyDeclarationParser +{ + private readonly TypeReferenceParser $typeReferenceParser; + + public function __construct() + { + $this->typeReferenceParser = new TypeReferenceParser(); + } + + /** + * @param \Iterator $tokens + * @return PropertyDeclarationNode + */ + public function parse(\Iterator $tokens): PropertyDeclarationNode + { + Scanner::assertType($tokens, TokenType::STRING); + $propertyNameToken = $tokens->current(); + + Scanner::skipOne($tokens); + + Scanner::assertType($tokens, TokenType::COLON); + Scanner::skipOne($tokens); + + Scanner::skipSpace($tokens); + + $typeReferenceNode = $this->typeReferenceParser->parse($tokens); + + return new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + $propertyNameToken->boundaries->start, + $typeReferenceNode->attributes->rangeInSource->end + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: $propertyNameToken->boundaries + ), + value: PropertyName::from($propertyNameToken->value) + ), + type: $typeReferenceNode + ); + } +} diff --git a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php new file mode 100644 index 00000000..8180d821 --- /dev/null +++ b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php @@ -0,0 +1,271 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\PropertyDeclaration; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration\PropertyDeclarationParser; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class PropertyDeclarationParserTest extends TestCase +{ + /** + * @test + */ + public function parsesPropertyDeclarationWithSimpleType(): void + { + $propertyDeclarationParser = new PropertyDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar'))->getIterator(); + + $expectedPropertyDeclarationNode = new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 7) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: PropertyName::from('foo') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: TypeName::from('Bar') + ) + ), + isArray: false, + isOptional: false + ) + ); + + $this->assertEquals( + $expectedPropertyDeclarationNode, + $propertyDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesPropertyDeclarationWithOptionalType(): void + { + $propertyDeclarationParser = new PropertyDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('foo: ?Bar'))->getIterator(); + + $expectedPropertyDeclarationNode = new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 8) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: PropertyName::from('foo') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 8) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 6), + new Position(0, 8) + ) + ), + value: TypeName::from('Bar') + ) + ), + isArray: false, + isOptional: true + ) + ); + + $this->assertEquals( + $expectedPropertyDeclarationNode, + $propertyDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesPropertyDeclarationWithArrayType(): void + { + $propertyDeclarationParser = new PropertyDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar[]'))->getIterator(); + + $expectedPropertyDeclarationNode = new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 9) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: PropertyName::from('foo') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 9) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: TypeName::from('Bar') + ) + ), + isArray: true, + isOptional: false + ) + ); + + $this->assertEquals( + $expectedPropertyDeclarationNode, + $propertyDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesPropertyDeclarationWithUnionType(): void + { + $propertyDeclarationParser = new PropertyDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar|Baz|Qux'))->getIterator(); + + $expectedPropertyDeclarationNode = new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 15) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + value: PropertyName::from('foo') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 15) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: TypeName::from('Bar') + ), + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 9), + new Position(0, 11) + ) + ), + value: TypeName::from('Baz') + ), + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 15) + ) + ), + value: TypeName::from('Qux') + ) + ), + isArray: false, + isOptional: false + ) + ); + + $this->assertEquals( + $expectedPropertyDeclarationNode, + $propertyDeclarationParser->parse($tokens) + ); + } +} From 93dea796c7aaf969d7e5d67794cd0982a7976840 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 1 Aug 2023 11:58:17 +0200 Subject: [PATCH 38/64] TASK: Implement StructDeclarationParser --- src/Domain/StructName/StructName.php | 36 + .../PropertyDeclarationNodes.php | 41 ++ .../StructDeclarationNode.php | 37 + .../Node/StructDeclaration/StructNameNode.php | 36 + .../StructDeclarationParser.php | 146 ++++ .../StructDeclarationParserTest.php | 675 ++++++++++++++++++ 6 files changed, 971 insertions(+) create mode 100644 src/Domain/StructName/StructName.php create mode 100644 src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNodes.php create mode 100644 src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php create mode 100644 src/Language/AST/Node/StructDeclaration/StructNameNode.php create mode 100644 src/Language/Parser/StructDeclaration/StructDeclarationParser.php create mode 100644 test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php diff --git a/src/Domain/StructName/StructName.php b/src/Domain/StructName/StructName.php new file mode 100644 index 00000000..be02d2cb --- /dev/null +++ b/src/Domain/StructName/StructName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\StructName; + +final class StructName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNodes.php b/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNodes.php new file mode 100644 index 00000000..23579520 --- /dev/null +++ b/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNodes.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration; + +final class PropertyDeclarationNodes +{ + /** + * @var array + */ + public readonly array $items; + + public function __construct(PropertyDeclarationNode ...$items) + { + $itemsAsHashMap = []; + foreach ($items as $item) { + $itemsAsHashMap[$item->name->value->value] = $item; + } + + $this->items = $itemsAsHashMap; + } +} diff --git a/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php b/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php new file mode 100644 index 00000000..996e84dd --- /dev/null +++ b/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class StructDeclarationNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly StructNameNode $name, + public readonly PropertyDeclarationNodes $properties + ) { + } +} diff --git a/src/Language/AST/Node/StructDeclaration/StructNameNode.php b/src/Language/AST/Node/StructDeclaration/StructNameNode.php new file mode 100644 index 00000000..69a3bf97 --- /dev/null +++ b/src/Language/AST/Node/StructDeclaration/StructNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration; + +use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class StructNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly StructName $value + ) { + } +} diff --git a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php new file mode 100644 index 00000000..73461ed2 --- /dev/null +++ b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php @@ -0,0 +1,146 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\StructDeclaration; + +use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructNameNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration\PropertyDeclarationParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class StructDeclarationParser +{ + private readonly PropertyDeclarationParser $propertyDeclarationParser; + + public function __construct() + { + $this->propertyDeclarationParser = new PropertyDeclarationParser(); + } + + /** + * @param \Iterator $tokens + * @return StructDeclarationNode + */ + public function parse(\Iterator $tokens): StructDeclarationNode + { + $structKeywordToken = $this->extractStructKeywordToken($tokens); + $structNameNode = $this->parseStructName($tokens); + $this->skipOpeningBracketToken($tokens); + $propertyDeclarationNodes = $this->parsePropertyDeclarations($tokens); + $closingBracketToken = $this->extractClosingBracketToken($tokens); + + return new StructDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + $structKeywordToken->boundaries->start, + $closingBracketToken->boundaries->end + ) + ), + name: $structNameNode, + properties: $propertyDeclarationNodes + ); + } + + /** + * @param \Iterator $tokens + * @return Token + */ + public function extractStructKeywordToken(\Iterator $tokens): Token + { + Scanner::assertType($tokens, TokenType::KEYWORD_STRUCT); + + $structKeywordToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $structKeywordToken; + } + + /** + * @param \Iterator $tokens + * @return StructNameNode + */ + public function parseStructName(\Iterator $tokens): StructNameNode + { + Scanner::assertType($tokens, TokenType::STRING); + + $structNameToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + return new StructNameNode( + attributes: new NodeAttributes( + rangeInSource: $structNameToken->boundaries + ), + value: StructName::from($structNameToken->value) + ); + } + + /** + * @param \Iterator $tokens + * @return void + */ + public function skipOpeningBracketToken(\Iterator $tokens): void + { + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + /** + * @param \Iterator $tokens + * @return PropertyDeclarationNodes + */ + public function parsePropertyDeclarations(\Iterator $tokens): PropertyDeclarationNodes + { + $items = []; + while (Scanner::type($tokens) === TokenType::STRING) { + $items[] = $this->propertyDeclarationParser->parse($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + return new PropertyDeclarationNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return Token + */ + public function extractClosingBracketToken(\Iterator $tokens): Token + { + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + + $closingBracketToken = $tokens->current(); + + Scanner::skipOne($tokens); + + return $closingBracketToken; + } +} diff --git a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php new file mode 100644 index 00000000..05c72570 --- /dev/null +++ b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php @@ -0,0 +1,675 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\StructDeclaration; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\StructDeclaration\StructDeclarationParser; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class StructDeclarationParserTest extends TestCase +{ + /** + * @test + */ + public function parsesStructDeclarationOnSingleLineWithOneProperty(): void + { + $structDeclarationParser = new StructDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('struct Foo { bar: Baz }'))->getIterator(); + + $expectedStructDeclarationNode = new StructDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) + ) + ), + name: new StructNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: StructName::from('Foo') + ), + properties: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 20) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 15) + ) + ), + value: PropertyName::from('bar') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) + ) + ), + value: TypeName::from('Baz') + ) + ), + isArray: false, + isOptional: false + ) + ) + ) + ); + + $this->assertEquals( + $expectedStructDeclarationNode, + $structDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): void + { + $structDeclarationParser = new StructDeclarationParser(); + $tokens = Tokenizer::fromSource(Source::fromString('struct Foo { bar: Baz qux: Quux corge: Grault }'))->getIterator(); + + $expectedStructDeclarationNode = new StructDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 46) + ) + ), + name: new StructNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: StructName::from('Foo') + ), + properties: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 20) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 15) + ) + ), + value: PropertyName::from('bar') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) + ) + ), + value: TypeName::from('Baz') + ) + ), + isArray: false, + isOptional: false + ) + ), + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 22), + new Position(0, 30) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 22), + new Position(0, 24) + ) + ), + value: PropertyName::from('qux') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 30) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 30) + ) + ), + value: TypeName::from('Quux') + ) + ), + isArray: false, + isOptional: false + ) + ), + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 32), + new Position(0, 44) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 32), + new Position(0, 36) + ) + ), + value: PropertyName::from('corge') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 39), + new Position(0, 44) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 39), + new Position(0, 44) + ) + ), + value: TypeName::from('Grault') + ) + ), + isArray: false, + isOptional: false + ) + ) + ) + ); + + $this->assertEquals( + $expectedStructDeclarationNode, + $structDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesStructDeclarationOnMultipleLinesWithMultipleProperties(): void + { + $structDeclarationParser = new StructDeclarationParser(); + $structAsString = <<getIterator(); + + $expectedStructDeclarationNode = new StructDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(3, 0) + ) + ), + name: new StructNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 10) + ) + ), + value: StructName::from('Link') + ), + properties: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 15) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 7) + ) + ), + value: PropertyName::from('href') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 10), + new Position(1, 15) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 10), + new Position(1, 15) + ) + ), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: false + ) + ), + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 17) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 9) + ) + ), + value: PropertyName::from('target') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 12), + new Position(2, 17) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 12), + new Position(2, 17) + ) + ), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: false + ) + ) + ) + ); + + $this->assertEquals( + $expectedStructDeclarationNode, + $structDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesStructDeclarationOnMultipleLinesWithMultiplePropertiesAndSpaceAndComments(): void + { + $structDeclarationParser = new StructDeclarationParser(); + $structAsString = <<getIterator(); + + $expectedStructDeclarationNode = new StructDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(8, 0) + ) + ), + name: new StructNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 10) + ) + ), + value: StructName::from('Link') + ), + properties: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 15) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 7) + ) + ), + value: PropertyName::from('href') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 10), + new Position(3, 15) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 10), + new Position(3, 15) + ) + ), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: false + ) + ), + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 17) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 9) + ) + ), + value: PropertyName::from('target') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(6, 12), + new Position(6, 17) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(6, 12), + new Position(6, 17) + ) + ), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: false + ) + ) + ) + ); + + $this->assertEquals( + $expectedStructDeclarationNode, + $structDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionProperties(): void + { + $structDeclarationParser = new StructDeclarationParser(); + $structAsString = <<getIterator(); + + $expectedStructDeclarationNode = new StructDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(4, 0) + ) + ), + name: new StructNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 13) + ) + ), + value: StructName::from('Picture') + ), + properties: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 16) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 6) + ) + ), + value: PropertyName::from('src') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 9), + new Position(1, 16) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(1, 9), + new Position(1, 14) + ) + ), + value: TypeName::from('string') + ) + ), + isArray: true, + isOptional: false + ) + ), + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 39) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 14) + ) + ), + value: PropertyName::from('description') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 17), + new Position(2, 39) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 17), + new Position(2, 22) + ) + ), + value: TypeName::from('string') + ), + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 24), + new Position(2, 27) + ) + ), + value: TypeName::from('slot') + ), + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 29), + new Position(2, 39) + ) + ), + value: TypeName::from('Description') + ) + ), + isArray: false, + isOptional: false + ) + ), + new PropertyDeclarationNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 17) + ) + ), + name: new PropertyNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 8) + ) + ), + value: PropertyName::from('title') + ), + type: new TypeReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 11), + new Position(3, 17) + ) + ), + names: new TypeNameNodes( + new TypeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 12), + new Position(3, 17) + ) + ), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: true + ) + ), + ) + ); + + $this->assertEquals( + $expectedStructDeclarationNode, + $structDeclarationParser->parse($tokens) + ); + } +} From 2f5a0a1be8a34e5220d0c8de04a2ff2e8f6a08f0 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 1 Aug 2023 23:03:19 +0200 Subject: [PATCH 39/64] TASK: Implement TextParser --- src/Language/AST/Node/Text/TextNode.php | 35 +++ src/Language/Parser/Text/TextParser.php | 96 +++++++ src/Parser/Tokenizer/Tokenizer.php | 4 + .../Language/Parser/Text/TextParserTest.php | 261 ++++++++++++++++++ test/Unit/Parser/Tokenizer/TokenizerTest.php | 71 +++++ 5 files changed, 467 insertions(+) create mode 100644 src/Language/AST/Node/Text/TextNode.php create mode 100644 src/Language/Parser/Text/TextParser.php create mode 100644 test/Unit/Language/Parser/Text/TextParserTest.php create mode 100644 test/Unit/Parser/Tokenizer/TokenizerTest.php diff --git a/src/Language/AST/Node/Text/TextNode.php b/src/Language/AST/Node/Text/TextNode.php new file mode 100644 index 00000000..bb57f426 --- /dev/null +++ b/src/Language/AST/Node/Text/TextNode.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Text; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TextNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly string $value + ) { + } +} diff --git a/src/Language/Parser/Text/TextParser.php b/src/Language/Parser/Text/TextParser.php new file mode 100644 index 00000000..8ca2525d --- /dev/null +++ b/src/Language/Parser/Text/TextParser.php @@ -0,0 +1,96 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Text; + +use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class TextParser +{ + /** + * @param \Iterator $tokens + * @param boolean $preserveLeadingSpace + * @return null|TextNode + */ + public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?TextNode + { + $value = ''; + $startingToken = null; + $finalToken = null; + $ignoreSpace = false; + $keepTrailingSpace = false; + while (!Scanner::isEnd($tokens)) { + $startingToken ??= $tokens->current(); + switch (Scanner::type($tokens)) { + case TokenType::BRACKET_CURLY_OPEN: + case TokenType::TAG_START_OPENING: + $keepTrailingSpace = true; + break 2; + case TokenType::TAG_START_CLOSING: + $value = rtrim($value); + break 2; + case TokenType::SPACE: + case TokenType::END_OF_LINE: + if (!$ignoreSpace) { + $value .= ' '; + } + $ignoreSpace = true; + $finalToken = $tokens->current(); + Scanner::skipOne($tokens); + break; + default: + $value .= Scanner::value($tokens); + $ignoreSpace = false; + $finalToken = $tokens->current(); + Scanner::skipOne($tokens); + break; + } + } + + if (is_null($startingToken) || is_null($finalToken)) { + return null; + } + + if (!$keepTrailingSpace) { + $value = $preserveLeadingSpace ? rtrim($value) : trim($value); + } + + if ($value === '' || $value === ' ') { + return null; + } + + return new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + $startingToken->boundaries->start, + $finalToken->boundaries->end + ) + ), + value: $value + ); + } +} diff --git a/src/Parser/Tokenizer/Tokenizer.php b/src/Parser/Tokenizer/Tokenizer.php index dc3008ce..c670e207 100644 --- a/src/Parser/Tokenizer/Tokenizer.php +++ b/src/Parser/Tokenizer/Tokenizer.php @@ -56,6 +56,10 @@ public function getIterator(): \Iterator */ private static function block(\Iterator $fragments): \Iterator { + if (!$fragments->valid()) { + return; + } + $bracket = TokenType::tryBracketOpenFromFragment($fragments->current()); $buffer = Buffer::empty(); diff --git a/test/Unit/Language/Parser/Text/TextParserTest.php b/test/Unit/Language/Parser/Text/TextParserTest.php new file mode 100644 index 00000000..91eec8c2 --- /dev/null +++ b/test/Unit/Language/Parser/Text/TextParserTest.php @@ -0,0 +1,261 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Text; + +use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\Parser\Text\TextParser; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class TextParserTest extends TestCase +{ + /** + * @test + */ + public function parsesEmptyStringToNull(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $this->assertNull( + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTextWithSpacesOnlyToNull(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" \t \n \t "))->getIterator(); + + $this->assertNull($textParser->parse($tokens)); + } + + /** + * @test + */ + public function parsesTrivialText(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Hello World'))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) + ) + ), + value: 'Hello World' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function trimsLeadingAndTrailingSpaces(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" \t\t Hello World \t\t "))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) + ) + ), + value: 'Hello World' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function preservesLeadingSpaceIfFlagIsSet(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" \t\t Hello World \t\t "))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) + ) + ), + value: ' Hello World' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens, true) + ); + } + + /** + * @test + */ + public function reducesInnerSpacesToSingleSpaceCharacterEach(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("Hello \t \n \t folks and\t\t\tpeople"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 22) + ) + ), + value: 'Hello folks and people' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function terminatesAtEmbeddedExpressionAndKeepsTrailingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t {foo}!"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 1) + ) + ), + value: 'Hello ' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function returnsNullAtEmbeddedExpressionIfTheresOnlySpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" \n\t {foo}!"))->getIterator(); + + $this->assertNull($textParser->parse($tokens)); + } + + /** + * @test + */ + public function terminatesAtOpeningTagAndKeepsTrailingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t World"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 1) + ) + ), + value: 'Hello ' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function returnsNullAtOpeningTagIfTheresOnlySpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" \n\t "))->getIterator(); + + $this->assertNull($textParser->parse($tokens)); + } + + /** + * @test + */ + public function terminatesAtClosingTagAndTrimsTrailingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("World \n\t "))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 1) + ) + ), + value: 'World' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function returnsNullAtClosingTagIfTheresOnlySpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" \n\t "))->getIterator(); + + $this->assertNull($textParser->parse($tokens)); + } +} diff --git a/test/Unit/Parser/Tokenizer/TokenizerTest.php b/test/Unit/Parser/Tokenizer/TokenizerTest.php new file mode 100644 index 00000000..9eeef8cc --- /dev/null +++ b/test/Unit/Parser/Tokenizer/TokenizerTest.php @@ -0,0 +1,71 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Parser\Tokenizer; + +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PHPUnit\Framework\TestCase; + +final class TokenizerTest extends TestCase +{ + /** + * @test + */ + public function tokenizesEmptySourceToEmptyIterator(): void + { + $source = Source::fromString(''); + $tokenizer = Tokenizer::fromSource($source); + $iterator = $tokenizer->getIterator(); + + $this->assertFalse($iterator->valid()); + } + + /** + * @test + */ + public function tokenizesOpeningTag(): void + { + $source = Source::fromString(''); + $tokenizer = Tokenizer::fromSource($source); + $tokens = \iterator_to_array($tokenizer->getIterator(), false); + + $this->assertEquals(TokenType::TAG_START_OPENING, $tokens[0]->type); + $this->assertEquals(TokenType::STRING, $tokens[1]->type); + $this->assertEquals(TokenType::TAG_END, $tokens[2]->type); + } + + /** + * @test + */ + public function tokenizesClosingTag(): void + { + $source = Source::fromString(''); + $tokenizer = Tokenizer::fromSource($source); + $tokens = \iterator_to_array($tokenizer->getIterator(), false); + + $this->assertEquals(TokenType::TAG_START_CLOSING, $tokens[0]->type); + $this->assertEquals(TokenType::STRING, $tokens[1]->type); + $this->assertEquals(TokenType::TAG_END, $tokens[2]->type); + } +} From f908a6d6ff583f665c59e29a2603df73b6b72c12 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 2 Aug 2023 11:44:13 +0200 Subject: [PATCH 40/64] TASK: Implement ValueReferenceParser --- src/Domain/VariableName/VariableName.php | 36 +++++++++++ .../ValueReference/ValueReferenceNode.php | 36 +++++++++++ .../ValueReference/ValueReferenceParser.php | 53 ++++++++++++++++ .../ValueReferenceParserTest.php | 60 +++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 src/Domain/VariableName/VariableName.php create mode 100644 src/Language/AST/Node/ValueReference/ValueReferenceNode.php create mode 100644 src/Language/Parser/ValueReference/ValueReferenceParser.php create mode 100644 test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php diff --git a/src/Domain/VariableName/VariableName.php b/src/Domain/VariableName/VariableName.php new file mode 100644 index 00000000..75592494 --- /dev/null +++ b/src/Domain/VariableName/VariableName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\VariableName; + +final class VariableName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/Node/ValueReference/ValueReferenceNode.php b/src/Language/AST/Node/ValueReference/ValueReferenceNode.php new file mode 100644 index 00000000..b93b76cf --- /dev/null +++ b/src/Language/AST/Node/ValueReference/ValueReferenceNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\ValueReference; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class ValueReferenceNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly VariableName $name + ) { + } +} diff --git a/src/Language/Parser/ValueReference/ValueReferenceParser.php b/src/Language/Parser/ValueReference/ValueReferenceParser.php new file mode 100644 index 00000000..0d9d3fb1 --- /dev/null +++ b/src/Language/Parser/ValueReference/ValueReferenceParser.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\ValueReference; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class ValueReferenceParser +{ + /** + * @param \Iterator $tokens + * @return ValueReferenceNode + */ + public function parse(\Iterator $tokens): ValueReferenceNode + { + Scanner::assertType($tokens, TokenType::STRING); + + $token = $tokens->current(); + + Scanner::skipOne($tokens); + + return new ValueReferenceNode( + attributes: new NodeAttributes( + rangeInSource: $token->boundaries + ), + name: VariableName::from($token->value) + ); + } +} diff --git a/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php b/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php new file mode 100644 index 00000000..13c6b0ec --- /dev/null +++ b/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php @@ -0,0 +1,60 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ValueReference; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\ValueReference\ValueReferenceParser; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class ValueReferenceParserTest extends TestCase +{ + /** + * @test + */ + public function parsesValueReference(): void + { + $valueReferenceParser = new ValueReferenceParser(); + $tokens = Tokenizer::fromSource(Source::fromString('foo'))->getIterator(); + + $expectedValueReferenceNode = new ValueReferenceNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) + ) + ), + name: VariableName::from('foo') + ); + + $this->assertEquals( + $expectedValueReferenceNode, + $valueReferenceParser->parse($tokens) + ); + } +} From a980d7d8a639bcb22df106e2532eeb37f8df1b10 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 2 Aug 2023 12:44:59 +0200 Subject: [PATCH 41/64] TASK: Add AST node objects for all remaining expression-related concepts Namely: - AccessChain - BinaryOperation - Expression - Match - Tag - TemplateLiteral - TernaryOperation - UnaryOperation --- src/Domain/AttributeName/AttributeName.php | 36 ++++++++++++++ src/Domain/TagName/TagName.php | 36 ++++++++++++++ .../AST/Node/AccessChain/AccessChainNode.php | 37 +++++++++++++++ .../AccessChain/AccessChainSegmentKeyNode.php | 36 ++++++++++++++ .../AccessChain/AccessChainSegmentNode.php | 36 ++++++++++++++ .../AccessChain/AccessChainSegmentNodes.php | 36 ++++++++++++++ .../AST/Node/AccessChain/AccessType.php | 29 ++++++++++++ .../BinaryOperation/BinaryOperationNode.php | 38 +++++++++++++++ .../Node/BinaryOperation/BinaryOperator.php | 36 ++++++++++++++ .../AST/Node/Expression/ExpressionNode.php | 47 +++++++++++++++++++ .../AST/Node/Expression/ExpressionNodes.php | 36 ++++++++++++++ src/Language/AST/Node/Match/MatchArmNode.php | 38 +++++++++++++++ src/Language/AST/Node/Match/MatchArmNodes.php | 36 ++++++++++++++ src/Language/AST/Node/Match/MatchNode.php | 37 +++++++++++++++ .../AST/Node/Tag/AttributeNameNode.php | 36 ++++++++++++++ src/Language/AST/Node/Tag/AttributeNode.php | 38 +++++++++++++++ src/Language/AST/Node/Tag/AttributeNodes.php | 41 ++++++++++++++++ src/Language/AST/Node/Tag/TagContentNode.php | 37 +++++++++++++++ src/Language/AST/Node/Tag/TagContentNodes.php | 36 ++++++++++++++ src/Language/AST/Node/Tag/TagNameNode.php | 36 ++++++++++++++ src/Language/AST/Node/Tag/TagNode.php | 38 +++++++++++++++ .../TemplateLiteral/TemplateLiteralNode.php | 43 +++++++++++++++++ .../TernaryOperation/TernaryOperationNode.php | 38 +++++++++++++++ .../UnaryOperation/UnaryOperationNode.php | 37 +++++++++++++++ .../AST/Node/UnaryOperation/UnaryOperator.php | 28 +++++++++++ 25 files changed, 922 insertions(+) create mode 100644 src/Domain/AttributeName/AttributeName.php create mode 100644 src/Domain/TagName/TagName.php create mode 100644 src/Language/AST/Node/AccessChain/AccessChainNode.php create mode 100644 src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php create mode 100644 src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php create mode 100644 src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php create mode 100644 src/Language/AST/Node/AccessChain/AccessType.php create mode 100644 src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php create mode 100644 src/Language/AST/Node/BinaryOperation/BinaryOperator.php create mode 100644 src/Language/AST/Node/Expression/ExpressionNode.php create mode 100644 src/Language/AST/Node/Expression/ExpressionNodes.php create mode 100644 src/Language/AST/Node/Match/MatchArmNode.php create mode 100644 src/Language/AST/Node/Match/MatchArmNodes.php create mode 100644 src/Language/AST/Node/Match/MatchNode.php create mode 100644 src/Language/AST/Node/Tag/AttributeNameNode.php create mode 100644 src/Language/AST/Node/Tag/AttributeNode.php create mode 100644 src/Language/AST/Node/Tag/AttributeNodes.php create mode 100644 src/Language/AST/Node/Tag/TagContentNode.php create mode 100644 src/Language/AST/Node/Tag/TagContentNodes.php create mode 100644 src/Language/AST/Node/Tag/TagNameNode.php create mode 100644 src/Language/AST/Node/Tag/TagNode.php create mode 100644 src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php create mode 100644 src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php create mode 100644 src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php create mode 100644 src/Language/AST/Node/UnaryOperation/UnaryOperator.php diff --git a/src/Domain/AttributeName/AttributeName.php b/src/Domain/AttributeName/AttributeName.php new file mode 100644 index 00000000..d85dba68 --- /dev/null +++ b/src/Domain/AttributeName/AttributeName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\AttributeName; + +final class AttributeName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Domain/TagName/TagName.php b/src/Domain/TagName/TagName.php new file mode 100644 index 00000000..137f01a6 --- /dev/null +++ b/src/Domain/TagName/TagName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\TagName; + +final class TagName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/Node/AccessChain/AccessChainNode.php b/src/Language/AST/Node/AccessChain/AccessChainNode.php new file mode 100644 index 00000000..bfc9ac94 --- /dev/null +++ b/src/Language/AST/Node/AccessChain/AccessChainNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class AccessChainNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly ExpressionNode $root, + public readonly AccessChainSegmentNodes $chain + ) { + } +} diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php b/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php new file mode 100644 index 00000000..a6d28be5 --- /dev/null +++ b/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class AccessChainSegmentKeyNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly PropertyName $value + ) { + } +} diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php b/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php new file mode 100644 index 00000000..4582484f --- /dev/null +++ b/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class AccessChainSegmentNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly AccessType $accessType, + public readonly AccessChainSegmentKeyNode $key + ) { + } +} diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php b/src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php new file mode 100644 index 00000000..4e172b67 --- /dev/null +++ b/src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; + +final class AccessChainSegmentNodes +{ + /** + * @var AccessChainSegmentNode[] + */ + public readonly array $items; + + public function __construct(AccessChainSegmentNode ...$items) + { + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/AccessChain/AccessType.php b/src/Language/AST/Node/AccessChain/AccessType.php new file mode 100644 index 00000000..10d95cda --- /dev/null +++ b/src/Language/AST/Node/AccessChain/AccessType.php @@ -0,0 +1,29 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; + +enum AccessType: string +{ + case MANDATORY = 'MANDATORY'; + case OPTIONAL = 'OPTIONAL'; +} diff --git a/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php b/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php new file mode 100644 index 00000000..2a03b706 --- /dev/null +++ b/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class BinaryOperationNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly ExpressionNode $leftOperand, + public readonly BinaryOperator $operator, + public readonly ExpressionNode $rightOperand + ) { + } +} diff --git a/src/Language/AST/Node/BinaryOperation/BinaryOperator.php b/src/Language/AST/Node/BinaryOperation/BinaryOperator.php new file mode 100644 index 00000000..128c2536 --- /dev/null +++ b/src/Language/AST/Node/BinaryOperation/BinaryOperator.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation; + +enum BinaryOperator: string +{ + case AND = 'AND'; + case OR = 'OR'; + + case EQUAL = 'EQUAL'; + case NOT_EQUAL = 'NOT_EQUAL'; + case GREATER_THAN = 'GREATER_THAN'; + case GREATER_THAN_OR_EQUAL = 'GREATER_THAN_OR_EQUAL'; + case LESS_THAN = 'LESS_THAN'; + case LESS_THAN_OR_EQUAL = 'LESS_THAN_OR_EQUAL'; +} diff --git a/src/Language/AST/Node/Expression/ExpressionNode.php b/src/Language/AST/Node/Expression/ExpressionNode.php new file mode 100644 index 00000000..316b82fd --- /dev/null +++ b/src/Language/AST/Node/Expression/ExpressionNode.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Expression; + +use PackageFactory\ComponentEngine\Language\AST\Node\AccessChain\AccessChainNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class ExpressionNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly AccessChainNode | BinaryOperationNode | BooleanLiteralNode | IntegerLiteralNode | MatchNode | NullLiteralNode | StringLiteralNode | TagNode | TemplateLiteralNode | TernaryOperationNode | UnaryOperationNode | ValueReferenceNode $root + ) { + } +} diff --git a/src/Language/AST/Node/Expression/ExpressionNodes.php b/src/Language/AST/Node/Expression/ExpressionNodes.php new file mode 100644 index 00000000..d6725791 --- /dev/null +++ b/src/Language/AST/Node/Expression/ExpressionNodes.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Expression; + +final class ExpressionNodes +{ + /** + * @var ExpressionNode[] + */ + public readonly array $items; + + public function __construct(ExpressionNode ...$items) + { + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/Match/MatchArmNode.php b/src/Language/AST/Node/Match/MatchArmNode.php new file mode 100644 index 00000000..26dbe261 --- /dev/null +++ b/src/Language/AST/Node/Match/MatchArmNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Match; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class MatchArmNode extends Node +{ + private function __construct( + public readonly NodeAttributes $attributes, + public readonly null | ExpressionNodes $left, + public readonly ExpressionNode $right + ) { + } +} diff --git a/src/Language/AST/Node/Match/MatchArmNodes.php b/src/Language/AST/Node/Match/MatchArmNodes.php new file mode 100644 index 00000000..c192a1fb --- /dev/null +++ b/src/Language/AST/Node/Match/MatchArmNodes.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Match; + +final class MatchArmNodes +{ + /** + * @var MatchArmNode[] + */ + public readonly array $items; + + public function __construct(MatchArmNode ...$items) + { + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/Match/MatchNode.php b/src/Language/AST/Node/Match/MatchNode.php new file mode 100644 index 00000000..fe677701 --- /dev/null +++ b/src/Language/AST/Node/Match/MatchNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Match; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class MatchNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly ExpressionNode $subject, + public readonly MatchArmNodes $arms + ) { + } +} diff --git a/src/Language/AST/Node/Tag/AttributeNameNode.php b/src/Language/AST/Node/Tag/AttributeNameNode.php new file mode 100644 index 00000000..d1f7748d --- /dev/null +++ b/src/Language/AST/Node/Tag/AttributeNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class AttributeNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly AttributeName $value + ) { + } +} diff --git a/src/Language/AST/Node/Tag/AttributeNode.php b/src/Language/AST/Node/Tag/AttributeNode.php new file mode 100644 index 00000000..b5ffc47b --- /dev/null +++ b/src/Language/AST/Node/Tag/AttributeNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class AttributeNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly AttributeNameNode $name, + public readonly null | ExpressionNode | StringLiteralNode $value + ) { + } +} diff --git a/src/Language/AST/Node/Tag/AttributeNodes.php b/src/Language/AST/Node/Tag/AttributeNodes.php new file mode 100644 index 00000000..25dbc166 --- /dev/null +++ b/src/Language/AST/Node/Tag/AttributeNodes.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +final class AttributeNodes +{ + /** + * @var array + */ + public readonly array $items; + + public function __construct(AttributeNode ...$items) + { + $itemsAsHashMap = []; + foreach ($items as $attribute) { + $itemsAsHashMap[$attribute->name->value->value] = $attribute; + } + + $this->items = $itemsAsHashMap; + } +} diff --git a/src/Language/AST/Node/Tag/TagContentNode.php b/src/Language/AST/Node/Tag/TagContentNode.php new file mode 100644 index 00000000..13b6f9e0 --- /dev/null +++ b/src/Language/AST/Node/Tag/TagContentNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TagContentNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly TextNode | ExpressionNode | TagNode $root + ) { + } +} diff --git a/src/Language/AST/Node/Tag/TagContentNodes.php b/src/Language/AST/Node/Tag/TagContentNodes.php new file mode 100644 index 00000000..b07168dc --- /dev/null +++ b/src/Language/AST/Node/Tag/TagContentNodes.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +final class TagContentNodes +{ + /** + * @var TagContentNode[] + */ + public readonly array $items; + + public function __construct(TagContentNode ...$items) + { + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/Tag/TagNameNode.php b/src/Language/AST/Node/Tag/TagNameNode.php new file mode 100644 index 00000000..ef221197 --- /dev/null +++ b/src/Language/AST/Node/Tag/TagNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TagNameNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly TagName $value + ) { + } +} diff --git a/src/Language/AST/Node/Tag/TagNode.php b/src/Language/AST/Node/Tag/TagNode.php new file mode 100644 index 00000000..969b71ed --- /dev/null +++ b/src/Language/AST/Node/Tag/TagNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TagNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly TagNameNode $name, + public readonly AttributeNodes $tagAttributes, + public readonly TagContentNodes $children, + public readonly bool $isSelfClosing + ) { + } +} diff --git a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php new file mode 100644 index 00000000..40ee93ba --- /dev/null +++ b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php @@ -0,0 +1,43 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TemplateLiteralNode extends Node +{ + /** + * @var (StringLiteralNode|ExpressionNode)[] + */ + public readonly array $segments; + + public function __construct( + public readonly NodeAttributes $attributes, + StringLiteralNode | ExpressionNode ...$segments + ) { + $this->segments = $segments; + } +} diff --git a/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php b/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php new file mode 100644 index 00000000..a2fe35f3 --- /dev/null +++ b/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class TernaryOperationNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly ExpressionNode $condition, + public readonly ExpressionNode $trueBranch, + public readonly ExpressionNode $falseBranch + ) { + } +} diff --git a/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php b/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php new file mode 100644 index 00000000..27821d6c --- /dev/null +++ b/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; + +final class UnaryOperationNode extends Node +{ + public function __construct( + public readonly NodeAttributes $attributes, + public readonly UnaryOperator $operator, + public readonly ExpressionNode $operand + ) { + } +} diff --git a/src/Language/AST/Node/UnaryOperation/UnaryOperator.php b/src/Language/AST/Node/UnaryOperation/UnaryOperator.php new file mode 100644 index 00000000..37845208 --- /dev/null +++ b/src/Language/AST/Node/UnaryOperation/UnaryOperator.php @@ -0,0 +1,28 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation; + +enum UnaryOperator: string +{ + case NOT = 'NOT'; +} From e9cc01e15876af264afac5f02cccdffdeebab192 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 2 Aug 2023 16:56:57 +0200 Subject: [PATCH 42/64] TASK: Implement TagParser with limited capabilities Embedded expressions are still missing. --- .../{TagContentNodes.php => ChildNodes.php} | 9 +- src/Language/AST/Node/Tag/TagNode.php | 2 +- src/Language/Parser/ParserException.php | 2 +- .../Tag/TagCouldNotBeParsed.php} | 29 +- src/Language/Parser/Tag/TagParser.php | 305 +++ src/Language/Parser/Text/TextParser.php | 13 +- .../Language/Parser/Tag/TagParserTest.php | 1628 +++++++++++++++++ .../Language/Parser/Text/TextParserTest.php | 149 +- 8 files changed, 2117 insertions(+), 20 deletions(-) rename src/Language/AST/Node/Tag/{TagContentNodes.php => ChildNodes.php} (77%) rename src/Language/{AST/Node/Tag/TagContentNode.php => Parser/Tag/TagCouldNotBeParsed.php} (50%) create mode 100644 src/Language/Parser/Tag/TagParser.php create mode 100644 test/Unit/Language/Parser/Tag/TagParserTest.php diff --git a/src/Language/AST/Node/Tag/TagContentNodes.php b/src/Language/AST/Node/Tag/ChildNodes.php similarity index 77% rename from src/Language/AST/Node/Tag/TagContentNodes.php rename to src/Language/AST/Node/Tag/ChildNodes.php index b07168dc..a05f7250 100644 --- a/src/Language/AST/Node/Tag/TagContentNodes.php +++ b/src/Language/AST/Node/Tag/ChildNodes.php @@ -22,14 +22,17 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; -final class TagContentNodes +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; + +final class ChildNodes { /** - * @var TagContentNode[] + * @var (TextNode|ExpressionNode|TagNode)[] */ public readonly array $items; - public function __construct(TagContentNode ...$items) + public function __construct(TextNode | ExpressionNode | TagNode ...$items) { $this->items = $items; } diff --git a/src/Language/AST/Node/Tag/TagNode.php b/src/Language/AST/Node/Tag/TagNode.php index 969b71ed..3bf2dcef 100644 --- a/src/Language/AST/Node/Tag/TagNode.php +++ b/src/Language/AST/Node/Tag/TagNode.php @@ -31,7 +31,7 @@ public function __construct( public readonly NodeAttributes $attributes, public readonly TagNameNode $name, public readonly AttributeNodes $tagAttributes, - public readonly TagContentNodes $children, + public readonly ChildNodes $children, public readonly bool $isSelfClosing ) { } diff --git a/src/Language/Parser/ParserException.php b/src/Language/Parser/ParserException.php index d98f0cb0..e58224f9 100644 --- a/src/Language/Parser/ParserException.php +++ b/src/Language/Parser/ParserException.php @@ -26,7 +26,7 @@ abstract class ParserException extends \Exception { - protected function __construct( + final protected function __construct( int $code, string $message, public readonly ?Range $affectedRangeInSource = null, diff --git a/src/Language/AST/Node/Tag/TagContentNode.php b/src/Language/Parser/Tag/TagCouldNotBeParsed.php similarity index 50% rename from src/Language/AST/Node/Tag/TagContentNode.php rename to src/Language/Parser/Tag/TagCouldNotBeParsed.php index 13b6f9e0..0d06f353 100644 --- a/src/Language/AST/Node/Tag/TagContentNode.php +++ b/src/Language/Parser/Tag/TagCouldNotBeParsed.php @@ -20,18 +20,27 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; +namespace PackageFactory\ComponentEngine\Language\Parser\Tag; -use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; -use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Source\Range; -final class TagContentNode extends Node +final class TagCouldNotBeParsed extends ParserException { - public function __construct( - public readonly NodeAttributes $attributes, - public readonly TextNode | ExpressionNode | TagNode $root - ) { + public static function becauseOfClosingTagNameMismatch( + TagName $expectedTagName, + string $actualTagName, + Range $affectedRangeInSource + ): self { + return new self( + code: 1690976372, + message: sprintf( + 'TagNode could not be parsed, because the closing tag name "%s" did not match the opening tag name "%s".', + $actualTagName, + $expectedTagName->value + ), + affectedRangeInSource: $affectedRangeInSource + ); } } diff --git a/src/Language/Parser/Tag/TagParser.php b/src/Language/Parser/Tag/TagParser.php new file mode 100644 index 00000000..2cefde99 --- /dev/null +++ b/src/Language/Parser/Tag/TagParser.php @@ -0,0 +1,305 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Tag; + +use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\Text\TextParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class TagParser +{ + private readonly StringLiteralParser $stringLiteralParser; + private readonly TextParser $textParser; + + public function __construct() + { + $this->stringLiteralParser = new StringLiteralParser(); + $this->textParser = new TextParser(); + } + + /** + * @param \Iterator $tokens + * @return TagNode + */ + public function parse(\Iterator $tokens): TagNode + { + $tagStartOpeningToken = $this->extractTagStartOpeningToken($tokens); + $tagNameNode = $this->parseTagName($tokens); + $attributeNodes = $this->parseAttributes($tokens); + + if ($tagSelfCloseToken = $this->extractTagSelfCloseToken($tokens)) { + return new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + $tagStartOpeningToken->boundaries->start, + $tagSelfCloseToken->boundaries->end + ) + ), + name: $tagNameNode, + tagAttributes: $attributeNodes, + children: new ChildNodes(), + isSelfClosing: true + ); + } else { + $this->skipTagEndToken($tokens); + $children = $this->parseChildren($tokens); + $this->skipTagStartClosingToken($tokens); + $this->assertAndSkipClosingTagName($tokens, $tagNameNode); + $closingTagEndToken = $this->extractTagEndToken($tokens); + + return new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + $tagStartOpeningToken->boundaries->start, + $closingTagEndToken->boundaries->end + ) + ), + name: $tagNameNode, + tagAttributes: $attributeNodes, + children: $children, + isSelfClosing: false + ); + } + } + + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractTagStartOpeningToken(\Iterator $tokens): Token + { + Scanner::assertType($tokens, TokenType::TAG_START_OPENING); + $tagStartOpeningToken = $tokens->current(); + Scanner::skipOne($tokens); + + return $tagStartOpeningToken; + } + + /** + * @param \Iterator $tokens + * @return TagNameNode + */ + private function parseTagName(\Iterator $tokens): TagNameNode + { + Scanner::assertType($tokens, TokenType::STRING); + $tagNameToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: $tagNameToken->boundaries + ), + value: TagName::from($tagNameToken->value) + ); + } + + /** + * @param \Iterator $tokens + * @return AttributeNodes + */ + private function parseAttributes(\Iterator $tokens): AttributeNodes + { + $items = []; + while (!$this->isTagEnd($tokens)) { + Scanner::skipSpace($tokens); + + $items[] = $this->parseAttribute($tokens); + + Scanner::skipSpace($tokens); + } + + return new AttributeNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return boolean + */ + private function isTagEnd($tokens): bool + { + return ( + Scanner::type($tokens) === TokenType::TAG_END || + Scanner::type($tokens) === TokenType::TAG_SELF_CLOSE + ); + } + + /** + * @param \Iterator $tokens + * @return AttributeNode + */ + private function parseAttribute(\Iterator $tokens): AttributeNode + { + $attributeNameNode = $this->parseAttributeName($tokens); + $attributeValueNode = $this->parseAttributeValue($tokens); + + return new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + $attributeNameNode->attributes->rangeInSource->start, + $attributeValueNode?->attributes->rangeInSource->end ?? + $attributeNameNode->attributes->rangeInSource->end + ) + ), + name: $attributeNameNode, + value: $attributeValueNode + ); + } + + /** + * @param \Iterator $tokens + * @return AttributeNameNode + */ + private function parseAttributeName(\Iterator $tokens): AttributeNameNode + { + Scanner::assertType($tokens, TokenType::STRING); + $attributeNameToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: $attributeNameToken->boundaries + ), + value: AttributeName::from($attributeNameToken->value) + ); + } + + /** + * @param \Iterator $tokens + * @return null|StringLiteralNode + */ + private function parseAttributeValue(\Iterator $tokens): null|StringLiteralNode + { + if (Scanner::type($tokens) === TokenType::EQUALS) { + Scanner::skipOne($tokens); + Scanner::assertType($tokens, TokenType::STRING_QUOTED); + + return $this->stringLiteralParser->parse($tokens); + } + + return null; + } + + /** + * @param \Iterator $tokens + * @return null|Token + */ + private function extractTagSelfCloseToken(\Iterator $tokens): ?Token + { + if (Scanner::type($tokens) === TokenType::TAG_SELF_CLOSE) { + $tagSelfCloseToken = $tokens->current(); + Scanner::skipOne($tokens); + + return $tagSelfCloseToken; + } + + return null; + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipTagEndToken(\Iterator $tokens): void + { + Scanner::assertType($tokens, TokenType::TAG_END); + Scanner::skipOne($tokens); + } + + /** + * @param \Iterator $tokens + * @return ChildNodes + */ + private function parseChildren(\Iterator $tokens): ChildNodes + { + $items = []; + $preserveLeadingSpace = false; + while (Scanner::type($tokens) !== TokenType::TAG_START_CLOSING) { + if ($textNode = $this->textParser->parse($tokens, $preserveLeadingSpace)) { + $items[] = $textNode; + } + + if (Scanner::type($tokens) === TokenType::TAG_START_OPENING) { + $items[] = $this->parse($tokens); + $preserveLeadingSpace = Scanner::type($tokens) !== TokenType::END_OF_LINE; + } + } + + return new ChildNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipTagStartClosingToken(\Iterator $tokens): void + { + Scanner::assertType($tokens, TokenType::TAG_START_CLOSING); + Scanner::skipOne($tokens); + } + + /** + * @param \Iterator $tokens + * @param TagNameNode $openingTagNameNode + * @return void + */ + private function assertAndSkipClosingTagName(\Iterator $tokens, TagNameNode $openingTagNameNode): void + { + Scanner::assertType($tokens, TokenType::STRING); + $tagNameToken = $tokens->current(); + Scanner::skipOne($tokens); + + if ($tagNameToken->value !== $openingTagNameNode->value->value) { + throw TagCouldNotBeParsed::becauseOfClosingTagNameMismatch( + expectedTagName: $openingTagNameNode->value, + actualTagName: $tagNameToken->value, + affectedRangeInSource: $tagNameToken->boundaries + ); + } + } + + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractTagEndToken(\Iterator $tokens): Token + { + Scanner::assertType($tokens, TokenType::TAG_END); + $tagEndToken = $tokens->current(); + Scanner::skipOne($tokens); + + return $tagEndToken; + } +} diff --git a/src/Language/Parser/Text/TextParser.php b/src/Language/Parser/Text/TextParser.php index 8ca2525d..2094feaf 100644 --- a/src/Language/Parser/Text/TextParser.php +++ b/src/Language/Parser/Text/TextParser.php @@ -43,6 +43,7 @@ public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?T $finalToken = null; $ignoreSpace = false; $keepTrailingSpace = false; + $forceTrimTrailingSpace = false; while (!Scanner::isEnd($tokens)) { $startingToken ??= $tokens->current(); switch (Scanner::type($tokens)) { @@ -59,12 +60,16 @@ public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?T $value .= ' '; } $ignoreSpace = true; + if (Scanner::type($tokens) === TokenType::END_OF_LINE) { + $forceTrimTrailingSpace = true; + } $finalToken = $tokens->current(); Scanner::skipOne($tokens); break; default: $value .= Scanner::value($tokens); $ignoreSpace = false; + $forceTrimTrailingSpace = false; $finalToken = $tokens->current(); Scanner::skipOne($tokens); break; @@ -75,8 +80,12 @@ public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?T return null; } - if (!$keepTrailingSpace) { - $value = $preserveLeadingSpace ? rtrim($value) : trim($value); + if (!$preserveLeadingSpace) { + $value = ltrim($value); + } + + if (!$keepTrailingSpace || $forceTrimTrailingSpace) { + $value = rtrim($value); } if ($value === '' || $value === ' ') { diff --git a/test/Unit/Language/Parser/Tag/TagParserTest.php b/test/Unit/Language/Parser/Tag/TagParserTest.php new file mode 100644 index 00000000..a774bc85 --- /dev/null +++ b/test/Unit/Language/Parser/Tag/TagParserTest.php @@ -0,0 +1,1628 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Tag; + +use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; +use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; +use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Language\Parser\Tag\TagCouldNotBeParsed; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +final class TagParserTest extends TestCase +{ + /** + * @test + */ + public function parsesSelfClosingTagWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 3) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesSelfClosingTagWithValuelessAttribute(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 11) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) + ) + ), + value: TagName::from('table') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: AttributeName::from('foo') + ), + value: null + ) + ), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 19) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) + ) + ), + value: TagName::from('table') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: AttributeName::from('foo') + ), + value: null + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ) + ), + value: AttributeName::from('bar') + ), + value: null + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) + ) + ), + value: AttributeName::from('baz') + ), + value: null + ) + ), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesSelfClosingTagWithStringAttribute(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 13) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 10) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ) + ), + value: AttributeName::from('foo') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 8), + new Position(0, 10) + ) + ), + value: 'bar' + ) + ) + ), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesSelfClosingTagWithMultipleStringAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 38) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) + ) + ), + value: TagName::from('div') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 12) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) + ) + ), + value: AttributeName::from('foo') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 10), + new Position(0, 12) + ) + ), + value: 'bar' + ) + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 22) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) + ) + ), + value: AttributeName::from('baz') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 20), + new Position(0, 22) + ) + ), + value: 'qux' + ) + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 25), + new Position(0, 35) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 25), + new Position(0, 28) + ) + ), + value: AttributeName::from('quux') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 31), + new Position(0, 35) + ) + ), + value: 'corge' + ) + ) + ), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithEmptyContentAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 6) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function throwsIfClosingTagNameDoesNotMatchOpeningTagName(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $this->expectException(ParserException::class); + $this->expectExceptionObject( + TagCouldNotBeParsed::becauseOfClosingTagNameMismatch( + expectedTagName: TagName::from('a'), + actualTagName: 'b', + affectedRangeInSource: Range::from( + new Position(0, 5), + new Position(0, 5) + ) + ) + ); + + $tagParser->parse($tokens); + } + + /** + * @test + */ + public function parsesTagWithEmptyContentAndValuelessAttribute(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ) + ), + value: AttributeName::from('foo') + ), + value: null + ), + ), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 18) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ) + ), + value: AttributeName::from('foo') + ), + value: null + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: AttributeName::from('bar') + ), + value: null + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ) + ), + value: AttributeName::from('baz') + ), + value: null + ), + ), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithEmptyContentAndStringAttribute(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 24) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) + ) + ), + value: TagName::from('audio') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 14) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: AttributeName::from('foo') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 12), + new Position(0, 14) + ) + ), + value: 'bar' + ) + ), + ), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 47) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) + ) + ), + value: TagName::from('video') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 14) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ) + ), + value: AttributeName::from('foo') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 12), + new Position(0, 14) + ) + ), + value: 'bar' + ) + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 17), + new Position(0, 24) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 17), + new Position(0, 19) + ) + ), + value: AttributeName::from('baz') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 22), + new Position(0, 24) + ) + ), + value: 'qux' + ) + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 37) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 30) + ) + ), + value: AttributeName::from('quux') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 33), + new Position(0, 37) + ) + ), + value: 'corge' + ) + ), + ), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithTextContentAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Lorem ipsum...'))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 20) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 16) + ) + ), + value: 'Lorem ipsum...' + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 6) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) + ) + ), + value: TagName::from('b') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: true + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithNestedTagAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 13) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 9) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) + ) + ), + value: TagName::from('b') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: false + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 24) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 20) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) + ) + ), + value: TagName::from('b') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 6), + new Position(0, 16) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 7) + ) + ), + value: TagName::from('c') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 9), + new Position(0, 12) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 10), + new Position(0, 10) + ) + ), + value: TagName::from('d') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: true + ) + ), + isSelfClosing: false + ) + ), + isSelfClosing: false + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(' '))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 19) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 6), + new Position(0, 12) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 7) + ) + ), + value: TagName::from('b') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: false + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundTheNestedTag(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString('Something important happened.'))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 42) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 12) + ) + ), + value: 'Something ' + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 28) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 14) + ) + ), + value: TagName::from('b') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 16), + new Position(0, 24) + ) + ), + value: 'important' + ) + ), + isSelfClosing: false + ), + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 29), + new Position(0, 38) + ) + ), + value: ' happened.' + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 24) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 9) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) + ) + ), + value: TagName::from('b') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: false + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 10), + new Position(0, 13) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 11) + ) + ), + value: TagName::from('c') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: true + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 15) + ) + ), + value: TagName::from('d') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes(), + isSelfClosing: false + ), + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttributesAndContentsThemselves(): void + { + $tagParser = new TagParser(); + $tagAsString = <<
+ AFX; + $tokens = Tokenizer::fromSource(Source::fromString($tagAsString))->getIterator(); + + $expectedTagNode = new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(8, 5) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) + ) + ), + value: TagName::from('div') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 15) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 9) + ) + ), + value: AttributeName::from('class') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 12), + new Position(0, 15) + ) + ), + value: 'test' + ) + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 23) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 23) + ) + ), + value: AttributeName::from('hidden') + ), + value: null + ), + ), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 25), + new Position(2, 3) + ) + ), + value: 'Some opening text' + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 20) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 5), + new Position(2, 6) + ) + ), + value: TagName::from('h1') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(2, 8), + new Position(2, 15) + ) + ), + value: 'Headline' + ), + ), + isSelfClosing: false + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 59) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 5), + new Position(3, 5) + ) + ), + value: TagName::from('a') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 7), + new Position(3, 23) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 7), + new Position(3, 10) + ) + ), + value: AttributeName::from('href') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 13), + new Position(3, 23) + ) + ), + value: 'about:blank' + ) + ), + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 26), + new Position(3, 39) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 26), + new Position(3, 31) + ) + ), + value: AttributeName::from('target') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 34), + new Position(3, 39) + ) + ), + value: '_blank' + ) + ), + ), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(3, 42), + new Position(3, 55) + ) + ), + value: 'This is a link' + ), + ), + isSelfClosing: false + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(4, 4), + new Position(6, 7) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(4, 5), + new Position(4, 5) + ) + ), + value: TagName::from('p') + ), + tagAttributes: new AttributeNodes( + new AttributeNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(4, 7), + new Position(4, 16) + ) + ), + name: new AttributeNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(4, 7), + new Position(4, 11) + ) + ), + value: AttributeName::from('class') + ), + value: new StringLiteralNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(4, 14), + new Position(4, 16) + ) + ), + value: 'rte' + ) + ), + ), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(4, 19), + new Position(5, 32) + ) + ), + value: 'This is a paragraph with ' + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 33), + new Position(5, 51) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 34), + new Position(5, 35) + ) + ), + value: TagName::from('em') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 37), + new Position(5, 46) + ) + ), + value: 'emphasized' + ), + ), + isSelfClosing: false + ), + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 52), + new Position(5, 56) + ) + ), + value: ' and ' + ), + new TagNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 57), + new Position(5, 81) + ) + ), + name: new TagNameNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 58), + new Position(5, 63) + ) + ), + value: TagName::from('strong') + ), + tagAttributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 65), + new Position(5, 72) + ) + ), + value: 'boldened' + ), + ), + isSelfClosing: false + ), + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(5, 82), + new Position(6, 3) + ) + ), + value: ' text.' + ) + ), + isSelfClosing: false + ), + new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(6, 8), + new Position(7, 21) + ) + ), + value: 'Some closing text' + ), + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } +} diff --git a/test/Unit/Language/Parser/Text/TextParserTest.php b/test/Unit/Language/Parser/Text/TextParserTest.php index 91eec8c2..5e0531eb 100644 --- a/test/Unit/Language/Parser/Text/TextParserTest.php +++ b/test/Unit/Language/Parser/Text/TextParserTest.php @@ -28,7 +28,6 @@ use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; use PHPUnit\Framework\TestCase; @@ -106,6 +105,54 @@ public function trimsLeadingAndTrailingSpaces(): void ); } + /** + * @test + */ + public function trimsLeadingLineBreak(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("\nHello World"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 10) + ) + ), + value: 'Hello World' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function trimsLeadingLineBreakAndIndentation(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("\n Hello World"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 14) + ) + ), + value: 'Hello World' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + /** * @test */ @@ -154,10 +201,58 @@ public function reducesInnerSpacesToSingleSpaceCharacterEach(): void ); } + /** + * @test + */ + public function terminatesAtEmbeddedExpressionAndTrimsLeadingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" Hello{"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 8) + ) + ), + value: 'Hello' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + /** * @test */ public function terminatesAtEmbeddedExpressionAndKeepsTrailingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("Hello \t {foo}!"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 7) + ) + ), + value: 'Hello ' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function terminatesAtEmbeddedExpressionAndTrimsTrailingSpaceIfItContainsLineBreaks(): void { $textParser = new TextParser(); $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t {foo}!"))->getIterator(); @@ -169,7 +264,7 @@ public function terminatesAtEmbeddedExpressionAndKeepsTrailingSpace(): void new Position(1, 1) ) ), - value: 'Hello ' + value: 'Hello' ); $this->assertEquals( @@ -189,10 +284,58 @@ public function returnsNullAtEmbeddedExpressionIfTheresOnlySpace(): void $this->assertNull($textParser->parse($tokens)); } + /** + * @test + */ + public function terminatesAtOpeningTagAndTrimsLeadingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString(" Hello"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 8) + ) + ), + value: 'Hello' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + /** * @test */ public function terminatesAtOpeningTagAndKeepsTrailingSpace(): void + { + $textParser = new TextParser(); + $tokens = Tokenizer::fromSource(Source::fromString("Hello \t World"))->getIterator(); + + $expectedTextNode = new TextNode( + attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 7) + ) + ), + value: 'Hello ' + ); + + $this->assertEquals( + $expectedTextNode, + $textParser->parse($tokens) + ); + } + + /** + * @test + */ + public function terminatesAtOpeningTagAndTrimsTrailingSpaceIfItContainsLineBreaks(): void { $textParser = new TextParser(); $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t World"))->getIterator(); @@ -204,7 +347,7 @@ public function terminatesAtOpeningTagAndKeepsTrailingSpace(): void new Position(1, 1) ) ), - value: 'Hello ' + value: 'Hello' ); $this->assertEquals( From 6e44ca47f143859ff55fa074b03f4fd341aad58c Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 2 Aug 2023 21:53:50 +0200 Subject: [PATCH 43/64] TASK: Remove NodeAttributes class Every node has a property `rangeInSource` instead. --- src/Language/AST/ASTException.php | 4 +- .../AST/Node/AccessChain/AccessChainNode.php | 4 +- .../AccessChain/AccessChainSegmentKeyNode.php | 4 +- .../AccessChain/AccessChainSegmentNode.php | 4 +- .../BinaryOperation/BinaryOperationNode.php | 4 +- .../BooleanLiteral/BooleanLiteralNode.php | 5 +- .../EnumDeclaration/EnumDeclarationNode.php | 4 +- .../EnumMemberDeclarationNode.php | 4 +- .../EnumMemberDeclarationNodes.php | 5 +- .../EnumDeclaration/EnumMemberNameNode.php | 4 +- .../EnumDeclaration/EnumMemberValueNode.php | 6 +- .../AST/Node/EnumDeclaration/EnumNameNode.php | 4 +- .../AST/Node/Expression/ExpressionNode.php | 4 +- .../IntegerLiteral/IntegerLiteralNode.php | 4 +- src/Language/AST/Node/Match/MatchArmNode.php | 4 +- src/Language/AST/Node/Match/MatchNode.php | 4 +- src/Language/AST/Node/Node.php | 4 +- .../AST/Node/NullLiteral/NullLiteralNode.php | 4 +- .../PropertyDeclarationNode.php | 4 +- .../PropertyDeclaration/PropertyNameNode.php | 4 +- .../Node/StringLiteral/StringLiteralNode.php | 4 +- .../StructDeclarationNode.php | 4 +- .../Node/StructDeclaration/StructNameNode.php | 4 +- .../AST/Node/Tag/AttributeNameNode.php | 4 +- src/Language/AST/Node/Tag/AttributeNode.php | 4 +- src/Language/AST/Node/Tag/TagNameNode.php | 4 +- src/Language/AST/Node/Tag/TagNode.php | 4 +- .../TemplateLiteral/TemplateLiteralNode.php | 4 +- .../TernaryOperation/TernaryOperationNode.php | 4 +- src/Language/AST/Node/Text/TextNode.php | 4 +- .../TypeReference/InvalidTypeNameNodes.php | 2 +- .../InvalidTypeReferenceNode.php | 14 +- .../AST/Node/TypeReference/TypeNameNode.php | 4 +- .../Node/TypeReference/TypeReferenceNode.php | 10 +- .../UnaryOperation/UnaryOperationNode.php | 4 +- .../ValueReference/ValueReferenceNode.php | 4 +- .../AST/NodeAttributes/NodeAttributes.php | 33 - .../BooleanLiteral/BooleanLiteralParser.php | 5 +- .../EnumDeclaration/EnumDeclarationParser.php | 35 +- .../IntegerLiteral/IntegerLiteralParser.php | 5 +- .../Parser/NullLiteral/NullLiteralParser.php | 5 +- .../PropertyDeclarationParser.php | 13 +- .../StringLiteral/StringLiteralParser.php | 5 +- .../StructDeclarationParser.php | 13 +- src/Language/Parser/Tag/TagParser.php | 35 +- src/Language/Parser/Text/TextParser.php | 9 +- .../TypeReferenceCouldNotBeParsed.php | 4 +- .../TypeReference/TypeReferenceParser.php | 11 +- .../ValueReference/ValueReferenceParser.php | 5 +- .../Language/AST/Helpers/DummyAttributes.php | 45 - .../Node/TypeReference/TypeNameNodesTest.php | 17 +- .../TypeReference/TypeReferenceNodeTest.php | 120 +- .../BooleanLiteralParserTest.php | 17 +- .../EnumDeclarationParserTest.php | 969 ++++++--------- .../IntegerLiteralParserTest.php | 33 +- .../NullLiteral/NullLiteralParserTest.php | 9 +- .../PropertyDeclarationParserTest.php | 145 +-- .../StringLiteral/StringLiteralParserTest.php | 9 +- .../StructDeclarationParserTest.php | 449 +++---- .../Language/Parser/Tag/TagParserTest.php | 1047 ++++++----------- .../Language/Parser/Text/TextParserTest.php | 105 +- .../TypeReference/TypeReferenceParserTest.php | 97 +- .../ValueReferenceParserTest.php | 9 +- 63 files changed, 1302 insertions(+), 2109 deletions(-) delete mode 100644 src/Language/AST/NodeAttributes/NodeAttributes.php delete mode 100644 test/Unit/Language/AST/Helpers/DummyAttributes.php diff --git a/src/Language/AST/ASTException.php b/src/Language/AST/ASTException.php index 6de58c30..516375fb 100644 --- a/src/Language/AST/ASTException.php +++ b/src/Language/AST/ASTException.php @@ -22,14 +22,14 @@ namespace PackageFactory\ComponentEngine\Language\AST; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; abstract class ASTException extends \Exception { protected function __construct( int $code, string $message, - public readonly ?NodeAttributes $attributesOfAffectedNode = null + public readonly ?Range $affectedRangeInSource = null ) { parent::__construct($message, $code); } diff --git a/src/Language/AST/Node/AccessChain/AccessChainNode.php b/src/Language/AST/Node/AccessChain/AccessChainNode.php index bfc9ac94..328a6d77 100644 --- a/src/Language/AST/Node/AccessChain/AccessChainNode.php +++ b/src/Language/AST/Node/AccessChain/AccessChainNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class AccessChainNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly ExpressionNode $root, public readonly AccessChainSegmentNodes $chain ) { diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php b/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php index a6d28be5..eceb645b 100644 --- a/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php +++ b/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class AccessChainSegmentKeyNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly PropertyName $value ) { } diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php b/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php index 4582484f..b3dd166d 100644 --- a/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php +++ b/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class AccessChainSegmentNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly AccessType $accessType, public readonly AccessChainSegmentKeyNode $key ) { diff --git a/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php b/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php index 2a03b706..cbf4a7ff 100644 --- a/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php +++ b/src/Language/AST/Node/BinaryOperation/BinaryOperationNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class BinaryOperationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly ExpressionNode $leftOperand, public readonly BinaryOperator $operator, public readonly ExpressionNode $rightOperand diff --git a/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php index 2e17fa05..ec6476f2 100644 --- a/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php +++ b/src/Language/AST/Node/BooleanLiteral/BooleanLiteralNode.php @@ -23,14 +23,13 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class BooleanLiteralNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly bool $value ) { - // parent::__construct($attributes); } } diff --git a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php index 3482e001..3ecb6e82 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumDeclarationNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class EnumDeclarationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly EnumNameNode $name, public readonly EnumMemberDeclarationNodes $members ) { diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php index e4e001e5..261a434d 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class EnumMemberDeclarationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly EnumMemberNameNode $name, public readonly ?EnumMemberValueNode $value ) { diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php index 51797009..f1f2d23c 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberDeclarationNodes.php @@ -29,9 +29,8 @@ final class EnumMemberDeclarationNodes */ public readonly array $items; - public function __construct( - EnumMemberDeclarationNode ...$items - ) { + public function __construct(EnumMemberDeclarationNode ...$items) + { $itemsAsHashMap = []; foreach ($items as $item) { $itemsAsHashMap[$item->name->value->value] = $item; diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php index 3447a39b..d7c6dc00 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class EnumMemberNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly EnumMemberName $value ) { } diff --git a/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php b/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php index 5d0796ff..4801e044 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumMemberValueNode.php @@ -25,13 +25,13 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class EnumMemberValueNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, - public readonly StringLiteralNode|IntegerLiteralNode $value + public readonly Range $rangeInSource, + public readonly StringLiteralNode | IntegerLiteralNode $value ) { } } diff --git a/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php b/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php index adc24bc5..ae82df47 100644 --- a/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php +++ b/src/Language/AST/Node/EnumDeclaration/EnumNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class EnumNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly EnumName $value ) { } diff --git a/src/Language/AST/Node/Expression/ExpressionNode.php b/src/Language/AST/Node/Expression/ExpressionNode.php index 316b82fd..34fabca3 100644 --- a/src/Language/AST/Node/Expression/ExpressionNode.php +++ b/src/Language/AST/Node/Expression/ExpressionNode.php @@ -35,12 +35,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class ExpressionNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly AccessChainNode | BinaryOperationNode | BooleanLiteralNode | IntegerLiteralNode | MatchNode | NullLiteralNode | StringLiteralNode | TagNode | TemplateLiteralNode | TernaryOperationNode | UnaryOperationNode | ValueReferenceNode $root ) { } diff --git a/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php index 6ee74007..1ab2631a 100644 --- a/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php +++ b/src/Language/AST/Node/IntegerLiteral/IntegerLiteralNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class IntegerLiteralNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly IntegerFormat $format, public readonly string $value ) { diff --git a/src/Language/AST/Node/Match/MatchArmNode.php b/src/Language/AST/Node/Match/MatchArmNode.php index 26dbe261..fd93ac38 100644 --- a/src/Language/AST/Node/Match/MatchArmNode.php +++ b/src/Language/AST/Node/Match/MatchArmNode.php @@ -25,12 +25,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class MatchArmNode extends Node { private function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly null | ExpressionNodes $left, public readonly ExpressionNode $right ) { diff --git a/src/Language/AST/Node/Match/MatchNode.php b/src/Language/AST/Node/Match/MatchNode.php index fe677701..4ee8a357 100644 --- a/src/Language/AST/Node/Match/MatchNode.php +++ b/src/Language/AST/Node/Match/MatchNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class MatchNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly ExpressionNode $subject, public readonly MatchArmNodes $arms ) { diff --git a/src/Language/AST/Node/Node.php b/src/Language/AST/Node/Node.php index a49380eb..c65f9ce6 100644 --- a/src/Language/AST/Node/Node.php +++ b/src/Language/AST/Node/Node.php @@ -22,12 +22,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; abstract class Node { protected function __construct( - public readonly NodeAttributes $attributes + public readonly Range $rangeInSource ) { } } diff --git a/src/Language/AST/Node/NullLiteral/NullLiteralNode.php b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php index d85ec9c4..ac096b85 100644 --- a/src/Language/AST/Node/NullLiteral/NullLiteralNode.php +++ b/src/Language/AST/Node/NullLiteral/NullLiteralNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class NullLiteralNode extends Node { public function __construct( - public readonly NodeAttributes $attributes + public readonly Range $rangeInSource ) { } } diff --git a/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php b/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php index 70edbf8f..8845b8e4 100644 --- a/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php +++ b/src/Language/AST/Node/PropertyDeclaration/PropertyDeclarationNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class PropertyDeclarationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly PropertyNameNode $name, public readonly TypeReferenceNode $type ) { diff --git a/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php b/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php index 5bc7e7ad..d7b59d20 100644 --- a/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php +++ b/src/Language/AST/Node/PropertyDeclaration/PropertyNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class PropertyNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly PropertyName $value ) { } diff --git a/src/Language/AST/Node/StringLiteral/StringLiteralNode.php b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php index 4a199ae9..c7954867 100644 --- a/src/Language/AST/Node/StringLiteral/StringLiteralNode.php +++ b/src/Language/AST/Node/StringLiteral/StringLiteralNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class StringLiteralNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly string $value ) { } diff --git a/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php b/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php index 996e84dd..e19a0c78 100644 --- a/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php +++ b/src/Language/AST/Node/StructDeclaration/StructDeclarationNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class StructDeclarationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly StructNameNode $name, public readonly PropertyDeclarationNodes $properties ) { diff --git a/src/Language/AST/Node/StructDeclaration/StructNameNode.php b/src/Language/AST/Node/StructDeclaration/StructNameNode.php index 69a3bf97..95aa76d7 100644 --- a/src/Language/AST/Node/StructDeclaration/StructNameNode.php +++ b/src/Language/AST/Node/StructDeclaration/StructNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\StructName\StructName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class StructNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly StructName $value ) { } diff --git a/src/Language/AST/Node/Tag/AttributeNameNode.php b/src/Language/AST/Node/Tag/AttributeNameNode.php index d1f7748d..181f4101 100644 --- a/src/Language/AST/Node/Tag/AttributeNameNode.php +++ b/src/Language/AST/Node/Tag/AttributeNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class AttributeNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly AttributeName $value ) { } diff --git a/src/Language/AST/Node/Tag/AttributeNode.php b/src/Language/AST/Node/Tag/AttributeNode.php index b5ffc47b..1033c40c 100644 --- a/src/Language/AST/Node/Tag/AttributeNode.php +++ b/src/Language/AST/Node/Tag/AttributeNode.php @@ -25,12 +25,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class AttributeNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly AttributeNameNode $name, public readonly null | ExpressionNode | StringLiteralNode $value ) { diff --git a/src/Language/AST/Node/Tag/TagNameNode.php b/src/Language/AST/Node/Tag/TagNameNode.php index ef221197..1bf76835 100644 --- a/src/Language/AST/Node/Tag/TagNameNode.php +++ b/src/Language/AST/Node/Tag/TagNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\TagName\TagName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TagNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly TagName $value ) { } diff --git a/src/Language/AST/Node/Tag/TagNode.php b/src/Language/AST/Node/Tag/TagNode.php index 3bf2dcef..3410edb2 100644 --- a/src/Language/AST/Node/Tag/TagNode.php +++ b/src/Language/AST/Node/Tag/TagNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\Tag; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TagNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly TagNameNode $name, public readonly AttributeNodes $tagAttributes, public readonly ChildNodes $children, diff --git a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php index 40ee93ba..65621c41 100644 --- a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php +++ b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php @@ -25,7 +25,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TemplateLiteralNode extends Node { @@ -35,7 +35,7 @@ final class TemplateLiteralNode extends Node public readonly array $segments; public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, StringLiteralNode | ExpressionNode ...$segments ) { $this->segments = $segments; diff --git a/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php b/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php index a2fe35f3..88018eea 100644 --- a/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php +++ b/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TernaryOperationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly ExpressionNode $condition, public readonly ExpressionNode $trueBranch, public readonly ExpressionNode $falseBranch diff --git a/src/Language/AST/Node/Text/TextNode.php b/src/Language/AST/Node/Text/TextNode.php index bb57f426..d17cd868 100644 --- a/src/Language/AST/Node/Text/TextNode.php +++ b/src/Language/AST/Node/Text/TextNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\Text; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TextNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly string $value ) { } diff --git a/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php b/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php index 975dcc3d..9864f8d3 100644 --- a/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php +++ b/src/Language/AST/Node/TypeReference/InvalidTypeNameNodes.php @@ -40,7 +40,7 @@ public static function becauseTheyContainDuplicates( return new self( code: 1690551330, message: 'A type reference must not contain duplicates.', - attributesOfAffectedNode: $duplicateTypeNameNode->attributes + affectedRangeInSource: $duplicateTypeNameNode->rangeInSource ); } } diff --git a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php index d712ae87..abee1885 100644 --- a/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/InvalidTypeReferenceNode.php @@ -24,13 +24,13 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; use PackageFactory\ComponentEngine\Language\AST\ASTException; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class InvalidTypeReferenceNode extends ASTException { public static function becauseItWasOptionalAndArrayAtTheSameTime( TypeNames $affectedTypeNames, - NodeAttributes $attributesOfAffectedNode + Range $affectedRangeInSource ): self { return new self( code: 1690538480, @@ -38,13 +38,13 @@ public static function becauseItWasOptionalAndArrayAtTheSameTime( 'The type reference to "%s" must not be optional and array at the same time.', $affectedTypeNames->toDebugString() ), - attributesOfAffectedNode: $attributesOfAffectedNode + affectedRangeInSource: $affectedRangeInSource ); } public static function becauseItWasUnionAndArrayAtTheSameTime( TypeNames $affectedTypeNames, - NodeAttributes $attributesOfAffectedNode + Range $affectedRangeInSource ): self { return new self( code: 1690552344, @@ -52,13 +52,13 @@ public static function becauseItWasUnionAndArrayAtTheSameTime( 'The type reference to "%s" must not be union and array at the same time.', $affectedTypeNames->toDebugString() ), - attributesOfAffectedNode: $attributesOfAffectedNode + affectedRangeInSource: $affectedRangeInSource ); } public static function becauseItWasUnionAndOptionalAtTheSameTime( TypeNames $affectedTypeNames, - NodeAttributes $attributesOfAffectedNode + Range $affectedRangeInSource ): self { return new self( code: 1690552586, @@ -66,7 +66,7 @@ public static function becauseItWasUnionAndOptionalAtTheSameTime( 'The type reference to "%s" must not be union and optional at the same time.', $affectedTypeNames->toDebugString() ), - attributesOfAffectedNode: $attributesOfAffectedNode + affectedRangeInSource: $affectedRangeInSource ); } } diff --git a/src/Language/AST/Node/TypeReference/TypeNameNode.php b/src/Language/AST/Node/TypeReference/TypeNameNode.php index 92c9f89f..bf928439 100644 --- a/src/Language/AST/Node/TypeReference/TypeNameNode.php +++ b/src/Language/AST/Node/TypeReference/TypeNameNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TypeNameNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly TypeName $value ) { } diff --git a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php index 390c3d50..10c61808 100644 --- a/src/Language/AST/Node/TypeReference/TypeReferenceNode.php +++ b/src/Language/AST/Node/TypeReference/TypeReferenceNode.php @@ -23,12 +23,12 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\TypeReference; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class TypeReferenceNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly TypeNameNodes $names, public readonly bool $isArray, public readonly bool $isOptional @@ -36,21 +36,21 @@ public function __construct( if ($isArray === true && $isOptional === true) { throw InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( affectedTypeNames: $names->toTypeNames(), - attributesOfAffectedNode: $attributes + affectedRangeInSource: $rangeInSource ); } if ($names->getSize() > 1 && $isArray === true) { throw InvalidTypeReferenceNode::becauseItWasUnionAndArrayAtTheSameTime( affectedTypeNames: $names->toTypeNames(), - attributesOfAffectedNode: $attributes + affectedRangeInSource: $rangeInSource ); } if ($names->getSize() > 1 && $isOptional === true) { throw InvalidTypeReferenceNode::becauseItWasUnionAndOptionalAtTheSameTime( affectedTypeNames: $names->toTypeNames(), - attributesOfAffectedNode: $attributes + affectedRangeInSource: $rangeInSource ); } } diff --git a/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php b/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php index 27821d6c..b55c215c 100644 --- a/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php +++ b/src/Language/AST/Node/UnaryOperation/UnaryOperationNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class UnaryOperationNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly UnaryOperator $operator, public readonly ExpressionNode $operand ) { diff --git a/src/Language/AST/Node/ValueReference/ValueReferenceNode.php b/src/Language/AST/Node/ValueReference/ValueReferenceNode.php index b93b76cf..7168bc2c 100644 --- a/src/Language/AST/Node/ValueReference/ValueReferenceNode.php +++ b/src/Language/AST/Node/ValueReference/ValueReferenceNode.php @@ -24,12 +24,12 @@ use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Range; final class ValueReferenceNode extends Node { public function __construct( - public readonly NodeAttributes $attributes, + public readonly Range $rangeInSource, public readonly VariableName $name ) { } diff --git a/src/Language/AST/NodeAttributes/NodeAttributes.php b/src/Language/AST/NodeAttributes/NodeAttributes.php deleted file mode 100644 index 7347e1ab..00000000 --- a/src/Language/AST/NodeAttributes/NodeAttributes.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace PackageFactory\ComponentEngine\Language\AST\NodeAttributes; - -use PackageFactory\ComponentEngine\Parser\Source\Range; - -final class NodeAttributes -{ - public function __construct( - public readonly Range $rangeInSource - ) { - } -} diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index 81b9dbda..db5436d1 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -23,7 +23,6 @@ namespace PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -44,9 +43,7 @@ public function parse(\Iterator $tokens): BooleanLiteralNode Scanner::skipOne($tokens); return new BooleanLiteralNode( - attributes: new NodeAttributes( - rangeInSource: $token->boundaries - ), + rangeInSource: $token->boundaries, value: $value ); } diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 74f271cd..7f6fdb6a 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -32,7 +32,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -64,11 +63,9 @@ public function parse(\Iterator $tokens): EnumDeclarationNode $closingBracketToken = $this->extractClosingBracketToken($tokens); return new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $enumKeyWordToken->boundaries->start, - $closingBracketToken->boundaries->end - ) + rangeInSource: Range::from( + $enumKeyWordToken->boundaries->start, + $closingBracketToken->boundaries->end ), name: $enumNameNode, members: $enumMemberDeclarations @@ -101,9 +98,7 @@ private function parseEnumName(\Iterator $tokens): EnumNameNode $enumKeyNameToken = $tokens->current(); $enumNameNode = new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: $enumKeyNameToken->boundaries - ), + rangeInSource: $enumKeyNameToken->boundaries, value: EnumName::from($enumKeyNameToken->value) ); @@ -173,12 +168,10 @@ private function parseEnumMemberDeclaration(\Iterator $tokens): EnumMemberDeclar $value = $this->parseEnumMemberValue($tokens); return new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $enumMemberName->attributes->rangeInSource->start, - $value?->attributes->rangeInSource->end - ?? $enumMemberName->attributes->rangeInSource->end - ) + rangeInSource: Range::from( + $enumMemberName->rangeInSource->start, + $value?->rangeInSource->end + ?? $enumMemberName->rangeInSource->end ), name: $enumMemberName, value: $value @@ -195,9 +188,7 @@ private function parseEnumMemberName(\Iterator $tokens): EnumMemberNameNode $enumMemberNameToken = $tokens->current(); $enumMemberNameNode = new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: $enumMemberNameToken->boundaries - ), + rangeInSource: $enumMemberNameToken->boundaries, value: EnumMemberName::from($enumMemberNameToken->value) ); @@ -236,11 +227,9 @@ private function parseEnumMemberValue(\Iterator $tokens): ?EnumMemberValueNode Scanner::skipOne($tokens); return new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $openingBracketToken->boundaries->start, - $closingBracketToken->boundaries->end - ) + rangeInSource: Range::from( + $openingBracketToken->boundaries->start, + $closingBracketToken->boundaries->end ), value: $value ); diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index 774465d9..f2160ba3 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -24,7 +24,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -41,9 +40,7 @@ public function parse(\Iterator $tokens): IntegerLiteralNode Scanner::skipOne($tokens); return new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: $token->boundaries - ), + rangeInSource: $token->boundaries, format: IntegerFormat::fromTokenType($token->type), value: $token->value ); diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index 4cbcccee..91786fd9 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -23,7 +23,6 @@ namespace PackageFactory\ComponentEngine\Language\Parser\NullLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -43,9 +42,7 @@ public function parse(\Iterator $tokens): NullLiteralNode Scanner::skipOne($tokens); return new NullLiteralNode( - attributes: new NodeAttributes( - rangeInSource: $token->boundaries - ) + rangeInSource: $token->boundaries ); } } diff --git a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php index 5699ba35..59933f4b 100644 --- a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php +++ b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php @@ -25,7 +25,6 @@ use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; @@ -60,16 +59,12 @@ public function parse(\Iterator $tokens): PropertyDeclarationNode $typeReferenceNode = $this->typeReferenceParser->parse($tokens); return new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $propertyNameToken->boundaries->start, - $typeReferenceNode->attributes->rangeInSource->end - ) + rangeInSource: Range::from( + $propertyNameToken->boundaries->start, + $typeReferenceNode->rangeInSource->end ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: $propertyNameToken->boundaries - ), + rangeInSource: $propertyNameToken->boundaries, value: PropertyName::from($propertyNameToken->value) ), type: $typeReferenceNode diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index 5f891039..66815c42 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -23,7 +23,6 @@ namespace PackageFactory\ComponentEngine\Language\Parser\StringLiteral; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -43,9 +42,7 @@ public function parse(\Iterator $tokens): StringLiteralNode Scanner::skipOne($tokens); return new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: $token->boundaries - ), + rangeInSource: $token->boundaries, value: $token->value ); } diff --git a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php index 73461ed2..c49c2701 100644 --- a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php +++ b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php @@ -26,7 +26,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructNameNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration\PropertyDeclarationParser; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; @@ -55,11 +54,9 @@ public function parse(\Iterator $tokens): StructDeclarationNode $closingBracketToken = $this->extractClosingBracketToken($tokens); return new StructDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $structKeywordToken->boundaries->start, - $closingBracketToken->boundaries->end - ) + rangeInSource: Range::from( + $structKeywordToken->boundaries->start, + $closingBracketToken->boundaries->end ), name: $structNameNode, properties: $propertyDeclarationNodes @@ -96,9 +93,7 @@ public function parseStructName(\Iterator $tokens): StructNameNode Scanner::skipSpaceAndComments($tokens); return new StructNameNode( - attributes: new NodeAttributes( - rangeInSource: $structNameToken->boundaries - ), + rangeInSource: $structNameToken->boundaries, value: StructName::from($structNameToken->value) ); } diff --git a/src/Language/Parser/Tag/TagParser.php b/src/Language/Parser/Tag/TagParser.php index 2cefde99..44d073cd 100644 --- a/src/Language/Parser/Tag/TagParser.php +++ b/src/Language/Parser/Tag/TagParser.php @@ -31,7 +31,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\Text\TextParser; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -62,11 +61,9 @@ public function parse(\Iterator $tokens): TagNode if ($tagSelfCloseToken = $this->extractTagSelfCloseToken($tokens)) { return new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $tagStartOpeningToken->boundaries->start, - $tagSelfCloseToken->boundaries->end - ) + rangeInSource: Range::from( + $tagStartOpeningToken->boundaries->start, + $tagSelfCloseToken->boundaries->end ), name: $tagNameNode, tagAttributes: $attributeNodes, @@ -81,11 +78,9 @@ public function parse(\Iterator $tokens): TagNode $closingTagEndToken = $this->extractTagEndToken($tokens); return new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $tagStartOpeningToken->boundaries->start, - $closingTagEndToken->boundaries->end - ) + rangeInSource: Range::from( + $tagStartOpeningToken->boundaries->start, + $closingTagEndToken->boundaries->end ), name: $tagNameNode, tagAttributes: $attributeNodes, @@ -119,9 +114,7 @@ private function parseTagName(\Iterator $tokens): TagNameNode Scanner::skipOne($tokens); return new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: $tagNameToken->boundaries - ), + rangeInSource: $tagNameToken->boundaries, value: TagName::from($tagNameToken->value) ); } @@ -166,12 +159,10 @@ private function parseAttribute(\Iterator $tokens): AttributeNode $attributeValueNode = $this->parseAttributeValue($tokens); return new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $attributeNameNode->attributes->rangeInSource->start, - $attributeValueNode?->attributes->rangeInSource->end ?? - $attributeNameNode->attributes->rangeInSource->end - ) + rangeInSource: Range::from( + $attributeNameNode->rangeInSource->start, + $attributeValueNode?->rangeInSource->end ?? + $attributeNameNode->rangeInSource->end ), name: $attributeNameNode, value: $attributeValueNode @@ -189,9 +180,7 @@ private function parseAttributeName(\Iterator $tokens): AttributeNameNode Scanner::skipOne($tokens); return new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: $attributeNameToken->boundaries - ), + rangeInSource: $attributeNameToken->boundaries, value: AttributeName::from($attributeNameToken->value) ); } diff --git a/src/Language/Parser/Text/TextParser.php b/src/Language/Parser/Text/TextParser.php index 2094feaf..0aeaf065 100644 --- a/src/Language/Parser/Text/TextParser.php +++ b/src/Language/Parser/Text/TextParser.php @@ -23,7 +23,6 @@ namespace PackageFactory\ComponentEngine\Language\Parser\Text; use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -93,11 +92,9 @@ public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?T } return new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - $startingToken->boundaries->start, - $finalToken->boundaries->end - ) + rangeInSource: Range::from( + $startingToken->boundaries->start, + $finalToken->boundaries->end ), value: $value ); diff --git a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php index 84cc8d2f..7bf42746 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php +++ b/src/Language/Parser/TypeReference/TypeReferenceCouldNotBeParsed.php @@ -37,7 +37,7 @@ public static function becauseOfInvalidTypeReferenceNode( 'TypeReferenceNode could not be parsed, because the result would be invalid: %s', $cause->getMessage() ), - affectedRangeInSource: $cause->attributesOfAffectedNode?->rangeInSource ?? null, + affectedRangeInSource: $cause->affectedRangeInSource, cause: $cause ); } @@ -51,7 +51,7 @@ public static function becauseOfInvalidTypeTypeNameNodes( 'TypeReferenceNode could not be parsed, because the list of type names was invalid: %s', $cause->getMessage() ), - affectedRangeInSource: $cause->attributesOfAffectedNode?->rangeInSource ?? null, + affectedRangeInSource: $cause->affectedRangeInSource, cause: $cause ); } diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index a0f3bf4d..08f2297c 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -28,7 +28,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -54,14 +53,12 @@ public function parse(\Iterator $tokens): TypeReferenceNode $rangeInSource = Range::from( $startingToken->boundaries->start, $closingArrayToken?->boundaries->end - ?? $typeNameNodes->getLast()->attributes->rangeInSource->end + ?? $typeNameNodes->getLast()->rangeInSource->end ); try { return new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: $rangeInSource - ), + rangeInSource: $rangeInSource, names: $typeNameNodes, isArray: $isArray, isOptional: $isOptional @@ -124,9 +121,7 @@ public function parseTypeName(\Iterator $tokens): TypeNameNode Scanner::skipOne($tokens); return new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: $typeNameToken->boundaries - ), + rangeInSource: $typeNameToken->boundaries, value: TypeName::from($typeNameToken->value) ); } diff --git a/src/Language/Parser/ValueReference/ValueReferenceParser.php b/src/Language/Parser/ValueReference/ValueReferenceParser.php index 0d9d3fb1..ff842edb 100644 --- a/src/Language/Parser/ValueReference/ValueReferenceParser.php +++ b/src/Language/Parser/ValueReference/ValueReferenceParser.php @@ -24,7 +24,6 @@ use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; @@ -44,9 +43,7 @@ public function parse(\Iterator $tokens): ValueReferenceNode Scanner::skipOne($tokens); return new ValueReferenceNode( - attributes: new NodeAttributes( - rangeInSource: $token->boundaries - ), + rangeInSource: $token->boundaries, name: VariableName::from($token->value) ); } diff --git a/test/Unit/Language/AST/Helpers/DummyAttributes.php b/test/Unit/Language/AST/Helpers/DummyAttributes.php deleted file mode 100644 index 4376f2c9..00000000 --- a/test/Unit/Language/AST/Helpers/DummyAttributes.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers; - -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Range; - -trait DummyAttributes -{ - protected NodeAttributes $dummyAttributes; - - /** - * @before - */ - public function setUpDummyAttributes(): void - { - $this->dummyAttributes = new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 0) - ) - ); - } -} diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php index b79f9d2e..19995512 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeNameNodesTest.php @@ -27,20 +27,19 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers\DummyAttributes; use PHPUnit\Framework\TestCase; final class TypeNameNodesTest extends TestCase { - use DummyAttributes; - protected function createTypeNameNode(string $typeName): TypeNameNode { return new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from($typeName) ); } @@ -63,11 +62,9 @@ public function mustNotBeEmpty(): void public function mustNotContainDuplicates(): void { $duplicate = new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 1), - new Position(1, 1) - ) + rangeInSource: Range::from( + new Position(1, 1), + new Position(1, 1) ), value: TypeName::from('Foo') ); diff --git a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php index 5d4c7a0e..ef70055b 100644 --- a/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php +++ b/test/Unit/Language/AST/Node/TypeReference/TypeReferenceNodeTest.php @@ -28,23 +28,28 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; -use PackageFactory\ComponentEngine\Test\Unit\Language\AST\Helpers\DummyAttributes; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; use PHPUnit\Framework\TestCase; final class TypeReferenceNodeTest extends TestCase { - use DummyAttributes; - /** * @test */ public function validSimpleTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Foo') ) ), @@ -64,10 +69,16 @@ public function validSimpleTypeReferenceIsValid(): void public function validArrayTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Foo') ) ), @@ -87,10 +98,16 @@ public function validArrayTypeReferenceIsValid(): void public function validOptionalTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Foo') ) ), @@ -110,18 +127,30 @@ public function validOptionalTypeReferenceIsValid(): void public function validUnionTypeReferenceIsValid(): void { $typeReferenceNode = new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Foo') ), new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Bar') ), new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Baz') ) ), @@ -147,15 +176,24 @@ public function mustNotBeArrayAndOptionalSimultaneously(): void $this->expectExceptionObject( InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( affectedTypeNames: new TypeNames($name), - attributesOfAffectedNode: $this->dummyAttributes + affectedRangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) ) ); new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: $name ) ), @@ -171,15 +209,24 @@ public function mustNotBeUnionAndArraySimultaneously(): void { $typeNameNodes = new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Foo') ), new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Bar') ), new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Baz') ) ); @@ -187,12 +234,18 @@ public function mustNotBeUnionAndArraySimultaneously(): void $this->expectExceptionObject( InvalidTypeReferenceNode::becauseItWasUnionAndArrayAtTheSameTime( affectedTypeNames: $typeNameNodes->toTypeNames(), - attributesOfAffectedNode: $this->dummyAttributes + affectedRangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) ) ); new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: $typeNameNodes, isArray: true, isOptional: false @@ -206,15 +259,24 @@ public function mustNotBeUnionAndOptionalSimultaneously(): void { $typeNameNodes = new TypeNameNodes( new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Foo') ), new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Bar') ), new TypeNameNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), value: TypeName::from('Baz') ) ); @@ -222,12 +284,18 @@ public function mustNotBeUnionAndOptionalSimultaneously(): void $this->expectExceptionObject( InvalidTypeReferenceNode::becauseItWasUnionAndOptionalAtTheSameTime( affectedTypeNames: $typeNameNodes->toTypeNames(), - attributesOfAffectedNode: $this->dummyAttributes + affectedRangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ) ) ); new TypeReferenceNode( - attributes: $this->dummyAttributes, + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), names: $typeNameNodes, isArray: false, isOptional: true diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 0a862e43..4144d460 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -24,7 +24,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -42,11 +41,9 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void $tokens = Tokenizer::fromSource(Source::fromString('true'))->getIterator(); $expectedBooleanLiteralNode = new BooleanLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 3) ), value: true ); @@ -66,11 +63,9 @@ public function producesAstNodeForFalseIfGivenOneFalseToken(): void $tokens = Tokenizer::fromSource(Source::fromString('false'))->getIterator(); $expectedBooleanLiteralNode = new BooleanLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) ), value: false ); diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 343a170d..27c3bda1 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -34,7 +34,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -52,35 +51,27 @@ public function oneValuelessMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 15) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ), + name: new EnumMemberNameNode( rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) - ) - ), - name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) ), value: EnumMemberName::from('BAR') ), @@ -104,71 +95,55 @@ public function threeValuelessMembers(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR BAZ QUX }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 23) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 23) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ), + name: new EnumMemberNameNode( rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) - ) - ), - name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) ), value: EnumMemberName::from('BAR') ), value: null ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) + ), + name: new EnumMemberNameNode( rangeInSource: Range::from( new Position(0, 15), new Position(0, 17) - ) - ), - name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ) ), value: EnumMemberName::from('BAZ') ), value: null ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 19), + new Position(0, 21) + ), + name: new EnumMemberNameNode( rangeInSource: Range::from( new Position(0, 19), new Position(0, 21) - ) - ), - name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 19), - new Position(0, 21) - ) ), value: EnumMemberName::from('QUX') ), @@ -192,51 +167,39 @@ public function oneStringValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR("BAR") }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 20) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) ), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 16), - new Position(0, 18) - ) + rangeInSource: Range::from( + new Position(0, 16), + new Position(0, 18) ), value: 'BAR' ) @@ -271,255 +234,195 @@ enum Weekday { $tokens = Tokenizer::fromSource(Source::fromString($enumAsString))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(8, 0) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(8, 0) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 11) ), value: EnumName::from('Weekday') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 16) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 16) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 9) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 9) ), value: EnumMemberName::from('MONDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 10), - new Position(1, 16) - ) + rangeInSource: Range::from( + new Position(1, 10), + new Position(1, 16) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 12), - new Position(1, 14) - ) + rangeInSource: Range::from( + new Position(1, 12), + new Position(1, 14) ), value: 'mon' ) ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 17) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 17) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 10) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 10) ), value: EnumMemberName::from('TUESDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 11), - new Position(2, 17) - ) + rangeInSource: Range::from( + new Position(2, 11), + new Position(2, 17) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 13), - new Position(2, 15) - ) + rangeInSource: Range::from( + new Position(2, 13), + new Position(2, 15) ), value: 'tue' ) ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 19) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 19) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 12) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 12) ), value: EnumMemberName::from('WEDNESDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 13), - new Position(3, 19) - ) + rangeInSource: Range::from( + new Position(3, 13), + new Position(3, 19) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 15), - new Position(3, 17) - ) + rangeInSource: Range::from( + new Position(3, 15), + new Position(3, 17) ), value: 'wed' ) ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 18) - ) + rangeInSource: Range::from( + new Position(4, 4), + new Position(4, 18) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 11) - ) + rangeInSource: Range::from( + new Position(4, 4), + new Position(4, 11) ), value: EnumMemberName::from('THURSDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 12), - new Position(4, 18) - ) + rangeInSource: Range::from( + new Position(4, 12), + new Position(4, 18) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 14), - new Position(4, 16) - ) + rangeInSource: Range::from( + new Position(4, 14), + new Position(4, 16) ), value: 'thu' ) ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 16) - ) + rangeInSource: Range::from( + new Position(5, 4), + new Position(5, 16) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 9) - ) + rangeInSource: Range::from( + new Position(5, 4), + new Position(5, 9) ), value: EnumMemberName::from('FRIDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 10), - new Position(5, 16) - ) + rangeInSource: Range::from( + new Position(5, 10), + new Position(5, 16) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 12), - new Position(5, 14) - ) + rangeInSource: Range::from( + new Position(5, 12), + new Position(5, 14) ), value: 'fri' ) ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 18) - ) + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 18) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 11) - ) + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 11) ), value: EnumMemberName::from('SATURDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 12), - new Position(6, 18) - ) + rangeInSource: Range::from( + new Position(6, 12), + new Position(6, 18) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 14), - new Position(6, 16) - ) + rangeInSource: Range::from( + new Position(6, 14), + new Position(6, 16) ), value: 'sat' ) ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 16) - ) + rangeInSource: Range::from( + new Position(7, 4), + new Position(7, 16) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 9) - ) + rangeInSource: Range::from( + new Position(7, 4), + new Position(7, 9) ), value: EnumMemberName::from('SUNDAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 10), - new Position(7, 16) - ) + rangeInSource: Range::from( + new Position(7, 10), + new Position(7, 16) ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 12), - new Position(7, 14) - ) + rangeInSource: Range::from( + new Position(7, 12), + new Position(7, 14) ), value: 'sun' ) @@ -543,51 +446,39 @@ public function oneBinaryIntegerValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0b101) }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 20) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) ), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 19) ), format: IntegerFormat::BINARY, value: '0b101' @@ -612,51 +503,39 @@ public function oneOctalIntegerValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0o644) }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 20) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) ), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 19) ), format: IntegerFormat::OCTAL, value: '0o644' @@ -681,51 +560,39 @@ public function oneDecimalIntegerValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(42) }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 19) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 17) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 17) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) ), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 17) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 17) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 16) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 16) ), format: IntegerFormat::DECIMAL, value: '42' @@ -750,51 +617,39 @@ public function oneHexadecimalIntegerValueMember(): void $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0xABC) }'))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 20) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) ), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 19) ), format: IntegerFormat::HEXADECIMAL, value: '0xABC' @@ -835,51 +690,39 @@ enum Month { $tokens = Tokenizer::fromSource(Source::fromString($enumAsString))->getIterator(); $expectedEnumDeclarationNode = new EnumDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(13, 0) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(13, 0) ), name: new EnumNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 9) ), value: EnumName::from('Month') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 13) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 13) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 10) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 10) ), value: EnumMemberName::from('JANUARY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 11), - new Position(1, 13) - ) + rangeInSource: Range::from( + new Position(1, 11), + new Position(1, 13) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 12), - new Position(1, 12) - ) + rangeInSource: Range::from( + new Position(1, 12), + new Position(1, 12) ), format: IntegerFormat::DECIMAL, value: '1' @@ -887,34 +730,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 14) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 14) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 11) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 11) ), value: EnumMemberName::from('FEBRUARY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 12), - new Position(2, 14) - ) + rangeInSource: Range::from( + new Position(2, 12), + new Position(2, 14) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 13), - new Position(2, 13) - ) + rangeInSource: Range::from( + new Position(2, 13), + new Position(2, 13) ), format: IntegerFormat::DECIMAL, value: '2' @@ -922,34 +757,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 11) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 11) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 8) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 8) ), value: EnumMemberName::from('MARCH') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 9), - new Position(3, 11) - ) + rangeInSource: Range::from( + new Position(3, 9), + new Position(3, 11) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 10) - ) + rangeInSource: Range::from( + new Position(3, 10), + new Position(3, 10) ), format: IntegerFormat::DECIMAL, value: '3' @@ -957,34 +784,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 11) - ) + rangeInSource: Range::from( + new Position(4, 4), + new Position(4, 11) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 8) - ) + rangeInSource: Range::from( + new Position(4, 4), + new Position(4, 8) ), value: EnumMemberName::from('APRIL') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 9), - new Position(4, 11) - ) + rangeInSource: Range::from( + new Position(4, 9), + new Position(4, 11) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 10), - new Position(4, 10) - ) + rangeInSource: Range::from( + new Position(4, 10), + new Position(4, 10) ), format: IntegerFormat::DECIMAL, value: '4' @@ -992,34 +811,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 9) - ) + rangeInSource: Range::from( + new Position(5, 4), + new Position(5, 9) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 6) - ) + rangeInSource: Range::from( + new Position(5, 4), + new Position(5, 6) ), value: EnumMemberName::from('MAY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 7), - new Position(5, 9) - ) + rangeInSource: Range::from( + new Position(5, 7), + new Position(5, 9) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 8), - new Position(5, 8) - ) + rangeInSource: Range::from( + new Position(5, 8), + new Position(5, 8) ), format: IntegerFormat::DECIMAL, value: '5' @@ -1027,34 +838,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 10) - ) + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 10) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 7) - ) + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 7) ), value: EnumMemberName::from('JUNE') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 8), - new Position(6, 10) - ) + rangeInSource: Range::from( + new Position(6, 8), + new Position(6, 10) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 9), - new Position(6, 9) - ) + rangeInSource: Range::from( + new Position(6, 9), + new Position(6, 9) ), format: IntegerFormat::DECIMAL, value: '6' @@ -1062,34 +865,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 10) - ) + rangeInSource: Range::from( + new Position(7, 4), + new Position(7, 10) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 7) - ) + rangeInSource: Range::from( + new Position(7, 4), + new Position(7, 7) ), value: EnumMemberName::from('JULY') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 8), - new Position(7, 10) - ) + rangeInSource: Range::from( + new Position(7, 8), + new Position(7, 10) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(7, 9), - new Position(7, 9) - ) + rangeInSource: Range::from( + new Position(7, 9), + new Position(7, 9) ), format: IntegerFormat::DECIMAL, value: '7' @@ -1097,34 +892,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(8, 4), - new Position(8, 12) - ) + rangeInSource: Range::from( + new Position(8, 4), + new Position(8, 12) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(8, 4), - new Position(8, 9) - ) + rangeInSource: Range::from( + new Position(8, 4), + new Position(8, 9) ), value: EnumMemberName::from('AUGUST') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(8, 10), - new Position(8, 12) - ) + rangeInSource: Range::from( + new Position(8, 10), + new Position(8, 12) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(8, 11), - new Position(8, 11) - ) + rangeInSource: Range::from( + new Position(8, 11), + new Position(8, 11) ), format: IntegerFormat::DECIMAL, value: '8' @@ -1132,34 +919,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(9, 4), - new Position(9, 15) - ) + rangeInSource: Range::from( + new Position(9, 4), + new Position(9, 15) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(9, 4), - new Position(9, 12) - ) + rangeInSource: Range::from( + new Position(9, 4), + new Position(9, 12) ), value: EnumMemberName::from('SEPTEMBER') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(9, 13), - new Position(9, 15) - ) + rangeInSource: Range::from( + new Position(9, 13), + new Position(9, 15) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(9, 14), - new Position(9, 14) - ) + rangeInSource: Range::from( + new Position(9, 14), + new Position(9, 14) ), format: IntegerFormat::DECIMAL, value: '9' @@ -1167,34 +946,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(10, 4), - new Position(10, 14) - ) + rangeInSource: Range::from( + new Position(10, 4), + new Position(10, 14) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(10, 4), - new Position(10, 10) - ) + rangeInSource: Range::from( + new Position(10, 4), + new Position(10, 10) ), value: EnumMemberName::from('OCTOBER') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(10, 11), - new Position(10, 14) - ) + rangeInSource: Range::from( + new Position(10, 11), + new Position(10, 14) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(10, 12), - new Position(10, 13) - ) + rangeInSource: Range::from( + new Position(10, 12), + new Position(10, 13) ), format: IntegerFormat::DECIMAL, value: '10' @@ -1202,34 +973,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(11, 4), - new Position(11, 15) - ) + rangeInSource: Range::from( + new Position(11, 4), + new Position(11, 15) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(11, 4), - new Position(11, 11) - ) + rangeInSource: Range::from( + new Position(11, 4), + new Position(11, 11) ), value: EnumMemberName::from('NOVEMBER') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(11, 12), - new Position(11, 15) - ) + rangeInSource: Range::from( + new Position(11, 12), + new Position(11, 15) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(11, 13), - new Position(11, 14) - ) + rangeInSource: Range::from( + new Position(11, 13), + new Position(11, 14) ), format: IntegerFormat::DECIMAL, value: '11' @@ -1237,34 +1000,26 @@ enum Month { ) ), new EnumMemberDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(12, 4), - new Position(12, 15) - ) + rangeInSource: Range::from( + new Position(12, 4), + new Position(12, 15) ), name: new EnumMemberNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(12, 4), - new Position(12, 11) - ) + rangeInSource: Range::from( + new Position(12, 4), + new Position(12, 11) ), value: EnumMemberName::from('DECEMBER') ), value: new EnumMemberValueNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(12, 12), - new Position(12, 15) - ) + rangeInSource: Range::from( + new Position(12, 12), + new Position(12, 15) ), value: new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(12, 13), - new Position(12, 14) - ) + rangeInSource: Range::from( + new Position(12, 13), + new Position(12, 14) ), format: IntegerFormat::DECIMAL, value: '12' diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index c01a87a0..f984bb8b 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -25,7 +25,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -43,11 +42,9 @@ public function binaryInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('0b1010110101'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 11) ), format: IntegerFormat::BINARY, value: '0b1010110101' @@ -68,11 +65,9 @@ public function octalInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('0o755'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) ), format: IntegerFormat::OCTAL, value: '0o755' @@ -93,11 +88,9 @@ public function decimalInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('1234567890'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 9) ), format: IntegerFormat::DECIMAL, value: '1234567890' @@ -118,11 +111,9 @@ public function hexadecimalInteger(): void $tokens = Tokenizer::fromSource(Source::fromString('0x123456789ABCDEF'))->getIterator(); $expectedIntegerLiteralNode = new IntegerLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 16) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 16) ), format: IntegerFormat::HEXADECIMAL, value: '0x123456789ABCDEF' diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index 2d90535c..ea87cce9 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -24,7 +24,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -42,11 +41,9 @@ public function producesAstNodeForNullIfGivenOneNullToken(): void $tokens = Tokenizer::fromSource(Source::fromString('null'))->getIterator(); $expectedNullLiteralNode = new NullLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 3) ) ); diff --git a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php index 8180d821..a282ff90 100644 --- a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php +++ b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php @@ -30,7 +30,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration\PropertyDeclarationParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -48,35 +47,27 @@ public function parsesPropertyDeclarationWithSimpleType(): void $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar'))->getIterator(); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 7) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: TypeName::from('Bar') ) @@ -101,35 +92,27 @@ public function parsesPropertyDeclarationWithOptionalType(): void $tokens = Tokenizer::fromSource(Source::fromString('foo: ?Bar'))->getIterator(); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 8) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 8) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 8) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 8) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 6), - new Position(0, 8) - ) + rangeInSource: Range::from( + new Position(0, 6), + new Position(0, 8) ), value: TypeName::from('Bar') ) @@ -154,35 +137,27 @@ public function parsesPropertyDeclarationWithArrayType(): void $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar[]'))->getIterator(); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 9) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 9) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: TypeName::from('Bar') ) @@ -207,53 +182,41 @@ public function parsesPropertyDeclarationWithUnionType(): void $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar|Baz|Qux'))->getIterator(); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 15) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 15) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: TypeName::from('Bar') ), new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 9), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 9), + new Position(0, 11) ), value: TypeName::from('Baz') ), new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 15) ), value: TypeName::from('Qux') ) diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 2d88c6c1..ec3024c3 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -24,7 +24,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -42,11 +41,9 @@ public function producesStringLiteralNodeForLiteralString(): void $tokens = Tokenizer::fromSource(Source::fromString('"Hello World"'))->getIterator(); $expectedStringLiteralNode = new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 11) ), value: 'Hello World' ); diff --git a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php index 05c72570..5097dd01 100644 --- a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php +++ b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php @@ -34,7 +34,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\StructDeclaration\StructDeclarationParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -52,52 +51,40 @@ public function parsesStructDeclarationOnSingleLineWithOneProperty(): void $tokens = Tokenizer::fromSource(Source::fromString('struct Foo { bar: Baz }'))->getIterator(); $expectedStructDeclarationNode = new StructDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), name: new StructNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) ), value: StructName::from('Foo') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 20) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 15) ), value: PropertyName::from('bar') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) ), value: TypeName::from('Baz') ) @@ -124,52 +111,40 @@ public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): voi $tokens = Tokenizer::fromSource(Source::fromString('struct Foo { bar: Baz qux: Quux corge: Grault }'))->getIterator(); $expectedStructDeclarationNode = new StructDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 46) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 46) ), name: new StructNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) ), value: StructName::from('Foo') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 20) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 15) ), value: PropertyName::from('bar') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 20) ), value: TypeName::from('Baz') ) @@ -179,35 +154,27 @@ public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): voi ) ), new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 22), - new Position(0, 30) - ) + rangeInSource: Range::from( + new Position(0, 22), + new Position(0, 30) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 22), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 22), + new Position(0, 24) ), value: PropertyName::from('qux') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 30) - ) + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 30) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 30) - ) + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 30) ), value: TypeName::from('Quux') ) @@ -217,35 +184,27 @@ public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): voi ) ), new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 32), - new Position(0, 44) - ) + rangeInSource: Range::from( + new Position(0, 32), + new Position(0, 44) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 32), - new Position(0, 36) - ) + rangeInSource: Range::from( + new Position(0, 32), + new Position(0, 36) ), value: PropertyName::from('corge') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 39), - new Position(0, 44) - ) + rangeInSource: Range::from( + new Position(0, 39), + new Position(0, 44) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 39), - new Position(0, 44) - ) + rangeInSource: Range::from( + new Position(0, 39), + new Position(0, 44) ), value: TypeName::from('Grault') ) @@ -278,52 +237,40 @@ public function parsesStructDeclarationOnMultipleLinesWithMultipleProperties(): $tokens = Tokenizer::fromSource(Source::fromString($structAsString))->getIterator(); $expectedStructDeclarationNode = new StructDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(3, 0) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(3, 0) ), name: new StructNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 10) ), value: StructName::from('Link') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 15) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 15) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 7) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 7) ), value: PropertyName::from('href') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 10), - new Position(1, 15) - ) + rangeInSource: Range::from( + new Position(1, 10), + new Position(1, 15) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 10), - new Position(1, 15) - ) + rangeInSource: Range::from( + new Position(1, 10), + new Position(1, 15) ), value: TypeName::from('string') ) @@ -333,35 +280,27 @@ public function parsesStructDeclarationOnMultipleLinesWithMultipleProperties(): ) ), new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 17) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 17) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 9) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 9) ), value: PropertyName::from('target') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 12), - new Position(2, 17) - ) + rangeInSource: Range::from( + new Position(2, 12), + new Position(2, 17) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 12), - new Position(2, 17) - ) + rangeInSource: Range::from( + new Position(2, 12), + new Position(2, 17) ), value: TypeName::from('string') ) @@ -399,52 +338,40 @@ public function parsesStructDeclarationOnMultipleLinesWithMultiplePropertiesAndS $tokens = Tokenizer::fromSource(Source::fromString($structAsString))->getIterator(); $expectedStructDeclarationNode = new StructDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(8, 0) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(8, 0) ), name: new StructNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 10) ), value: StructName::from('Link') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 15) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 15) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 7) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 7) ), value: PropertyName::from('href') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 15) - ) + rangeInSource: Range::from( + new Position(3, 10), + new Position(3, 15) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 15) - ) + rangeInSource: Range::from( + new Position(3, 10), + new Position(3, 15) ), value: TypeName::from('string') ) @@ -454,35 +381,27 @@ public function parsesStructDeclarationOnMultipleLinesWithMultiplePropertiesAndS ) ), new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 17) - ) + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 17) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 9) - ) + rangeInSource: Range::from( + new Position(6, 4), + new Position(6, 9) ), value: PropertyName::from('target') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 12), - new Position(6, 17) - ) + rangeInSource: Range::from( + new Position(6, 12), + new Position(6, 17) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 12), - new Position(6, 17) - ) + rangeInSource: Range::from( + new Position(6, 12), + new Position(6, 17) ), value: TypeName::from('string') ) @@ -516,52 +435,40 @@ public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionPr $tokens = Tokenizer::fromSource(Source::fromString($structAsString))->getIterator(); $expectedStructDeclarationNode = new StructDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(4, 0) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(4, 0) ), name: new StructNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 13) ), value: StructName::from('Picture') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 16) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 16) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 6) - ) + rangeInSource: Range::from( + new Position(1, 4), + new Position(1, 6) ), value: PropertyName::from('src') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 9), - new Position(1, 16) - ) + rangeInSource: Range::from( + new Position(1, 9), + new Position(1, 16) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(1, 9), - new Position(1, 14) - ) + rangeInSource: Range::from( + new Position(1, 9), + new Position(1, 14) ), value: TypeName::from('string') ) @@ -571,53 +478,41 @@ public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionPr ) ), new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 39) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 39) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 14) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 14) ), value: PropertyName::from('description') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 17), - new Position(2, 39) - ) + rangeInSource: Range::from( + new Position(2, 17), + new Position(2, 39) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 17), - new Position(2, 22) - ) + rangeInSource: Range::from( + new Position(2, 17), + new Position(2, 22) ), value: TypeName::from('string') ), new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 24), - new Position(2, 27) - ) + rangeInSource: Range::from( + new Position(2, 24), + new Position(2, 27) ), value: TypeName::from('slot') ), new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 29), - new Position(2, 39) - ) + rangeInSource: Range::from( + new Position(2, 29), + new Position(2, 39) ), value: TypeName::from('Description') ) @@ -627,35 +522,27 @@ public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionPr ) ), new PropertyDeclarationNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 17) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 17) ), name: new PropertyNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 8) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 8) ), value: PropertyName::from('title') ), type: new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 11), - new Position(3, 17) - ) + rangeInSource: Range::from( + new Position(3, 11), + new Position(3, 17) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 12), - new Position(3, 17) - ) + rangeInSource: Range::from( + new Position(3, 12), + new Position(3, 17) ), value: TypeName::from('string') ) diff --git a/test/Unit/Language/Parser/Tag/TagParserTest.php b/test/Unit/Language/Parser/Tag/TagParserTest.php index a774bc85..f59ffa10 100644 --- a/test/Unit/Language/Parser/Tag/TagParserTest.php +++ b/test/Unit/Language/Parser/Tag/TagParserTest.php @@ -33,7 +33,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagCouldNotBeParsed; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -53,18 +52,14 @@ public function parsesSelfClosingTagWithoutAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 3) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), @@ -88,35 +83,27 @@ public function parsesSelfClosingTagWithValuelessAttribute(): void $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 11) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) ), value: TagName::from('table') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 7), new Position(0, 9) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) ), value: AttributeName::from('foo') ), @@ -142,71 +129,55 @@ public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 19) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) ), value: TagName::from('table') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 7), new Position(0, 9) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) ), value: AttributeName::from('foo') ), value: null ), new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) ), value: AttributeName::from('bar') ), value: null ), new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 15), new Position(0, 17) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ) ), value: AttributeName::from('baz') ), @@ -232,44 +203,34 @@ public function parsesSelfClosingTagWithStringAttribute(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 13) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 10) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) ), value: AttributeName::from('foo') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 8), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 8), + new Position(0, 10) ), value: 'bar' ) @@ -294,96 +255,74 @@ public function parsesSelfClosingTagWithMultipleStringAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 38) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 38) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) ), value: TagName::from('div') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 12) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 12) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 7) ), value: AttributeName::from('foo') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 10), - new Position(0, 12) - ) + rangeInSource: Range::from( + new Position(0, 10), + new Position(0, 12) ), value: 'bar' ) ), new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 22) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 17) ), value: AttributeName::from('baz') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 20), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 20), + new Position(0, 22) ), value: 'qux' ) ), new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 25), - new Position(0, 35) - ) + rangeInSource: Range::from( + new Position(0, 25), + new Position(0, 35) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 25), - new Position(0, 28) - ) + rangeInSource: Range::from( + new Position(0, 25), + new Position(0, 28) ), value: AttributeName::from('quux') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 31), - new Position(0, 35) - ) + rangeInSource: Range::from( + new Position(0, 31), + new Position(0, 35) ), value: 'corge' ) @@ -408,18 +347,14 @@ public function parsesTagWithEmptyContentAndWithoutAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 6) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 6) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), @@ -466,35 +401,27 @@ public function parsesTagWithEmptyContentAndValuelessAttribute(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 3), new Position(0, 5) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ) ), value: AttributeName::from('foo') ), @@ -520,71 +447,55 @@ public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 18) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 18) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 3), new Position(0, 5) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ) ), value: AttributeName::from('foo') ), value: null ), new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 7), new Position(0, 9) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) ), value: AttributeName::from('bar') ), value: null ), new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 13) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 11), new Position(0, 13) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ) ), value: AttributeName::from('baz') ), @@ -610,44 +521,34 @@ public function parsesTagWithEmptyContentAndStringAttribute(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 24) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) ), value: TagName::from('audio') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 14) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 14) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) ), value: AttributeName::from('foo') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 12), - new Position(0, 14) - ) + rangeInSource: Range::from( + new Position(0, 12), + new Position(0, 14) ), value: 'bar' ) @@ -672,96 +573,74 @@ public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 47) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 47) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 5) ), value: TagName::from('video') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 14) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 14) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 9) ), value: AttributeName::from('foo') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 12), - new Position(0, 14) - ) + rangeInSource: Range::from( + new Position(0, 12), + new Position(0, 14) ), value: 'bar' ) ), new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 17), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 17), + new Position(0, 24) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 17), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 17), + new Position(0, 19) ), value: AttributeName::from('baz') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 22), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 22), + new Position(0, 24) ), value: 'qux' ) ), new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 37) - ) + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 37) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 30) - ) + rangeInSource: Range::from( + new Position(0, 27), + new Position(0, 30) ), value: AttributeName::from('quux') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 33), - new Position(0, 37) - ) + rangeInSource: Range::from( + new Position(0, 33), + new Position(0, 37) ), value: 'corge' ) @@ -786,29 +665,23 @@ public function parsesTagWithTextContentAndWithoutAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString('Lorem ipsum...'))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 20) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 16) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 16) ), value: 'Lorem ipsum...' ) @@ -831,36 +704,28 @@ public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 6) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 6) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) ), value: TagName::from('b') ), @@ -887,36 +752,28 @@ public function parsesTagWithNestedTagAndWithoutAttributes(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 13) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 9) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) ), value: TagName::from('b') ), @@ -943,72 +800,56 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 24) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 20) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) ), value: TagName::from('b') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 6), - new Position(0, 16) - ) + rangeInSource: Range::from( + new Position(0, 6), + new Position(0, 16) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 7) ), value: TagName::from('c') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 9), - new Position(0, 12) - ) + rangeInSource: Range::from( + new Position(0, 9), + new Position(0, 12) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 10), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 10), + new Position(0, 10) ), value: TagName::from('d') ), @@ -1041,36 +882,28 @@ public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): voi $tokens = Tokenizer::fromSource(Source::fromString(' '))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 19) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 19) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 6), - new Position(0, 12) - ) + rangeInSource: Range::from( + new Position(0, 6), + new Position(0, 12) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 7), + new Position(0, 7) ), value: TagName::from('b') ), @@ -1097,56 +930,44 @@ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundT $tokens = Tokenizer::fromSource(Source::fromString('Something important happened.'))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 42) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 42) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 12) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 12) ), value: 'Something ' ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 28) - ) + rangeInSource: Range::from( + new Position(0, 13), + new Position(0, 28) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 14) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 14) ), value: TagName::from('b') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 16), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 16), + new Position(0, 24) ), value: 'important' ) @@ -1154,11 +975,9 @@ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundT isSelfClosing: false ), new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 29), - new Position(0, 38) - ) + rangeInSource: Range::from( + new Position(0, 29), + new Position(0, 38) ), value: ' happened.' ) @@ -1181,36 +1000,28 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 24) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 24) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 9) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 4) ), value: TagName::from('b') ), @@ -1219,18 +1030,14 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void isSelfClosing: false ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 10), - new Position(0, 13) - ) + rangeInSource: Range::from( + new Position(0, 10), + new Position(0, 13) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 11), + new Position(0, 11) ), value: TagName::from('c') ), @@ -1239,18 +1046,14 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void isSelfClosing: true ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ) + rangeInSource: Range::from( + new Position(0, 14), + new Position(0, 20) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 15), + new Position(0, 15) ), value: TagName::from('d') ), @@ -1288,61 +1091,47 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut $tokens = Tokenizer::fromSource(Source::fromString($tagAsString))->getIterator(); $expectedTagNode = new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(8, 5) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(8, 5) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) ), value: TagName::from('div') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 15) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 9) - ) + rangeInSource: Range::from( + new Position(0, 5), + new Position(0, 9) ), value: AttributeName::from('class') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 12), - new Position(0, 15) - ) + rangeInSource: Range::from( + new Position(0, 12), + new Position(0, 15) ), value: 'test' ) ), new AttributeNode( - attributes: new NodeAttributes( + rangeInSource: Range::from( + new Position(0, 18), + new Position(0, 23) + ), + name: new AttributeNameNode( rangeInSource: Range::from( new Position(0, 18), new Position(0, 23) - ) - ), - name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 23) - ) ), value: AttributeName::from('hidden') ), @@ -1351,38 +1140,30 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 25), - new Position(2, 3) - ) + rangeInSource: Range::from( + new Position(0, 25), + new Position(2, 3) ), value: 'Some opening text' ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 20) - ) + rangeInSource: Range::from( + new Position(2, 4), + new Position(2, 20) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 5), - new Position(2, 6) - ) + rangeInSource: Range::from( + new Position(2, 5), + new Position(2, 6) ), value: TagName::from('h1') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(2, 8), - new Position(2, 15) - ) + rangeInSource: Range::from( + new Position(2, 8), + new Position(2, 15) ), value: 'Headline' ), @@ -1390,70 +1171,54 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut isSelfClosing: false ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 59) - ) + rangeInSource: Range::from( + new Position(3, 4), + new Position(3, 59) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 5), - new Position(3, 5) - ) + rangeInSource: Range::from( + new Position(3, 5), + new Position(3, 5) ), value: TagName::from('a') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 7), - new Position(3, 23) - ) + rangeInSource: Range::from( + new Position(3, 7), + new Position(3, 23) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 7), - new Position(3, 10) - ) + rangeInSource: Range::from( + new Position(3, 7), + new Position(3, 10) ), value: AttributeName::from('href') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 13), - new Position(3, 23) - ) + rangeInSource: Range::from( + new Position(3, 13), + new Position(3, 23) ), value: 'about:blank' ) ), new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 26), - new Position(3, 39) - ) + rangeInSource: Range::from( + new Position(3, 26), + new Position(3, 39) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 26), - new Position(3, 31) - ) + rangeInSource: Range::from( + new Position(3, 26), + new Position(3, 31) ), value: AttributeName::from('target') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 34), - new Position(3, 39) - ) + rangeInSource: Range::from( + new Position(3, 34), + new Position(3, 39) ), value: '_blank' ) @@ -1461,11 +1226,9 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(3, 42), - new Position(3, 55) - ) + rangeInSource: Range::from( + new Position(3, 42), + new Position(3, 55) ), value: 'This is a link' ), @@ -1473,44 +1236,34 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut isSelfClosing: false ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 4), - new Position(6, 7) - ) + rangeInSource: Range::from( + new Position(4, 4), + new Position(6, 7) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 5), - new Position(4, 5) - ) + rangeInSource: Range::from( + new Position(4, 5), + new Position(4, 5) ), value: TagName::from('p') ), tagAttributes: new AttributeNodes( new AttributeNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 7), - new Position(4, 16) - ) + rangeInSource: Range::from( + new Position(4, 7), + new Position(4, 16) ), name: new AttributeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 7), - new Position(4, 11) - ) + rangeInSource: Range::from( + new Position(4, 7), + new Position(4, 11) ), value: AttributeName::from('class') ), value: new StringLiteralNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 14), - new Position(4, 16) - ) + rangeInSource: Range::from( + new Position(4, 14), + new Position(4, 16) ), value: 'rte' ) @@ -1518,38 +1271,30 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(4, 19), - new Position(5, 32) - ) + rangeInSource: Range::from( + new Position(4, 19), + new Position(5, 32) ), value: 'This is a paragraph with ' ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 33), - new Position(5, 51) - ) + rangeInSource: Range::from( + new Position(5, 33), + new Position(5, 51) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 34), - new Position(5, 35) - ) + rangeInSource: Range::from( + new Position(5, 34), + new Position(5, 35) ), value: TagName::from('em') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 37), - new Position(5, 46) - ) + rangeInSource: Range::from( + new Position(5, 37), + new Position(5, 46) ), value: 'emphasized' ), @@ -1557,38 +1302,30 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut isSelfClosing: false ), new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 52), - new Position(5, 56) - ) + rangeInSource: Range::from( + new Position(5, 52), + new Position(5, 56) ), value: ' and ' ), new TagNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 57), - new Position(5, 81) - ) + rangeInSource: Range::from( + new Position(5, 57), + new Position(5, 81) ), name: new TagNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 58), - new Position(5, 63) - ) + rangeInSource: Range::from( + new Position(5, 58), + new Position(5, 63) ), value: TagName::from('strong') ), tagAttributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 65), - new Position(5, 72) - ) + rangeInSource: Range::from( + new Position(5, 65), + new Position(5, 72) ), value: 'boldened' ), @@ -1596,11 +1333,9 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut isSelfClosing: false ), new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(5, 82), - new Position(6, 3) - ) + rangeInSource: Range::from( + new Position(5, 82), + new Position(6, 3) ), value: ' text.' ) @@ -1608,11 +1343,9 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut isSelfClosing: false ), new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(6, 8), - new Position(7, 21) - ) + rangeInSource: Range::from( + new Position(6, 8), + new Position(7, 21) ), value: 'Some closing text' ), diff --git a/test/Unit/Language/Parser/Text/TextParserTest.php b/test/Unit/Language/Parser/Text/TextParserTest.php index 5e0531eb..63da880e 100644 --- a/test/Unit/Language/Parser/Text/TextParserTest.php +++ b/test/Unit/Language/Parser/Text/TextParserTest.php @@ -23,7 +23,6 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Text; use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Language\Parser\Text\TextParser; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -66,11 +65,9 @@ public function parsesTrivialText(): void $tokens = Tokenizer::fromSource(Source::fromString('Hello World'))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) ), value: 'Hello World' ); @@ -90,11 +87,9 @@ public function trimsLeadingAndTrailingSpaces(): void $tokens = Tokenizer::fromSource(Source::fromString(" \t\t Hello World \t\t "))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), value: 'Hello World' ); @@ -114,11 +109,9 @@ public function trimsLeadingLineBreak(): void $tokens = Tokenizer::fromSource(Source::fromString("\nHello World"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 10) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 10) ), value: 'Hello World' ); @@ -138,11 +131,9 @@ public function trimsLeadingLineBreakAndIndentation(): void $tokens = Tokenizer::fromSource(Source::fromString("\n Hello World"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 14) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 14) ), value: 'Hello World' ); @@ -162,11 +153,9 @@ public function preservesLeadingSpaceIfFlagIsSet(): void $tokens = Tokenizer::fromSource(Source::fromString(" \t\t Hello World \t\t "))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 22) ), value: ' Hello World' ); @@ -186,11 +175,9 @@ public function reducesInnerSpacesToSingleSpaceCharacterEach(): void $tokens = Tokenizer::fromSource(Source::fromString("Hello \t \n \t folks and\t\t\tpeople"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 22) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 22) ), value: 'Hello folks and people' ); @@ -210,11 +197,9 @@ public function terminatesAtEmbeddedExpressionAndTrimsLeadingSpace(): void $tokens = Tokenizer::fromSource(Source::fromString(" Hello{"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 8) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 8) ), value: 'Hello' ); @@ -234,11 +219,9 @@ public function terminatesAtEmbeddedExpressionAndKeepsTrailingSpace(): void $tokens = Tokenizer::fromSource(Source::fromString("Hello \t {foo}!"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 7) ), value: 'Hello ' ); @@ -258,11 +241,9 @@ public function terminatesAtEmbeddedExpressionAndTrimsTrailingSpaceIfItContainsL $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t {foo}!"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 1) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 1) ), value: 'Hello' ); @@ -293,11 +274,9 @@ public function terminatesAtOpeningTagAndTrimsLeadingSpace(): void $tokens = Tokenizer::fromSource(Source::fromString(" Hello"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 8) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 8) ), value: 'Hello' ); @@ -317,11 +296,9 @@ public function terminatesAtOpeningTagAndKeepsTrailingSpace(): void $tokens = Tokenizer::fromSource(Source::fromString("Hello \t World"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 7) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 7) ), value: 'Hello ' ); @@ -341,11 +318,9 @@ public function terminatesAtOpeningTagAndTrimsTrailingSpaceIfItContainsLineBreak $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t World"))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 1) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 1) ), value: 'Hello' ); @@ -376,11 +351,9 @@ public function terminatesAtClosingTagAndTrimsTrailingSpace(): void $tokens = Tokenizer::fromSource(Source::fromString("World \n\t "))->getIterator(); $expectedTextNode = new TextNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 1) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(1, 1) ), value: 'World' ); diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index b4aa1db7..00c20dc1 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -30,7 +30,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceCouldNotBeParsed; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -50,19 +49,15 @@ public function producesAstNodeForSimpleTypeReference(): void $tokens = Tokenizer::fromSource(Source::fromString('Foo'))->getIterator(); $expectedTypeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: TypeName::from('Foo') ) @@ -86,19 +81,15 @@ public function producesAstNodeForArrayTypeReference(): void $tokens = Tokenizer::fromSource(Source::fromString('Foo[]'))->getIterator(); $expectedTypeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: TypeName::from('Foo') ) @@ -122,19 +113,15 @@ public function producesAstNodeForOptionalTypeReference(): void $tokens = Tokenizer::fromSource(Source::fromString('?Foo'))->getIterator(); $expectedTypeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 3) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ) + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 3) ), value: TypeName::from('Foo') ) @@ -158,37 +145,29 @@ public function producesAstNodeForUnionTypeReference(): void $tokens = Tokenizer::fromSource(Source::fromString('Foo|Bar|Baz'))->getIterator(); $expectedTypeReferenceNode = new TypeReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 10) ), names: new TypeNameNodes( new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), value: TypeName::from('Foo') ), new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 6) - ) + rangeInSource: Range::from( + new Position(0, 4), + new Position(0, 6) ), value: TypeName::from('Bar') ), new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 8), - new Position(0, 10) - ) + rangeInSource: Range::from( + new Position(0, 8), + new Position(0, 10) ), value: TypeName::from('Baz') ) @@ -216,11 +195,9 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( cause: InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( affectedTypeNames: new TypeNames(TypeName::from('Foo')), - attributesOfAffectedNode: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ) + affectedRangeInSource: Range::from( + new Position(0, 0), + new Position(0, 4) ), ) ) @@ -242,11 +219,9 @@ public function throwsParserExceptionWhenDuplicatesOccur(): void TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeTypeNameNodes( cause: InvalidTypeNameNodes::becauseTheyContainDuplicates( duplicateTypeNameNode: new TypeNameNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 9), - new Position(0, 11) - ) + rangeInSource: Range::from( + new Position(0, 9), + new Position(0, 11) ), value: TypeName::from('Foo') ) diff --git a/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php b/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php index 13c6b0ec..72229252 100644 --- a/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php +++ b/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php @@ -25,7 +25,6 @@ use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\ValueReference\ValueReferenceParser; -use PackageFactory\ComponentEngine\Language\AST\NodeAttributes\NodeAttributes; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -43,11 +42,9 @@ public function parsesValueReference(): void $tokens = Tokenizer::fromSource(Source::fromString('foo'))->getIterator(); $expectedValueReferenceNode = new ValueReferenceNode( - attributes: new NodeAttributes( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ) + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 2) ), name: VariableName::from('foo') ); From 9098ce27be5be6b736bf96beb5178fbed9f65dd6 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 2 Aug 2023 21:56:23 +0200 Subject: [PATCH 44/64] TASK: Rename property tagAttributes of TagNode to attributes --- src/Language/AST/Node/Tag/TagNode.php | 2 +- src/Language/Parser/Tag/TagParser.php | 4 +- .../Language/Parser/Tag/TagParserTest.php | 66 +++++++++---------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/Language/AST/Node/Tag/TagNode.php b/src/Language/AST/Node/Tag/TagNode.php index 3410edb2..aa471551 100644 --- a/src/Language/AST/Node/Tag/TagNode.php +++ b/src/Language/AST/Node/Tag/TagNode.php @@ -30,7 +30,7 @@ final class TagNode extends Node public function __construct( public readonly Range $rangeInSource, public readonly TagNameNode $name, - public readonly AttributeNodes $tagAttributes, + public readonly AttributeNodes $attributes, public readonly ChildNodes $children, public readonly bool $isSelfClosing ) { diff --git a/src/Language/Parser/Tag/TagParser.php b/src/Language/Parser/Tag/TagParser.php index 44d073cd..a2297baf 100644 --- a/src/Language/Parser/Tag/TagParser.php +++ b/src/Language/Parser/Tag/TagParser.php @@ -66,7 +66,7 @@ public function parse(\Iterator $tokens): TagNode $tagSelfCloseToken->boundaries->end ), name: $tagNameNode, - tagAttributes: $attributeNodes, + attributes: $attributeNodes, children: new ChildNodes(), isSelfClosing: true ); @@ -83,7 +83,7 @@ public function parse(\Iterator $tokens): TagNode $closingTagEndToken->boundaries->end ), name: $tagNameNode, - tagAttributes: $attributeNodes, + attributes: $attributeNodes, children: $children, isSelfClosing: false ); diff --git a/test/Unit/Language/Parser/Tag/TagParserTest.php b/test/Unit/Language/Parser/Tag/TagParserTest.php index f59ffa10..18e7c240 100644 --- a/test/Unit/Language/Parser/Tag/TagParserTest.php +++ b/test/Unit/Language/Parser/Tag/TagParserTest.php @@ -63,7 +63,7 @@ public function parsesSelfClosingTagWithoutAttributes(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: true ); @@ -94,7 +94,7 @@ public function parsesSelfClosingTagWithValuelessAttribute(): void ), value: TagName::from('table') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 7), @@ -140,7 +140,7 @@ public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void ), value: TagName::from('table') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 7), @@ -214,7 +214,7 @@ public function parsesSelfClosingTagWithStringAttribute(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 3), @@ -266,7 +266,7 @@ public function parsesSelfClosingTagWithMultipleStringAttributes(): void ), value: TagName::from('div') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 5), @@ -358,7 +358,7 @@ public function parsesTagWithEmptyContentAndWithoutAttributes(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: false ); @@ -412,7 +412,7 @@ public function parsesTagWithEmptyContentAndValuelessAttribute(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 3), @@ -458,7 +458,7 @@ public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 3), @@ -532,7 +532,7 @@ public function parsesTagWithEmptyContentAndStringAttribute(): void ), value: TagName::from('audio') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 7), @@ -584,7 +584,7 @@ public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void ), value: TagName::from('video') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 7), @@ -676,7 +676,7 @@ public function parsesTagWithTextContentAndWithoutAttributes(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( rangeInSource: Range::from( @@ -715,7 +715,7 @@ public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -729,7 +729,7 @@ public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): ), value: TagName::from('b') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: true ) @@ -763,7 +763,7 @@ public function parsesTagWithNestedTagAndWithoutAttributes(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -777,7 +777,7 @@ public function parsesTagWithNestedTagAndWithoutAttributes(): void ), value: TagName::from('b') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: false ) @@ -811,7 +811,7 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -825,7 +825,7 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v ), value: TagName::from('b') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -839,7 +839,7 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v ), value: TagName::from('c') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -853,7 +853,7 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v ), value: TagName::from('d') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: true ) @@ -893,7 +893,7 @@ public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): voi ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -907,7 +907,7 @@ public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): voi ), value: TagName::from('b') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: false ) @@ -941,7 +941,7 @@ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundT ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( rangeInSource: Range::from( @@ -962,7 +962,7 @@ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundT ), value: TagName::from('b') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( rangeInSource: Range::from( @@ -1011,7 +1011,7 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( rangeInSource: Range::from( @@ -1025,7 +1025,7 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void ), value: TagName::from('b') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: false ), @@ -1041,7 +1041,7 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void ), value: TagName::from('c') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: true ), @@ -1057,7 +1057,7 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void ), value: TagName::from('d') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes(), isSelfClosing: false ), @@ -1102,7 +1102,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: TagName::from('div') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(0, 5), @@ -1158,7 +1158,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: TagName::from('h1') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( rangeInSource: Range::from( @@ -1182,7 +1182,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: TagName::from('a') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(3, 7), @@ -1247,7 +1247,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: TagName::from('p') ), - tagAttributes: new AttributeNodes( + attributes: new AttributeNodes( new AttributeNode( rangeInSource: Range::from( new Position(4, 7), @@ -1289,7 +1289,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: TagName::from('em') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( rangeInSource: Range::from( @@ -1320,7 +1320,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: TagName::from('strong') ), - tagAttributes: new AttributeNodes(), + attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( rangeInSource: Range::from( From 1d1e1011b69bf41f4468332f43ff9cca8dda7a6d Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 2 Aug 2023 22:43:04 +0200 Subject: [PATCH 45/64] TASK: Refactor TextParser after builder pattern --- src/Language/Parser/Text/TextParser.php | 142 ++++++++++++++++-------- 1 file changed, 98 insertions(+), 44 deletions(-) diff --git a/src/Language/Parser/Text/TextParser.php b/src/Language/Parser/Text/TextParser.php index 0aeaf065..040e80e8 100644 --- a/src/Language/Parser/Text/TextParser.php +++ b/src/Language/Parser/Text/TextParser.php @@ -30,6 +30,17 @@ final class TextParser { + private string $value; + + private ?Token $startingToken; + private ?Token $finalToken; + + private bool $trimLeadingSpace; + private bool $trimTrailingSpace; + private bool $currentlyCapturingSpace; + private bool $trailingSpaceContainsLineBreak; + private bool $terminated; + /** * @param \Iterator $tokens * @param boolean $preserveLeadingSpace @@ -37,66 +48,109 @@ final class TextParser */ public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?TextNode { - $value = ''; - $startingToken = null; - $finalToken = null; - $ignoreSpace = false; - $keepTrailingSpace = false; - $forceTrimTrailingSpace = false; - while (!Scanner::isEnd($tokens)) { - $startingToken ??= $tokens->current(); - switch (Scanner::type($tokens)) { - case TokenType::BRACKET_CURLY_OPEN: - case TokenType::TAG_START_OPENING: - $keepTrailingSpace = true; - break 2; - case TokenType::TAG_START_CLOSING: - $value = rtrim($value); - break 2; - case TokenType::SPACE: - case TokenType::END_OF_LINE: - if (!$ignoreSpace) { - $value .= ' '; - } - $ignoreSpace = true; - if (Scanner::type($tokens) === TokenType::END_OF_LINE) { - $forceTrimTrailingSpace = true; - } - $finalToken = $tokens->current(); - Scanner::skipOne($tokens); - break; - default: - $value .= Scanner::value($tokens); - $ignoreSpace = false; - $forceTrimTrailingSpace = false; - $finalToken = $tokens->current(); - Scanner::skipOne($tokens); - break; + $this->reset($preserveLeadingSpace); + + while (!Scanner::isEnd($tokens) && !$this->terminated) { + $this->startingToken ??= $tokens->current(); + + match (Scanner::type($tokens)) { + TokenType::BRACKET_CURLY_OPEN, + TokenType::TAG_START_OPENING => + $this->terminateAtAdjacentChildNode(), + TokenType::TAG_START_CLOSING => + $this->terminateAtClosingTag(), + TokenType::SPACE => + $this->captureSpace($tokens->current()), + TokenType::END_OF_LINE => + $this->captureLineBreak($tokens->current()), + default => + $this->captureText($tokens->current()), + }; + + if (!$this->terminated) { + Scanner::skipOne($tokens); } } - if (is_null($startingToken) || is_null($finalToken)) { + return $this->build(); + } + + private function reset(bool $preserveLeadingSpace): void + { + $this->value = ''; + + $this->startingToken = null; + $this->finalToken = null; + + $this->trimLeadingSpace = !$preserveLeadingSpace; + $this->trimTrailingSpace = true; + $this->currentlyCapturingSpace = false; + $this->trailingSpaceContainsLineBreak = false; + $this->terminated = false; + } + + private function terminateAtAdjacentChildNode(): void + { + $this->terminated = true; + $this->trimTrailingSpace = $this->trailingSpaceContainsLineBreak; + } + + private function terminateAtClosingTag(): void + { + $this->terminated = true; + } + + private function captureSpace(Token $token): void + { + $this->finalToken = $token; + + if ($this->currentlyCapturingSpace) { + return; + } + + $this->currentlyCapturingSpace = true; + $this->value .= ' '; + } + + private function captureLineBreak(Token $token): void + { + $this->captureSpace($token); + $this->trailingSpaceContainsLineBreak = true; + } + + private function captureText(Token $token): void + { + $this->finalToken = $token; + $this->currentlyCapturingSpace = false; + $this->trailingSpaceContainsLineBreak = false; + + $this->value .= $token->value; + } + + private function build(): ?TextNode + { + if (is_null($this->startingToken) || is_null($this->finalToken)) { return null; } - if (!$preserveLeadingSpace) { - $value = ltrim($value); + if ($this->trimLeadingSpace) { + $this->value = ltrim($this->value); } - if (!$keepTrailingSpace || $forceTrimTrailingSpace) { - $value = rtrim($value); + if ($this->trimTrailingSpace) { + $this->value = rtrim($this->value); } - if ($value === '' || $value === ' ') { + if ($this->value === '' || $this->value === ' ') { return null; } return new TextNode( rangeInSource: Range::from( - $startingToken->boundaries->start, - $finalToken->boundaries->end + $this->startingToken->boundaries->start, + $this->finalToken->boundaries->end ), - value: $value + value: $this->value ); } } From ac7f3ec182f9baabcb4e6c90c9a422ec0993f5ca Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 3 Aug 2023 20:47:48 +0200 Subject: [PATCH 46/64] TASK: Implement ExpressionParser (partially) --- .../AccessKeyNode.php} | 4 +- .../AccessNode.php} | 9 +- .../{AccessChain => Access}/AccessType.php | 2 +- .../AccessChain/AccessChainSegmentNodes.php | 36 - .../AST/Node/Expression/ExpressionNode.php | 4 +- .../TernaryOperation/TernaryOperationNode.php | 7 +- .../ExpressionCouldNotBeParsed.php} | 28 +- .../Parser/Expression/ExpressionParser.php | 498 ++++++ src/Parser/Tokenizer/Token.php | 7 +- src/Parser/Tokenizer/TokenType.php | 60 + src/Parser/Tokenizer/TokenTypes.php | 66 + .../Expression/ExpressionParserTest.php | 1357 +++++++++++++++++ test/Unit/Language/Parser/ParserTestCase.php | 58 + test/Unit/Parser/Tokenizer/TokenTest.php | 55 + test/Unit/Parser/Tokenizer/TokenTypesTest.php | 110 ++ test/Unit/Parser/Tokenizer/TokenizerTest.php | 97 ++ 16 files changed, 2342 insertions(+), 56 deletions(-) rename src/Language/AST/Node/{AccessChain/AccessChainSegmentKeyNode.php => Access/AccessKeyNode.php} (95%) rename src/Language/AST/Node/{AccessChain/AccessChainNode.php => Access/AccessNode.php} (87%) rename src/Language/AST/Node/{AccessChain => Access}/AccessType.php (99%) delete mode 100644 src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php rename src/Language/{AST/Node/AccessChain/AccessChainSegmentNode.php => Parser/Expression/ExpressionCouldNotBeParsed.php} (50%) create mode 100644 src/Language/Parser/Expression/ExpressionParser.php create mode 100644 src/Parser/Tokenizer/TokenTypes.php create mode 100644 test/Unit/Language/Parser/Expression/ExpressionParserTest.php create mode 100644 test/Unit/Language/Parser/ParserTestCase.php create mode 100644 test/Unit/Parser/Tokenizer/TokenTest.php create mode 100644 test/Unit/Parser/Tokenizer/TokenTypesTest.php diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php b/src/Language/AST/Node/Access/AccessKeyNode.php similarity index 95% rename from src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php rename to src/Language/AST/Node/Access/AccessKeyNode.php index eceb645b..0dd4858c 100644 --- a/src/Language/AST/Node/AccessChain/AccessChainSegmentKeyNode.php +++ b/src/Language/AST/Node/Access/AccessKeyNode.php @@ -20,13 +20,13 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; +namespace PackageFactory\ComponentEngine\Language\AST\Node\Access; use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Parser\Source\Range; -final class AccessChainSegmentKeyNode extends Node +final class AccessKeyNode extends Node { public function __construct( public readonly Range $rangeInSource, diff --git a/src/Language/AST/Node/AccessChain/AccessChainNode.php b/src/Language/AST/Node/Access/AccessNode.php similarity index 87% rename from src/Language/AST/Node/AccessChain/AccessChainNode.php rename to src/Language/AST/Node/Access/AccessNode.php index 328a6d77..50c31717 100644 --- a/src/Language/AST/Node/AccessChain/AccessChainNode.php +++ b/src/Language/AST/Node/Access/AccessNode.php @@ -20,18 +20,19 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; +namespace PackageFactory\ComponentEngine\Language\AST\Node\Access; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; use PackageFactory\ComponentEngine\Parser\Source\Range; -final class AccessChainNode extends Node +final class AccessNode extends Node { public function __construct( public readonly Range $rangeInSource, - public readonly ExpressionNode $root, - public readonly AccessChainSegmentNodes $chain + public readonly ExpressionNode $parent, + public readonly AccessType $type, + public readonly AccessKeyNode $key ) { } } diff --git a/src/Language/AST/Node/AccessChain/AccessType.php b/src/Language/AST/Node/Access/AccessType.php similarity index 99% rename from src/Language/AST/Node/AccessChain/AccessType.php rename to src/Language/AST/Node/Access/AccessType.php index 10d95cda..ee2fc74b 100644 --- a/src/Language/AST/Node/AccessChain/AccessType.php +++ b/src/Language/AST/Node/Access/AccessType.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; +namespace PackageFactory\ComponentEngine\Language\AST\Node\Access; enum AccessType: string { diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php b/src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php deleted file mode 100644 index 4e172b67..00000000 --- a/src/Language/AST/Node/AccessChain/AccessChainSegmentNodes.php +++ /dev/null @@ -1,36 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; - -final class AccessChainSegmentNodes -{ - /** - * @var AccessChainSegmentNode[] - */ - public readonly array $items; - - public function __construct(AccessChainSegmentNode ...$items) - { - $this->items = $items; - } -} diff --git a/src/Language/AST/Node/Expression/ExpressionNode.php b/src/Language/AST/Node/Expression/ExpressionNode.php index 34fabca3..d770a575 100644 --- a/src/Language/AST/Node/Expression/ExpressionNode.php +++ b/src/Language/AST/Node/Expression/ExpressionNode.php @@ -22,7 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\Expression; -use PackageFactory\ComponentEngine\Language\AST\Node\AccessChain\AccessChainNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessNode; use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; @@ -41,7 +41,7 @@ final class ExpressionNode extends Node { public function __construct( public readonly Range $rangeInSource, - public readonly AccessChainNode | BinaryOperationNode | BooleanLiteralNode | IntegerLiteralNode | MatchNode | NullLiteralNode | StringLiteralNode | TagNode | TemplateLiteralNode | TernaryOperationNode | UnaryOperationNode | ValueReferenceNode $root + public readonly AccessNode | BinaryOperationNode | BooleanLiteralNode | IntegerLiteralNode | MatchNode | NullLiteralNode | StringLiteralNode | TagNode | TemplateLiteralNode | TernaryOperationNode | UnaryOperationNode | ValueReferenceNode $root ) { } } diff --git a/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php b/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php index 88018eea..9c73556f 100644 --- a/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php +++ b/src/Language/AST/Node/TernaryOperation/TernaryOperationNode.php @@ -29,10 +29,15 @@ final class TernaryOperationNode extends Node { public function __construct( - public readonly Range $rangeInSource, public readonly ExpressionNode $condition, public readonly ExpressionNode $trueBranch, public readonly ExpressionNode $falseBranch ) { + parent::__construct( + rangeInSource: Range::from( + $condition->rangeInSource->start, + $falseBranch->rangeInSource->end + ) + ); } } diff --git a/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php b/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php similarity index 50% rename from src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php rename to src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php index b3dd166d..d3d4533c 100644 --- a/src/Language/AST/Node/AccessChain/AccessChainSegmentNode.php +++ b/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php @@ -20,17 +20,27 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Language\AST\Node\AccessChain; +namespace PackageFactory\ComponentEngine\Language\Parser\Expression; -use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; -final class AccessChainSegmentNode extends Node +final class ExpressionCouldNotBeParsed extends ParserException { - public function __construct( - public readonly Range $rangeInSource, - public readonly AccessType $accessType, - public readonly AccessChainSegmentKeyNode $key - ) { + public static function becauseOfUnexpectedToken( + TokenTypes $expectedTokenTypes, + Token $actualToken + ): self { + return new self( + code: 1691063089, + message: sprintf( + 'Expression could not be parsed because of unexpected token %s. ' + . 'Expected %s instead.', + $actualToken->toDebugString(), + $expectedTokenTypes->toDebugString() + ), + affectedRangeInSource: $actualToken->boundaries + ); } } diff --git a/src/Language/Parser/Expression/ExpressionParser.php b/src/Language/Parser/Expression/ExpressionParser.php new file mode 100644 index 00000000..fe794e03 --- /dev/null +++ b/src/Language/Parser/Expression/ExpressionParser.php @@ -0,0 +1,498 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Expression; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessKeyNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessType; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperator; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperator; +use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; +use PackageFactory\ComponentEngine\Language\Parser\ValueReference\ValueReferenceParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; + +final class ExpressionParser +{ + private readonly BooleanLiteralParser $booleanLiteralParser; + private readonly NullLiteralParser $nullLiteralParser; + private readonly StringLiteralParser $stringLiteralParser; + private readonly IntegerLiteralParser $integerLiteralParser; + private readonly ValueReferenceParser $valueReferenceParser; + private readonly TagParser $tagParser; + + public function __construct( + private ?TokenType $stopAt = null + ) { + $this->booleanLiteralParser = new BooleanLiteralParser(); + $this->nullLiteralParser = new NullLiteralParser(); + $this->stringLiteralParser = new StringLiteralParser(); + $this->integerLiteralParser = new IntegerLiteralParser(); + $this->valueReferenceParser = new ValueReferenceParser(); + $this->tagParser = new TagParser(); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + public function parse(\Iterator &$tokens): ExpressionNode + { + $result = $this->parseUnaryStatement($tokens); + + if ($this->shouldStop($tokens)) { + return $result; + } + + $result = match (Scanner::type($tokens)) { + TokenType::OPERATOR_BOOLEAN_AND, + TokenType::OPERATOR_BOOLEAN_OR, + TokenType::COMPARATOR_EQUAL, + TokenType::COMPARATOR_NOT_EQUAL, + TokenType::COMPARATOR_GREATER_THAN, + TokenType::COMPARATOR_GREATER_THAN_OR_EQUAL, + TokenType::COMPARATOR_LESS_THAN, + TokenType::COMPARATOR_LESS_THAN_OR_EQUAL => $this->parseBinaryOperation($tokens, $result), + default => $result + }; + + if ($this->shouldStop($tokens)) { + return $result; + } + + $result = match (Scanner::type($tokens)) { + TokenType::QUESTIONMARK => + $this->parseTernaryOperation($tokens, $result), + default => + throw ExpressionCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from(TokenType::QUESTIONMARK), + actualToken: $tokens->current() + ) + }; + + return $result; + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode + { + $result = match (Scanner::type($tokens)) { + TokenType::OPERATOR_BOOLEAN_NOT => + $this->parseUnaryOperation($tokens), + TokenType::KEYWORD_TRUE, + TokenType::KEYWORD_FALSE => + $this->parseBooleanLiteral($tokens), + TokenType::KEYWORD_NULL => + $this->parseNullLiteral($tokens), + TokenType::STRING_QUOTED => + $this->parseStringLiteral($tokens), + TokenType::NUMBER_BINARY, + TokenType::NUMBER_OCTAL, + TokenType::NUMBER_DECIMAL, + TokenType::NUMBER_HEXADECIMAL => + $this->parseIntegerLiteral($tokens), + TokenType::STRING => + $this->parseValueReference($tokens), + TokenType::TAG_START_OPENING => + $this->parseTag($tokens), + TokenType::BRACKET_ROUND_OPEN => + $this->parseBracketedExpression($tokens), + default => + throw ExpressionCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::KEYWORD_TRUE, + TokenType::KEYWORD_FALSE, + TokenType::KEYWORD_NULL, + TokenType::STRING_QUOTED, + TokenType::NUMBER_BINARY, + TokenType::NUMBER_OCTAL, + TokenType::NUMBER_DECIMAL, + TokenType::NUMBER_HEXADECIMAL, + TokenType::STRING, + TokenType::TAG_START_OPENING, + TokenType::BRACKET_ROUND_OPEN + ), + actualToken: $tokens->current() + ) + }; + + if (!Scanner::isEnd($tokens)) { + $result = match (Scanner::type($tokens)) { + TokenType::PERIOD, + TokenType::OPTCHAIN => $this->parseAcccess($tokens, $result), + default => $result + }; + } + + return $result; + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + public function parseUnaryOperation(\Iterator &$tokens): ExpressionNode + { + $startingToken = $tokens->current(); + + $operator = $this->parseUnaryOperator($tokens); + $operand = $this->parseUnaryStatement($tokens); + + $unaryOperationNode = new UnaryOperationNode( + rangeInSource: Range::from( + $startingToken->boundaries->start, + $operand->rangeInSource->end + ), + operator: $operator, + operand: $operand + ); + + return new ExpressionNode( + rangeInSource: $unaryOperationNode->rangeInSource, + root: $unaryOperationNode + ); + } + + /** + * @param \Iterator $tokens + * @return UnaryOperator + */ + private function parseUnaryOperator(\Iterator &$tokens): UnaryOperator + { + $unaryOperator = match (Scanner::type($tokens)) { + TokenType::OPERATOR_BOOLEAN_NOT => UnaryOperator::NOT, + default => throw ExpressionCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from(TokenType::OPERATOR_BOOLEAN_NOT), + actualToken: $tokens->current() + ) + }; + + Scanner::skipOne($tokens); + + return $unaryOperator; + } + + private function withStopAt(TokenType $stopAt): self + { + $newExpressionParser = clone $this; + $newExpressionParser->stopAt = $stopAt; + + return $newExpressionParser; + } + + /** + * @param \Iterator $tokens + * @return boolean + */ + private function shouldStop(\Iterator &$tokens): bool + { + Scanner::skipSpaceAndComments($tokens); + + if (is_null($this->stopAt)) { + return Scanner::isEnd($tokens); + } + + return Scanner::type($tokens) === $this->stopAt; + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseBooleanLiteral(\Iterator &$tokens): ExpressionNode + { + $booleanLiteralNode = $this->booleanLiteralParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $booleanLiteralNode->rangeInSource, + root: $booleanLiteralNode + ); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseNullLiteral(\Iterator &$tokens): ExpressionNode + { + $nullLiteralNode = $this->nullLiteralParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $nullLiteralNode->rangeInSource, + root: $nullLiteralNode + ); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseStringLiteral(\Iterator &$tokens): ExpressionNode + { + $stringLiteralNode = $this->stringLiteralParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $stringLiteralNode->rangeInSource, + root: $stringLiteralNode + ); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseIntegerLiteral(\Iterator &$tokens): ExpressionNode + { + $integerLiteralNode = $this->integerLiteralParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $integerLiteralNode->rangeInSource, + root: $integerLiteralNode + ); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseValueReference(\Iterator &$tokens): ExpressionNode + { + $valueReferenceNode = $this->valueReferenceParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $valueReferenceNode->rangeInSource, + root: $valueReferenceNode + ); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseTag(\Iterator &$tokens): ExpressionNode + { + $tagNode = $this->tagParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $tagNode->rangeInSource, + root: $tagNode + ); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseBracketedExpression(\Iterator &$tokens): ExpressionNode + { + Scanner::assertType($tokens, TokenType::BRACKET_ROUND_OPEN); + + $openingBracketToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + $innerExpressionNode = $this->withStopAt(TokenType::BRACKET_ROUND_CLOSE)->parse($tokens); + + Scanner::assertType($tokens, TokenType::BRACKET_ROUND_CLOSE); + + $closingBracketToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + return new ExpressionNode( + rangeInSource: Range::from( + $openingBracketToken->boundaries->start, + $closingBracketToken->boundaries->end + ), + root: $innerExpressionNode->root + ); + } + + /** + * @param \Iterator $tokens + * @param ExpressionNode $parent + * @return ExpressionNode + */ + private function parseAcccess(\Iterator &$tokens, ExpressionNode $parent): ExpressionNode + { + $accessTokenTypes = TokenTypes::from(TokenType::PERIOD, TokenType::OPTCHAIN); + + while (!Scanner::isEnd($tokens) && $accessTokenTypes->contains(Scanner::type($tokens))) { + $type = $this->parseAccessType($tokens); + + Scanner::assertType($tokens, TokenType::STRING); + $keyToken = $tokens->current(); + Scanner::skipOne($tokens); + + $rangeInSource = Range::from( + $parent->rangeInSource->start, + $keyToken->boundaries->end + ); + + $parent = new ExpressionNode( + rangeInSource: $rangeInSource, + root: new AccessNode( + rangeInSource: $rangeInSource, + parent: $parent, + type: $type, + key: new AccessKeyNode( + rangeInSource: $keyToken->boundaries, + value: PropertyName::from($keyToken->value) + ) + ) + ); + } + + return $parent; + } + + /** + * @param \Iterator $tokens + * @return AccessType + */ + private function parseAccessType(\Iterator &$tokens): AccessType + { + $accessType = match (Scanner::type($tokens)) { + TokenType::PERIOD => AccessType::MANDATORY, + TokenType::OPTCHAIN => AccessType::OPTIONAL, + default => throw ExpressionCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from(TokenType::PERIOD, TokenType::OPTCHAIN), + actualToken: $tokens->current() + ) + }; + + Scanner::skipOne($tokens); + + return $accessType; + } + + /** + * @param \Iterator $tokens + * @param ExpressionNode $leftOperand + * @return ExpressionNode + */ + private function parseBinaryOperation(\Iterator &$tokens, ExpressionNode $leftOperand): ExpressionNode + { + $operator = $this->parseBinaryOperator($tokens); + $rightOperand = $this->parse($tokens); + $rangeInSource = Range::from( + $leftOperand->rangeInSource->start, + $rightOperand->rangeInSource->end + ); + + return new ExpressionNode( + rangeInSource: $rangeInSource, + root: new BinaryOperationNode( + rangeInSource: $rangeInSource, + leftOperand: $leftOperand, + operator: $operator, + rightOperand: $rightOperand + ) + ); + } + + /** + * @param \Iterator $tokens + * @return BinaryOperator + */ + private function parseBinaryOperator(\Iterator &$tokens): BinaryOperator + { + $operator = match (Scanner::type($tokens)) { + TokenType::OPERATOR_BOOLEAN_AND => BinaryOperator::AND, + TokenType::OPERATOR_BOOLEAN_OR => BinaryOperator::OR, + TokenType::COMPARATOR_EQUAL => BinaryOperator::EQUAL, + TokenType::COMPARATOR_NOT_EQUAL => BinaryOperator::NOT_EQUAL, + TokenType::COMPARATOR_GREATER_THAN => BinaryOperator::GREATER_THAN, + TokenType::COMPARATOR_GREATER_THAN_OR_EQUAL => BinaryOperator::GREATER_THAN_OR_EQUAL, + TokenType::COMPARATOR_LESS_THAN => BinaryOperator::LESS_THAN, + TokenType::COMPARATOR_LESS_THAN_OR_EQUAL => BinaryOperator::LESS_THAN_OR_EQUAL, + default => throw ExpressionCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::OPERATOR_BOOLEAN_AND, + TokenType::OPERATOR_BOOLEAN_OR, + TokenType::COMPARATOR_EQUAL, + TokenType::COMPARATOR_NOT_EQUAL, + TokenType::COMPARATOR_GREATER_THAN, + TokenType::COMPARATOR_GREATER_THAN_OR_EQUAL, + TokenType::COMPARATOR_LESS_THAN, + TokenType::COMPARATOR_LESS_THAN_OR_EQUAL + ), + actualToken: $tokens->current() + ) + }; + + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + return $operator; + } + + /** + * @param \Iterator $tokens + * @param ExpressionNode $condition + * @return ExpressionNode + */ + private function parseTernaryOperation(\Iterator $tokens, ExpressionNode $condition): ExpressionNode + { + Scanner::assertType($tokens, TokenType::QUESTIONMARK); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + $trueBranch = $this->withStopAt(TokenType::COLON)->parse($tokens); + + Scanner::assertType($tokens, TokenType::COLON); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + $falseBranch = $this->parse($tokens); + + $root = new TernaryOperationNode( + condition: $condition, + trueBranch: $trueBranch, + falseBranch: $falseBranch + ); + + return new ExpressionNode( + rangeInSource: $root->rangeInSource, + root: $root + ); + } +} diff --git a/src/Parser/Tokenizer/Token.php b/src/Parser/Tokenizer/Token.php index 8fa8e49b..66b5eb08 100644 --- a/src/Parser/Tokenizer/Token.php +++ b/src/Parser/Tokenizer/Token.php @@ -28,7 +28,7 @@ final class Token { - private function __construct( + public function __construct( public readonly TokenType $type, public readonly string $value, public readonly Range $boundaries, @@ -65,4 +65,9 @@ public function __toString(): string { return $this->value; } + + public function toDebugString(): string + { + return sprintf('%s ("%s")', $this->type->value, $this->value); + } } diff --git a/src/Parser/Tokenizer/TokenType.php b/src/Parser/Tokenizer/TokenType.php index 694170b0..0c2b8fae 100644 --- a/src/Parser/Tokenizer/TokenType.php +++ b/src/Parser/Tokenizer/TokenType.php @@ -163,4 +163,64 @@ public function matchesString(string $string): bool default => false }; } + + public function toDebugString(): string + { + return $this->value . match ($this) { + self::COMMENT => ' (e.g. "# ...")', + self::KEYWORD_FROM => ' ("from")', + self::KEYWORD_IMPORT => ' ("import")', + self::KEYWORD_EXPORT => ' ("export")', + self::KEYWORD_ENUM => ' ("enum")', + self::KEYWORD_STRUCT => ' ("struct")', + self::KEYWORD_COMPONENT => ' ("component")', + self::KEYWORD_MATCH => ' ("match")', + self::KEYWORD_DEFAULT => ' ("default")', + self::KEYWORD_RETURN => ' ("return")', + self::KEYWORD_TRUE => ' ("true")', + self::KEYWORD_FALSE => ' ("false")', + self::KEYWORD_NULL => ' ("null")', + self::CONSTANT => '', + self::STRING => '', + self::STRING_QUOTED => '', + self::NUMBER_BINARY => ' (e.g. "0b1001")', + self::NUMBER_OCTAL => ' (e.g. "0o644")', + self::NUMBER_DECIMAL => ' (e.g. "42")', + self::NUMBER_HEXADECIMAL => ' (e.g. "0xABC")', + self::TEMPLATE_LITERAL_START => ' ("`")', + self::TEMPLATE_LITERAL_END => ' ("`")', + self::OPERATOR_BOOLEAN_AND => ' ("&&")', + self::OPERATOR_BOOLEAN_OR => ' ("||")', + self::OPERATOR_BOOLEAN_NOT => ' ("!")', + self::COMPARATOR_EQUAL => ' ("===")', + self::COMPARATOR_NOT_EQUAL => ' ("!==")', + self::COMPARATOR_GREATER_THAN => ' (">")', + self::COMPARATOR_GREATER_THAN_OR_EQUAL => ' (">=")', + self::COMPARATOR_LESS_THAN => ' ("<")', + self::COMPARATOR_LESS_THAN_OR_EQUAL => ' ("<=")', + self::ARROW_SINGLE => ' ("->")', + self::BRACKET_CURLY_OPEN => ' ("{")', + self::BRACKET_CURLY_CLOSE => ' ("}")', + self::BRACKET_ROUND_OPEN => ' ("(")', + self::BRACKET_ROUND_CLOSE => ' (")")', + self::BRACKET_SQUARE_OPEN => ' ("[")', + self::BRACKET_SQUARE_CLOSE => ' ("]")', + self::TAG_START_OPENING => ' ("<")', + self::TAG_START_CLOSING => ' (" ' ("/>")', + self::TAG_END => ' (">")', + self::PERIOD => ' (".")', + self::COLON => ' (":")', + self::QUESTIONMARK => ' ("?")', + self::COMMA => ' (",")', + self::EQUALS => ' ("=")', + self::SLASH_FORWARD => ' ("/")', + self::DOLLAR => ' ("$")', + self::PIPE => ' ("|")', + self::OPTCHAIN => ' ("?.")', + self::NULLISH_COALESCE => ' ("??")', + self::SPACE => '', + self::END_OF_LINE => '' + }; + } } diff --git a/src/Parser/Tokenizer/TokenTypes.php b/src/Parser/Tokenizer/TokenTypes.php new file mode 100644 index 00000000..135e1d77 --- /dev/null +++ b/src/Parser/Tokenizer/TokenTypes.php @@ -0,0 +1,66 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Parser\Tokenizer; + +final class TokenTypes +{ + /** + * @var TokenType[] + */ + private readonly array $items; + + private function __construct(TokenType ...$items) + { + assert(count($items) > 0); + + $this->items = $items; + } + + public static function from(TokenType ...$items): self + { + $items = array_unique($items, SORT_REGULAR); + $items = array_values($items); + + return new self(...$items); + } + + public function contains(TokenType $needle): bool + { + return in_array($needle, $this->items); + } + + public function toDebugString(): string + { + if (count($this->items) === 1) { + return $this->items[0]->toDebugString(); + } + + $leadingItems = array_slice($this->items, 0, -1); + $trailingItem = array_slice($this->items, -1)[0]; + + return join(', ', array_map( + static fn (TokenType $tokenType) => $tokenType->toDebugString(), + $leadingItems + )) . ' or ' . $trailingItem->toDebugString(); + } +} diff --git a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php new file mode 100644 index 00000000..5620ddb7 --- /dev/null +++ b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php @@ -0,0 +1,1357 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Expression; + +use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessKeyNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Access\AccessType; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperator; +use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; +use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperator; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class ExpressionParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesMandatoryAccessWithOneLevel(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a.b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 2]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 2]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 2], [0, 2]), + value: PropertyName::from('b') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMandatoryAccessWithMultipleLevels(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a.b.c.d.e'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 8]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 8]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 6]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 6]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 4]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 2]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 2]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 2], [0, 2]), + value: PropertyName::from('b') + ) + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 4], [0, 4]), + value: PropertyName::from('c') + ) + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 6], [0, 6]), + value: PropertyName::from('d') + ) + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 8], [0, 8]), + value: PropertyName::from('e') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesOptionalAccessWithOneLevel(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a?.b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 3]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 3]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 3], [0, 3]), + value: PropertyName::from('b') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesOptionalAccessWithMultipleLevels(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a?.b?.c?.d?.e'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 12]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 12]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 9]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 9]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 6]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 6]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 3]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 3]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 3], [0, 3]), + value: PropertyName::from('b') + ) + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 6], [0, 6]), + value: PropertyName::from('c') + ) + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 9], [0, 9]), + value: PropertyName::from('d') + ) + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 12], [0, 12]), + value: PropertyName::from('e') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMixedAccessChainStartingWithMandatoryAccess(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a.b?.c'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 5]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 2]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 2]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 2], [0, 2]), + value: PropertyName::from('b') + ) + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 5], [0, 5]), + value: PropertyName::from('c') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMixedAccessChainStartingWithOptionalAccess(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a?.b.c'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 5]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 3]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 3]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 3], [0, 3]), + value: PropertyName::from('b') + ) + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 5], [0, 5]), + value: PropertyName::from('c') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMandatoryAccessWithBracketedEpxressionAsParent(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('(a ? b : c).d'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 12]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 12]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 10]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 1]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 1], [0, 1]), + name: VariableName::from('a') + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 9]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 9], [0, 9]), + name: VariableName::from('c') + ) + ) + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 12], [0, 12]), + value: PropertyName::from('d') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesOptionalAccessWithBracketedEpxressionAsParent(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('(a ? b : c)?.d'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 13]), + root: new AccessNode( + rangeInSource: $this->range([0, 0], [0, 13]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 10]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 1]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 1], [0, 1]), + name: VariableName::from('a') + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 9]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 9], [0, 9]), + name: VariableName::from('c') + ) + ) + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 13], [0, 13]), + value: PropertyName::from('d') + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationAnd(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a && b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 5]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::AND, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationOr(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a || b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 5]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::OR, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationEquals(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a === b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 6]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 6]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::EQUAL, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 6]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 6], [0, 6]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationNotEquals(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a !== b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 6]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 6]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::NOT_EQUAL, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 6]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 6], [0, 6]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationGreaterThan(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a > b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 4]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::GREATER_THAN, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 4], [0, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 4], [0, 4]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationGreaterThanOrEqual(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a >= b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 5]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::GREATER_THAN_OR_EQUAL, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationLessThan(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a < b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 4]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::LESS_THAN, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 4], [0, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 4], [0, 4]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationLessThanOrEqual(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a <= b'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 5]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::LESS_THAN_OR_EQUAL, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationInBrackets(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('(a <= b)'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 7]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 1], [0, 6]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 1]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 1], [0, 1]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::LESS_THAN_OR_EQUAL, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 6]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 6], [0, 6]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryOperationInMultipleBrackets(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('((((a <= b))))'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 13]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 4], [0, 9]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 4], [0, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 4], [0, 4]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::LESS_THAN_OR_EQUAL, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 9]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 9], [0, 9]), + name: VariableName::from('b') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBooleanLiteralTrue(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('true'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 3]), + root: new BooleanLiteralNode( + rangeInSource: $this->range([0, 0], [0, 3]), + value: true + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBooleanLiteralFalse(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('false'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new BooleanLiteralNode( + rangeInSource: $this->range([0, 0], [0, 4]), + value: false + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesBinaryIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('0b1001'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 5]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 5]), + format: IntegerFormat::BINARY, + value: '0b1001' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesOctalIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('0o755'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 4]), + format: IntegerFormat::OCTAL, + value: '0o755' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesDecimalIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('42'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 1]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 1]), + format: IntegerFormat::DECIMAL, + value: '42' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesHexadecimalIntegerLiteral(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('0xABC'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new IntegerLiteralNode( + rangeInSource: $this->range([0, 0], [0, 4]), + format: IntegerFormat::HEXADECIMAL, + value: '0xABC' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatch(): void + { + $this->markTestSkipped('@TODO: parses Match'); + } + + /** + * @test + */ + public function parsesNullLiteral(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('null'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 3]), + root: new NullLiteralNode( + rangeInSource: $this->range([0, 0], [0, 3]) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesStringLiteral(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('"Hello World"'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 11]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 1], [0, 11]), + value: 'Hello World' + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTag(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('Bar!'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 22]), + root: new TagNode( + rangeInSource: $this->range([0, 0], [0, 22]), + name: new TagNameNode( + rangeInSource: $this->range([0, 1], [0, 1]), + value: TagName::from('a') + ), + attributes: new AttributeNodes( + new AttributeNode( + rangeInSource: $this->range([0, 3], [0, 12]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 3], [0, 6]), + value: AttributeName::from('href') + ), + value: new StringLiteralNode( + rangeInSource: $this->range([0, 9], [0, 12]), + value: '#foo' + ) + ) + ), + children: new ChildNodes( + new TextNode( + rangeInSource: $this->range([0, 15], [0, 18]), + value: 'Bar!' + ) + ), + isSelfClosing: false + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTemplateLiteral(): void + { + $this->markTestSkipped('@TODO: parses TemplateLiteral'); + } + + /** + * @test + */ + public function parsesTernaryOperation(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a ? b : c'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 8]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 4], [0, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 4], [0, 4]), + name: VariableName::from('b') + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 8], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 8], [0, 8]), + name: VariableName::from('c') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesNestedTernaryOperation(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('(a ? b : c) ? (d ? e : f) : (g ? h : i)'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 38]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 10]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 1]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 1], [0, 1]), + name: VariableName::from('a') + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 5], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 5], [0, 5]), + name: VariableName::from('b') + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 9]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 9], [0, 9]), + name: VariableName::from('c') + ) + ) + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 14], [0, 24]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 15], [0, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 15], [0, 15]), + name: VariableName::from('d') + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 19], [0, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 19], [0, 19]), + name: VariableName::from('e') + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 23], [0, 23]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 23], [0, 23]), + name: VariableName::from('f') + ) + ) + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 28], [0, 38]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 29], [0, 29]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 29], [0, 29]), + name: VariableName::from('g') + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 33], [0, 33]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 33], [0, 33]), + name: VariableName::from('h') + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 37], [0, 37]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 37], [0, 37]), + name: VariableName::from('i') + ) + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesUnaryOperation(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('!a'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 1]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 1]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 1]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 1], [0, 1]), + name: VariableName::from('a') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesDoubleUnaryOperation(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('!!a'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 2]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 2]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 2]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 1], [0, 2]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 2], [0, 2]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 2], [0, 2]), + name: VariableName::from('a') + ) + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTripleUnaryOperation(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('!!!a'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 3]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 3]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 3]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 1], [0, 3]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 2], [0, 3]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 2], [0, 3]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 3], [0, 3]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 3], [0, 3]), + name: VariableName::from('a') + ) + ) + ) + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesUnaryOperationWithBracketedExpressionAsOperand(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('!(a > b)'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 7]), + root: new UnaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 7]), + operator: UnaryOperator::NOT, + operand: new ExpressionNode( + rangeInSource: $this->range([0, 1], [0, 7]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 2], [0, 6]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 2], [0, 2]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 2], [0, 2]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::GREATER_THAN, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 6]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 6], [0, 6]), + name: VariableName::from('b') + ) + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesValueReference(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('foo'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 2]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 2]), + name: VariableName::from('foo') + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } +} diff --git a/test/Unit/Language/Parser/ParserTestCase.php b/test/Unit/Language/Parser/ParserTestCase.php new file mode 100644 index 00000000..97a9402c --- /dev/null +++ b/test/Unit/Language/Parser/ParserTestCase.php @@ -0,0 +1,58 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser; + +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Source\Source; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; +use PHPUnit\Framework\TestCase; + +abstract class ParserTestCase extends TestCase +{ + /** + * @param string $sourceAsString + * @return \Iterator + */ + protected function createTokenIterator(string $sourceAsString): \Iterator + { + $source = Source::fromString($sourceAsString); + $tokenizer = Tokenizer::fromSource($source); + + return $tokenizer->getIterator(); + } + + /** + * @param array{int,int} $startAsArray + * @param array{int,int} $endAsArray + * @return Range + */ + protected function range(array $startAsArray, array $endAsArray): Range + { + return Range::from( + new Position(...$startAsArray), + new Position(...$endAsArray) + ); + } +} diff --git a/test/Unit/Parser/Tokenizer/TokenTest.php b/test/Unit/Parser/Tokenizer/TokenTest.php new file mode 100644 index 00000000..44159ce8 --- /dev/null +++ b/test/Unit/Parser/Tokenizer/TokenTest.php @@ -0,0 +1,55 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Parser\Tokenizer; + +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; +use PHPUnit\Framework\TestCase; + +final class TokenTest extends TestCase +{ + /** + * @test + */ + public function providesDebugString(): void + { + $token = new Token( + type: TokenType::COMMENT, + value: '# This is a comment', + boundaries: Range::from( + new Position(0, 0), + new Position(0, 0) + ), + sourcePath: Path::createMemory() + ); + + $this->assertEquals( + 'COMMENT ("# This is a comment")', + $token->toDebugString() + ); + } +} diff --git a/test/Unit/Parser/Tokenizer/TokenTypesTest.php b/test/Unit/Parser/Tokenizer/TokenTypesTest.php new file mode 100644 index 00000000..5afe1e4d --- /dev/null +++ b/test/Unit/Parser/Tokenizer/TokenTypesTest.php @@ -0,0 +1,110 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Parser\Tokenizer; + +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; +use PHPUnit\Framework\TestCase; + +final class TokenTypesTest extends TestCase +{ + /** + * @test + */ + public function providesDebugStringForSingleItem(): void + { + $tokenTypes = TokenTypes::from(TokenType::COLON); + + $this->assertEquals( + 'COLON (":")', + $tokenTypes->toDebugString() + ); + } + + /** + * @test + */ + public function providesDebugStringForTwoItems(): void + { + $tokenTypes = TokenTypes::from(TokenType::PERIOD, TokenType::COMMA); + + $this->assertEquals( + 'PERIOD (".") or COMMA (",")', + $tokenTypes->toDebugString() + ); + } + + /** + * @test + */ + public function providesDebugStringForThreeOrMoreItems(): void + { + $tokenTypes = TokenTypes::from( + TokenType::PERIOD, + TokenType::COMMA, + TokenType::COLON, + TokenType::DOLLAR + ); + + $this->assertEquals( + 'PERIOD ("."), COMMA (","), COLON (":") or DOLLAR ("$")', + $tokenTypes->toDebugString() + ); + } + + /** + * @test + */ + public function containsReturnsTrueIfCollectionContainsGivenTokenType(): void + { + $tokenTypes = TokenTypes::from( + TokenType::PERIOD, + TokenType::COMMA, + TokenType::COLON, + TokenType::DOLLAR + ); + + $this->assertTrue($tokenTypes->contains(TokenType::PERIOD)); + $this->assertTrue($tokenTypes->contains(TokenType::COMMA)); + $this->assertTrue($tokenTypes->contains(TokenType::COLON)); + $this->assertTrue($tokenTypes->contains(TokenType::DOLLAR)); + } + + /** + * @test + */ + public function containsReturnsFalseIfCollectionDoesNotContainGivenTokenType(): void + { + $tokenTypes = TokenTypes::from( + TokenType::PERIOD, + TokenType::COMMA, + TokenType::COLON, + TokenType::DOLLAR + ); + + $this->assertFalse($tokenTypes->contains(TokenType::SLASH_FORWARD)); + $this->assertFalse($tokenTypes->contains(TokenType::COMMENT)); + $this->assertFalse($tokenTypes->contains(TokenType::STRING)); + $this->assertFalse($tokenTypes->contains(TokenType::EQUALS)); + } +} diff --git a/test/Unit/Parser/Tokenizer/TokenizerTest.php b/test/Unit/Parser/Tokenizer/TokenizerTest.php index 9eeef8cc..27ab6601 100644 --- a/test/Unit/Parser/Tokenizer/TokenizerTest.php +++ b/test/Unit/Parser/Tokenizer/TokenizerTest.php @@ -68,4 +68,101 @@ public function tokenizesClosingTag(): void $this->assertEquals(TokenType::STRING, $tokens[1]->type); $this->assertEquals(TokenType::TAG_END, $tokens[2]->type); } + + /** + * @test + */ + public function tokenizesMultipleBracketedStatements(): void + { + $source = Source::fromString('(a ? b : c) ? (d ? e : f) : (g ? h : i)'); + $tokenizer = Tokenizer::fromSource($source); + $tokens = \iterator_to_array($tokenizer->getIterator(), false); + + $this->assertEquals(TokenType::BRACKET_ROUND_OPEN, $tokens[0]->type); + + $this->assertEquals(TokenType::STRING, $tokens[1]->type); + $this->assertEquals('a', $tokens[1]->value); + + $this->assertEquals(TokenType::SPACE, $tokens[2]->type); + + $this->assertEquals(TokenType::QUESTIONMARK, $tokens[3]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[4]->type); + + $this->assertEquals(TokenType::STRING, $tokens[5]->type); + $this->assertEquals('b', $tokens[5]->value); + + $this->assertEquals(TokenType::SPACE, $tokens[6]->type); + + $this->assertEquals(TokenType::COLON, $tokens[7]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[8]->type); + + $this->assertEquals(TokenType::STRING, $tokens[9]->type); + $this->assertEquals('c', $tokens[9]->value); + + $this->assertEquals(TokenType::BRACKET_ROUND_CLOSE, $tokens[10]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[11]->type); + + $this->assertEquals(TokenType::QUESTIONMARK, $tokens[12]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[13]->type); + + $this->assertEquals(TokenType::BRACKET_ROUND_OPEN, $tokens[14]->type); + + $this->assertEquals(TokenType::STRING, $tokens[15]->type); + $this->assertEquals('d', $tokens[15]->value); + + $this->assertEquals(TokenType::SPACE, $tokens[16]->type); + + $this->assertEquals(TokenType::QUESTIONMARK, $tokens[17]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[18]->type); + + $this->assertEquals(TokenType::STRING, $tokens[19]->type); + $this->assertEquals('e', $tokens[19]->value); + + $this->assertEquals(TokenType::SPACE, $tokens[20]->type); + + $this->assertEquals(TokenType::COLON, $tokens[21]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[22]->type); + + $this->assertEquals(TokenType::STRING, $tokens[23]->type); + $this->assertEquals('f', $tokens[23]->value); + + $this->assertEquals(TokenType::BRACKET_ROUND_CLOSE, $tokens[24]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[25]->type); + + $this->assertEquals(TokenType::COLON, $tokens[26]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[27]->type); + + $this->assertEquals(TokenType::BRACKET_ROUND_OPEN, $tokens[28]->type); + + $this->assertEquals(TokenType::STRING, $tokens[29]->type); + $this->assertEquals('g', $tokens[29]->value); + + $this->assertEquals(TokenType::SPACE, $tokens[30]->type); + + $this->assertEquals(TokenType::QUESTIONMARK, $tokens[31]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[32]->type); + + $this->assertEquals(TokenType::STRING, $tokens[33]->type); + $this->assertEquals('h', $tokens[33]->value); + + $this->assertEquals(TokenType::SPACE, $tokens[34]->type); + + $this->assertEquals(TokenType::COLON, $tokens[35]->type); + + $this->assertEquals(TokenType::SPACE, $tokens[36]->type); + + $this->assertEquals(TokenType::STRING, $tokens[37]->type); + $this->assertEquals('i', $tokens[37]->value); + + $this->assertEquals(TokenType::BRACKET_ROUND_CLOSE, $tokens[38]->type); + } } From e88566a24639a9b14d2105ab7a0cfdff2de6ac0c Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 3 Aug 2023 23:06:32 +0200 Subject: [PATCH 47/64] TASK: Implement TemplateLiteralParser --- .../TemplateLiteralExpressionSegmentNode.php | 37 ++ .../TemplateLiteral/TemplateLiteralNode.php | 10 +- .../TemplateLiteralSegments.php | 37 ++ .../TemplateLiteralStringSegmentNode.php | 36 ++ .../Parser/Expression/ExpressionParser.php | 52 ++- src/Language/Parser/Expression/Precedence.php | 94 +++++ .../TemplateLiteral/TemplateLiteralParser.php | 135 +++++++ .../Expression/ExpressionParserTest.php | 114 +++++- .../TemplateLiteralParserTest.php | 347 ++++++++++++++++++ 9 files changed, 845 insertions(+), 17 deletions(-) create mode 100644 src/Language/AST/Node/TemplateLiteral/TemplateLiteralExpressionSegmentNode.php create mode 100644 src/Language/AST/Node/TemplateLiteral/TemplateLiteralSegments.php create mode 100644 src/Language/AST/Node/TemplateLiteral/TemplateLiteralStringSegmentNode.php create mode 100644 src/Language/Parser/Expression/Precedence.php create mode 100644 src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php create mode 100644 test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php diff --git a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralExpressionSegmentNode.php b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralExpressionSegmentNode.php new file mode 100644 index 00000000..7b9cfdb5 --- /dev/null +++ b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralExpressionSegmentNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class TemplateLiteralExpressionSegmentNode extends Node +{ + + public function __construct( + public readonly Range $rangeInSource, + public readonly ExpressionNode $expression + ) { + } +} diff --git a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php index 65621c41..1fbbabc9 100644 --- a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php +++ b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralNode.php @@ -22,22 +22,14 @@ namespace PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral; -use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Node; -use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Parser\Source\Range; final class TemplateLiteralNode extends Node { - /** - * @var (StringLiteralNode|ExpressionNode)[] - */ - public readonly array $segments; - public function __construct( public readonly Range $rangeInSource, - StringLiteralNode | ExpressionNode ...$segments + public readonly TemplateLiteralSegments $segments ) { - $this->segments = $segments; } } diff --git a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralSegments.php b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralSegments.php new file mode 100644 index 00000000..f5c0c066 --- /dev/null +++ b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralSegments.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral; + +final class TemplateLiteralSegments +{ + /** + * @var (TemplateLiteralStringSegmentNode|TemplateLiteralExpressionSegmentNode)[] + */ + public readonly array $items; + + public function __construct( + TemplateLiteralStringSegmentNode | TemplateLiteralExpressionSegmentNode ...$items + ) { + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/TemplateLiteral/TemplateLiteralStringSegmentNode.php b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralStringSegmentNode.php new file mode 100644 index 00000000..5cce5609 --- /dev/null +++ b/src/Language/AST/Node/TemplateLiteral/TemplateLiteralStringSegmentNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class TemplateLiteralStringSegmentNode extends Node +{ + + public function __construct( + public readonly Range $rangeInSource, + public readonly string $value + ) { + } +} diff --git a/src/Language/Parser/Expression/ExpressionParser.php b/src/Language/Parser/Expression/ExpressionParser.php index fe794e03..49c6a9be 100644 --- a/src/Language/Parser/Expression/ExpressionParser.php +++ b/src/Language/Parser/Expression/ExpressionParser.php @@ -29,7 +29,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperator; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; -use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperator; @@ -38,6 +37,7 @@ use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; +use PackageFactory\ComponentEngine\Language\Parser\TemplateLiteral\TemplateLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\ValueReference\ValueReferenceParser; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; @@ -52,16 +52,19 @@ final class ExpressionParser private readonly StringLiteralParser $stringLiteralParser; private readonly IntegerLiteralParser $integerLiteralParser; private readonly ValueReferenceParser $valueReferenceParser; + private readonly TemplateLiteralParser $templateLiteralParser; private readonly TagParser $tagParser; public function __construct( - private ?TokenType $stopAt = null + private ?TokenType $stopAt = null, + private Precedence $precedence = Precedence::SEQUENCE ) { $this->booleanLiteralParser = new BooleanLiteralParser(); $this->nullLiteralParser = new NullLiteralParser(); $this->stringLiteralParser = new StringLiteralParser(); $this->integerLiteralParser = new IntegerLiteralParser(); $this->valueReferenceParser = new ValueReferenceParser(); + $this->templateLiteralParser = new TemplateLiteralParser(); $this->tagParser = new TagParser(); } @@ -131,6 +134,8 @@ public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode $this->parseValueReference($tokens), TokenType::TAG_START_OPENING => $this->parseTag($tokens), + TokenType::TEMPLATE_LITERAL_START => + $this->parseTemplateLiteral($tokens), TokenType::BRACKET_ROUND_OPEN => $this->parseBracketedExpression($tokens), default => @@ -146,6 +151,7 @@ public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode TokenType::NUMBER_HEXADECIMAL, TokenType::STRING, TokenType::TAG_START_OPENING, + TokenType::TEMPLATE_LITERAL_START, TokenType::BRACKET_ROUND_OPEN ), actualToken: $tokens->current() @@ -216,6 +222,14 @@ private function withStopAt(TokenType $stopAt): self return $newExpressionParser; } + private function withPrecedence(Precedence $precedence): self + { + $newExpressionParser = clone $this; + $newExpressionParser->precedence = $precedence; + + return $newExpressionParser; + } + /** * @param \Iterator $tokens * @return boolean @@ -224,11 +238,21 @@ private function shouldStop(\Iterator &$tokens): bool { Scanner::skipSpaceAndComments($tokens); - if (is_null($this->stopAt)) { - return Scanner::isEnd($tokens); + if (Scanner::isEnd($tokens)) { + return true; + } + + $type = Scanner::type($tokens); + + if ($this->precedence->mustStopAt($type)) { + return true; + } + + if ($this->stopAt && $type === $this->stopAt) { + return true; } - return Scanner::type($tokens) === $this->stopAt; + return false; } /** @@ -315,6 +339,20 @@ private function parseTag(\Iterator &$tokens): ExpressionNode ); } + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseTemplateLiteral(\Iterator &$tokens): ExpressionNode + { + $templateLiteralNode = $this->templateLiteralParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $templateLiteralNode->rangeInSource, + root: $templateLiteralNode + ); + } + /** * @param \Iterator $tokens * @return ExpressionNode @@ -412,7 +450,9 @@ private function parseAccessType(\Iterator &$tokens): AccessType private function parseBinaryOperation(\Iterator &$tokens, ExpressionNode $leftOperand): ExpressionNode { $operator = $this->parseBinaryOperator($tokens); - $rightOperand = $this->parse($tokens); + $rightOperand = $this + ->withPrecedence(Precedence::forBinaryOperator($operator)) + ->parse($tokens); $rangeInSource = Range::from( $leftOperand->rangeInSource->start, $rightOperand->rangeInSource->end diff --git a/src/Language/Parser/Expression/Precedence.php b/src/Language/Parser/Expression/Precedence.php new file mode 100644 index 00000000..a96d1553 --- /dev/null +++ b/src/Language/Parser/Expression/Precedence.php @@ -0,0 +1,94 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Expression; + +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperator; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +enum Precedence: int +{ + // + // Precedence indices as per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence + // + + case ACCESS = 18; + case UNARY = 15; + case COMPARISON = 10; + case EQUALITY = 9; + case LOGICAL_AND = 5; + case LOGICAL_OR = 4; + case TERNARY = 3; + case SEQUENCE = 1; + + public static function forTokenType(TokenType $tokenType): self + { + return match ($tokenType) { + TokenType::BRACKET_ROUND_OPEN, + TokenType::BRACKET_ROUND_CLOSE, + TokenType::BRACKET_SQUARE_OPEN, + TokenType::BRACKET_SQUARE_CLOSE, + TokenType::OPTCHAIN, + TokenType::PERIOD => self::ACCESS, + + TokenType::OPERATOR_BOOLEAN_NOT => self::UNARY, + + TokenType::COMPARATOR_GREATER_THAN, + TokenType::COMPARATOR_GREATER_THAN_OR_EQUAL, + TokenType::COMPARATOR_LESS_THAN, + TokenType::COMPARATOR_LESS_THAN_OR_EQUAL => self::COMPARISON, + + TokenType::COMPARATOR_EQUAL, + TokenType::COMPARATOR_NOT_EQUAL => self::EQUALITY, + + TokenType::OPERATOR_BOOLEAN_AND => self::LOGICAL_AND, + + TokenType::OPERATOR_BOOLEAN_OR => self::LOGICAL_OR, + + TokenType::QUESTIONMARK, + TokenType::COLON => self::TERNARY, + + default => self::SEQUENCE + }; + } + + public static function forBinaryOperator(BinaryOperator $binaryOperator): self + { + return match ($binaryOperator) { + BinaryOperator::AND => self::LOGICAL_AND, + BinaryOperator::OR => self::LOGICAL_OR, + + BinaryOperator::EQUAL, + BinaryOperator::NOT_EQUAL => self::EQUALITY, + + BinaryOperator::GREATER_THAN, + BinaryOperator::GREATER_THAN_OR_EQUAL, + BinaryOperator::LESS_THAN, + BinaryOperator::LESS_THAN_OR_EQUAL => self::COMPARISON + }; + } + + public function mustStopAt(TokenType $tokenType): bool + { + return self::forTokenType($tokenType)->value <= $this->value; + } +} diff --git a/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php b/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php new file mode 100644 index 00000000..8a06c2e3 --- /dev/null +++ b/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php @@ -0,0 +1,135 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\TemplateLiteral; + +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralExpressionSegmentNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralSegments; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralStringSegmentNode; +use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class TemplateLiteralParser +{ + private ?ExpressionParser $expressionParser = null; + + private function initializeExpressionParser(): void + { + $this->expressionParser ??= new ExpressionParser( + stopAt: TokenType::BRACKET_CURLY_CLOSE + ); + } + + /** + * @param \Iterator $tokens + * @return TemplateLiteralNode + */ + public function parse(\Iterator &$tokens): TemplateLiteralNode + { + Scanner::assertType($tokens, TokenType::TEMPLATE_LITERAL_START); + $startingDelimiterToken = $tokens->current(); + Scanner::skipOne($tokens); + + $segments = $this->parseSegments($tokens); + + Scanner::assertType($tokens, TokenType::TEMPLATE_LITERAL_END); + $finalDelimiterToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new TemplateLiteralNode( + rangeInSource: Range::from( + $startingDelimiterToken->boundaries->start, + $finalDelimiterToken->boundaries->end + ), + segments: $segments + ); + } + + /** + * @param \Iterator $tokens + * @return TemplateLiteralSegments + */ + public function parseSegments(\Iterator &$tokens): TemplateLiteralSegments + { + $items = []; + while (Scanner::type($tokens) !== TokenType::TEMPLATE_LITERAL_END) { + $items[] = match (Scanner::type($tokens)) { + TokenType::STRING_QUOTED => $this->parseStringSegment($tokens), + TokenType::DOLLAR => $this->parseExpressionSegment($tokens), + default => throw new \Exception(__METHOD__ . ' for ' . Scanner::type($tokens)->value . ' is not implemented yet!') + }; + } + + return new TemplateLiteralSegments(...$items); + } + + /** + * @param \Iterator $tokens + * @return TemplateLiteralStringSegmentNode + */ + public function parseStringSegment(\Iterator &$tokens): TemplateLiteralStringSegmentNode + { + Scanner::assertType($tokens, TokenType::STRING_QUOTED); + $stringToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new TemplateLiteralStringSegmentNode( + rangeInSource: $stringToken->boundaries, + value: $stringToken->value + ); + } + + /** + * @param \Iterator $tokens + * @return TemplateLiteralExpressionSegmentNode + */ + public function parseExpressionSegment(\Iterator &$tokens): TemplateLiteralExpressionSegmentNode + { + $this->initializeExpressionParser(); + + Scanner::assertType($tokens, TokenType::DOLLAR); + $dollarToken = $tokens->current(); + Scanner::skipOne($tokens); + + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + + assert($this->expressionParser !== null); + $expression = $this->expressionParser->parse($tokens); + + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + $closingBracketToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new TemplateLiteralExpressionSegmentNode( + rangeInSource: Range::from( + $dollarToken->boundaries->start, + $closingBracketToken->boundaries->end + ), + expression: $expression + ); + } +} diff --git a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php index 5620ddb7..04630e42 100644 --- a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php +++ b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php @@ -43,6 +43,10 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralExpressionSegmentNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralSegments; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralStringSegmentNode; use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; @@ -1040,7 +1044,40 @@ public function parsesTag(): void */ public function parsesTemplateLiteral(): void { - $this->markTestSkipped('@TODO: parses TemplateLiteral'); + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('`Hello ${friend}!`'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 17]), + root: new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 17]), + segments: new TemplateLiteralSegments( + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 1], [0, 6]), + value: 'Hello ' + ), + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 7], [0, 15]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 14]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 9], [0, 14]), + name: VariableName::from('friend') + ) + ) + ), + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 16], [0, 16]), + value: '!' + ), + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); } /** @@ -1087,7 +1124,7 @@ public function parsesTernaryOperation(): void /** * @test */ - public function parsesNestedTernaryOperation(): void + public function parsesNestedBracketedTernaryOperation(): void { $expressionParser = new ExpressionParser(); $tokens = $this->createTokenIterator('(a ? b : c) ? (d ? e : f) : (g ? h : i)'); @@ -1181,6 +1218,79 @@ public function parsesNestedTernaryOperation(): void $expressionParser->parse($tokens) ); } + /** + * @test + */ + public function parsesNestedUnbracketedTernaryOperation(): void + { + $expressionParser = new ExpressionParser(); + $tokens = $this->createTokenIterator('a < b ? "yes" : (foo ? "maybe" : "no")'); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 37]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 4]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 0], [0, 4]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 0], [0, 0]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 0], [0, 0]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::LESS_THAN, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 4], [0, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 4], [0, 4]), + name: VariableName::from('b') + ) + ), + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 11]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 9], [0, 11]), + value: 'yes' + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 16], [0, 37]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 17], [0, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 17], [0, 19]), + name: VariableName::from('foo') + ), + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 24], [0, 28]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 24], [0, 28]), + value: 'maybe' + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 34], [0, 35]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 34], [0, 35]), + value: 'no' + ) + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); + } /** * @test diff --git a/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php b/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php new file mode 100644 index 00000000..daf3201c --- /dev/null +++ b/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php @@ -0,0 +1,347 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\TemplateLiteral; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperator; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralExpressionSegmentNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralSegments; +use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralStringSegmentNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TernaryOperation\TernaryOperationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\TemplateLiteral\TemplateLiteralParser; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class TemplateLiteralParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesTemplateLiteralWithoutEmbeddedExpressions(): void + { + $templateLiteralParser = new TemplateLiteralParser(); + $tokens = $this->createTokenIterator('`Hello World`'); + + $expectedTemplateLiteralNode = new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 12]), + segments: new TemplateLiteralSegments( + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 1], [0, 11]), + value: 'Hello World' + ) + ) + ); + + $this->assertEquals( + $expectedTemplateLiteralNode, + $templateLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTemplateLiteralWithOnlyEmbeddedExpression(): void + { + $templateLiteralParser = new TemplateLiteralParser(); + $tokens = $this->createTokenIterator('`${foo}`'); + + $expectedTemplateLiteralNode = new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 7]), + segments: new TemplateLiteralSegments( + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 1], [0, 6]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 3], [0, 5]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 3], [0, 5]), + name: VariableName::from('foo') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedTemplateLiteralNode, + $templateLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTemplateLiteralWithLeadingAndTrailingStringSegments(): void + { + $templateLiteralParser = new TemplateLiteralParser(); + $tokens = $this->createTokenIterator('`Hello ${friend}!`'); + + $expectedTemplateLiteralNode = new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 17]), + segments: new TemplateLiteralSegments( + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 1], [0, 6]), + value: 'Hello ' + ), + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 7], [0, 15]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 14]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 9], [0, 14]), + name: VariableName::from('friend') + ) + ) + ), + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 16], [0, 16]), + value: '!' + ), + ) + ); + + $this->assertEquals( + $expectedTemplateLiteralNode, + $templateLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTemplateLiteralWithLeadingAndTrailingExpressionSegments(): void + { + $templateLiteralParser = new TemplateLiteralParser(); + $tokens = $this->createTokenIterator('`${greeting} to you, ${friend}`'); + + $expectedTemplateLiteralNode = new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 30]), + segments: new TemplateLiteralSegments( + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 1], [0, 11]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 3], [0, 10]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 3], [0, 10]), + name: VariableName::from('greeting') + ) + ) + ), + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 12], [0, 20]), + value: ' to you, ' + ), + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 21], [0, 29]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 23], [0, 28]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 23], [0, 28]), + name: VariableName::from('friend') + ) + ) + ), + ) + ); + + $this->assertEquals( + $expectedTemplateLiteralNode, + $templateLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTemplateLiteralWithComplexExpression(): void + { + $templateLiteralParser = new TemplateLiteralParser(); + $tokens = $this->createTokenIterator( + '`The result is: ${a < b ? "yes" : (foo ? "maybe" : "no")}`' + ); + + $expectedTemplateLiteralNode = new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 57]), + segments: new TemplateLiteralSegments( + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 1], [0, 15]), + value: 'The result is: ' + ), + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 16], [0, 56]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 55]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 22]), + root: new BinaryOperationNode( + rangeInSource: $this->range([0, 18], [0, 22]), + leftOperand: new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 18]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 18], [0, 18]), + name: VariableName::from('a') + ) + ), + operator: BinaryOperator::LESS_THAN, + rightOperand: new ExpressionNode( + rangeInSource: $this->range([0, 22], [0, 22]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 22], [0, 22]), + name: VariableName::from('b') + ) + ), + ) + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 27], [0, 29]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 27], [0, 29]), + value: 'yes' + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 34], [0, 55]), + root: new TernaryOperationNode( + condition: new ExpressionNode( + rangeInSource: $this->range([0, 35], [0, 37]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 35], [0, 37]), + name: VariableName::from('foo') + ), + ), + trueBranch: new ExpressionNode( + rangeInSource: $this->range([0, 42], [0, 46]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 42], [0, 46]), + value: 'maybe' + ) + ), + falseBranch: new ExpressionNode( + rangeInSource: $this->range([0, 52], [0, 53]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 52], [0, 53]), + value: 'no' + ) + ) + ) + ) + ) + ) + ), + ) + ); + + $this->assertEquals( + $expectedTemplateLiteralNode, + $templateLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTemplateLiteralWithEmbeddedTemplateLiteral(): void + { + $templateLiteralParser = new TemplateLiteralParser(); + $tokens = $this->createTokenIterator('`Lorem ${`ipsum ${foo} sit`} amet`'); + + $expectedTemplateLiteralNode = new TemplateLiteralNode( + rangeInSource: $this->range([0, 0], [0, 33]), + segments: new TemplateLiteralSegments( + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 1], [0, 6]), + value: 'Lorem ' + ), + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 7], [0, 27]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 9], [0, 26]), + root: new TemplateLiteralNode( + rangeInSource: $this->range([0, 9], [0, 26]), + segments: new TemplateLiteralSegments( + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 10], [0, 15]), + value: 'ipsum ' + ), + new TemplateLiteralExpressionSegmentNode( + rangeInSource: $this->range([0, 16], [0, 21]), + expression: new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 20]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 18], [0, 20]), + name: VariableName::from('foo') + ) + ) + ), + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 22], [0, 25]), + value: ' sit' + ) + ) + ) + ) + ), + new TemplateLiteralStringSegmentNode( + rangeInSource: $this->range([0, 28], [0, 32]), + value: ' amet' + ) + ) + ); + + $this->assertEquals( + $expectedTemplateLiteralNode, + $templateLiteralParser->parse($tokens) + ); + } + + /** + * @test + */ + public function toleratesIsolatedDollarSigns(): void + { + $this->markTestSkipped('@TODO: This will require significant redesign of the tokenizer.'); + + // $templateLiteralParser = new TemplateLiteralParser(); + // $tokens = $this->createTokenIterator('`$$$$$$$$`'); + + // $expectedTemplateLiteralNode = new TemplateLiteralNode( + // rangeInSource: $this->range([0, 0], [0, 9]), + // segments: new TemplateLiteralSegments( + // new TemplateLiteralStringSegmentNode( + // rangeInSource: $this->range([0, 1], [0, 8]), + // value: '$$$$$$$$' + // ) + // ) + // ); + + // $this->assertEquals( + // $expectedTemplateLiteralNode, + // $templateLiteralParser->parse($tokens) + // ); + } +} From 19c56cbb1f78ca6ebc968ce3e7065b43ecf99231 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 4 Aug 2023 14:36:29 +0200 Subject: [PATCH 48/64] TASK: Implement MatchParser --- .../AST/Node/Match/InvalidMatchArmNodes.php | 47 + src/Language/AST/Node/Match/MatchArmNode.php | 7 +- src/Language/AST/Node/Match/MatchArmNodes.php | 18 + .../Expression/ExpressionCouldNotBeParsed.php | 14 + .../Parser/Expression/ExpressionParser.php | 24 +- .../Parser/Match/MatchCouldNotBeParsed.php | 45 + src/Language/Parser/Match/MatchParser.php | 235 ++++ .../AST/Node/Match/MatchArmNodeTest.php | 92 ++ .../AST/Node/Match/MatchArmNodesTest.php | 119 ++ .../Expression/ExpressionParserTest.php | 152 ++- .../Language/Parser/Match/MatchParserTest.php | 1168 +++++++++++++++++ 11 files changed, 1917 insertions(+), 4 deletions(-) create mode 100644 src/Language/AST/Node/Match/InvalidMatchArmNodes.php create mode 100644 src/Language/Parser/Match/MatchCouldNotBeParsed.php create mode 100644 src/Language/Parser/Match/MatchParser.php create mode 100644 test/Unit/Language/AST/Node/Match/MatchArmNodeTest.php create mode 100644 test/Unit/Language/AST/Node/Match/MatchArmNodesTest.php create mode 100644 test/Unit/Language/Parser/Match/MatchParserTest.php diff --git a/src/Language/AST/Node/Match/InvalidMatchArmNodes.php b/src/Language/AST/Node/Match/InvalidMatchArmNodes.php new file mode 100644 index 00000000..8f98e653 --- /dev/null +++ b/src/Language/AST/Node/Match/InvalidMatchArmNodes.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Match; + +use PackageFactory\ComponentEngine\Language\AST\ASTException; + +final class InvalidMatchArmNodes extends ASTException +{ + public static function becauseTheyWereEmpty(): self + { + return new self( + code: 1691150119, + message: 'A match statement must contain at least one match arm.' + ); + } + + public static function becauseTheyContainMoreThanOneDefaultMatchArmNode( + MatchArmNode $secondDefaultMatchArmNode + ): self + { + return new self( + code: 1691150238, + message: 'A match statement must not contain more than one default match arm.', + affectedRangeInSource: $secondDefaultMatchArmNode->rangeInSource + ); + } +} diff --git a/src/Language/AST/Node/Match/MatchArmNode.php b/src/Language/AST/Node/Match/MatchArmNode.php index fd93ac38..735c313b 100644 --- a/src/Language/AST/Node/Match/MatchArmNode.php +++ b/src/Language/AST/Node/Match/MatchArmNode.php @@ -29,10 +29,15 @@ final class MatchArmNode extends Node { - private function __construct( + public function __construct( public readonly Range $rangeInSource, public readonly null | ExpressionNodes $left, public readonly ExpressionNode $right ) { } + + public function isDefault(): bool + { + return is_null($this->left); + } } diff --git a/src/Language/AST/Node/Match/MatchArmNodes.php b/src/Language/AST/Node/Match/MatchArmNodes.php index c192a1fb..46785cd8 100644 --- a/src/Language/AST/Node/Match/MatchArmNodes.php +++ b/src/Language/AST/Node/Match/MatchArmNodes.php @@ -29,8 +29,26 @@ final class MatchArmNodes */ public readonly array $items; + private ?MatchArmNode $defaultArm = null; + public function __construct(MatchArmNode ...$items) { + if (count($items) === 0) { + throw InvalidMatchArmNodes::becauseTheyWereEmpty(); + } + + foreach ($items as $item) { + if ($item->isDefault()) { + if (is_null($this->defaultArm)) { + $this->defaultArm = $item; + } else { + throw InvalidMatchArmNodes::becauseTheyContainMoreThanOneDefaultMatchArmNode( + secondDefaultMatchArmNode: $item + ); + } + } + } + $this->items = $items; } } diff --git a/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php b/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php index d3d4533c..4a8c6afe 100644 --- a/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php +++ b/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php @@ -43,4 +43,18 @@ public static function becauseOfUnexpectedToken( affectedRangeInSource: $actualToken->boundaries ); } + + public static function becauseOfUnexpectedExceedingToken( + Token $exceedingToken + ): self { + return new self( + code: 1691141293, + message: sprintf( + 'Expression could not be parsed because token stream was expected to end, ' + . 'but continued with %s instead.', + $exceedingToken->toDebugString() + ), + affectedRangeInSource: $exceedingToken->boundaries + ); + } } diff --git a/src/Language/Parser/Expression/ExpressionParser.php b/src/Language/Parser/Expression/ExpressionParser.php index 49c6a9be..16d3b081 100644 --- a/src/Language/Parser/Expression/ExpressionParser.php +++ b/src/Language/Parser/Expression/ExpressionParser.php @@ -34,6 +34,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperator; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; +use PackageFactory\ComponentEngine\Language\Parser\Match\MatchParser; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; @@ -54,6 +55,7 @@ final class ExpressionParser private readonly ValueReferenceParser $valueReferenceParser; private readonly TemplateLiteralParser $templateLiteralParser; private readonly TagParser $tagParser; + private readonly MatchParser $matchParser; public function __construct( private ?TokenType $stopAt = null, @@ -66,6 +68,7 @@ public function __construct( $this->valueReferenceParser = new ValueReferenceParser(); $this->templateLiteralParser = new TemplateLiteralParser(); $this->tagParser = new TagParser(); + $this->matchParser = new MatchParser(); } /** @@ -113,7 +116,7 @@ public function parse(\Iterator &$tokens): ExpressionNode * @param \Iterator $tokens * @return ExpressionNode */ - public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode + private function parseUnaryStatement(\Iterator &$tokens): ExpressionNode { $result = match (Scanner::type($tokens)) { TokenType::OPERATOR_BOOLEAN_NOT => @@ -136,6 +139,8 @@ public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode $this->parseTag($tokens), TokenType::TEMPLATE_LITERAL_START => $this->parseTemplateLiteral($tokens), + TokenType::KEYWORD_MATCH => + $this->parseMatch($tokens), TokenType::BRACKET_ROUND_OPEN => $this->parseBracketedExpression($tokens), default => @@ -152,6 +157,7 @@ public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode TokenType::STRING, TokenType::TAG_START_OPENING, TokenType::TEMPLATE_LITERAL_START, + TokenType::KEYWORD_MATCH, TokenType::BRACKET_ROUND_OPEN ), actualToken: $tokens->current() @@ -173,7 +179,7 @@ public function parseUnaryStatement(\Iterator &$tokens): ExpressionNode * @param \Iterator $tokens * @return ExpressionNode */ - public function parseUnaryOperation(\Iterator &$tokens): ExpressionNode + private function parseUnaryOperation(\Iterator &$tokens): ExpressionNode { $startingToken = $tokens->current(); @@ -353,6 +359,20 @@ private function parseTemplateLiteral(\Iterator &$tokens): ExpressionNode ); } + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseMatch(\Iterator &$tokens): ExpressionNode + { + $matchNode = $this->matchParser->parse($tokens); + + return new ExpressionNode( + rangeInSource: $matchNode->rangeInSource, + root: $matchNode + ); + } + /** * @param \Iterator $tokens * @return ExpressionNode diff --git a/src/Language/Parser/Match/MatchCouldNotBeParsed.php b/src/Language/Parser/Match/MatchCouldNotBeParsed.php new file mode 100644 index 00000000..b23ed512 --- /dev/null +++ b/src/Language/Parser/Match/MatchCouldNotBeParsed.php @@ -0,0 +1,45 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Match; + +use PackageFactory\ComponentEngine\Language\AST\Node\Match\InvalidMatchArmNodes; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class MatchCouldNotBeParsed extends ParserException +{ + public static function becauseOfInvalidMatchArmNodes( + InvalidMatchArmNodes $cause, + ?Range $affectedRangeInSource = null + ): self { + return new self( + code: 1691152175, + message: sprintf( + 'Match could not be parsed because of invalid match arm nodes: %s.', + $cause->getMessage() + ), + affectedRangeInSource: $affectedRangeInSource ?? $cause->affectedRangeInSource, + cause: $cause + ); + } +} diff --git a/src/Language/Parser/Match/MatchParser.php b/src/Language/Parser/Match/MatchParser.php new file mode 100644 index 00000000..5cf689a2 --- /dev/null +++ b/src/Language/Parser/Match/MatchParser.php @@ -0,0 +1,235 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Match; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\InvalidMatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchNode; +use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class MatchParser +{ + private ?ExpressionParser $subjectParser = null; + private ?ExpressionParser $matchArmLeftParser = null; + private ?ExpressionParser $matchArmRightParser = null; + + /** + * @param \Iterator $tokens + * @return MatchNode + */ + public function parse(\Iterator &$tokens): MatchNode + { + $matchKeywordToken = $this->extractMatchKeywordToken($tokens); + $subject = $this->parseSubject($tokens); + + $this->skipOpeningBracketToken($tokens); + + try { + $arms = $this->parseArms($tokens); + + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + $closingBracketToken = $tokens->current(); + Scanner::skipOne($tokens); + + return new MatchNode( + rangeInSource: Range::from( + $matchKeywordToken->boundaries->start, + $closingBracketToken->boundaries->end + ), + subject: $subject, + arms: $arms + ); + } catch (InvalidMatchArmNodes $e) { + throw MatchCouldNotBeParsed::becauseOfInvalidMatchArmNodes( + cause: $e, + affectedRangeInSource: $matchKeywordToken->boundaries + ); + } + } + + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractMatchKeywordToken(\Iterator &$tokens): Token + { + Scanner::assertType($tokens, TokenType::KEYWORD_MATCH); + + $matchKeywordToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $matchKeywordToken; + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseSubject(\Iterator &$tokens): ExpressionNode + { + $this->subjectParser ??= new ExpressionParser( + stopAt: TokenType::BRACKET_CURLY_OPEN + ); + + return $this->subjectParser->parse($tokens); + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipOpeningBracketToken(\Iterator &$tokens): void + { + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + /** + * @param \Iterator $tokens + * @return MatchArmNodes + */ + private function parseArms(\Iterator &$tokens): MatchArmNodes + { + $items = []; + while (Scanner::type($tokens) !== TokenType::BRACKET_CURLY_CLOSE) { + $items[] = $this->parseArm($tokens); + } + + return new MatchArmNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return MatchArmNode + */ + private function parseArm(\Iterator &$tokens): MatchArmNode + { + $defaultKeywordToken = $this->extractDefaultKeywordToken($tokens); + $left = is_null($defaultKeywordToken) ? $this->parseArmLeft($tokens) : null; + + $this->skipArrowSingleToken($tokens); + + $right = $this->parseArmRight($tokens); + + if (is_null($defaultKeywordToken)) { + assert($left !== null); + $start = $left->items[0]->rangeInSource->start; + } else { + $start = $defaultKeywordToken->boundaries->start; + } + + return new MatchArmNode( + rangeInSource: Range::from( + $start, + $right->rangeInSource->end + ), + left: $left, + right: $right + ); + } + + /** + * @param \Iterator $tokens + * @return null|Token + */ + private function extractDefaultKeywordToken(\Iterator &$tokens): ?Token + { + if (Scanner::type($tokens) === TokenType::KEYWORD_DEFAULT) { + $defaultKeywordToken = $tokens->current(); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + + return $defaultKeywordToken; + } + + return null; + } + + /** + * @param \Iterator $tokens + * @return ExpressionNodes + */ + private function parseArmLeft(\Iterator &$tokens): ExpressionNodes + { + $this->matchArmLeftParser ??= new ExpressionParser( + stopAt: TokenType::ARROW_SINGLE + ); + + $items = []; + while (Scanner::type($tokens) !== TokenType::ARROW_SINGLE) { + assert($this->matchArmLeftParser !== null); + $items[] = $this->matchArmLeftParser->parse($tokens); + + if (Scanner::type($tokens) !== TokenType::ARROW_SINGLE) { + $this->skipCommaToken($tokens); + } + } + + return new ExpressionNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipCommaToken(\Iterator &$tokens): void + { + Scanner::assertType($tokens, TokenType::COMMA); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipArrowSingleToken(\Iterator &$tokens): void + { + Scanner::assertType($tokens, TokenType::ARROW_SINGLE); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseArmRight(\Iterator &$tokens): ExpressionNode + { + $this->matchArmRightParser ??= new ExpressionParser( + stopAt: TokenType::BRACKET_CURLY_CLOSE + ); + + return $this->matchArmRightParser->parse($tokens); + } +} diff --git a/test/Unit/Language/AST/Node/Match/MatchArmNodeTest.php b/test/Unit/Language/AST/Node/Match/MatchArmNodeTest.php new file mode 100644 index 00000000..fca24aba --- /dev/null +++ b/test/Unit/Language/AST/Node/Match/MatchArmNodeTest.php @@ -0,0 +1,92 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Node\Match; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PHPUnit\Framework\TestCase; + +final class MatchArmNodeTest extends TestCase +{ + /** + * @test + */ + public function matchArmWithEmptyLeftIsDefault(): void + { + $zeroRange = Range::from(new Position(0, 0), new Position(0, 0)); + $matchArmNode = new MatchArmNode( + rangeInSource: $zeroRange, + left: null, + right: new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from('foo') + ) + ) + ); + + $this->assertTrue($matchArmNode->isDefault()); + } + + /** + * @test + */ + public function matchArmWithNonEmptyLeftIsNotDefault(): void + { + $zeroRange = Range::from(new Position(0, 0), new Position(0, 0)); + $matchArmNode = new MatchArmNode( + rangeInSource: $zeroRange, + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from('foo') + ) + ), + new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from('bar') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from('baz') + ) + ) + ); + + $this->assertFalse($matchArmNode->isDefault()); + } +} diff --git a/test/Unit/Language/AST/Node/Match/MatchArmNodesTest.php b/test/Unit/Language/AST/Node/Match/MatchArmNodesTest.php new file mode 100644 index 00000000..b943db10 --- /dev/null +++ b/test/Unit/Language/AST/Node/Match/MatchArmNodesTest.php @@ -0,0 +1,119 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Node\Match; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\InvalidMatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PHPUnit\Framework\TestCase; + +final class MatchArmNodesTest extends TestCase +{ + /** + * @param string[] $left + * @param string $right + * @return MatchArmNode + */ + protected function createMatchArmNode(array $left, string $right): MatchArmNode + { + $zeroRange = Range::from(new Position(0, 0), new Position(0, 0)); + + return new MatchArmNode( + rangeInSource: $zeroRange, + left: new ExpressionNodes( + ...array_map( + static fn(string $name) => new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from($name) + ) + ), + $left + ) + ), + right: new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from($right) + ) + ) + ); + + } + protected function createDefaultMatchArmNode(string $right): MatchArmNode + { + $zeroRange = Range::from(new Position(0, 0), new Position(0, 0)); + + return new MatchArmNode( + rangeInSource: $zeroRange, + left: null, + right: new ExpressionNode( + rangeInSource: $zeroRange, + root: new ValueReferenceNode( + rangeInSource: $zeroRange, + name: VariableName::from($right) + ) + ) + ); + } + + /** + * @test + */ + public function mustNotBeEmpty(): void + { + $this->expectExceptionObject( + InvalidMatchArmNodes::becauseTheyWereEmpty() + ); + + new MatchArmNodes(); + } + + /** + * @test + */ + public function mustNotContainMultipleDefaultArms(): void + { + $secondDefaultMatchArmNode = $this->createDefaultMatchArmNode('bar'); + + $this->expectExceptionObject( + InvalidMatchArmNodes::becauseTheyContainMoreThanOneDefaultMatchArmNode( + secondDefaultMatchArmNode: $secondDefaultMatchArmNode + ) + ); + + new MatchArmNodes( + $this->createMatchArmNode(['a', 'b'], 'c'), + $this->createDefaultMatchArmNode('foo'), + $secondDefaultMatchArmNode + ); + } +} diff --git a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php index 04630e42..bd3e2582 100644 --- a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php +++ b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php @@ -33,8 +33,12 @@ use PackageFactory\ComponentEngine\Language\AST\Node\BinaryOperation\BinaryOperator; use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchNode; use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; @@ -52,7 +56,13 @@ use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperator; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionCouldNotBeParsed; use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; final class ExpressionParserTest extends ParserTestCase @@ -948,7 +958,147 @@ public function parsesHexadecimalIntegerLiteral(): void */ public function parsesMatch(): void { - $this->markTestSkipped('@TODO: parses Match'); + $expressionParser = new ExpressionParser(); + $matchAsString = << foo + null -> foo.bar + default -> "N/A" + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); + + $expectedExpressioNode = new ExpressionNode( + rangeInSource: $this->range([0, 0], [5, 0]), + root: new MatchNode( + rangeInSource: $this->range([0, 0], [5, 0]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 17]), + root: new AccessNode( + rangeInSource: $this->range([0, 6], [0, 17]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 12]), + root: new AccessNode( + rangeInSource: $this->range([0, 6], [0, 12]), + parent: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 6], [0, 8]), + name: VariableName::from('foo') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 10], [0, 12]), + value: PropertyName::from('bar') + ) + ) + ), + type: AccessType::OPTIONAL, + key: new AccessKeyNode( + rangeInSource: $this->range([0, 15], [0, 17]), + value: PropertyName::from('baz') + ) + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 4], [2, 19]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 4], [1, 11]), + root: new AccessNode( + rangeInSource: $this->range([1, 4], [1, 11]), + parent: new ExpressionNode( + rangeInSource: $this->range([1, 4], [1, 6]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 4], [1, 6]), + name: VariableName::from('Qux') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([1, 8], [1, 11]), + value: PropertyName::from('QUUX') + ) + ) + ), + new ExpressionNode( + rangeInSource: $this->range([2, 4], [2, 12]), + root: new AccessNode( + rangeInSource: $this->range([2, 4], [2, 12]), + parent: new ExpressionNode( + rangeInSource: $this->range([2, 4], [2, 6]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 4], [2, 6]), + name: VariableName::from('Qux') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([2, 8], [2, 12]), + value: PropertyName::from('CORGE') + ) + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([2, 17], [2, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 17], [2, 19]), + name: VariableName::from('foo') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([3, 4], [3, 18]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([3, 4], [3, 7]), + root: new NullLiteralNode( + rangeInSource: $this->range([3, 4], [3, 7]), + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([3, 12], [3, 18]), + root: new AccessNode( + rangeInSource: $this->range([3, 12], [3, 18]), + parent: new ExpressionNode( + rangeInSource: $this->range([3, 12], [3, 14]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 12], [3, 14]), + name: VariableName::from('foo') + ) + ), + type: AccessType::MANDATORY, + key: new AccessKeyNode( + rangeInSource: $this->range([3, 16], [3, 18]), + value: PropertyName::from('bar') + ) + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([4, 4], [4, 18]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([4, 16], [4, 18]), + root: new StringLiteralNode( + rangeInSource: $this->range([4, 16], [4, 18]), + value: 'N/A' + ) + ) + ), + ) + ) + ); + + $this->assertEquals( + $expectedExpressioNode, + $expressionParser->parse($tokens) + ); } /** diff --git a/test/Unit/Language/Parser/Match/MatchParserTest.php b/test/Unit/Language/Parser/Match/MatchParserTest.php new file mode 100644 index 00000000..cea3a771 --- /dev/null +++ b/test/Unit/Language/Parser/Match/MatchParserTest.php @@ -0,0 +1,1168 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Match; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\InvalidMatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchArmNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Match\MatchNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\Match\MatchCouldNotBeParsed; +use PackageFactory\ComponentEngine\Language\Parser\Match\MatchParser; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class MatchParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesMatchWithOneArm(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { b -> c }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 19]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 17]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 12]), + name: VariableName::from('b') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 17], [0, 17]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 17], [0, 17]), + name: VariableName::from('c') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithMultipleArms(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { b -> c d -> e f -> g }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 33]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 17]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 12]), + name: VariableName::from('b') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 17], [0, 17]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 17], [0, 17]), + name: VariableName::from('c') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 19], [0, 24]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 19], [0, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 19], [0, 19]), + name: VariableName::from('d') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 24], [0, 24]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 24], [0, 24]), + name: VariableName::from('e') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 26], [0, 31]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 26], [0, 26]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 26], [0, 26]), + name: VariableName::from('f') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 31], [0, 31]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 31], [0, 31]), + name: VariableName::from('g') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithOneSummarizedArm(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { b, c, d -> e }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 25]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 23]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 12]), + name: VariableName::from('b') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 15], [0, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 15], [0, 15]), + name: VariableName::from('c') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 18]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 18], [0, 18]), + name: VariableName::from('d') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 23], [0, 23]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 23], [0, 23]), + name: VariableName::from('e') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithMultipleSummarizedArms(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { b, c, d -> e f, g, h -> i j, k, l -> m }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 51]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 23]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 12]), + name: VariableName::from('b') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 15], [0, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 15], [0, 15]), + name: VariableName::from('c') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 18]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 18], [0, 18]), + name: VariableName::from('d') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 23], [0, 23]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 23], [0, 23]), + name: VariableName::from('e') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 25], [0, 36]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 25], [0, 25]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 25], [0, 25]), + name: VariableName::from('f') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 28], [0, 28]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 28], [0, 28]), + name: VariableName::from('g') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 31], [0, 31]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 31], [0, 31]), + name: VariableName::from('h') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 36], [0, 36]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 36], [0, 36]), + name: VariableName::from('i') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 38], [0, 49]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 38], [0, 38]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 38], [0, 38]), + name: VariableName::from('j') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 41], [0, 41]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 41], [0, 41]), + name: VariableName::from('k') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 44], [0, 44]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 44], [0, 44]), + name: VariableName::from('l') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 49], [0, 49]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 49], [0, 49]), + name: VariableName::from('m') + ) + ) + ), + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithOnlyDefaultArm(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { default -> b }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 25]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 23]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([0, 23], [0, 23]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 23], [0, 23]), + name: VariableName::from('b') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithOneArmAndDefaultArm(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { b -> c default -> d }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 32]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 17]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 12]), + name: VariableName::from('b') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 17], [0, 17]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 17], [0, 17]), + name: VariableName::from('c') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 19], [0, 30]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([0, 30], [0, 30]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 30], [0, 30]), + name: VariableName::from('d') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithOneSummarizedArmAndDefaultArm(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator( + 'match (a) { b, c, d -> e default -> f }' + ); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [0, 38]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 12], [0, 23]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 12]), + name: VariableName::from('b') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 15], [0, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 15], [0, 15]), + name: VariableName::from('c') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 18], [0, 18]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 18], [0, 18]), + name: VariableName::from('d') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 23], [0, 23]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 23], [0, 23]), + name: VariableName::from('e') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 25], [0, 36]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([0, 36], [0, 36]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 36], [0, 36]), + name: VariableName::from('f') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesMatchWithMixedArms(): void + { + $matchParser = new MatchParser(); + $matchAsString = << c + d, e, f -> g + default -> h + i, j -> k + l -> m + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [6, 0]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 4], [1, 9]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 4], [1, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 4], [1, 4]), + name: VariableName::from('b') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([1, 9], [1, 9]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 9], [1, 9]), + name: VariableName::from('c') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([2, 4], [2, 15]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([2, 4], [2, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 4], [2, 4]), + name: VariableName::from('d') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([2, 7], [2, 7]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 7], [2, 7]), + name: VariableName::from('e') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([2, 10], [2, 10]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 10], [2, 10]), + name: VariableName::from('f') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([2, 15], [2, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 15], [2, 15]), + name: VariableName::from('g') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([3, 4], [3, 15]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([3, 15], [3, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 15], [3, 15]), + name: VariableName::from('h') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([4, 4], [4, 12]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([4, 4], [4, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([4, 4], [4, 4]), + name: VariableName::from('i') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([4, 7], [4, 7]), + root: new ValueReferenceNode( + rangeInSource: $this->range([4, 7], [4, 7]), + name: VariableName::from('j') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([4, 12], [4, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([4, 12], [4, 12]), + name: VariableName::from('k') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([5, 4], [5, 9]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([5, 4], [5, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([5, 4], [5, 4]), + name: VariableName::from('l') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([5, 9], [5, 9]), + root: new ValueReferenceNode( + rangeInSource: $this->range([5, 9], [5, 9]), + name: VariableName::from('m') + ) + ) + ), + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesNestedMatchAsSubject(): void + { + $matchParser = new MatchParser(); + $matchAsString = << d default -> e }) { + d, e -> f + default -> g + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [3, 0]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 43]), + root: new MatchNode( + rangeInSource: $this->range([0, 7], [0, 42]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 13], [0, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 14], [0, 14]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([0, 19], [0, 27]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 19], [0, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 19], [0, 19]), + name: VariableName::from('b') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([0, 22], [0, 22]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 22], [0, 22]), + name: VariableName::from('c') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([0, 27], [0, 27]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 27], [0, 27]), + name: VariableName::from('d') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([0, 29], [0, 40]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([0, 40], [0, 40]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 40], [0, 40]), + name: VariableName::from('e') + ) + ) + ), + ) + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 4], [1, 12]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 4], [1, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 4], [1, 4]), + name: VariableName::from('d') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([1, 7], [1, 7]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 7], [1, 7]), + name: VariableName::from('e') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([1, 12], [1, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 12], [1, 12]), + name: VariableName::from('f') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([2, 4], [2, 15]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([2, 15], [2, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 15], [2, 15]), + name: VariableName::from('g') + ) + ) + ), + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesNestedMatchAsArmLeft(): void + { + $matchParser = new MatchParser(); + $matchAsString = << e default -> f } -> g + match (h) { i -> j }, + match (k) { l, m -> n default -> o } -> p + default -> q + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [5, 0]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 4], [1, 44]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 4], [1, 39]), + root: new MatchNode( + rangeInSource: $this->range([1, 4], [1, 39]), + subject: new ExpressionNode( + rangeInSource: $this->range([1, 10], [1, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 11], [1, 11]), + name: VariableName::from('b') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 16], [1, 24]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 16], [1, 16]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 16], [1, 16]), + name: VariableName::from('c') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([1, 19], [1, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 19], [1, 19]), + name: VariableName::from('d') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([1, 24], [1, 24]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 24], [1, 24]), + name: VariableName::from('e') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([1, 26], [1, 37]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([1, 37], [1, 37]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 37], [1, 37]), + name: VariableName::from('f') + ) + ) + ), + ) + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([1, 44], [1, 44]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 44], [1, 44]), + name: VariableName::from('g') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([2, 4], [3, 44]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([2, 4], [2, 23]), + root: new MatchNode( + rangeInSource: $this->range([2, 4], [2, 23]), + subject: new ExpressionNode( + rangeInSource: $this->range([2, 10], [2, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 11], [2, 11]), + name: VariableName::from('h') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([2, 16], [2, 21]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([2, 16], [2, 16]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 16], [2, 16]), + name: VariableName::from('i') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([2, 21], [2, 21]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 21], [2, 21]), + name: VariableName::from('j') + ) + ) + ), + ) + ) + ), + new ExpressionNode( + rangeInSource: $this->range([3, 4], [3, 39]), + root: new MatchNode( + rangeInSource: $this->range([3, 4], [3, 39]), + subject: new ExpressionNode( + rangeInSource: $this->range([3, 10], [3, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 11], [3, 11]), + name: VariableName::from('k') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([3, 16], [3, 24]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([3, 16], [3, 16]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 16], [3, 16]), + name: VariableName::from('l') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([3, 19], [3, 19]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 19], [3, 19]), + name: VariableName::from('m') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([3, 24], [3, 24]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 24], [3, 24]), + name: VariableName::from('n') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([3, 26], [3, 37]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([3, 37], [3, 37]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 37], [3, 37]), + name: VariableName::from('o') + ) + ) + ), + ) + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([3, 44], [3, 44]), + root: new ValueReferenceNode( + rangeInSource: $this->range([3, 44], [3, 44]), + name: VariableName::from('p') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([4, 4], [4, 15]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([4, 15], [4, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([4, 15], [4, 15]), + name: VariableName::from('q') + ) + ) + ), + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesNestedMatchAsArmRight(): void + { + $matchParser = new MatchParser(); + $matchAsString = << match (c) { d, e -> f default -> g } + default -> h + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); + + $expectedMatchNode = new MatchNode( + rangeInSource: $this->range([0, 0], [3, 0]), + subject: new ExpressionNode( + rangeInSource: $this->range([0, 6], [0, 8]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 7], [0, 7]), + name: VariableName::from('a') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 4], [1, 44]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 4], [1, 4]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 4], [1, 4]), + name: VariableName::from('b') + ) + ), + ), + right: new ExpressionNode( + rangeInSource: $this->range([1, 9], [1, 44]), + root: new MatchNode( + rangeInSource: $this->range([1, 9], [1, 44]), + subject: new ExpressionNode( + rangeInSource: $this->range([1, 15], [1, 17]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 16], [1, 16]), + name: VariableName::from('c') + ) + ), + arms: new MatchArmNodes( + new MatchArmNode( + rangeInSource: $this->range([1, 21], [1, 29]), + left: new ExpressionNodes( + new ExpressionNode( + rangeInSource: $this->range([1, 21], [1, 21]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 21], [1, 21]), + name: VariableName::from('d') + ) + ), + new ExpressionNode( + rangeInSource: $this->range([1, 24], [1, 24]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 24], [1, 24]), + name: VariableName::from('e') + ) + ) + ), + right: new ExpressionNode( + rangeInSource: $this->range([1, 29], [1, 29]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 29], [1, 29]), + name: VariableName::from('f') + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([1, 31], [1, 42]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([1, 42], [1, 42]), + root: new ValueReferenceNode( + rangeInSource: $this->range([1, 42], [1, 42]), + name: VariableName::from('g') + ) + ) + ), + ) + ) + ) + ), + new MatchArmNode( + rangeInSource: $this->range([2, 4], [2, 15]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([2, 15], [2, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([2, 15], [2, 15]), + name: VariableName::from('h') + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedMatchNode, + $matchParser->parse($tokens) + ); + } + + /** + * @test + */ + public function emptyMatchArmsAreNotAllowed(): void + { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator('match (a) {}'); + + $this->expectException(ParserException::class); + $this->expectExceptionObject( + MatchCouldNotBeParsed::becauseOfInvalidMatchArmNodes( + cause: InvalidMatchArmNodes::becauseTheyWereEmpty(), + affectedRangeInSource: $this->range([0, 0], [0, 4]) + ) + ); + + $matchParser->parse($tokens); + } + + /** + * @test + */ + public function multipleDefaultArmsAreNotAllowed(): void + { + $matchParser = new MatchParser(); + $matchAsString = << d + default -> e + f, g -> h + default -> i + j -> k + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); + + $this->expectException(ParserException::class); + $this->expectExceptionObject( + MatchCouldNotBeParsed::becauseOfInvalidMatchArmNodes( + cause: InvalidMatchArmNodes::becauseTheyContainMoreThanOneDefaultMatchArmNode( + secondDefaultMatchArmNode: new MatchArmNode( + rangeInSource: $this->range([4, 4], [4, 15]), + left: null, + right: new ExpressionNode( + rangeInSource: $this->range([4, 15], [4, 15]), + root: new ValueReferenceNode( + rangeInSource: $this->range([4, 15], [4, 15]), + name: VariableName::from('i') + ) + ) + ) + ) + ) + ); + + $matchParser->parse($tokens); + } +} From 4e7760f65897ca41cb333aba97cee50d74c6a4fd Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 4 Aug 2023 17:10:38 +0200 Subject: [PATCH 49/64] TASK: Implement ComponentDeclarationParser --- src/Domain/ComponentName/ComponentName.php | 36 ++ .../ComponentDeclarationNode.php | 39 ++ .../ComponentNameNode.php | 36 ++ .../ComponentDeclarationParser.php | 176 ++++++++ .../Expression/ExpressionCouldNotBeParsed.php | 14 - .../Parser/Tag/TagCouldNotBeParsed.php | 20 +- src/Language/Parser/Tag/TagParser.php | 62 ++- src/Parser/Ast/EnumMemberDeclarationNode.php | 3 - src/Parser/Tokenizer/LookAhead.php | 2 +- src/Parser/Tokenizer/Scanner.php | 2 +- .../ComponentDeclarationParserTest.php | 305 ++++++++++++++ .../Language/Parser/Tag/TagParserTest.php | 379 ++++++++++++++++-- 12 files changed, 1023 insertions(+), 51 deletions(-) create mode 100644 src/Domain/ComponentName/ComponentName.php create mode 100644 src/Language/AST/Node/ComponentDeclaration/ComponentDeclarationNode.php create mode 100644 src/Language/AST/Node/ComponentDeclaration/ComponentNameNode.php create mode 100644 src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php create mode 100644 test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php diff --git a/src/Domain/ComponentName/ComponentName.php b/src/Domain/ComponentName/ComponentName.php new file mode 100644 index 00000000..a37f2bb4 --- /dev/null +++ b/src/Domain/ComponentName/ComponentName.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Domain\ComponentName; + +final class ComponentName +{ + private function __construct( + public readonly string $value + ) { + } + + public static function from(string $string): self + { + return new self($string); + } +} diff --git a/src/Language/AST/Node/ComponentDeclaration/ComponentDeclarationNode.php b/src/Language/AST/Node/ComponentDeclaration/ComponentDeclarationNode.php new file mode 100644 index 00000000..68e31865 --- /dev/null +++ b/src/Language/AST/Node/ComponentDeclaration/ComponentDeclarationNode.php @@ -0,0 +1,39 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration; + +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ComponentDeclarationNode extends Node +{ + public function __construct( + public readonly Range $rangeInSource, + public readonly ComponentNameNode $name, + public readonly PropertyDeclarationNodes $props, + public readonly ExpressionNode $return + ) { + } +} diff --git a/src/Language/AST/Node/ComponentDeclaration/ComponentNameNode.php b/src/Language/AST/Node/ComponentDeclaration/ComponentNameNode.php new file mode 100644 index 00000000..f3bba98d --- /dev/null +++ b/src/Language/AST/Node/ComponentDeclaration/ComponentNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration; + +use PackageFactory\ComponentEngine\Domain\ComponentName\ComponentName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ComponentNameNode extends Node +{ + public function __construct( + public readonly Range $rangeInSource, + public readonly ComponentName $value + ) { + } +} diff --git a/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php b/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php new file mode 100644 index 00000000..d02db95b --- /dev/null +++ b/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php @@ -0,0 +1,176 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\ComponentDeclaration; + +use PackageFactory\ComponentEngine\Domain\ComponentName\ComponentName; +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; +use PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration\PropertyDeclarationParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class ComponentDeclarationParser +{ + private readonly PropertyDeclarationParser $propertyDeclarationParser; + private ?ExpressionParser $returnParser = null; + + public function __construct() + { + $this->propertyDeclarationParser = new PropertyDeclarationParser(); + } + + /** + * @param \Iterator $tokens + * @return ComponentDeclarationNode + */ + public function parse(\Iterator &$tokens): ComponentDeclarationNode + { + $componentKeywordToken = $this->extractComponentKeywordToken($tokens); + $name = $this->parseName($tokens); + + $this->skipOpeningBracketToken($tokens); + + $props = $this->parseProps($tokens); + + $this->skipReturnKeywordToken($tokens); + + $return = $this->parseReturn($tokens); + $closingBracketToken = $this->extractClosingBracketToken($tokens); + + return new ComponentDeclarationNode( + rangeInSource: Range::from( + $componentKeywordToken->boundaries->start, + $closingBracketToken->boundaries->end + ), + name: $name, + props: $props, + return: $return + ); + } + + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractComponentKeywordToken(\Iterator &$tokens): Token + { + Scanner::assertType($tokens, TokenType::KEYWORD_COMPONENT); + + $componentKeywordToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $componentKeywordToken; + } + + /** + * @param \Iterator $tokens + * @return ComponentNameNode + */ + private function parseName(\Iterator &$tokens): ComponentNameNode + { + Scanner::assertType($tokens, TokenType::STRING); + + $componentNameToken = $tokens->current(); + + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return new ComponentNameNode( + rangeInSource: $componentNameToken->boundaries, + value: ComponentName::from($componentNameToken->value) + ); + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipOpeningBracketToken(\Iterator &$tokens): void + { + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + /** + * @param \Iterator $tokens + * @return PropertyDeclarationNodes + */ + private function parseProps(\Iterator &$tokens): PropertyDeclarationNodes + { + $items = []; + while (Scanner::type($tokens) !== TokenType::KEYWORD_RETURN) { + $items[] = $this->propertyDeclarationParser->parse($tokens); + + Scanner::skipSpaceAndComments($tokens); + } + + return new PropertyDeclarationNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return void + */ + private function skipReturnKeywordToken(\Iterator &$tokens): void + { + Scanner::assertType($tokens, TokenType::KEYWORD_RETURN); + Scanner::skipOne($tokens); + Scanner::skipSpaceAndComments($tokens); + } + + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseReturn(\Iterator &$tokens): ExpressionNode + { + $this->returnParser ??= new ExpressionParser( + stopAt: TokenType::BRACKET_CURLY_CLOSE + ); + + return $this->returnParser->parse($tokens); + } + + /** + * @param \Iterator $tokens + * @return Token + */ + private function extractClosingBracketToken(\Iterator &$tokens): Token + { + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + + $closingBracketToken = $tokens->current(); + + Scanner::skipOne($tokens); + + return $closingBracketToken; + } +} diff --git a/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php b/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php index 4a8c6afe..d3d4533c 100644 --- a/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php +++ b/src/Language/Parser/Expression/ExpressionCouldNotBeParsed.php @@ -43,18 +43,4 @@ public static function becauseOfUnexpectedToken( affectedRangeInSource: $actualToken->boundaries ); } - - public static function becauseOfUnexpectedExceedingToken( - Token $exceedingToken - ): self { - return new self( - code: 1691141293, - message: sprintf( - 'Expression could not be parsed because token stream was expected to end, ' - . 'but continued with %s instead.', - $exceedingToken->toDebugString() - ), - affectedRangeInSource: $exceedingToken->boundaries - ); - } } diff --git a/src/Language/Parser/Tag/TagCouldNotBeParsed.php b/src/Language/Parser/Tag/TagCouldNotBeParsed.php index 0d06f353..91408753 100644 --- a/src/Language/Parser/Tag/TagCouldNotBeParsed.php +++ b/src/Language/Parser/Tag/TagCouldNotBeParsed.php @@ -25,6 +25,8 @@ use PackageFactory\ComponentEngine\Domain\TagName\TagName; use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; final class TagCouldNotBeParsed extends ParserException { @@ -36,11 +38,27 @@ public static function becauseOfClosingTagNameMismatch( return new self( code: 1690976372, message: sprintf( - 'TagNode could not be parsed, because the closing tag name "%s" did not match the opening tag name "%s".', + 'Tag could not be parsed, because the closing tag name "%s" did not match the opening tag name "%s".', $actualTagName, $expectedTagName->value ), affectedRangeInSource: $affectedRangeInSource ); } + + public static function becauseOfUnexpectedToken( + TokenTypes $expectedTokenTypes, + Token $actualToken + ): self { + return new self( + code: 1691156112, + message: sprintf( + 'Tag could not be parsed because of unexpected token %s. ' + . 'Expected %s instead.', + $actualToken->toDebugString(), + $expectedTokenTypes->toDebugString() + ), + affectedRangeInSource: $actualToken->boundaries + ); + } } diff --git a/src/Language/Parser/Tag/TagParser.php b/src/Language/Parser/Tag/TagParser.php index a2297baf..df3a9df2 100644 --- a/src/Language/Parser/Tag/TagParser.php +++ b/src/Language/Parser/Tag/TagParser.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNode; @@ -31,17 +32,20 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\Text\TextParser; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; final class TagParser { private readonly StringLiteralParser $stringLiteralParser; private readonly TextParser $textParser; + private ?ExpressionParser $expressionParser; public function __construct() { @@ -187,20 +191,52 @@ private function parseAttributeName(\Iterator $tokens): AttributeNameNode /** * @param \Iterator $tokens - * @return null|StringLiteralNode + * @return null|StringLiteralNode|ExpressionNode */ - private function parseAttributeValue(\Iterator $tokens): null|StringLiteralNode + private function parseAttributeValue(\Iterator $tokens): null|StringLiteralNode|ExpressionNode { if (Scanner::type($tokens) === TokenType::EQUALS) { Scanner::skipOne($tokens); - Scanner::assertType($tokens, TokenType::STRING_QUOTED); - return $this->stringLiteralParser->parse($tokens); + return match (Scanner::type($tokens)) { + TokenType::STRING_QUOTED => + $this->stringLiteralParser->parse($tokens), + TokenType::BRACKET_CURLY_OPEN => + $this->parseExpression($tokens), + default => throw TagCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::STRING_QUOTED, + TokenType::BRACKET_CURLY_OPEN + ), + actualToken: $tokens->current() + ) + }; } return null; } + /** + * @param \Iterator $tokens + * @return ExpressionNode + */ + private function parseExpression(\Iterator &$tokens): ExpressionNode + { + $this->expressionParser ??= new ExpressionParser( + stopAt: TokenType::BRACKET_CURLY_CLOSE + ); + + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); + Scanner::skipOne($tokens); + + $expressionNode = $this->expressionParser->parse($tokens); + + Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); + Scanner::skipOne($tokens); + + return $expressionNode; + } + /** * @param \Iterator $tokens * @return null|Token @@ -243,6 +279,24 @@ private function parseChildren(\Iterator $tokens): ChildNodes if (Scanner::type($tokens) === TokenType::TAG_START_OPENING) { $items[] = $this->parse($tokens); $preserveLeadingSpace = Scanner::type($tokens) !== TokenType::END_OF_LINE; + continue; + } + + if (Scanner::type($tokens) === TokenType::BRACKET_CURLY_OPEN) { + $items[] = $this->parseExpression($tokens); + $preserveLeadingSpace = Scanner::type($tokens) !== TokenType::END_OF_LINE; + continue; + } + + if (Scanner::type($tokens) !== TokenType::TAG_START_CLOSING) { + throw TagCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::TAG_START_OPENING, + TokenType::TAG_START_CLOSING, + TokenType::BRACKET_CURLY_OPEN + ), + actualToken: $tokens->current() + ); } } diff --git a/src/Parser/Ast/EnumMemberDeclarationNode.php b/src/Parser/Ast/EnumMemberDeclarationNode.php index ccc03929..95896dd2 100644 --- a/src/Parser/Ast/EnumMemberDeclarationNode.php +++ b/src/Parser/Ast/EnumMemberDeclarationNode.php @@ -51,13 +51,10 @@ public static function fromTokens(\Iterator $tokens): self if (Scanner::type($tokens) === TokenType::BRACKET_ROUND_OPEN) { Scanner::skipOne($tokens); $value = match (Scanner::type($tokens)) { - /** @phpstan-ignore-next-line */ TokenType::STRING_QUOTED => StringLiteralNode::fromTokens($tokens), - /** @phpstan-ignore-next-line */ TokenType::NUMBER_DECIMAL => IntegerLiteralNode::fromTokens($tokens), default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) }; - /** @phpstan-ignore-next-line */ Scanner::assertType($tokens, TokenType::BRACKET_ROUND_CLOSE); Scanner::skipOne($tokens); } diff --git a/src/Parser/Tokenizer/LookAhead.php b/src/Parser/Tokenizer/LookAhead.php index 6dfb7252..4f7c3251 100644 --- a/src/Parser/Tokenizer/LookAhead.php +++ b/src/Parser/Tokenizer/LookAhead.php @@ -36,7 +36,7 @@ final class LookAhead implements \IteratorAggregate * @param \Iterator $tokens */ private function __construct( - public readonly \Iterator $tokens + public \Iterator $tokens ) { } diff --git a/src/Parser/Tokenizer/Scanner.php b/src/Parser/Tokenizer/Scanner.php index 97fff1cb..3e11f3e3 100644 --- a/src/Parser/Tokenizer/Scanner.php +++ b/src/Parser/Tokenizer/Scanner.php @@ -86,7 +86,7 @@ public static function assertValue(\Iterator $tokens, string ...$values): void * @param \Iterator $tokens * @return \Iterator */ - public static function skipOne(\Iterator $tokens): \Iterator + public static function skipOne(\Iterator &$tokens): \Iterator { $tokens->next(); return $tokens; diff --git a/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php b/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php new file mode 100644 index 00000000..958fd61a --- /dev/null +++ b/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php @@ -0,0 +1,305 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ComponentDeclaration; + +use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; +use PackageFactory\ComponentEngine\Domain\ComponentName\ComponentName; +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\ChildNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\ComponentDeclaration\ComponentDeclarationParser; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class ComponentDeclarationParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesComponentDeclarationWithNoProps(): void + { + $componentDeclarationParser = new ComponentDeclarationParser(); + $tokens = $this->createTokenIterator('component Foo { return "bar" }'); + + $expectedComponentDeclarationNode = new ComponentDeclarationNode( + rangeInSource: $this->range([0, 0], [0, 29]), + name: new ComponentNameNode( + rangeInSource: $this->range([0, 10], [0, 12]), + value: ComponentName::from('Foo') + ), + props: new PropertyDeclarationNodes(), + return: new ExpressionNode( + rangeInSource: $this->range([0, 24], [0, 26]), + root: new StringLiteralNode( + rangeInSource: $this->range([0, 24], [0, 26]), + value: 'bar' + ) + ) + ); + + $this->assertEquals( + $expectedComponentDeclarationNode, + $componentDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesComponentDeclarationWithOneProp(): void + { + $componentDeclarationParser = new ComponentDeclarationParser(); + $tokens = $this->createTokenIterator('component Foo { bar: string return bar }'); + + $expectedComponentDeclarationNode = new ComponentDeclarationNode( + rangeInSource: $this->range([0, 0], [0, 39]), + name: new ComponentNameNode( + rangeInSource: $this->range([0, 10], [0, 12]), + value: ComponentName::from('Foo') + ), + props: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + rangeInSource: $this->range([0, 16], [0, 26]), + name: new PropertyNameNode( + rangeInSource: $this->range([0, 16], [0, 18]), + value: PropertyName::from('bar') + ), + type: new TypeReferenceNode( + rangeInSource: $this->range([0, 21], [0, 26]), + names: new TypeNameNodes( + new TypeNameNode( + rangeInSource: $this->range([0, 21], [0, 26]), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: false + ) + ) + ), + return: new ExpressionNode( + rangeInSource: $this->range([0, 35], [0, 37]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 35], [0, 37]), + name: VariableName::from('bar') + ) + ) + ); + + $this->assertEquals( + $expectedComponentDeclarationNode, + $componentDeclarationParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesComponentDeclarationWithMultiplePropsAndComplexReturnStatement(): void + { + $componentDeclarationParser = new ComponentDeclarationParser(); + $componentAsString = <<{children} + } + AFX; + $tokens = $this->createTokenIterator($componentAsString); + + $expectedComponentDeclarationNode = new ComponentDeclarationNode( + rangeInSource: $this->range([0, 0], [7, 0]), + name: new ComponentNameNode( + rangeInSource: $this->range([0, 10], [0, 13]), + value: ComponentName::from('Link') + ), + props: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + rangeInSource: $this->range([1, 4], [1, 19]), + name: new PropertyNameNode( + rangeInSource: $this->range([1, 4], [1, 7]), + value: PropertyName::from('href') + ), + type: new TypeReferenceNode( + rangeInSource: $this->range([1, 10], [1, 19]), + names: new TypeNameNodes( + new TypeNameNode( + rangeInSource: $this->range([1, 10], [1, 15]), + value: TypeName::from('string') + ), + new TypeNameNode( + rangeInSource: $this->range([1, 17], [1, 19]), + value: TypeName::from('Uri') + ) + ), + isArray: false, + isOptional: false + ) + ), + new PropertyDeclarationNode( + rangeInSource: $this->range([2, 4], [2, 18]), + name: new PropertyNameNode( + rangeInSource: $this->range([2, 4], [2, 9]), + value: PropertyName::from('target') + ), + type: new TypeReferenceNode( + rangeInSource: $this->range([2, 12], [2, 18]), + names: new TypeNameNodes( + new TypeNameNode( + rangeInSource: $this->range([2, 13], [2, 18]), + value: TypeName::from('string') + ) + ), + isArray: false, + isOptional: true + ) + ), + new PropertyDeclarationNode( + rangeInSource: $this->range([3, 4], [3, 16]), + name: new PropertyNameNode( + rangeInSource: $this->range([3, 4], [3, 6]), + value: PropertyName::from('rel') + ), + type: new TypeReferenceNode( + rangeInSource: $this->range([3, 9], [3, 16]), + names: new TypeNameNodes( + new TypeNameNode( + rangeInSource: $this->range([3, 9], [3, 14]), + value: TypeName::from('string') + ) + ), + isArray: true, + isOptional: false + ) + ), + new PropertyDeclarationNode( + rangeInSource: $this->range([4, 4], [4, 17]), + name: new PropertyNameNode( + rangeInSource: $this->range([4, 4], [4, 11]), + value: PropertyName::from('children') + ), + type: new TypeReferenceNode( + rangeInSource: $this->range([4, 14], [4, 17]), + names: new TypeNameNodes( + new TypeNameNode( + rangeInSource: $this->range([4, 14], [4, 17]), + value: TypeName::from('slot') + ) + ), + isArray: false, + isOptional: false + ) + ), + ), + return: new ExpressionNode( + rangeInSource: $this->range([6, 11], [6, 65]), + root: new TagNode( + rangeInSource: $this->range([6, 11], [6, 65]), + name: new TagNameNode( + rangeInSource: $this->range([6, 12], [6, 12]), + value: TagName::from('a') + ), + attributes: new AttributeNodes( + new AttributeNode( + rangeInSource: $this->range([6, 14], [6, 23]), + name: new AttributeNameNode( + rangeInSource: $this->range([6, 14], [6, 17]), + value: AttributeName::from('href') + ), + value: new ExpressionNode( + rangeInSource: $this->range([6, 20], [6, 23]), + root: new ValueReferenceNode( + rangeInSource: $this->range([6, 20], [6, 23]), + name: VariableName::from('href') + ) + ) + ), + new AttributeNode( + rangeInSource: $this->range([6, 26], [6, 39]), + name: new AttributeNameNode( + rangeInSource: $this->range([6, 26], [6, 31]), + value: AttributeName::from('target') + ), + value: new ExpressionNode( + rangeInSource: $this->range([6, 34], [6, 39]), + root: new ValueReferenceNode( + rangeInSource: $this->range([6, 34], [6, 39]), + name: VariableName::from('target') + ) + ) + ), + new AttributeNode( + rangeInSource: $this->range([6, 42], [6, 49]), + name: new AttributeNameNode( + rangeInSource: $this->range([6, 42], [6, 44]), + value: AttributeName::from('rel') + ), + value: new ExpressionNode( + rangeInSource: $this->range([6, 47], [6, 49]), + root: new ValueReferenceNode( + rangeInSource: $this->range([6, 47], [6, 49]), + name: VariableName::from('rel') + ) + ) + ) + ), + children: new ChildNodes( + new ExpressionNode( + rangeInSource: $this->range([6, 53], [6, 60]), + root: new ValueReferenceNode( + rangeInSource: $this->range([6, 53], [6, 60]), + name: VariableName::from('children') + ) + ) + ), + isSelfClosing: false + ) + ) + ); + + $this->assertEquals( + $expectedComponentDeclarationNode, + $componentDeclarationParser->parse($tokens) + ); + } +} diff --git a/test/Unit/Language/Parser/Tag/TagParserTest.php b/test/Unit/Language/Parser/Tag/TagParserTest.php index 18e7c240..fe3c25a0 100644 --- a/test/Unit/Language/Parser/Tag/TagParserTest.php +++ b/test/Unit/Language/Parser/Tag/TagParserTest.php @@ -24,6 +24,8 @@ use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNode; @@ -32,6 +34,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\TagNode; use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagCouldNotBeParsed; @@ -39,9 +42,9 @@ use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Source; use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class TagParserTest extends TestCase +final class TagParserTest extends ParserTestCase { /** * @test @@ -338,6 +341,126 @@ public function parsesSelfClosingTagWithMultipleStringAttributes(): void ); } + /** + * @test + */ + public function parsesSelfClosingTagWithExpressionAttribute(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 13) + ), + name: new TagNameNode( + rangeInSource: Range::from( + new Position(0, 1), + new Position(0, 1) + ), + value: TagName::from('a') + ), + attributes: new AttributeNodes( + new AttributeNode( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 10) + ), + name: new AttributeNameNode( + rangeInSource: Range::from( + new Position(0, 3), + new Position(0, 5) + ), + value: AttributeName::from('foo') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 8], [0, 10]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 8], [0, 10]), + name: VariableName::from('bar') + ) + ) + ) + ), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesSelfClosingTagWithMultipleExpressionAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + + $expectedTagNode = new TagNode( + rangeInSource: $this->range([0, 0], [0, 38]), + name: new TagNameNode( + rangeInSource: $this->range([0, 1], [0, 3]), + value: TagName::from('div') + ), + attributes: new AttributeNodes( + new AttributeNode( + rangeInSource: $this->range([0, 5], [0, 12]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 5], [0, 7]), + value: AttributeName::from('foo') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 10], [0, 12]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 10], [0, 12]), + name: VariableName::from('bar') + ) + ) + ), + new AttributeNode( + rangeInSource: $this->range([0, 15], [0, 22]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 15], [0, 17]), + value: AttributeName::from('baz') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 20], [0, 22]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 20], [0, 22]), + name: VariableName::from('qux') + ) + ) + ), + new AttributeNode( + rangeInSource: $this->range([0, 25], [0, 35]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 25], [0, 28]), + value: AttributeName::from('quux') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 31], [0, 35]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 31], [0, 35]), + name: VariableName::from('corge') + ) + ) + ) + ), + children: new ChildNodes(), + isSelfClosing: true + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + /** * @test */ @@ -656,6 +779,114 @@ public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void ); } + /** + * @test + */ + public function parsesTagWithEmptyContentAndExpressionAttribute(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + rangeInSource: $this->range([0, 0], [0, 24]), + name: new TagNameNode( + rangeInSource: $this->range([0, 1], [0, 5]), + value: TagName::from('audio') + ), + attributes: new AttributeNodes( + new AttributeNode( + rangeInSource: $this->range([0, 7], [0, 14]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 7], [0, 9]), + value: AttributeName::from('foo') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 14]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 14]), + name: VariableName::from('bar') + ) + ) + ), + ), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesTagWithEmptyContentAndMultipleExpressionAttributes(): void + { + $tagParser = new TagParser(); + $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + + $expectedTagNode = new TagNode( + rangeInSource: $this->range([0, 0], [0, 47]), + name: new TagNameNode( + rangeInSource: $this->range([0, 1], [0, 5]), + value: TagName::from('video') + ), + attributes: new AttributeNodes( + new AttributeNode( + rangeInSource: $this->range([0, 7], [0, 14]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 7], [0, 9]), + value: AttributeName::from('foo') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 12], [0, 14]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 12], [0, 14]), + name: VariableName::from('bar') + ) + ) + ), + new AttributeNode( + rangeInSource: $this->range([0, 17], [0, 24]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 17], [0, 19]), + value: AttributeName::from('baz') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 22], [0, 24]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 22], [0, 24]), + name: VariableName::from('qux') + ) + ) + ), + new AttributeNode( + rangeInSource: $this->range([0, 27], [0, 37]), + name: new AttributeNameNode( + rangeInSource: $this->range([0, 27], [0, 30]), + value: AttributeName::from('quux') + ), + value: new ExpressionNode( + rangeInSource: $this->range([0, 33], [0, 37]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 33], [0, 37]), + name: VariableName::from('corge') + ) + ) + ), + ), + children: new ChildNodes(), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + /** * @test */ @@ -695,6 +926,39 @@ public function parsesTagWithTextContentAndWithoutAttributes(): void ); } + /** + * @test + */ + public function parsesTagWithExpressionContentAndWithoutAttributes(): void + { + $tagParser = new TagParser(); + $tokens = $this->createTokenIterator('{someExpression}'); + + $expectedTagNode = new TagNode( + rangeInSource: $this->range([0, 0], [0, 22]), + name: new TagNameNode( + rangeInSource: $this->range([0, 1], [0, 1]), + value: TagName::from('a') + ), + attributes: new AttributeNodes(), + children: new ChildNodes( + new ExpressionNode( + rangeInSource: $this->range([0, 4], [0, 17]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 4], [0, 17]), + name: VariableName::from('someExpression') + ) + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + /** * @test */ @@ -991,6 +1255,47 @@ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundT ); } + /** + * @test + */ + public function parsesTagWithExpressionInBetweenTextContentPreservingSpaceAroundTheExpression(): void + { + $tagParser = new TagParser(); + $tokens = $this->createTokenIterator('Something {variable} happened.'); + + $expectedTagNode = new TagNode( + rangeInSource: $this->range([0, 0], [0, 36]), + name: new TagNameNode( + rangeInSource: $this->range([0, 1], [0, 1]), + value: TagName::from('a') + ), + attributes: new AttributeNodes(), + children: new ChildNodes( + new TextNode( + rangeInSource: $this->range([0, 3], [0, 12]), + value: 'Something ' + ), + new ExpressionNode( + rangeInSource: $this->range([0, 14], [0, 21]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 14], [0, 21]), + name: VariableName::from('variable') + ) + ), + new TextNode( + rangeInSource: $this->range([0, 23], [0, 32]), + value: ' happened.' + ) + ), + isSelfClosing: false + ); + + $this->assertEquals( + $expectedTagNode, + $tagParser->parse($tokens) + ); + } + /** * @test */ @@ -1082,8 +1387,8 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut Some opening text

Headline

This is a link -

- This is a paragraph with emphasized and boldened text. +

+ This is a {paragraph} with emphasized and boldened text.

Some closing text
@@ -1260,12 +1565,12 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), value: AttributeName::from('class') ), - value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(4, 14), - new Position(4, 16) - ), - value: 'rte' + value: new ExpressionNode( + rangeInSource: $this->range([4, 14], [4, 16]), + root: new ValueReferenceNode( + rangeInSource: $this->range([4, 14], [4, 16]), + name: VariableName::from('rte') + ) ) ), ), @@ -1273,19 +1578,39 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut new TextNode( rangeInSource: Range::from( new Position(4, 19), - new Position(5, 32) + new Position(5, 17) + ), + value: 'This is a ' + ), + new ExpressionNode( + rangeInSource: Range::from( + new Position(5, 19), + new Position(5, 27) + ), + root: new ValueReferenceNode( + rangeInSource: Range::from( + new Position(5, 19), + new Position(5, 27) + ), + name: VariableName::from('paragraph') + ) + ), + new TextNode( + rangeInSource: Range::from( + new Position(5, 29), + new Position(5, 34) ), - value: 'This is a paragraph with ' + value: ' with ' ), new TagNode( rangeInSource: Range::from( - new Position(5, 33), - new Position(5, 51) + new Position(5, 35), + new Position(5, 53) ), name: new TagNameNode( rangeInSource: Range::from( - new Position(5, 34), - new Position(5, 35) + new Position(5, 36), + new Position(5, 37) ), value: TagName::from('em') ), @@ -1293,8 +1618,8 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut children: new ChildNodes( new TextNode( rangeInSource: Range::from( - new Position(5, 37), - new Position(5, 46) + new Position(5, 39), + new Position(5, 48) ), value: 'emphasized' ), @@ -1303,20 +1628,20 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), new TextNode( rangeInSource: Range::from( - new Position(5, 52), - new Position(5, 56) + new Position(5, 54), + new Position(5, 58) ), value: ' and ' ), new TagNode( rangeInSource: Range::from( - new Position(5, 57), - new Position(5, 81) + new Position(5, 59), + new Position(5, 83) ), name: new TagNameNode( rangeInSource: Range::from( - new Position(5, 58), - new Position(5, 63) + new Position(5, 60), + new Position(5, 65) ), value: TagName::from('strong') ), @@ -1324,8 +1649,8 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut children: new ChildNodes( new TextNode( rangeInSource: Range::from( - new Position(5, 65), - new Position(5, 72) + new Position(5, 67), + new Position(5, 74) ), value: 'boldened' ), @@ -1334,7 +1659,7 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), new TextNode( rangeInSource: Range::from( - new Position(5, 82), + new Position(5, 84), new Position(6, 3) ), value: ' text.' From e7aed5a9f845c91fe6ab7ef5db029fd70f644004 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 4 Aug 2023 23:06:56 +0200 Subject: [PATCH 50/64] TASK: Implement ImportParser --- src/Language/AST/Node/Import/ImportNode.php | 37 +++++ .../AST/Node/Import/ImportedNameNode.php | 36 +++++ .../AST/Node/Import/ImportedNameNodes.php | 51 ++++++ .../Node/Import/InvalidImportedNameNodes.php | 46 ++++++ .../Parser/Import/ImportCouldNotBeParsed.php | 44 +++++ src/Language/Parser/Import/ImportParser.php | 148 +++++++++++++++++ .../AST/Node/Import/ImportedNameNodesTest.php | 84 ++++++++++ .../Parser/Import/ImportParserTest.php | 152 ++++++++++++++++++ test/Unit/Language/Parser/ParserTestCase.php | 13 ++ 9 files changed, 611 insertions(+) create mode 100644 src/Language/AST/Node/Import/ImportNode.php create mode 100644 src/Language/AST/Node/Import/ImportedNameNode.php create mode 100644 src/Language/AST/Node/Import/ImportedNameNodes.php create mode 100644 src/Language/AST/Node/Import/InvalidImportedNameNodes.php create mode 100644 src/Language/Parser/Import/ImportCouldNotBeParsed.php create mode 100644 src/Language/Parser/Import/ImportParser.php create mode 100644 test/Unit/Language/AST/Node/Import/ImportedNameNodesTest.php create mode 100644 test/Unit/Language/Parser/Import/ImportParserTest.php diff --git a/src/Language/AST/Node/Import/ImportNode.php b/src/Language/AST/Node/Import/ImportNode.php new file mode 100644 index 00000000..fbcdaff0 --- /dev/null +++ b/src/Language/AST/Node/Import/ImportNode.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Import; + +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ImportNode extends Node +{ + public function __construct( + public readonly Range $rangeInSource, + public readonly StringLiteralNode $path, + public readonly ImportedNameNodes $names + ) { + } +} diff --git a/src/Language/AST/Node/Import/ImportedNameNode.php b/src/Language/AST/Node/Import/ImportedNameNode.php new file mode 100644 index 00000000..2e88a582 --- /dev/null +++ b/src/Language/AST/Node/Import/ImportedNameNode.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Import; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ImportedNameNode extends Node +{ + public function __construct( + public readonly Range $rangeInSource, + public readonly VariableName $value + ) { + } +} diff --git a/src/Language/AST/Node/Import/ImportedNameNodes.php b/src/Language/AST/Node/Import/ImportedNameNodes.php new file mode 100644 index 00000000..f4fcf2de --- /dev/null +++ b/src/Language/AST/Node/Import/ImportedNameNodes.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Import; + +final class ImportedNameNodes +{ + /** + * @var ImportedNameNode[] + */ + public readonly array $items; + + public function __construct(ImportedNameNode ...$items) + { + if (count($items) === 0) { + throw InvalidImportedNameNodes::becauseTheyWereEmpty(); + } + + $typeNames = []; + foreach ($items as $item) { + if (isset($typeNames[$item->value->value])) { + throw InvalidImportedNameNodes::becauseTheyContainDuplicates( + duplicateImportedNameNode: $item + ); + } + + $typeNames[$item->value->value] = true; + } + + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/Import/InvalidImportedNameNodes.php b/src/Language/AST/Node/Import/InvalidImportedNameNodes.php new file mode 100644 index 00000000..76a368ef --- /dev/null +++ b/src/Language/AST/Node/Import/InvalidImportedNameNodes.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Import; + +use PackageFactory\ComponentEngine\Language\AST\ASTException; + +final class InvalidImportedNameNodes extends ASTException +{ + public static function becauseTheyWereEmpty(): self + { + return new self( + code: 1691163487, + message: 'An import statement must import at least one name.' + ); + } + + public static function becauseTheyContainDuplicates( + ImportedNameNode $duplicateImportedNameNode + ): self { + return new self( + code: 1691163492, + message: 'An import statement must not import duplicate names.', + affectedRangeInSource: $duplicateImportedNameNode->rangeInSource + ); + } +} diff --git a/src/Language/Parser/Import/ImportCouldNotBeParsed.php b/src/Language/Parser/Import/ImportCouldNotBeParsed.php new file mode 100644 index 00000000..38dd1036 --- /dev/null +++ b/src/Language/Parser/Import/ImportCouldNotBeParsed.php @@ -0,0 +1,44 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Import; + +use PackageFactory\ComponentEngine\Language\AST\Node\Import\InvalidImportedNameNodes; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ImportCouldNotBeParsed extends ParserException +{ + public static function becauseOfInvalidImportedNameNodes( + InvalidImportedNameNodes $cause, + Range $affectedRangeInSource + ): self { + return new self( + code: 1691181627, + message: sprintf( + 'Import could not be parsed, because of invalid imported names: %s', + $cause->getMessage() + ), + affectedRangeInSource: $cause->affectedRangeInSource ?? $affectedRangeInSource + ); + } +} diff --git a/src/Language/Parser/Import/ImportParser.php b/src/Language/Parser/Import/ImportParser.php new file mode 100644 index 00000000..6551fe8b --- /dev/null +++ b/src/Language/Parser/Import/ImportParser.php @@ -0,0 +1,148 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Import; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\InvalidImportedNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class ImportParser +{ + private readonly StringLiteralParser $pathParser; + + public function __construct() + { + $this->pathParser = new StringLiteralParser(); + } + + /** + * @param \Iterator $tokens + * @return ImportNode + */ + public function parse(\Iterator &$tokens): ImportNode + { + $fromKeywordToken = $this->extractToken($tokens, TokenType::KEYWORD_FROM); + $path = $this->parsePath($tokens); + + $this->skipToken($tokens, TokenType::KEYWORD_IMPORT); + $openingBracketToken = $this->extractToken($tokens, TokenType::BRACKET_CURLY_OPEN); + + try { + $names = $this->parseNames($tokens); + $closingBracketToken = $this->extractToken($tokens, TokenType::BRACKET_CURLY_CLOSE); + + return new ImportNode( + rangeInSource: Range::from( + $fromKeywordToken->boundaries->start, + $closingBracketToken->boundaries->end + ), + path: $path, + names: $names + ); + } catch (InvalidImportedNameNodes $e) { + throw ImportCouldNotBeParsed::becauseOfInvalidImportedNameNodes( + cause: $e, + affectedRangeInSource: $openingBracketToken->boundaries + ); + } + } + + /** + * @param \Iterator $tokens + * @param TokenType $tokenType + * @return Token + */ + private function extractToken(\Iterator &$tokens, TokenType $tokenType): Token + { + Scanner::assertType($tokens, $tokenType); + $token = $tokens->current(); + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $token; + } + + /** + * @param \Iterator $tokens + * @param TokenType $tokenType + * @return void + */ + private function skipToken(\Iterator &$tokens, TokenType $tokenType): void + { + Scanner::assertType($tokens, $tokenType); + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + } + + /** + * @param \Iterator $tokens + * @return StringLiteralNode + */ + private function parsePath(\Iterator &$tokens): StringLiteralNode + { + $path = $this->pathParser->parse($tokens); + Scanner::skipSpace($tokens); + + return $path; + } + + /** + * @param \Iterator $tokens + * @return ImportedNameNodes + */ + private function parseNames(\Iterator &$tokens): ImportedNameNodes + { + $items = []; + while (Scanner::type($tokens) !== TokenType::BRACKET_CURLY_CLOSE) { + $items[] = $this->parseName($tokens); + + if (Scanner::type($tokens) !== TokenType::BRACKET_CURLY_CLOSE) { + $this->skipToken($tokens, TokenType::COMMA); + } + } + + return new ImportedNameNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return ImportedNameNode + */ + private function parseName(\Iterator &$tokens): ImportedNameNode + { + $nameToken = $this->extractToken($tokens, TokenType::STRING); + + return new ImportedNameNode( + rangeInSource: $nameToken->boundaries, + value: VariableName::from($nameToken->value) + ); + } +} diff --git a/test/Unit/Language/AST/Node/Import/ImportedNameNodesTest.php b/test/Unit/Language/AST/Node/Import/ImportedNameNodesTest.php new file mode 100644 index 00000000..84906c3d --- /dev/null +++ b/test/Unit/Language/AST/Node/Import/ImportedNameNodesTest.php @@ -0,0 +1,84 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\AST\Node\Import; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\InvalidImportedNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNodes; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PHPUnit\Framework\TestCase; + +final class ImportedNameNodesTest extends TestCase +{ + protected function createImportedNameNode(string $typeName): ImportedNameNode + { + return new ImportedNameNode( + rangeInSource: Range::from( + new Position(0, 0), + new Position(0, 0) + ), + value: VariableName::from($typeName) + ); + } + + /** + * @test + */ + public function mustNotBeEmpty(): void + { + $this->expectExceptionObject( + InvalidImportedNameNodes::becauseTheyWereEmpty() + ); + + new ImportedNameNodes(); + } + + /** + * @test + */ + public function mustNotContainDuplicates(): void + { + $duplicate = new ImportedNameNode( + rangeInSource: Range::from( + new Position(1, 1), + new Position(1, 1) + ), + value: VariableName::from('Foo') + ); + + $this->expectExceptionObject( + InvalidImportedNameNodes::becauseTheyContainDuplicates( + duplicateImportedNameNode: $duplicate + ) + ); + + new ImportedNameNodes( + $this->createImportedNameNode('Foo'), + $this->createImportedNameNode('Bar'), + $duplicate, + $this->createImportedNameNode('Baz'), + ); + } +} diff --git a/test/Unit/Language/Parser/Import/ImportParserTest.php b/test/Unit/Language/Parser/Import/ImportParserTest.php new file mode 100644 index 00000000..790788f3 --- /dev/null +++ b/test/Unit/Language/Parser/Import/ImportParserTest.php @@ -0,0 +1,152 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Import; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\InvalidImportedNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\Parser\Import\ImportCouldNotBeParsed; +use PackageFactory\ComponentEngine\Language\Parser\Import\ImportParser; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class ImportParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesImportWithOneName(): void + { + $importParser = new ImportParser(); + $tokens = $this->createTokenIterator( + 'from "/some/where/in/the/filesystem" import { Foo }' + ); + + $expectedImportNode = new ImportNode( + rangeInSource: $this->range([0, 0], [0, 50]), + path: new StringLiteralNode( + rangeInSource: $this->range([0, 6], [0, 34]), + value: '/some/where/in/the/filesystem' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([0, 46], [0, 48]), + value: VariableName::from('Foo') + ) + ) + ); + + $this->assertEquals( + $expectedImportNode, + $importParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesImportWithMultipleNames(): void + { + $importParser = new ImportParser(); + $tokens = $this->createTokenIterator( + 'from "./some/other.component" import { Foo, Bar, Baz }' + ); + + $expectedImportNode = new ImportNode( + rangeInSource: $this->range([0, 0], [0, 53]), + path: new StringLiteralNode( + rangeInSource: $this->range([0, 6], [0, 27]), + value: './some/other.component' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([0, 39], [0, 41]), + value: VariableName::from('Foo') + ), + new ImportedNameNode( + rangeInSource: $this->range([0, 44], [0, 46]), + value: VariableName::from('Bar') + ), + new ImportedNameNode( + rangeInSource: $this->range([0, 49], [0, 51]), + value: VariableName::from('Baz') + ) + ) + ); + + $this->assertEquals( + $expectedImportNode, + $importParser->parse($tokens) + ); + } + + /** + * @test + */ + public function emptyImportIsNotAllowed(): void + { + $this->assertThrowsParserException( + function () { + $importParser = new ImportParser(); + $tokens = $this->createTokenIterator( + 'from "/some/where" import {}' + ); + + $importParser->parse($tokens); + }, + ImportCouldNotBeParsed::becauseOfInvalidImportedNameNodes( + cause: InvalidImportedNameNodes::becauseTheyWereEmpty(), + affectedRangeInSource: $this->range([0, 26], [0, 26]) + ) + ); + } + + /** + * @test + */ + public function duplicateImportsAreNotAllowed(): void + { + $this->assertThrowsParserException( + function () { + $importParser = new ImportParser(); + $tokens = $this->createTokenIterator( + 'from "/some/where" import { Foo, Bar, Baz, Bar, Qux }' + ); + + $importParser->parse($tokens); + }, + ImportCouldNotBeParsed::becauseOfInvalidImportedNameNodes( + cause: InvalidImportedNameNodes::becauseTheyContainDuplicates( + duplicateImportedNameNode: new ImportedNameNode( + rangeInSource: $this->range([0, 43], [0, 45]), + value: VariableName::from('Bar') + ) + ), + affectedRangeInSource: $this->range([0, 43], [0, 45]), + ) + ); + } +} diff --git a/test/Unit/Language/Parser/ParserTestCase.php b/test/Unit/Language/Parser/ParserTestCase.php index 97a9402c..15120259 100644 --- a/test/Unit/Language/Parser/ParserTestCase.php +++ b/test/Unit/Language/Parser/ParserTestCase.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser; +use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Parser\Source\Position; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Source\Source; @@ -55,4 +56,16 @@ protected function range(array $startAsArray, array $endAsArray): Range new Position(...$endAsArray) ); } + + protected function assertThrowsParserException(callable $fn, ParserException $expectedParserException): void + { + $this->expectExceptionObject($expectedParserException); + + try { + $fn(); + } catch (ParserException $e) { + $this->assertEquals($expectedParserException, $e); + throw $e; + } + } } From 99bb80a7018a6b4b4ccc767991798d69f139890c Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Fri, 4 Aug 2023 23:46:28 +0200 Subject: [PATCH 51/64] TASK: Implement ExportParser --- src/Language/AST/Node/Export/ExportNode.php | 38 ++++ .../Parser/Export/ExportCouldNotBeParsed.php | 46 ++++ src/Language/Parser/Export/ExportParser.php | 122 +++++++++++ .../Parser/Export/ExportParserTest.php | 206 ++++++++++++++++++ 4 files changed, 412 insertions(+) create mode 100644 src/Language/AST/Node/Export/ExportNode.php create mode 100644 src/Language/Parser/Export/ExportCouldNotBeParsed.php create mode 100644 src/Language/Parser/Export/ExportParser.php create mode 100644 test/Unit/Language/Parser/Export/ExportParserTest.php diff --git a/src/Language/AST/Node/Export/ExportNode.php b/src/Language/AST/Node/Export/ExportNode.php new file mode 100644 index 00000000..a316bf6d --- /dev/null +++ b/src/Language/AST/Node/Export/ExportNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Export; + +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ExportNode extends Node +{ + public function __construct( + public readonly Range $rangeInSource, + public readonly ComponentDeclarationNode | EnumDeclarationNode | StructDeclarationNode $declaration + ) { + } +} diff --git a/src/Language/Parser/Export/ExportCouldNotBeParsed.php b/src/Language/Parser/Export/ExportCouldNotBeParsed.php new file mode 100644 index 00000000..53da8b64 --- /dev/null +++ b/src/Language/Parser/Export/ExportCouldNotBeParsed.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Export; + +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; + +final class ExportCouldNotBeParsed extends ParserException +{ + public static function becauseOfUnexpectedToken( + TokenTypes $expectedTokenTypes, + Token $actualToken + ): self { + return new self( + code: 1691184282, + message: sprintf( + 'Export could not be parsed because of unexpected token %s. ' + . 'Expected %s instead.', + $actualToken->toDebugString(), + $expectedTokenTypes->toDebugString() + ), + affectedRangeInSource: $actualToken->boundaries + ); + } +} diff --git a/src/Language/Parser/Export/ExportParser.php b/src/Language/Parser/Export/ExportParser.php new file mode 100644 index 00000000..795f7fa0 --- /dev/null +++ b/src/Language/Parser/Export/ExportParser.php @@ -0,0 +1,122 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Export; + +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; +use PackageFactory\ComponentEngine\Language\Parser\ComponentDeclaration\ComponentDeclarationParser; +use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; +use PackageFactory\ComponentEngine\Language\Parser\StructDeclaration\StructDeclarationParser; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; + +final class ExportParser +{ + private readonly ComponentDeclarationParser $componentDeclarationParser; + private readonly EnumDeclarationParser $enumDeclarationParser; + private readonly StructDeclarationParser $structDeclarationParser; + + public function __construct() + { + $this->componentDeclarationParser = new ComponentDeclarationParser(); + $this->enumDeclarationParser = new EnumDeclarationParser(); + $this->structDeclarationParser = new StructDeclarationParser(); + } + + /** + * @param \Iterator $tokens + * @return ExportNode + */ + public function parse(\Iterator &$tokens): ExportNode + { + $exportKeywordToken = $this->extractToken($tokens, TokenType::KEYWORD_EXPORT); + $declaration = match (Scanner::type($tokens)) { + TokenType::KEYWORD_COMPONENT => $this->parseComponentDeclaration($tokens), + TokenType::KEYWORD_ENUM => $this->parseEnumDeclaration($tokens), + TokenType::KEYWORD_STRUCT => $this->parseStructDeclaration($tokens), + default => throw ExportCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::KEYWORD_COMPONENT, + TokenType::KEYWORD_ENUM, + TokenType::KEYWORD_STRUCT + ), + actualToken: $tokens->current() + ) + }; + + return new ExportNode( + rangeInSource: Range::from( + $exportKeywordToken->boundaries->start, + $declaration->rangeInSource->end + ), + declaration: $declaration + ); + } + + /** + * @param \Iterator $tokens + * @param TokenType $tokenType + * @return Token + */ + private function extractToken(\Iterator &$tokens, TokenType $tokenType): Token + { + Scanner::assertType($tokens, $tokenType); + $token = $tokens->current(); + Scanner::skipOne($tokens); + Scanner::skipSpace($tokens); + + return $token; + } + + /** + * @param \Iterator $tokens + * @return ComponentDeclarationNode + */ + private function parseComponentDeclaration(\Iterator &$tokens): ComponentDeclarationNode + { + return $this->componentDeclarationParser->parse($tokens); + } + + /** + * @param \Iterator $tokens + * @return EnumDeclarationNode + */ + private function parseEnumDeclaration(\Iterator &$tokens): EnumDeclarationNode + { + return $this->enumDeclarationParser->parse($tokens); + } + + /** + * @param \Iterator $tokens + * @return StructDeclarationNode + */ + private function parseStructDeclaration(\Iterator &$tokens): StructDeclarationNode + { + return $this->structDeclarationParser->parse($tokens); + } +} diff --git a/test/Unit/Language/Parser/Export/ExportParserTest.php b/test/Unit/Language/Parser/Export/ExportParserTest.php new file mode 100644 index 00000000..61c0c288 --- /dev/null +++ b/test/Unit/Language/Parser/Export/ExportParserTest.php @@ -0,0 +1,206 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Export; + +use PackageFactory\ComponentEngine\Domain\ComponentName\ComponentName; +use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; +use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; +use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; +use PackageFactory\ComponentEngine\Language\Parser\Export\ExportCouldNotBeParsed; +use PackageFactory\ComponentEngine\Language\Parser\Export\ExportParser; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class ExportParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesComponentExport(): void + { + $exportParser = new ExportParser(); + $tokens = $this->createTokenIterator( + 'export component Foo { return bar }' + ); + + $expectedExportNode = new ExportNode( + rangeInSource: $this->range([0, 0], [0, 34]), + declaration: new ComponentDeclarationNode( + rangeInSource: $this->range([0, 7], [0, 34]), + name: new ComponentNameNode( + rangeInSource: $this->range([0, 17], [0, 19]), + value: ComponentName::from('Foo') + ), + props: new PropertyDeclarationNodes(), + return: new ExpressionNode( + rangeInSource: $this->range([0, 30], [0, 32]), + root: new ValueReferenceNode( + rangeInSource: $this->range([0, 30], [0, 32]), + name: VariableName::from('bar') + ) + ) + ) + ); + + $this->assertEquals( + $expectedExportNode, + $exportParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesEnumExport(): void + { + $exportParser = new ExportParser(); + $tokens = $this->createTokenIterator( + 'export enum Foo { BAR }' + ); + + $expectedExportNode = new ExportNode( + rangeInSource: $this->range([0, 0], [0, 22]), + declaration: new EnumDeclarationNode( + rangeInSource: $this->range([0, 7], [0, 22]), + name: new EnumNameNode( + rangeInSource: $this->range([0, 12], [0, 14]), + value: EnumName::from('Foo') + ), + members: new EnumMemberDeclarationNodes( + new EnumMemberDeclarationNode( + rangeInSource: $this->range([0, 18], [0, 20]), + name: new EnumMemberNameNode( + rangeInSource: $this->range([0, 18], [0, 20]), + value: EnumMemberName::from('BAR') + ), + value: null + ) + ) + ) + ); + + $this->assertEquals( + $expectedExportNode, + $exportParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesStructExport(): void + { + $exportParser = new ExportParser(); + $tokens = $this->createTokenIterator( + 'export struct Foo { bar: baz }' + ); + + $expectedExportNode = new ExportNode( + rangeInSource: $this->range([0, 0], [0, 29]), + declaration: new StructDeclarationNode( + rangeInSource: $this->range([0, 7], [0, 29]), + name: new StructNameNode( + rangeInSource: $this->range([0, 14], [0, 16]), + value: StructName::from('Foo') + ), + properties: new PropertyDeclarationNodes( + new PropertyDeclarationNode( + rangeInSource: $this->range([0, 20], [0, 27]), + name: new PropertyNameNode( + rangeInSource: $this->range([0, 20], [0, 22]), + value: PropertyName::from('bar') + ), + type: new TypeReferenceNode( + rangeInSource: $this->range([0, 25], [0, 27]), + names: new TypeNameNodes( + new TypeNameNode( + rangeInSource: $this->range([0, 25], [0, 27]), + value: TypeName::from('baz') + ) + ), + isArray: false, + isOptional: false + ) + ) + ) + ) + ); + + $this->assertEquals( + $expectedExportNode, + $exportParser->parse($tokens) + ); + } + + /** + * @test + */ + public function throwsIfExportIsNoDeclaration(): void + { + $this->assertThrowsParserException( + function () { + $exportParser = new ExportParser(); + $tokens = $this->createTokenIterator('export null'); + + $exportParser->parse($tokens); + }, + ExportCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::KEYWORD_COMPONENT, + TokenType::KEYWORD_ENUM, + TokenType::KEYWORD_STRUCT + ), + actualToken: new Token( + type: TokenType::KEYWORD_NULL, + value: 'null', + boundaries: $this->range([0, 7], [0, 10]), + sourcePath: Path::createMemory() + ) + ) + ); + } +} From ba7e0bbf55b7846d473a6816f5a58e99e90401e8 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sat, 5 Aug 2023 13:51:23 +0200 Subject: [PATCH 52/64] TASK: Implement ModuleParser --- src/Language/AST/Node/Import/ImportNodes.php | 36 ++ src/Language/AST/Node/Module/ModuleNode.php | 38 +++ .../Parser/Module/ModuleCouldNotBeParsed.php | 42 +++ src/Language/Parser/Module/ModuleParser.php | 112 +++++++ .../Parser/Module/ModuleParserTest.php | 314 ++++++++++++++++++ 5 files changed, 542 insertions(+) create mode 100644 src/Language/AST/Node/Import/ImportNodes.php create mode 100644 src/Language/AST/Node/Module/ModuleNode.php create mode 100644 src/Language/Parser/Module/ModuleCouldNotBeParsed.php create mode 100644 src/Language/Parser/Module/ModuleParser.php create mode 100644 test/Unit/Language/Parser/Module/ModuleParserTest.php diff --git a/src/Language/AST/Node/Import/ImportNodes.php b/src/Language/AST/Node/Import/ImportNodes.php new file mode 100644 index 00000000..087aa9d1 --- /dev/null +++ b/src/Language/AST/Node/Import/ImportNodes.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Import; + +final class ImportNodes +{ + /** + * @var ImportNode[] + */ + public readonly array $items; + + public function __construct(ImportNode ...$items) + { + $this->items = $items; + } +} diff --git a/src/Language/AST/Node/Module/ModuleNode.php b/src/Language/AST/Node/Module/ModuleNode.php new file mode 100644 index 00000000..468348b4 --- /dev/null +++ b/src/Language/AST/Node/Module/ModuleNode.php @@ -0,0 +1,38 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\AST\Node\Module; + +use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Node; +use PackageFactory\ComponentEngine\Parser\Source\Range; + +final class ModuleNode extends Node +{ + public function __construct( + public readonly Range $rangeInSource, + public readonly ImportNodes $imports, + public readonly ExportNode $export, + ) { + } +} diff --git a/src/Language/Parser/Module/ModuleCouldNotBeParsed.php b/src/Language/Parser/Module/ModuleCouldNotBeParsed.php new file mode 100644 index 00000000..fac71860 --- /dev/null +++ b/src/Language/Parser/Module/ModuleCouldNotBeParsed.php @@ -0,0 +1,42 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Module; + +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; + +final class ModuleCouldNotBeParsed extends ParserException +{ + public static function becauseOfUnexpectedExceedingToken( + Token $exceedingToken + ): self { + return new self( + code: 1691235933, + message: sprintf( + 'Module could not be parsed because of unexpected exceeding token %s.', + $exceedingToken->toDebugString() + ), + affectedRangeInSource: $exceedingToken->boundaries + ); + } +} diff --git a/src/Language/Parser/Module/ModuleParser.php b/src/Language/Parser/Module/ModuleParser.php new file mode 100644 index 00000000..2e5fbfa0 --- /dev/null +++ b/src/Language/Parser/Module/ModuleParser.php @@ -0,0 +1,112 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\Module; + +use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Module\ModuleNode; +use PackageFactory\ComponentEngine\Language\Parser\Export\ExportParser; +use PackageFactory\ComponentEngine\Language\Parser\Import\ImportParser; +use PackageFactory\ComponentEngine\Parser\Source\Position; +use PackageFactory\ComponentEngine\Parser\Source\Range; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; + +final class ModuleParser +{ + private readonly ImportParser $importParser; + private readonly ExportParser $exportParser; + + public function __construct() + { + $this->importParser = new ImportParser(); + $this->exportParser = new ExportParser(); + } + + /** + * @param \Iterator $tokens + * @return ModuleNode + */ + public function parse(\Iterator &$tokens): ModuleNode + { + Scanner::skipSpaceAndComments($tokens); + + $imports = $this->parseImports($tokens); + $export = $this->parseExport($tokens); + + if (!Scanner::isEnd($tokens)) { + throw ModuleCouldNotBeParsed::becauseOfUnexpectedExceedingToken( + exceedingToken: $tokens->current() + ); + } + + return new ModuleNode( + rangeInSource: Range::from( + new Position(0, 0), + $export->rangeInSource->end + ), + imports: $imports, + export: $export + ); + } + + /** + * @param \Iterator $tokens + * @return ImportNodes + */ + private function parseImports(\Iterator &$tokens): ImportNodes + { + $items = []; + while (Scanner::type($tokens) !== TokenType::KEYWORD_EXPORT) { + $items[] = $this->parseImport($tokens); + } + + return new ImportNodes(...$items); + } + + /** + * @param \Iterator $tokens + * @return ImportNode + */ + private function parseImport(\Iterator &$tokens): ImportNode + { + $import = $this->importParser->parse($tokens); + Scanner::skipSpaceAndComments($tokens); + + return $import; + } + + /** + * @param \Iterator $tokens + * @return ExportNode + */ + private function parseExport(\Iterator &$tokens): ExportNode + { + $export = $this->exportParser->parse($tokens); + Scanner::skipSpaceAndComments($tokens); + + return $export; + } +} diff --git a/test/Unit/Language/Parser/Module/ModuleParserTest.php b/test/Unit/Language/Parser/Module/ModuleParserTest.php new file mode 100644 index 00000000..4d8a9e6a --- /dev/null +++ b/test/Unit/Language/Parser/Module/ModuleParserTest.php @@ -0,0 +1,314 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Language\Parser\Module; + +use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNode; +use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\Module\ModuleNode; +use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructNameNode; +use PackageFactory\ComponentEngine\Language\Parser\Module\ModuleCouldNotBeParsed; +use PackageFactory\ComponentEngine\Language\Parser\Module\ModuleParser; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; + +final class ModuleParserTest extends ParserTestCase +{ + /** + * @test + */ + public function parsesModuleWithNoImports(): void + { + $moduleParser = new ModuleParser(); + $moduleAsString = <<createTokenIterator($moduleAsString); + + $expectedModuleNode = new ModuleNode( + rangeInSource: $this->range([0, 0], [0, 19]), + imports: new ImportNodes(), + export: new ExportNode( + rangeInSource: $this->range([0, 0], [0, 19]), + declaration: new StructDeclarationNode( + rangeInSource: $this->range([0, 7], [0, 19]), + name: new StructNameNode( + rangeInSource: $this->range([0, 14], [0, 16]), + value: StructName::from('Foo') + ), + properties: new PropertyDeclarationNodes() + ) + ) + ); + + $this->assertEquals( + $expectedModuleNode, + $moduleParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesModuleWithOneImport(): void + { + $moduleParser = new ModuleParser(); + $moduleAsString = <<createTokenIterator($moduleAsString); + + $expectedModuleNode = new ModuleNode( + rangeInSource: $this->range([0, 0], [2, 19]), + imports: new ImportNodes( + new ImportNode( + rangeInSource: $this->range([0, 0], [0, 37]), + path: new StringLiteralNode( + rangeInSource: $this->range([0, 6], [0, 16]), + value: '/some/where' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([0, 28], [0, 30]), + value: VariableName::from('Foo') + ), + new ImportedNameNode( + rangeInSource: $this->range([0, 33], [0, 35]), + value: VariableName::from('Bar') + ) + ) + ) + ), + export: new ExportNode( + rangeInSource: $this->range([2, 0], [2, 19]), + declaration: new StructDeclarationNode( + rangeInSource: $this->range([2, 7], [2, 19]), + name: new StructNameNode( + rangeInSource: $this->range([2, 14], [2, 16]), + value: StructName::from('Baz') + ), + properties: new PropertyDeclarationNodes() + ) + ) + ); + + $this->assertEquals( + $expectedModuleNode, + $moduleParser->parse($tokens) + ); + } + + /** + * @test + */ + public function parsesModuleWithMultipleImports(): void + { + $moduleParser = new ModuleParser(); + $moduleAsString = <<createTokenIterator($moduleAsString); + + $expectedModuleNode = new ModuleNode( + rangeInSource: $this->range([0, 0], [4, 21]), + imports: new ImportNodes( + new ImportNode( + rangeInSource: $this->range([0, 0], [0, 37]), + path: new StringLiteralNode( + rangeInSource: $this->range([0, 6], [0, 16]), + value: '/some/where' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([0, 28], [0, 30]), + value: VariableName::from('Foo') + ), + new ImportedNameNode( + rangeInSource: $this->range([0, 33], [0, 35]), + value: VariableName::from('Bar') + ) + ) + ), + new ImportNode( + rangeInSource: $this->range([1, 0], [1, 37]), + path: new StringLiteralNode( + rangeInSource: $this->range([1, 6], [1, 21]), + value: '/some/where/else' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([1, 33], [1, 35]), + value: VariableName::from('Baz') + ), + ) + ), + new ImportNode( + rangeInSource: $this->range([2, 0], [2, 33]), + path: new StringLiteralNode( + rangeInSource: $this->range([2, 6], [2, 11]), + value: './here' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([2, 23], [2, 25]), + value: VariableName::from('Qux') + ), + new ImportedNameNode( + rangeInSource: $this->range([2, 28], [2, 31]), + value: VariableName::from('Quux') + ) + ) + ), + + ), + export: new ExportNode( + rangeInSource: $this->range([4, 0], [4, 21]), + declaration: new StructDeclarationNode( + rangeInSource: $this->range([4, 7], [4, 21]), + name: new StructNameNode( + rangeInSource: $this->range([4, 14], [4, 18]), + value: StructName::from('Corge') + ), + properties: new PropertyDeclarationNodes() + ) + ) + ); + + $this->assertEquals( + $expectedModuleNode, + $moduleParser->parse($tokens) + ); + } + + /** + * @test + */ + public function toleratesCommentsAndSpacesInBetweenStatements(): void + { + $moduleParser = new ModuleParser(); + $moduleAsString = <<createTokenIterator($moduleAsString); + + $expectedModuleNode = new ModuleNode( + rangeInSource: $this->range([0, 0], [11, 19]), + imports: new ImportNodes( + new ImportNode( + rangeInSource: $this->range([5, 0], [5, 37]), + path: new StringLiteralNode( + rangeInSource: $this->range([5, 6], [5, 16]), + value: '/some/where' + ), + names: new ImportedNameNodes( + new ImportedNameNode( + rangeInSource: $this->range([5, 28], [5, 30]), + value: VariableName::from('Foo') + ), + new ImportedNameNode( + rangeInSource: $this->range([5, 33], [5, 35]), + value: VariableName::from('Bar') + ) + ) + ) + ), + export: new ExportNode( + rangeInSource: $this->range([11, 0], [11, 19]), + declaration: new StructDeclarationNode( + rangeInSource: $this->range([11, 7], [11, 19]), + name: new StructNameNode( + rangeInSource: $this->range([11, 14], [11, 16]), + value: StructName::from('Baz') + ), + properties: new PropertyDeclarationNodes() + ) + ) + ); + + $this->assertEquals( + $expectedModuleNode, + $moduleParser->parse($tokens) + ); + } + + /** + * @test + */ + public function exceedingTokensAreNotAllowed(): void + { + $this->assertThrowsParserException( + function () { + $moduleParser = new ModuleParser(); + $moduleAsString = <<createTokenIterator($moduleAsString); + + $moduleParser->parse($tokens); + }, + ModuleCouldNotBeParsed::becauseOfUnexpectedExceedingToken( + exceedingToken: new Token( + type: TokenType::KEYWORD_EXPORT, + value: 'export', + boundaries: $this->range([4, 0], [4, 5]), + sourcePath: Path::createMemory() + ) + ) + ); + } +} From d7a3d8e170391dc62d645ca59b4788c9b619142c Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sat, 5 Aug 2023 14:24:30 +0200 Subject: [PATCH 53/64] TASK: Pass token iterator by-reference in all Parser implementations --- .../BooleanLiteral/BooleanLiteralParser.php | 2 +- .../EnumDeclaration/EnumDeclarationParser.php | 18 ++++++------ .../Parser/Expression/ExpressionParser.php | 2 +- .../IntegerLiteral/IntegerLiteralParser.php | 2 +- .../Parser/NullLiteral/NullLiteralParser.php | 2 +- .../PropertyDeclarationParser.php | 2 +- .../StringLiteral/StringLiteralParser.php | 2 +- .../StructDeclarationParser.php | 12 ++++---- src/Language/Parser/Tag/TagParser.php | 28 +++++++++---------- src/Language/Parser/Text/TextParser.php | 2 +- .../TypeReference/TypeReferenceParser.php | 10 +++---- .../ValueReference/ValueReferenceParser.php | 2 +- 12 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index db5436d1..300ef04d 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -33,7 +33,7 @@ final class BooleanLiteralParser * @param \Iterator $tokens * @return BooleanLiteralNode */ - public function parse(\Iterator $tokens): BooleanLiteralNode + public function parse(\Iterator &$tokens): BooleanLiteralNode { Scanner::assertType($tokens, TokenType::KEYWORD_TRUE, TokenType::KEYWORD_FALSE); diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 7f6fdb6a..3e0b06e2 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -52,7 +52,7 @@ public function __construct() * @param \Iterator $tokens * @return EnumDeclarationNode */ - public function parse(\Iterator $tokens): EnumDeclarationNode + public function parse(\Iterator &$tokens): EnumDeclarationNode { $enumKeyWordToken = $this->extractEnumKeywordToken($tokens); $enumNameNode = $this->parseEnumName($tokens); @@ -76,7 +76,7 @@ public function parse(\Iterator $tokens): EnumDeclarationNode * @param \Iterator $tokens * @return Token */ - private function extractEnumKeywordToken(\Iterator $tokens): Token + private function extractEnumKeywordToken(\Iterator &$tokens): Token { Scanner::assertType($tokens, TokenType::KEYWORD_ENUM); @@ -92,7 +92,7 @@ private function extractEnumKeywordToken(\Iterator $tokens): Token * @param \Iterator $tokens * @return EnumNameNode */ - private function parseEnumName(\Iterator $tokens): EnumNameNode + private function parseEnumName(\Iterator &$tokens): EnumNameNode { Scanner::assertType($tokens, TokenType::STRING); @@ -112,7 +112,7 @@ private function parseEnumName(\Iterator $tokens): EnumNameNode * @param \Iterator $tokens * @return void */ - private function skipOpeningBracketToken(\Iterator $tokens): void + private function skipOpeningBracketToken(\Iterator &$tokens): void { Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); Scanner::skipOne($tokens); @@ -122,7 +122,7 @@ private function skipOpeningBracketToken(\Iterator $tokens): void * @param \Iterator $tokens * @return EnumMemberDeclarationNodes */ - private function parseEnumMemberDeclarations(\Iterator $tokens): EnumMemberDeclarationNodes + private function parseEnumMemberDeclarations(\Iterator &$tokens): EnumMemberDeclarationNodes { $items = []; while (true) { @@ -146,7 +146,7 @@ private function parseEnumMemberDeclarations(\Iterator $tokens): EnumMemberDecla * @param \Iterator $tokens * @return Token */ - private function extractClosingBracketToken(\Iterator $tokens): Token + private function extractClosingBracketToken(\Iterator &$tokens): Token { Scanner::skipSpace($tokens); Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); @@ -162,7 +162,7 @@ private function extractClosingBracketToken(\Iterator $tokens): Token * @param \Iterator $tokens * @return EnumMemberDeclarationNode */ - private function parseEnumMemberDeclaration(\Iterator $tokens): EnumMemberDeclarationNode + private function parseEnumMemberDeclaration(\Iterator &$tokens): EnumMemberDeclarationNode { $enumMemberName = $this->parseEnumMemberName($tokens); $value = $this->parseEnumMemberValue($tokens); @@ -182,7 +182,7 @@ private function parseEnumMemberDeclaration(\Iterator $tokens): EnumMemberDeclar * @param \Iterator $tokens * @return EnumMemberNameNode */ - private function parseEnumMemberName(\Iterator $tokens): EnumMemberNameNode + private function parseEnumMemberName(\Iterator &$tokens): EnumMemberNameNode { Scanner::assertType($tokens, TokenType::STRING); @@ -201,7 +201,7 @@ private function parseEnumMemberName(\Iterator $tokens): EnumMemberNameNode * @param \Iterator $tokens * @return null|EnumMemberValueNode */ - private function parseEnumMemberValue(\Iterator $tokens): ?EnumMemberValueNode + private function parseEnumMemberValue(\Iterator &$tokens): ?EnumMemberValueNode { if (Scanner::type($tokens) !== TokenType::BRACKET_ROUND_OPEN) { return null; diff --git a/src/Language/Parser/Expression/ExpressionParser.php b/src/Language/Parser/Expression/ExpressionParser.php index 16d3b081..0620749e 100644 --- a/src/Language/Parser/Expression/ExpressionParser.php +++ b/src/Language/Parser/Expression/ExpressionParser.php @@ -530,7 +530,7 @@ private function parseBinaryOperator(\Iterator &$tokens): BinaryOperator * @param ExpressionNode $condition * @return ExpressionNode */ - private function parseTernaryOperation(\Iterator $tokens, ExpressionNode $condition): ExpressionNode + private function parseTernaryOperation(\Iterator &$tokens, ExpressionNode $condition): ExpressionNode { Scanner::assertType($tokens, TokenType::QUESTIONMARK); Scanner::skipOne($tokens); diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index f2160ba3..2aa2b159 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -33,7 +33,7 @@ final class IntegerLiteralParser * @param \Iterator $tokens * @return IntegerLiteralNode */ - public function parse(\Iterator $tokens): IntegerLiteralNode + public function parse(\Iterator &$tokens): IntegerLiteralNode { $token = $tokens->current(); diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index 91786fd9..baaebbf2 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -33,7 +33,7 @@ final class NullLiteralParser * @param \Iterator $tokens * @return NullLiteralNode */ - public function parse(\Iterator $tokens): NullLiteralNode + public function parse(\Iterator &$tokens): NullLiteralNode { Scanner::assertType($tokens, TokenType::KEYWORD_NULL); diff --git a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php index 59933f4b..9650e06b 100644 --- a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php +++ b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php @@ -44,7 +44,7 @@ public function __construct() * @param \Iterator $tokens * @return PropertyDeclarationNode */ - public function parse(\Iterator $tokens): PropertyDeclarationNode + public function parse(\Iterator &$tokens): PropertyDeclarationNode { Scanner::assertType($tokens, TokenType::STRING); $propertyNameToken = $tokens->current(); diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index 66815c42..96ed63e7 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -33,7 +33,7 @@ final class StringLiteralParser * @param \Iterator $tokens * @return StringLiteralNode */ - public function parse(\Iterator $tokens): StringLiteralNode + public function parse(\Iterator &$tokens): StringLiteralNode { Scanner::assertType($tokens, TokenType::STRING_QUOTED); diff --git a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php index c49c2701..8c764ca1 100644 --- a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php +++ b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php @@ -45,7 +45,7 @@ public function __construct() * @param \Iterator $tokens * @return StructDeclarationNode */ - public function parse(\Iterator $tokens): StructDeclarationNode + public function parse(\Iterator &$tokens): StructDeclarationNode { $structKeywordToken = $this->extractStructKeywordToken($tokens); $structNameNode = $this->parseStructName($tokens); @@ -67,7 +67,7 @@ public function parse(\Iterator $tokens): StructDeclarationNode * @param \Iterator $tokens * @return Token */ - public function extractStructKeywordToken(\Iterator $tokens): Token + public function extractStructKeywordToken(\Iterator &$tokens): Token { Scanner::assertType($tokens, TokenType::KEYWORD_STRUCT); @@ -83,7 +83,7 @@ public function extractStructKeywordToken(\Iterator $tokens): Token * @param \Iterator $tokens * @return StructNameNode */ - public function parseStructName(\Iterator $tokens): StructNameNode + public function parseStructName(\Iterator &$tokens): StructNameNode { Scanner::assertType($tokens, TokenType::STRING); @@ -102,7 +102,7 @@ public function parseStructName(\Iterator $tokens): StructNameNode * @param \Iterator $tokens * @return void */ - public function skipOpeningBracketToken(\Iterator $tokens): void + public function skipOpeningBracketToken(\Iterator &$tokens): void { Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); Scanner::skipOne($tokens); @@ -113,7 +113,7 @@ public function skipOpeningBracketToken(\Iterator $tokens): void * @param \Iterator $tokens * @return PropertyDeclarationNodes */ - public function parsePropertyDeclarations(\Iterator $tokens): PropertyDeclarationNodes + public function parsePropertyDeclarations(\Iterator &$tokens): PropertyDeclarationNodes { $items = []; while (Scanner::type($tokens) === TokenType::STRING) { @@ -128,7 +128,7 @@ public function parsePropertyDeclarations(\Iterator $tokens): PropertyDeclaratio * @param \Iterator $tokens * @return Token */ - public function extractClosingBracketToken(\Iterator $tokens): Token + public function extractClosingBracketToken(\Iterator &$tokens): Token { Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); diff --git a/src/Language/Parser/Tag/TagParser.php b/src/Language/Parser/Tag/TagParser.php index df3a9df2..c1aec7e7 100644 --- a/src/Language/Parser/Tag/TagParser.php +++ b/src/Language/Parser/Tag/TagParser.php @@ -57,7 +57,7 @@ public function __construct() * @param \Iterator $tokens * @return TagNode */ - public function parse(\Iterator $tokens): TagNode + public function parse(\Iterator &$tokens): TagNode { $tagStartOpeningToken = $this->extractTagStartOpeningToken($tokens); $tagNameNode = $this->parseTagName($tokens); @@ -98,7 +98,7 @@ public function parse(\Iterator $tokens): TagNode * @param \Iterator $tokens * @return Token */ - private function extractTagStartOpeningToken(\Iterator $tokens): Token + private function extractTagStartOpeningToken(\Iterator &$tokens): Token { Scanner::assertType($tokens, TokenType::TAG_START_OPENING); $tagStartOpeningToken = $tokens->current(); @@ -111,7 +111,7 @@ private function extractTagStartOpeningToken(\Iterator $tokens): Token * @param \Iterator $tokens * @return TagNameNode */ - private function parseTagName(\Iterator $tokens): TagNameNode + private function parseTagName(\Iterator &$tokens): TagNameNode { Scanner::assertType($tokens, TokenType::STRING); $tagNameToken = $tokens->current(); @@ -127,7 +127,7 @@ private function parseTagName(\Iterator $tokens): TagNameNode * @param \Iterator $tokens * @return AttributeNodes */ - private function parseAttributes(\Iterator $tokens): AttributeNodes + private function parseAttributes(\Iterator &$tokens): AttributeNodes { $items = []; while (!$this->isTagEnd($tokens)) { @@ -145,7 +145,7 @@ private function parseAttributes(\Iterator $tokens): AttributeNodes * @param \Iterator $tokens * @return boolean */ - private function isTagEnd($tokens): bool + private function isTagEnd(\Iterator $tokens): bool { return ( Scanner::type($tokens) === TokenType::TAG_END || @@ -157,7 +157,7 @@ private function isTagEnd($tokens): bool * @param \Iterator $tokens * @return AttributeNode */ - private function parseAttribute(\Iterator $tokens): AttributeNode + private function parseAttribute(\Iterator &$tokens): AttributeNode { $attributeNameNode = $this->parseAttributeName($tokens); $attributeValueNode = $this->parseAttributeValue($tokens); @@ -177,7 +177,7 @@ private function parseAttribute(\Iterator $tokens): AttributeNode * @param \Iterator $tokens * @return AttributeNameNode */ - private function parseAttributeName(\Iterator $tokens): AttributeNameNode + private function parseAttributeName(\Iterator &$tokens): AttributeNameNode { Scanner::assertType($tokens, TokenType::STRING); $attributeNameToken = $tokens->current(); @@ -193,7 +193,7 @@ private function parseAttributeName(\Iterator $tokens): AttributeNameNode * @param \Iterator $tokens * @return null|StringLiteralNode|ExpressionNode */ - private function parseAttributeValue(\Iterator $tokens): null|StringLiteralNode|ExpressionNode + private function parseAttributeValue(\Iterator &$tokens): null|StringLiteralNode|ExpressionNode { if (Scanner::type($tokens) === TokenType::EQUALS) { Scanner::skipOne($tokens); @@ -241,7 +241,7 @@ private function parseExpression(\Iterator &$tokens): ExpressionNode * @param \Iterator $tokens * @return null|Token */ - private function extractTagSelfCloseToken(\Iterator $tokens): ?Token + private function extractTagSelfCloseToken(\Iterator &$tokens): ?Token { if (Scanner::type($tokens) === TokenType::TAG_SELF_CLOSE) { $tagSelfCloseToken = $tokens->current(); @@ -257,7 +257,7 @@ private function extractTagSelfCloseToken(\Iterator $tokens): ?Token * @param \Iterator $tokens * @return void */ - private function skipTagEndToken(\Iterator $tokens): void + private function skipTagEndToken(\Iterator &$tokens): void { Scanner::assertType($tokens, TokenType::TAG_END); Scanner::skipOne($tokens); @@ -267,7 +267,7 @@ private function skipTagEndToken(\Iterator $tokens): void * @param \Iterator $tokens * @return ChildNodes */ - private function parseChildren(\Iterator $tokens): ChildNodes + private function parseChildren(\Iterator &$tokens): ChildNodes { $items = []; $preserveLeadingSpace = false; @@ -307,7 +307,7 @@ private function parseChildren(\Iterator $tokens): ChildNodes * @param \Iterator $tokens * @return void */ - private function skipTagStartClosingToken(\Iterator $tokens): void + private function skipTagStartClosingToken(\Iterator &$tokens): void { Scanner::assertType($tokens, TokenType::TAG_START_CLOSING); Scanner::skipOne($tokens); @@ -318,7 +318,7 @@ private function skipTagStartClosingToken(\Iterator $tokens): void * @param TagNameNode $openingTagNameNode * @return void */ - private function assertAndSkipClosingTagName(\Iterator $tokens, TagNameNode $openingTagNameNode): void + private function assertAndSkipClosingTagName(\Iterator &$tokens, TagNameNode $openingTagNameNode): void { Scanner::assertType($tokens, TokenType::STRING); $tagNameToken = $tokens->current(); @@ -337,7 +337,7 @@ private function assertAndSkipClosingTagName(\Iterator $tokens, TagNameNode $ope * @param \Iterator $tokens * @return Token */ - private function extractTagEndToken(\Iterator $tokens): Token + private function extractTagEndToken(\Iterator &$tokens): Token { Scanner::assertType($tokens, TokenType::TAG_END); $tagEndToken = $tokens->current(); diff --git a/src/Language/Parser/Text/TextParser.php b/src/Language/Parser/Text/TextParser.php index 040e80e8..78c38152 100644 --- a/src/Language/Parser/Text/TextParser.php +++ b/src/Language/Parser/Text/TextParser.php @@ -46,7 +46,7 @@ final class TextParser * @param boolean $preserveLeadingSpace * @return null|TextNode */ - public function parse(\Iterator $tokens, bool $preserveLeadingSpace = false): ?TextNode + public function parse(\Iterator &$tokens, bool $preserveLeadingSpace = false): ?TextNode { $this->reset($preserveLeadingSpace); diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index 08f2297c..fe4841a7 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -39,7 +39,7 @@ final class TypeReferenceParser * @param \Iterator $tokens * @return TypeReferenceNode */ - public function parse(\Iterator $tokens): TypeReferenceNode + public function parse(\Iterator &$tokens): TypeReferenceNode { $startingToken = $tokens->current(); $questionmarkToken = $this->extractQuestionmarkToken($tokens); @@ -72,7 +72,7 @@ public function parse(\Iterator $tokens): TypeReferenceNode * @param \Iterator $tokens * @return Token */ - public function extractQuestionmarkToken(\Iterator $tokens): ?Token + public function extractQuestionmarkToken(\Iterator &$tokens): ?Token { if (Scanner::type($tokens) === TokenType::QUESTIONMARK) { $questionmarkToken = $tokens->current(); @@ -88,7 +88,7 @@ public function extractQuestionmarkToken(\Iterator $tokens): ?Token * @param \Iterator $tokens * @return TypeNameNodes */ - public function parseTypeNames(\Iterator $tokens): TypeNameNodes + public function parseTypeNames(\Iterator &$tokens): TypeNameNodes { $items = []; while (true) { @@ -112,7 +112,7 @@ public function parseTypeNames(\Iterator $tokens): TypeNameNodes * @param \Iterator $tokens * @return TypeNameNode */ - public function parseTypeName(\Iterator $tokens): TypeNameNode + public function parseTypeName(\Iterator &$tokens): TypeNameNode { Scanner::assertType($tokens, TokenType::STRING); @@ -130,7 +130,7 @@ public function parseTypeName(\Iterator $tokens): TypeNameNode * @param \Iterator $tokens * @return Token */ - public function extractClosingArrayToken(\Iterator $tokens): ?Token + public function extractClosingArrayToken(\Iterator &$tokens): ?Token { if (!Scanner::isEnd($tokens) && Scanner::type($tokens) === TokenType::BRACKET_SQUARE_OPEN) { Scanner::skipOne($tokens); diff --git a/src/Language/Parser/ValueReference/ValueReferenceParser.php b/src/Language/Parser/ValueReference/ValueReferenceParser.php index ff842edb..42c687fc 100644 --- a/src/Language/Parser/ValueReference/ValueReferenceParser.php +++ b/src/Language/Parser/ValueReference/ValueReferenceParser.php @@ -34,7 +34,7 @@ final class ValueReferenceParser * @param \Iterator $tokens * @return ValueReferenceNode */ - public function parse(\Iterator $tokens): ValueReferenceNode + public function parse(\Iterator &$tokens): ValueReferenceNode { Scanner::assertType($tokens, TokenType::STRING); From 8d5ff202147aa0901e01d8f59422cb8e6184cfe9 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sat, 5 Aug 2023 14:40:33 +0200 Subject: [PATCH 54/64] TASK: Replace IntegerFormat::fromTokenType with parser-specific method --- .../AST/Node/IntegerLiteral/IntegerFormat.php | 12 --- .../IntegerLiteralCouldNotBeParsed.php | 54 ++++++++++++ .../IntegerLiteral/IntegerLiteralParser.php | 28 +++++- .../IntegerLiteralParserTest.php | 86 +++++++++++++------ 4 files changed, 141 insertions(+), 39 deletions(-) create mode 100644 src/Language/Parser/IntegerLiteral/IntegerLiteralCouldNotBeParsed.php diff --git a/src/Language/AST/Node/IntegerLiteral/IntegerFormat.php b/src/Language/AST/Node/IntegerLiteral/IntegerFormat.php index c4733b89..445ffd10 100644 --- a/src/Language/AST/Node/IntegerLiteral/IntegerFormat.php +++ b/src/Language/AST/Node/IntegerLiteral/IntegerFormat.php @@ -30,16 +30,4 @@ enum IntegerFormat: string case OCTAL = 'OCTAL'; case DECIMAL = 'DECIMAL'; case HEXADECIMAL = 'HEXADECIMAL'; - - public static function fromTokenType(TokenType $tokenType): self - { - return match ($tokenType) { - TokenType::NUMBER_BINARY => self::BINARY, - TokenType::NUMBER_OCTAL => self::OCTAL, - TokenType::NUMBER_DECIMAL => self::DECIMAL, - TokenType::NUMBER_HEXADECIMAL => self::HEXADECIMAL, - - default => throw new \Exception('@TODO: Unknown Integer Format: ' . $tokenType->value) - }; - } } diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralCouldNotBeParsed.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralCouldNotBeParsed.php new file mode 100644 index 00000000..b1d5dd37 --- /dev/null +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralCouldNotBeParsed.php @@ -0,0 +1,54 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral; + +use PackageFactory\ComponentEngine\Language\Parser\ParserException; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; + +final class IntegerLiteralCouldNotBeParsed extends ParserException +{ + public static function becauseOfUnexpectedEndOfFile(): self + { + return new self( + code: 1691238474, + message: 'Integer literal could not be parsed because of unexpected end of file.' + ); + } + + public static function becauseOfUnexpectedToken( + TokenTypes $expectedTokenTypes, + Token $actualToken + ): self { + return new self( + code: 1691238491, + message: sprintf( + 'Integer literal could not be parsed because of unexpected token %s. ' + . 'Expected %s instead.', + $actualToken->toDebugString(), + $expectedTokenTypes->toDebugString() + ), + affectedRangeInSource: $actualToken->boundaries + ); + } +} diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index 2aa2b159..cd3745bc 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -26,6 +26,8 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; final class IntegerLiteralParser { @@ -35,14 +37,38 @@ final class IntegerLiteralParser */ public function parse(\Iterator &$tokens): IntegerLiteralNode { + if (Scanner::isEnd($tokens)) { + throw IntegerLiteralCouldNotBeParsed::becauseOfUnexpectedEndOfFile(); + } + $token = $tokens->current(); Scanner::skipOne($tokens); return new IntegerLiteralNode( rangeInSource: $token->boundaries, - format: IntegerFormat::fromTokenType($token->type), + format: $this->getIntegerFormatFromToken($token), value: $token->value ); } + + private function getIntegerFormatFromToken(Token $token): IntegerFormat + { + return match ($token->type) { + TokenType::NUMBER_BINARY => IntegerFormat::BINARY, + TokenType::NUMBER_OCTAL => IntegerFormat::OCTAL, + TokenType::NUMBER_DECIMAL => IntegerFormat::DECIMAL, + TokenType::NUMBER_HEXADECIMAL => IntegerFormat::HEXADECIMAL, + + default => throw IntegerLiteralCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::NUMBER_BINARY, + TokenType::NUMBER_OCTAL, + TokenType::NUMBER_DECIMAL, + TokenType::NUMBER_HEXADECIMAL + ), + actualToken: $token + ) + }; + } } diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index f984bb8b..e6d169d8 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -24,14 +24,15 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralCouldNotBeParsed; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Parser\Source\Path; +use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; +use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenTypes; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class IntegerLiteralParserTest extends TestCase +final class IntegerLiteralParserTest extends ParserTestCase { /** * @test @@ -39,13 +40,10 @@ final class IntegerLiteralParserTest extends TestCase public function binaryInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('0b1010110101'))->getIterator(); + $tokens = $this->createTokenIterator('0b1010110101'); $expectedIntegerLiteralNode = new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 0], [0, 11]), format: IntegerFormat::BINARY, value: '0b1010110101' ); @@ -62,13 +60,10 @@ public function binaryInteger(): void public function octalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('0o755'))->getIterator(); + $tokens = $this->createTokenIterator('0o755'); $expectedIntegerLiteralNode = new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 0], [0, 4]), format: IntegerFormat::OCTAL, value: '0o755' ); @@ -85,13 +80,10 @@ public function octalInteger(): void public function decimalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('1234567890'))->getIterator(); + $tokens = $this->createTokenIterator('1234567890'); $expectedIntegerLiteralNode = new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 0], [0, 9]), format: IntegerFormat::DECIMAL, value: '1234567890' ); @@ -108,13 +100,10 @@ public function decimalInteger(): void public function hexadecimalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('0x123456789ABCDEF'))->getIterator(); + $tokens = $this->createTokenIterator('0x123456789ABCDEF'); $expectedIntegerLiteralNode = new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 16) - ), + rangeInSource: $this->range([0, 0], [0, 16]), format: IntegerFormat::HEXADECIMAL, value: '0x123456789ABCDEF' ); @@ -124,4 +113,49 @@ public function hexadecimalInteger(): void $integerLiteralParser->parse($tokens) ); } + + /** + * @test + */ + public function throwsIfTokenStreamsEndsUnexpectedly(): void + { + $this->assertThrowsParserException( + function () { + $integerLiteralParser = new IntegerLiteralParser(); + $tokens = $this->createTokenIterator(''); + + $integerLiteralParser->parse($tokens); + }, + IntegerLiteralCouldNotBeParsed::becauseOfUnexpectedEndOfFile() + ); + } + + /** + * @test + */ + public function throwsIfUnexpectedTokenIsEncountered(): void + { + $this->assertThrowsParserException( + function () { + $integerLiteralParser = new IntegerLiteralParser(); + $tokens = $this->createTokenIterator('foo1234'); + + $integerLiteralParser->parse($tokens); + }, + IntegerLiteralCouldNotBeParsed::becauseOfUnexpectedToken( + expectedTokenTypes: TokenTypes::from( + TokenType::NUMBER_BINARY, + TokenType::NUMBER_OCTAL, + TokenType::NUMBER_DECIMAL, + TokenType::NUMBER_HEXADECIMAL + ), + actualToken: new Token( + type: TokenType::STRING, + value: 'foo1234', + boundaries: $this->range([0, 0], [0, 6]), + sourcePath: Path::createMemory() + ) + ) + ); + } } From f2e47cc5cfd31e1f8c7724c944e354793f67387a Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sat, 5 Aug 2023 15:52:03 +0200 Subject: [PATCH 55/64] TASK: Refactor all parser tests, so they inherit from base test case --- .../Parser/Match/MatchCouldNotBeParsed.php | 2 +- .../BooleanLiteralParserTest.php | 28 +- .../EnumDeclarationParserTest.php | 656 ++++----------- .../Expression/ExpressionParserTest.php | 8 +- .../Parser/Import/ImportParserTest.php | 5 +- .../IntegerLiteralParserTest.php | 12 +- .../Language/Parser/Match/MatchParserTest.php | 47 +- .../Parser/Module/ModuleParserTest.php | 2 +- .../NullLiteral/NullLiteralParserTest.php | 19 +- .../PropertyDeclarationParserTest.php | 106 +-- .../StringLiteral/StringLiteralParserTest.php | 19 +- .../StructDeclarationParserTest.php | 352 ++------ .../Language/Parser/Tag/TagParserTest.php | 763 ++++-------------- .../TemplateLiteralParserTest.php | 2 +- .../Language/Parser/Text/TextParserTest.php | 111 +-- .../TypeReference/TypeReferenceParserTest.php | 92 +-- .../ValueReferenceParserTest.php | 17 +- 17 files changed, 514 insertions(+), 1727 deletions(-) diff --git a/src/Language/Parser/Match/MatchCouldNotBeParsed.php b/src/Language/Parser/Match/MatchCouldNotBeParsed.php index b23ed512..9b6efc68 100644 --- a/src/Language/Parser/Match/MatchCouldNotBeParsed.php +++ b/src/Language/Parser/Match/MatchCouldNotBeParsed.php @@ -38,7 +38,7 @@ public static function becauseOfInvalidMatchArmNodes( 'Match could not be parsed because of invalid match arm nodes: %s.', $cause->getMessage() ), - affectedRangeInSource: $affectedRangeInSource ?? $cause->affectedRangeInSource, + affectedRangeInSource: $cause->affectedRangeInSource ?? $affectedRangeInSource, cause: $cause ); } diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 4144d460..923c4f4f 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,27 +24,20 @@ use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral\BooleanLiteralParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class BooleanLiteralParserTest extends TestCase +final class BooleanLiteralParserTest extends ParserTestCase { /** * @test */ - public function producesAstNodeForTrueIfGivenOneTrueToken(): void + public function parsesTrue(): void { $booleanLiteralParser = new BooleanLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('true'))->getIterator(); + $tokens = $this->createTokenIterator('true'); $expectedBooleanLiteralNode = new BooleanLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ), + rangeInSource: $this->range([0, 0], [0, 3]), value: true ); @@ -57,16 +50,13 @@ public function producesAstNodeForTrueIfGivenOneTrueToken(): void /** * @test */ - public function producesAstNodeForFalseIfGivenOneFalseToken(): void + public function parsesFalse(): void { $booleanLiteralParser = new BooleanLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('false'))->getIterator(); + $tokens = $this->createTokenIterator('false'); $expectedBooleanLiteralNode = new BooleanLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 0], [0, 4]), value: false ); diff --git a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php index 27c3bda1..2015a8df 100644 --- a/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php +++ b/test/Unit/Language/Parser/EnumDeclaration/EnumDeclarationParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,45 +34,29 @@ use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\EnumDeclaration\EnumDeclarationParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class EnumDeclarationParserTest extends TestCase +final class EnumDeclarationParserTest extends ParserTestCase { /** * @test */ - public function oneValuelessMember(): void + public function parsesEnumDeclarationWithOneValuelessMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 0], [0, 15]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: null @@ -89,62 +73,38 @@ public function oneValuelessMember(): void /** * @test */ - public function threeValuelessMembers(): void + public function parsesEnumDeclarationWithThreeValuelessMembers(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR BAZ QUX }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR BAZ QUX }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 23) - ), + rangeInSource: $this->range([0, 0], [0, 23]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: null ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 15], [0, 17]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 15], [0, 17]), value: EnumMemberName::from('BAZ') ), value: null ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 19), - new Position(0, 21) - ), + rangeInSource: $this->range([0, 19], [0, 21]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 19), - new Position(0, 21) - ), + rangeInSource: $this->range([0, 19], [0, 21]), value: EnumMemberName::from('QUX') ), value: null @@ -161,46 +121,28 @@ public function threeValuelessMembers(): void /** * @test */ - public function oneStringValueMember(): void + public function parsesEnumDeclarationWithOneStringValueMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR("BAR") }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR("BAR") }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 11], [0, 20]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 14], [0, 20]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 16), - new Position(0, 18) - ), + rangeInSource: $this->range([0, 16], [0, 18]), value: 'BAR' ) ) @@ -217,7 +159,7 @@ public function oneStringValueMember(): void /** * @test */ - public function sevenStringValueMembers(): void + public function parsesEnumDeclarationWithSevenStringValueMembers(): void { $enumDeclarationParser = new EnumDeclarationParser(); $enumAsString = <<getIterator(); + $tokens = $this->createTokenIterator($enumAsString); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(8, 0) - ), + rangeInSource: $this->range([0, 0], [8, 0]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 5], [0, 11]), value: EnumName::from('Weekday') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 16) - ), + rangeInSource: $this->range([1, 4], [1, 16]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 9) - ), + rangeInSource: $this->range([1, 4], [1, 9]), value: EnumMemberName::from('MONDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(1, 10), - new Position(1, 16) - ), + rangeInSource: $this->range([1, 10], [1, 16]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(1, 12), - new Position(1, 14) - ), + rangeInSource: $this->range([1, 12], [1, 14]), value: 'mon' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 17) - ), + rangeInSource: $this->range([2, 4], [2, 17]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 10) - ), + rangeInSource: $this->range([2, 4], [2, 10]), value: EnumMemberName::from('TUESDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(2, 11), - new Position(2, 17) - ), + rangeInSource: $this->range([2, 11], [2, 17]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(2, 13), - new Position(2, 15) - ), + rangeInSource: $this->range([2, 13], [2, 15]), value: 'tue' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 19) - ), + rangeInSource: $this->range([3, 4], [3, 19]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 12) - ), + rangeInSource: $this->range([3, 4], [3, 12]), value: EnumMemberName::from('WEDNESDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(3, 13), - new Position(3, 19) - ), + rangeInSource: $this->range([3, 13], [3, 19]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(3, 15), - new Position(3, 17) - ), + rangeInSource: $this->range([3, 15], [3, 17]), value: 'wed' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 18) - ), + rangeInSource: $this->range([4, 4], [4, 18]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 11) - ), + rangeInSource: $this->range([4, 4], [4, 11]), value: EnumMemberName::from('THURSDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(4, 12), - new Position(4, 18) - ), + rangeInSource: $this->range([4, 12], [4, 18]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(4, 14), - new Position(4, 16) - ), + rangeInSource: $this->range([4, 14], [4, 16]), value: 'thu' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 16) - ), + rangeInSource: $this->range([5, 4], [5, 16]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 9) - ), + rangeInSource: $this->range([5, 4], [5, 9]), value: EnumMemberName::from('FRIDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(5, 10), - new Position(5, 16) - ), + rangeInSource: $this->range([5, 10], [5, 16]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(5, 12), - new Position(5, 14) - ), + rangeInSource: $this->range([5, 12], [5, 14]), value: 'fri' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 18) - ), + rangeInSource: $this->range([6, 4], [6, 18]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 11) - ), + rangeInSource: $this->range([6, 4], [6, 11]), value: EnumMemberName::from('SATURDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(6, 12), - new Position(6, 18) - ), + rangeInSource: $this->range([6, 12], [6, 18]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(6, 14), - new Position(6, 16) - ), + rangeInSource: $this->range([6, 14], [6, 16]), value: 'sat' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 16) - ), + rangeInSource: $this->range([7, 4], [7, 16]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 9) - ), + rangeInSource: $this->range([7, 4], [7, 9]), value: EnumMemberName::from('SUNDAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(7, 10), - new Position(7, 16) - ), + rangeInSource: $this->range([7, 10], [7, 16]), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(7, 12), - new Position(7, 14) - ), + rangeInSource: $this->range([7, 12], [7, 14]), value: 'sun' ) ) @@ -440,46 +292,28 @@ enum Weekday { /** * @test */ - public function oneBinaryIntegerValueMember(): void + public function parsesEnumDeclarationWithOneBinaryIntegerValueMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0b101) }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR(0b101) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 11], [0, 20]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 14], [0, 20]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 15], [0, 19]), format: IntegerFormat::BINARY, value: '0b101' ) @@ -497,46 +331,28 @@ public function oneBinaryIntegerValueMember(): void /** * @test */ - public function oneOctalIntegerValueMember(): void + public function parsesEnumDeclarationWithOneOctalIntegerValueMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0o644) }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR(0o644) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 11], [0, 20]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 14], [0, 20]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 15], [0, 19]), format: IntegerFormat::OCTAL, value: '0o644' ) @@ -554,46 +370,28 @@ public function oneOctalIntegerValueMember(): void /** * @test */ - public function oneDecimalIntegerValueMember(): void + public function parsesEnumDeclarationWithOneDecimalIntegerValueMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(42) }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR(42) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 0], [0, 19]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 11], [0, 17]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 14], [0, 17]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 16) - ), + rangeInSource: $this->range([0, 15], [0, 16]), format: IntegerFormat::DECIMAL, value: '42' ) @@ -611,46 +409,28 @@ public function oneDecimalIntegerValueMember(): void /** * @test */ - public function oneHexadecimalIntegerValueMember(): void + public function parsesEnumDeclarationWithOneHexadecimalIntegerValueMember(): void { $enumDeclarationParser = new EnumDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('enum Foo { BAR(0xABC) }'))->getIterator(); + $tokens = $this->createTokenIterator('enum Foo { BAR(0xABC) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: EnumName::from('Foo') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 11], [0, 20]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: EnumMemberName::from('BAR') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 14], [0, 20]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 15], [0, 19]), format: IntegerFormat::HEXADECIMAL, value: '0xABC' ) @@ -668,7 +448,7 @@ public function oneHexadecimalIntegerValueMember(): void /** * @test */ - public function twelveIntegerValueMembers(): void + public function parsesEnumDeclarationWithwelveIntegerValueMembers(): void { $enumDeclarationParser = new EnumDeclarationParser(); $enumAsString = <<getIterator(); + $tokens = $this->createTokenIterator($enumAsString); $expectedEnumDeclarationNode = new EnumDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(13, 0) - ), + rangeInSource: $this->range([0, 0], [13, 0]), name: new EnumNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 5], [0, 9]), value: EnumName::from('Month') ), members: new EnumMemberDeclarationNodes( new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 13) - ), + rangeInSource: $this->range([1, 4], [1, 13]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 10) - ), + rangeInSource: $this->range([1, 4], [1, 10]), value: EnumMemberName::from('JANUARY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(1, 11), - new Position(1, 13) - ), + rangeInSource: $this->range([1, 11], [1, 13]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(1, 12), - new Position(1, 12) - ), + rangeInSource: $this->range([1, 12], [1, 12]), format: IntegerFormat::DECIMAL, value: '1' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 14) - ), + rangeInSource: $this->range([2, 4], [2, 14]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 11) - ), + rangeInSource: $this->range([2, 4], [2, 11]), value: EnumMemberName::from('FEBRUARY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(2, 12), - new Position(2, 14) - ), + rangeInSource: $this->range([2, 12], [2, 14]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(2, 13), - new Position(2, 13) - ), + rangeInSource: $this->range([2, 13], [2, 13]), format: IntegerFormat::DECIMAL, value: '2' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 11) - ), + rangeInSource: $this->range([3, 4], [3, 11]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 8) - ), + rangeInSource: $this->range([3, 4], [3, 8]), value: EnumMemberName::from('MARCH') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(3, 9), - new Position(3, 11) - ), + rangeInSource: $this->range([3, 9], [3, 11]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 10) - ), + rangeInSource: $this->range([3, 10], [3, 10]), format: IntegerFormat::DECIMAL, value: '3' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 11) - ), + rangeInSource: $this->range([4, 4], [4, 11]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(4, 4), - new Position(4, 8) - ), + rangeInSource: $this->range([4, 4], [4, 8]), value: EnumMemberName::from('APRIL') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(4, 9), - new Position(4, 11) - ), + rangeInSource: $this->range([4, 9], [4, 11]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(4, 10), - new Position(4, 10) - ), + rangeInSource: $this->range([4, 10], [4, 10]), format: IntegerFormat::DECIMAL, value: '4' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 9) - ), + rangeInSource: $this->range([5, 4], [5, 9]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(5, 4), - new Position(5, 6) - ), + rangeInSource: $this->range([5, 4], [5, 6]), value: EnumMemberName::from('MAY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(5, 7), - new Position(5, 9) - ), + rangeInSource: $this->range([5, 7], [5, 9]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(5, 8), - new Position(5, 8) - ), + rangeInSource: $this->range([5, 8], [5, 8]), format: IntegerFormat::DECIMAL, value: '5' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 10) - ), + rangeInSource: $this->range([6, 4], [6, 10]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 7) - ), + rangeInSource: $this->range([6, 4], [6, 7]), value: EnumMemberName::from('JUNE') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(6, 8), - new Position(6, 10) - ), + rangeInSource: $this->range([6, 8], [6, 10]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(6, 9), - new Position(6, 9) - ), + rangeInSource: $this->range([6, 9], [6, 9]), format: IntegerFormat::DECIMAL, value: '6' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 10) - ), + rangeInSource: $this->range([7, 4], [7, 10]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(7, 4), - new Position(7, 7) - ), + rangeInSource: $this->range([7, 4], [7, 7]), value: EnumMemberName::from('JULY') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(7, 8), - new Position(7, 10) - ), + rangeInSource: $this->range([7, 8], [7, 10]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(7, 9), - new Position(7, 9) - ), + rangeInSource: $this->range([7, 9], [7, 9]), format: IntegerFormat::DECIMAL, value: '7' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(8, 4), - new Position(8, 12) - ), + rangeInSource: $this->range([8, 4], [8, 12]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(8, 4), - new Position(8, 9) - ), + rangeInSource: $this->range([8, 4], [8, 9]), value: EnumMemberName::from('AUGUST') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(8, 10), - new Position(8, 12) - ), + rangeInSource: $this->range([8, 10], [8, 12]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(8, 11), - new Position(8, 11) - ), + rangeInSource: $this->range([8, 11], [8, 11]), format: IntegerFormat::DECIMAL, value: '8' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(9, 4), - new Position(9, 15) - ), + rangeInSource: $this->range([9, 4], [9, 15]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(9, 4), - new Position(9, 12) - ), + rangeInSource: $this->range([9, 4], [9, 12]), value: EnumMemberName::from('SEPTEMBER') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(9, 13), - new Position(9, 15) - ), + rangeInSource: $this->range([9, 13], [9, 15]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(9, 14), - new Position(9, 14) - ), + rangeInSource: $this->range([9, 14], [9, 14]), format: IntegerFormat::DECIMAL, value: '9' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(10, 4), - new Position(10, 14) - ), + rangeInSource: $this->range([10, 4], [10, 14]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(10, 4), - new Position(10, 10) - ), + rangeInSource: $this->range([10, 4], [10, 10]), value: EnumMemberName::from('OCTOBER') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(10, 11), - new Position(10, 14) - ), + rangeInSource: $this->range([10, 11], [10, 14]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(10, 12), - new Position(10, 13) - ), + rangeInSource: $this->range([10, 12], [10, 13]), format: IntegerFormat::DECIMAL, value: '10' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(11, 4), - new Position(11, 15) - ), + rangeInSource: $this->range([11, 4], [11, 15]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(11, 4), - new Position(11, 11) - ), + rangeInSource: $this->range([11, 4], [11, 11]), value: EnumMemberName::from('NOVEMBER') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(11, 12), - new Position(11, 15) - ), + rangeInSource: $this->range([11, 12], [11, 15]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(11, 13), - new Position(11, 14) - ), + rangeInSource: $this->range([11, 13], [11, 14]), format: IntegerFormat::DECIMAL, value: '11' ) ) ), new EnumMemberDeclarationNode( - rangeInSource: Range::from( - new Position(12, 4), - new Position(12, 15) - ), + rangeInSource: $this->range([12, 4], [12, 15]), name: new EnumMemberNameNode( - rangeInSource: Range::from( - new Position(12, 4), - new Position(12, 11) - ), + rangeInSource: $this->range([12, 4], [12, 11]), value: EnumMemberName::from('DECEMBER') ), value: new EnumMemberValueNode( - rangeInSource: Range::from( - new Position(12, 12), - new Position(12, 15) - ), + rangeInSource: $this->range([12, 12], [12, 15]), value: new IntegerLiteralNode( - rangeInSource: Range::from( - new Position(12, 13), - new Position(12, 14) - ), + rangeInSource: $this->range([12, 13], [12, 14]), format: IntegerFormat::DECIMAL, value: '12' ) diff --git a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php index bd3e2582..2ccfb6b7 100644 --- a/test/Unit/Language/Parser/Expression/ExpressionParserTest.php +++ b/test/Unit/Language/Parser/Expression/ExpressionParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,13 +56,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperationNode; use PackageFactory\ComponentEngine\Language\AST\Node\UnaryOperation\UnaryOperator; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; -use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionCouldNotBeParsed; use PackageFactory\ComponentEngine\Language\Parser\Expression\ExpressionParser; -use PackageFactory\ComponentEngine\Language\Parser\ParserException; -use PackageFactory\ComponentEngine\Parser\Source\Path; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; -use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType; use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; final class ExpressionParserTest extends ParserTestCase diff --git a/test/Unit/Language/Parser/Import/ImportParserTest.php b/test/Unit/Language/Parser/Import/ImportParserTest.php index 790788f3..dce94709 100644 --- a/test/Unit/Language/Parser/Import/ImportParserTest.php +++ b/test/Unit/Language/Parser/Import/ImportParserTest.php @@ -30,7 +30,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\Import\ImportCouldNotBeParsed; use PackageFactory\ComponentEngine\Language\Parser\Import\ImportParser; -use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; final class ImportParserTest extends ParserTestCase @@ -106,7 +105,7 @@ public function parsesImportWithMultipleNames(): void /** * @test */ - public function emptyImportIsNotAllowed(): void + public function throwsIfEmptyImportOccurs(): void { $this->assertThrowsParserException( function () { @@ -127,7 +126,7 @@ function () { /** * @test */ - public function duplicateImportsAreNotAllowed(): void + public function throwsIfDuplicateImportsOccur(): void { $this->assertThrowsParserException( function () { diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index e6d169d8..cc3f8e7e 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ final class IntegerLiteralParserTest extends ParserTestCase /** * @test */ - public function binaryInteger(): void + public function parsesBinaryInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); $tokens = $this->createTokenIterator('0b1010110101'); @@ -57,7 +57,7 @@ public function binaryInteger(): void /** * @test */ - public function octalInteger(): void + public function parsesOctalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); $tokens = $this->createTokenIterator('0o755'); @@ -77,7 +77,7 @@ public function octalInteger(): void /** * @test */ - public function decimalInteger(): void + public function parsesDecimalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); $tokens = $this->createTokenIterator('1234567890'); @@ -97,7 +97,7 @@ public function decimalInteger(): void /** * @test */ - public function hexadecimalInteger(): void + public function parsesHexadecimalInteger(): void { $integerLiteralParser = new IntegerLiteralParser(); $tokens = $this->createTokenIterator('0x123456789ABCDEF'); @@ -117,7 +117,7 @@ public function hexadecimalInteger(): void /** * @test */ - public function throwsIfTokenStreamsEndsUnexpectedly(): void + public function throwsIfTokenStreamEndsUnexpectedly(): void { $this->assertThrowsParserException( function () { diff --git a/test/Unit/Language/Parser/Match/MatchParserTest.php b/test/Unit/Language/Parser/Match/MatchParserTest.php index cea3a771..168d8d34 100644 --- a/test/Unit/Language/Parser/Match/MatchParserTest.php +++ b/test/Unit/Language/Parser/Match/MatchParserTest.php @@ -32,7 +32,6 @@ use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\Match\MatchCouldNotBeParsed; use PackageFactory\ComponentEngine\Language\Parser\Match\MatchParser; -use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; final class MatchParserTest extends ParserTestCase @@ -1111,41 +1110,43 @@ public function parsesNestedMatchAsArmRight(): void /** * @test */ - public function emptyMatchArmsAreNotAllowed(): void + public function throwsIfMatchArmsAreEmpty(): void { - $matchParser = new MatchParser(); - $tokens = $this->createTokenIterator('match (a) {}'); + $this->assertThrowsParserException( + function () { + $matchParser = new MatchParser(); + $tokens = $this->createTokenIterator('match (a) {}'); - $this->expectException(ParserException::class); - $this->expectExceptionObject( + $matchParser->parse($tokens); + }, MatchCouldNotBeParsed::becauseOfInvalidMatchArmNodes( cause: InvalidMatchArmNodes::becauseTheyWereEmpty(), affectedRangeInSource: $this->range([0, 0], [0, 4]) ) ); - - $matchParser->parse($tokens); } /** * @test */ - public function multipleDefaultArmsAreNotAllowed(): void + public function throwsIfMultipleDefaultArmsOccur(): void { - $matchParser = new MatchParser(); - $matchAsString = << d - default -> e - f, g -> h - default -> i - j -> k - } - AFX; - $tokens = $this->createTokenIterator($matchAsString); + $this->assertThrowsParserException( + function () { + $matchParser = new MatchParser(); + $matchAsString = << d + default -> e + f, g -> h + default -> i + j -> k + } + AFX; + $tokens = $this->createTokenIterator($matchAsString); - $this->expectException(ParserException::class); - $this->expectExceptionObject( + $matchParser->parse($tokens); + }, MatchCouldNotBeParsed::becauseOfInvalidMatchArmNodes( cause: InvalidMatchArmNodes::becauseTheyContainMoreThanOneDefaultMatchArmNode( secondDefaultMatchArmNode: new MatchArmNode( @@ -1162,7 +1163,5 @@ public function multipleDefaultArmsAreNotAllowed(): void ) ) ); - - $matchParser->parse($tokens); } } diff --git a/test/Unit/Language/Parser/Module/ModuleParserTest.php b/test/Unit/Language/Parser/Module/ModuleParserTest.php index 4d8a9e6a..34f4d956 100644 --- a/test/Unit/Language/Parser/Module/ModuleParserTest.php +++ b/test/Unit/Language/Parser/Module/ModuleParserTest.php @@ -285,7 +285,7 @@ public function toleratesCommentsAndSpacesInBetweenStatements(): void /** * @test */ - public function exceedingTokensAreNotAllowed(): void + public function throwsIfExceedingTokensOccur(): void { $this->assertThrowsParserException( function () { diff --git a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php index ea87cce9..bc6e9ee3 100644 --- a/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php +++ b/test/Unit/Language/Parser/NullLiteral/NullLiteralParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,27 +24,20 @@ use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\NullLiteral\NullLiteralParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class NullLiteralParserTest extends TestCase +final class NullLiteralParserTest extends ParserTestCase { /** * @test */ - public function producesAstNodeForNullIfGivenOneNullToken(): void + public function parsesNull(): void { $nullLiteralParser = new NullLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('null'))->getIterator(); + $tokens = $this->createTokenIterator('null'); $expectedNullLiteralNode = new NullLiteralNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ) + rangeInSource: $this->range([0, 0], [0, 3]) ); $this->assertEquals( diff --git a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php index a282ff90..5aa59e14 100644 --- a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php +++ b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php @@ -30,13 +30,9 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration\PropertyDeclarationParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class PropertyDeclarationParserTest extends TestCase +final class PropertyDeclarationParserTest extends ParserTestCase { /** * @test @@ -44,31 +40,19 @@ final class PropertyDeclarationParserTest extends TestCase public function parsesPropertyDeclarationWithSimpleType(): void { $propertyDeclarationParser = new PropertyDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar'))->getIterator(); + $tokens = $this->createTokenIterator('foo: Bar'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 0], [0, 7]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: TypeName::from('Bar') ) ), @@ -89,31 +73,19 @@ public function parsesPropertyDeclarationWithSimpleType(): void public function parsesPropertyDeclarationWithOptionalType(): void { $propertyDeclarationParser = new PropertyDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('foo: ?Bar'))->getIterator(); + $tokens = $this->createTokenIterator('foo: ?Bar'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 8) - ), + rangeInSource: $this->range([0, 0], [0, 8]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 8) - ), + rangeInSource: $this->range([0, 5], [0, 8]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 6), - new Position(0, 8) - ), + rangeInSource: $this->range([0, 6], [0, 8]), value: TypeName::from('Bar') ) ), @@ -134,31 +106,19 @@ public function parsesPropertyDeclarationWithOptionalType(): void public function parsesPropertyDeclarationWithArrayType(): void { $propertyDeclarationParser = new PropertyDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar[]'))->getIterator(); + $tokens = $this->createTokenIterator('foo: Bar[]'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 0], [0, 9]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 5], [0, 9]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: TypeName::from('Bar') ) ), @@ -179,45 +139,27 @@ public function parsesPropertyDeclarationWithArrayType(): void public function parsesPropertyDeclarationWithUnionType(): void { $propertyDeclarationParser = new PropertyDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('foo: Bar|Baz|Qux'))->getIterator(); + $tokens = $this->createTokenIterator('foo: Bar|Baz|Qux'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 0], [0, 15]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: PropertyName::from('foo') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 5], [0, 15]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: TypeName::from('Bar') ), new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 9), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 9], [0, 11]), value: TypeName::from('Baz') ), new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 13], [0, 15]), value: TypeName::from('Qux') ) ), diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index ec3024c3..1da49710 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,27 +24,20 @@ use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class StringLiteralParserTest extends TestCase +final class StringLiteralParserTest extends ParserTestCase { /** * @test */ - public function producesStringLiteralNodeForLiteralString(): void + public function parsesString(): void { $stringLiteralParser = new StringLiteralParser(); - $tokens = Tokenizer::fromSource(Source::fromString('"Hello World"'))->getIterator(); + $tokens = $this->createTokenIterator('"Hello World"'); $expectedStringLiteralNode = new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 1], [0, 11]), value: 'Hello World' ); diff --git a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php index 5097dd01..76ae04f9 100644 --- a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php +++ b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,58 +34,36 @@ use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\StructDeclaration\StructDeclarationParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class StructDeclarationParserTest extends TestCase +final class StructDeclarationParserTest extends ParserTestCase { /** * @test */ - public function parsesStructDeclarationOnSingleLineWithOneProperty(): void + public function parsesStructDeclarationWithOneProperty(): void { $structDeclarationParser = new StructDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('struct Foo { bar: Baz }'))->getIterator(); + $tokens = $this->createTokenIterator('struct Foo { bar: Baz }'); $expectedStructDeclarationNode = new StructDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), name: new StructNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: StructName::from('Foo') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 13], [0, 20]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 13], [0, 15]), value: PropertyName::from('bar') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 18], [0, 20]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 18], [0, 20]), value: TypeName::from('Baz') ) ), @@ -105,47 +83,29 @@ public function parsesStructDeclarationOnSingleLineWithOneProperty(): void /** * @test */ - public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): void + public function parsesStructDeclarationWithMultipleProperties(): void { $structDeclarationParser = new StructDeclarationParser(); - $tokens = Tokenizer::fromSource(Source::fromString('struct Foo { bar: Baz qux: Quux corge: Grault }'))->getIterator(); + $tokens = $this->createTokenIterator('struct Foo { bar: Baz qux: Quux corge: Grault }'); $expectedStructDeclarationNode = new StructDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 46) - ), + rangeInSource: $this->range([0, 0], [0, 46]), name: new StructNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: StructName::from('Foo') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 13], [0, 20]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 13], [0, 15]), value: PropertyName::from('bar') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 18], [0, 20]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 18], [0, 20]), value: TypeName::from('Baz') ) ), @@ -154,28 +114,16 @@ public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): voi ) ), new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 22), - new Position(0, 30) - ), + rangeInSource: $this->range([0, 22], [0, 30]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 22), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 22], [0, 24]), value: PropertyName::from('qux') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 30) - ), + rangeInSource: $this->range([0, 27], [0, 30]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 30) - ), + rangeInSource: $this->range([0, 27], [0, 30]), value: TypeName::from('Quux') ) ), @@ -184,28 +132,16 @@ public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): voi ) ), new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(0, 32), - new Position(0, 44) - ), + rangeInSource: $this->range([0, 32], [0, 44]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(0, 32), - new Position(0, 36) - ), + rangeInSource: $this->range([0, 32], [0, 36]), value: PropertyName::from('corge') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 39), - new Position(0, 44) - ), + rangeInSource: $this->range([0, 39], [0, 44]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 39), - new Position(0, 44) - ), + rangeInSource: $this->range([0, 39], [0, 44]), value: TypeName::from('Grault') ) ), @@ -225,103 +161,7 @@ public function parsesStructDeclarationOnSingleLineWithMultipleProperties(): voi /** * @test */ - public function parsesStructDeclarationOnMultipleLinesWithMultipleProperties(): void - { - $structDeclarationParser = new StructDeclarationParser(); - $structAsString = <<getIterator(); - - $expectedStructDeclarationNode = new StructDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(3, 0) - ), - name: new StructNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 10) - ), - value: StructName::from('Link') - ), - properties: new PropertyDeclarationNodes( - new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 15) - ), - name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 7) - ), - value: PropertyName::from('href') - ), - type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(1, 10), - new Position(1, 15) - ), - names: new TypeNameNodes( - new TypeNameNode( - rangeInSource: Range::from( - new Position(1, 10), - new Position(1, 15) - ), - value: TypeName::from('string') - ) - ), - isArray: false, - isOptional: false - ) - ), - new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 17) - ), - name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 9) - ), - value: PropertyName::from('target') - ), - type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(2, 12), - new Position(2, 17) - ), - names: new TypeNameNodes( - new TypeNameNode( - rangeInSource: Range::from( - new Position(2, 12), - new Position(2, 17) - ), - value: TypeName::from('string') - ) - ), - isArray: false, - isOptional: false - ) - ) - ) - ); - - $this->assertEquals( - $expectedStructDeclarationNode, - $structDeclarationParser->parse($tokens) - ); - } - - /** - * @test - */ - public function parsesStructDeclarationOnMultipleLinesWithMultiplePropertiesAndSpaceAndComments(): void + public function parsesStructDeclarationWithMultiplePropertiesAndSpaceAndComments(): void { $structDeclarationParser = new StructDeclarationParser(); $structAsString = <<getIterator(); + $tokens = $this->createTokenIterator($structAsString); $expectedStructDeclarationNode = new StructDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(8, 0) - ), + rangeInSource: $this->range([0, 0], [8, 0]), name: new StructNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 7], [0, 10]), value: StructName::from('Link') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 15) - ), + rangeInSource: $this->range([3, 4], [3, 15]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 7) - ), + rangeInSource: $this->range([3, 4], [3, 7]), value: PropertyName::from('href') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 15) - ), + rangeInSource: $this->range([3, 10], [3, 15]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(3, 10), - new Position(3, 15) - ), + rangeInSource: $this->range([3, 10], [3, 15]), value: TypeName::from('string') ) ), @@ -381,28 +203,16 @@ public function parsesStructDeclarationOnMultipleLinesWithMultiplePropertiesAndS ) ), new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 17) - ), + rangeInSource: $this->range([6, 4], [6, 17]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(6, 4), - new Position(6, 9) - ), + rangeInSource: $this->range([6, 4], [6, 9]), value: PropertyName::from('target') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(6, 12), - new Position(6, 17) - ), + rangeInSource: $this->range([6, 12], [6, 17]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(6, 12), - new Position(6, 17) - ), + rangeInSource: $this->range([6, 12], [6, 17]), value: TypeName::from('string') ) ), @@ -422,7 +232,7 @@ public function parsesStructDeclarationOnMultipleLinesWithMultiplePropertiesAndS /** * @test */ - public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionProperties(): void + public function parsesStructDeclarationWitOptionalArrayAndUnionProperties(): void { $structDeclarationParser = new StructDeclarationParser(); $structAsString = <<getIterator(); + $tokens = $this->createTokenIterator($structAsString); $expectedStructDeclarationNode = new StructDeclarationNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(4, 0) - ), + rangeInSource: $this->range([0, 0], [4, 0]), name: new StructNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 7], [0, 13]), value: StructName::from('Picture') ), properties: new PropertyDeclarationNodes( new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 16) - ), + rangeInSource: $this->range([1, 4], [1, 16]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(1, 4), - new Position(1, 6) - ), + rangeInSource: $this->range([1, 4], [1, 6]), value: PropertyName::from('src') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(1, 9), - new Position(1, 16) - ), + rangeInSource: $this->range([1, 9], [1, 16]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(1, 9), - new Position(1, 14) - ), + rangeInSource: $this->range([1, 9], [1, 14]), value: TypeName::from('string') ) ), @@ -478,42 +270,24 @@ public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionPr ) ), new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 39) - ), + rangeInSource: $this->range([2, 4], [2, 39]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 14) - ), + rangeInSource: $this->range([2, 4], [2, 14]), value: PropertyName::from('description') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(2, 17), - new Position(2, 39) - ), + rangeInSource: $this->range([2, 17], [2, 39]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(2, 17), - new Position(2, 22) - ), + rangeInSource: $this->range([2, 17], [2, 22]), value: TypeName::from('string') ), new TypeNameNode( - rangeInSource: Range::from( - new Position(2, 24), - new Position(2, 27) - ), + rangeInSource: $this->range([2, 24], [2, 27]), value: TypeName::from('slot') ), new TypeNameNode( - rangeInSource: Range::from( - new Position(2, 29), - new Position(2, 39) - ), + rangeInSource: $this->range([2, 29], [2, 39]), value: TypeName::from('Description') ) ), @@ -522,28 +296,16 @@ public function parsesStructDeclarationOnMultipleLinesWitOptionalArrayAndUnionPr ) ), new PropertyDeclarationNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 17) - ), + rangeInSource: $this->range([3, 4], [3, 17]), name: new PropertyNameNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 8) - ), + rangeInSource: $this->range([3, 4], [3, 8]), value: PropertyName::from('title') ), type: new TypeReferenceNode( - rangeInSource: Range::from( - new Position(3, 11), - new Position(3, 17) - ), + rangeInSource: $this->range([3, 11], [3, 17]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(3, 12), - new Position(3, 17) - ), + rangeInSource: $this->range([3, 12], [3, 17]), value: TypeName::from('string') ) ), diff --git a/test/Unit/Language/Parser/Tag/TagParserTest.php b/test/Unit/Language/Parser/Tag/TagParserTest.php index fe3c25a0..be4fb7c5 100644 --- a/test/Unit/Language/Parser/Tag/TagParserTest.php +++ b/test/Unit/Language/Parser/Tag/TagParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,12 +36,7 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagParser; -use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Language\Parser\Tag\TagCouldNotBeParsed; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; final class TagParserTest extends ParserTestCase @@ -52,18 +47,12 @@ final class TagParserTest extends ParserTestCase public function parsesSelfClosingTagWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ), + rangeInSource: $this->range([0, 0], [0, 3]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), @@ -83,31 +72,19 @@ public function parsesSelfClosingTagWithoutAttributes(): void public function parsesSelfClosingTagWithValuelessAttribute(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 0], [0, 11]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 1], [0, 5]), value: TagName::from('table') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: AttributeName::from('foo') ), value: null @@ -129,59 +106,35 @@ public function parsesSelfClosingTagWithValuelessAttribute(): void public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 0], [0, 19]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 1], [0, 5]), value: TagName::from('table') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: AttributeName::from('foo') ), value: null ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: AttributeName::from('bar') ), value: null ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 15], [0, 17]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 15], [0, 17]), value: AttributeName::from('baz') ), value: null @@ -203,38 +156,23 @@ public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void public function parsesSelfClosingTagWithStringAttribute(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 0], [0, 13]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 3], [0, 10]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 3], [0, 5]), value: AttributeName::from('foo') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 8), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 8], [0, 10]), value: 'bar' ) ) @@ -255,78 +193,45 @@ public function parsesSelfClosingTagWithStringAttribute(): void public function parsesSelfClosingTagWithMultipleStringAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 38) - ), + rangeInSource: $this->range([0, 0], [0, 38]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ), + rangeInSource: $this->range([0, 1], [0, 3]), value: TagName::from('div') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 12) - ), + rangeInSource: $this->range([0, 5], [0, 12]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 5], [0, 7]), value: AttributeName::from('foo') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 10), - new Position(0, 12) - ), + rangeInSource: $this->range([0, 10], [0, 12]), value: 'bar' ) ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 15], [0, 22]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 17) - ), + rangeInSource: $this->range([0, 15], [0, 17]), value: AttributeName::from('baz') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 20), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 20], [0, 22]), value: 'qux' ) ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 25), - new Position(0, 35) - ), + rangeInSource: $this->range([0, 25], [0, 35]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 25), - new Position(0, 28) - ), + rangeInSource: $this->range([0, 25], [0, 28]), value: AttributeName::from('quux') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 31), - new Position(0, 35) - ), + rangeInSource: $this->range([0, 31], [0, 35]), value: 'corge' ) ) @@ -347,31 +252,19 @@ public function parsesSelfClosingTagWithMultipleStringAttributes(): void public function parsesSelfClosingTagWithExpressionAttribute(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 0], [0, 13]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 3], [0, 10]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 3], [0, 5]), value: AttributeName::from('foo') ), value: new ExpressionNode( @@ -399,7 +292,7 @@ public function parsesSelfClosingTagWithExpressionAttribute(): void public function parsesSelfClosingTagWithMultipleExpressionAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString('
'))->getIterator(); + $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( rangeInSource: $this->range([0, 0], [0, 38]), @@ -467,18 +360,12 @@ public function parsesSelfClosingTagWithMultipleExpressionAttributes(): void public function parsesTagWithEmptyContentAndWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 6) - ), + rangeInSource: $this->range([0, 0], [0, 6]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), @@ -497,22 +384,19 @@ public function parsesTagWithEmptyContentAndWithoutAttributes(): void */ public function throwsIfClosingTagNameDoesNotMatchOpeningTagName(): void { - $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $this->assertThrowsParserException( + function () { + $tagParser = new TagParser(); + $tokens = $this->createTokenIterator(''); - $this->expectException(ParserException::class); - $this->expectExceptionObject( + $tagParser->parse($tokens); + }, TagCouldNotBeParsed::becauseOfClosingTagNameMismatch( expectedTagName: TagName::from('a'), actualTagName: 'b', - affectedRangeInSource: Range::from( - new Position(0, 5), - new Position(0, 5) - ) + affectedRangeInSource: $this->range([0, 5], [0, 5]) ) ); - - $tagParser->parse($tokens); } /** @@ -521,31 +405,19 @@ public function throwsIfClosingTagNameDoesNotMatchOpeningTagName(): void public function parsesTagWithEmptyContentAndValuelessAttribute(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 0], [0, 10]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 3], [0, 5]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 3], [0, 5]), value: AttributeName::from('foo') ), value: null @@ -567,59 +439,35 @@ public function parsesTagWithEmptyContentAndValuelessAttribute(): void public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 18) - ), + rangeInSource: $this->range([0, 0], [0, 18]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 3], [0, 5]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 3], [0, 5]), value: AttributeName::from('foo') ), value: null ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: AttributeName::from('bar') ), value: null ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 11], [0, 13]), value: AttributeName::from('baz') ), value: null @@ -641,38 +489,23 @@ public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void public function parsesTagWithEmptyContentAndStringAttribute(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 0], [0, 24]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 1], [0, 5]), value: TagName::from('audio') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 14) - ), + rangeInSource: $this->range([0, 7], [0, 14]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: AttributeName::from('foo') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 12), - new Position(0, 14) - ), + rangeInSource: $this->range([0, 12], [0, 14]), value: 'bar' ) ), @@ -693,78 +526,45 @@ public function parsesTagWithEmptyContentAndStringAttribute(): void public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 47) - ), + rangeInSource: $this->range([0, 0], [0, 47]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 5) - ), + rangeInSource: $this->range([0, 1], [0, 5]), value: TagName::from('video') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 14) - ), + rangeInSource: $this->range([0, 7], [0, 14]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 7], [0, 9]), value: AttributeName::from('foo') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 12), - new Position(0, 14) - ), + rangeInSource: $this->range([0, 12], [0, 14]), value: 'bar' ) ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 17), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 17], [0, 24]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 17), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 17], [0, 19]), value: AttributeName::from('baz') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 22), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 22], [0, 24]), value: 'qux' ) ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 37) - ), + rangeInSource: $this->range([0, 27], [0, 37]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 27), - new Position(0, 30) - ), + rangeInSource: $this->range([0, 27], [0, 30]), value: AttributeName::from('quux') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 33), - new Position(0, 37) - ), + rangeInSource: $this->range([0, 33], [0, 37]), value: 'corge' ) ), @@ -785,7 +585,7 @@ public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void public function parsesTagWithEmptyContentAndExpressionAttribute(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( rangeInSource: $this->range([0, 0], [0, 24]), @@ -825,7 +625,7 @@ public function parsesTagWithEmptyContentAndExpressionAttribute(): void public function parsesTagWithEmptyContentAndMultipleExpressionAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( rangeInSource: $this->range([0, 0], [0, 47]), @@ -893,27 +693,18 @@ public function parsesTagWithEmptyContentAndMultipleExpressionAttributes(): void public function parsesTagWithTextContentAndWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Lorem ipsum...'))->getIterator(); + $tokens = $this->createTokenIterator('Lorem ipsum...'); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 0], [0, 20]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 16) - ), + rangeInSource: $this->range([0, 3], [0, 16]), value: 'Lorem ipsum...' ) ), @@ -965,32 +756,20 @@ public function parsesTagWithExpressionContentAndWithoutAttributes(): void public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 0], [0, 10]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 6) - ), + rangeInSource: $this->range([0, 3], [0, 6]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 4], [0, 4]), value: TagName::from('b') ), attributes: new AttributeNodes(), @@ -1013,32 +792,20 @@ public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): public function parsesTagWithNestedTagAndWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 0], [0, 13]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 3], [0, 9]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 4], [0, 4]), value: TagName::from('b') ), attributes: new AttributeNodes(), @@ -1061,60 +828,36 @@ public function parsesTagWithNestedTagAndWithoutAttributes(): void public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 0], [0, 24]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 3], [0, 20]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 4], [0, 4]), value: TagName::from('b') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 6), - new Position(0, 16) - ), + rangeInSource: $this->range([0, 6], [0, 16]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 7], [0, 7]), value: TagName::from('c') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 9), - new Position(0, 12) - ), + rangeInSource: $this->range([0, 9], [0, 12]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 10), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 10], [0, 10]), value: TagName::from('d') ), attributes: new AttributeNodes(), @@ -1143,32 +886,20 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(' '))->getIterator(); + $tokens = $this->createTokenIterator(' '); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 19) - ), + rangeInSource: $this->range([0, 0], [0, 19]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 6), - new Position(0, 12) - ), + rangeInSource: $this->range([0, 6], [0, 12]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 7), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 7], [0, 7]), value: TagName::from('b') ), attributes: new AttributeNodes(), @@ -1191,58 +922,37 @@ public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): voi public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundTheNestedTag(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Something important happened.'))->getIterator(); + $tokens = $this->createTokenIterator('Something important happened.'); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 42) - ), + rangeInSource: $this->range([0, 0], [0, 42]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 12) - ), + rangeInSource: $this->range([0, 3], [0, 12]), value: 'Something ' ), new TagNode( - rangeInSource: Range::from( - new Position(0, 13), - new Position(0, 28) - ), + rangeInSource: $this->range([0, 13], [0, 28]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 14) - ), + rangeInSource: $this->range([0, 14], [0, 14]), value: TagName::from('b') ), attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(0, 16), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 16], [0, 24]), value: 'important' ) ), isSelfClosing: false ), new TextNode( - rangeInSource: Range::from( - new Position(0, 29), - new Position(0, 38) - ), + rangeInSource: $this->range([0, 29], [0, 38]), value: ' happened.' ) ), @@ -1302,32 +1012,20 @@ public function parsesTagWithExpressionInBetweenTextContentPreservingSpaceAround public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void { $tagParser = new TagParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 24) - ), + rangeInSource: $this->range([0, 0], [0, 24]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 1) - ), + rangeInSource: $this->range([0, 1], [0, 1]), value: TagName::from('a') ), attributes: new AttributeNodes(), children: new ChildNodes( new TagNode( - rangeInSource: Range::from( - new Position(0, 3), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 3], [0, 9]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 4], [0, 4]), value: TagName::from('b') ), attributes: new AttributeNodes(), @@ -1335,15 +1033,9 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void isSelfClosing: false ), new TagNode( - rangeInSource: Range::from( - new Position(0, 10), - new Position(0, 13) - ), + rangeInSource: $this->range([0, 10], [0, 13]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 11), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 11], [0, 11]), value: TagName::from('c') ), attributes: new AttributeNodes(), @@ -1351,15 +1043,9 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void isSelfClosing: true ), new TagNode( - rangeInSource: Range::from( - new Position(0, 14), - new Position(0, 20) - ), + rangeInSource: $this->range([0, 14], [0, 20]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 15), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 15], [0, 15]), value: TagName::from('d') ), attributes: new AttributeNodes(), @@ -1393,51 +1079,30 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut Some closing text
AFX; - $tokens = Tokenizer::fromSource(Source::fromString($tagAsString))->getIterator(); + $tokens = $this->createTokenIterator($tagAsString); $expectedTagNode = new TagNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(8, 5) - ), + rangeInSource: $this->range([0, 0], [8, 5]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ), + rangeInSource: $this->range([0, 1], [0, 3]), value: TagName::from('div') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 5], [0, 15]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 5), - new Position(0, 9) - ), + rangeInSource: $this->range([0, 5], [0, 9]), value: AttributeName::from('class') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(0, 12), - new Position(0, 15) - ), + rangeInSource: $this->range([0, 12], [0, 15]), value: 'test' ) ), new AttributeNode( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 23) - ), + rangeInSource: $this->range([0, 18], [0, 23]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(0, 18), - new Position(0, 23) - ), + rangeInSource: $this->range([0, 18], [0, 23]), value: AttributeName::from('hidden') ), value: null @@ -1445,124 +1110,73 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(0, 25), - new Position(2, 3) - ), + rangeInSource: $this->range([0, 25], [2, 3]), value: 'Some opening text' ), new TagNode( - rangeInSource: Range::from( - new Position(2, 4), - new Position(2, 20) - ), + rangeInSource: $this->range([2, 4], [2, 20]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(2, 5), - new Position(2, 6) - ), + rangeInSource: $this->range([2, 5], [2, 6]), value: TagName::from('h1') ), attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(2, 8), - new Position(2, 15) - ), + rangeInSource: $this->range([2, 8], [2, 15]), value: 'Headline' ), ), isSelfClosing: false ), new TagNode( - rangeInSource: Range::from( - new Position(3, 4), - new Position(3, 59) - ), + rangeInSource: $this->range([3, 4], [3, 59]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(3, 5), - new Position(3, 5) - ), + rangeInSource: $this->range([3, 5], [3, 5]), value: TagName::from('a') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(3, 7), - new Position(3, 23) - ), + rangeInSource: $this->range([3, 7], [3, 23]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(3, 7), - new Position(3, 10) - ), + rangeInSource: $this->range([3, 7], [3, 10]), value: AttributeName::from('href') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(3, 13), - new Position(3, 23) - ), + rangeInSource: $this->range([3, 13], [3, 23]), value: 'about:blank' ) ), new AttributeNode( - rangeInSource: Range::from( - new Position(3, 26), - new Position(3, 39) - ), + rangeInSource: $this->range([3, 26], [3, 39]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(3, 26), - new Position(3, 31) - ), + rangeInSource: $this->range([3, 26], [3, 31]), value: AttributeName::from('target') ), value: new StringLiteralNode( - rangeInSource: Range::from( - new Position(3, 34), - new Position(3, 39) - ), + rangeInSource: $this->range([3, 34], [3, 39]), value: '_blank' ) ), ), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(3, 42), - new Position(3, 55) - ), + rangeInSource: $this->range([3, 42], [3, 55]), value: 'This is a link' ), ), isSelfClosing: false ), new TagNode( - rangeInSource: Range::from( - new Position(4, 4), - new Position(6, 7) - ), + rangeInSource: $this->range([4, 4], [6, 7]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(4, 5), - new Position(4, 5) - ), + rangeInSource: $this->range([4, 5], [4, 5]), value: TagName::from('p') ), attributes: new AttributeNodes( new AttributeNode( - rangeInSource: Range::from( - new Position(4, 7), - new Position(4, 16) - ), + rangeInSource: $this->range([4, 7], [4, 16]), name: new AttributeNameNode( - rangeInSource: Range::from( - new Position(4, 7), - new Position(4, 11) - ), + rangeInSource: $this->range([4, 7], [4, 11]), value: AttributeName::from('class') ), value: new ExpressionNode( @@ -1576,102 +1190,63 @@ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttribut ), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(4, 19), - new Position(5, 17) - ), + rangeInSource: $this->range([4, 19], [5, 17]), value: 'This is a ' ), new ExpressionNode( - rangeInSource: Range::from( - new Position(5, 19), - new Position(5, 27) - ), + rangeInSource: $this->range([5, 19], [5, 27]), root: new ValueReferenceNode( - rangeInSource: Range::from( - new Position(5, 19), - new Position(5, 27) - ), + rangeInSource: $this->range([5, 19], [5, 27]), name: VariableName::from('paragraph') ) ), new TextNode( - rangeInSource: Range::from( - new Position(5, 29), - new Position(5, 34) - ), + rangeInSource: $this->range([5, 29], [5, 34]), value: ' with ' ), new TagNode( - rangeInSource: Range::from( - new Position(5, 35), - new Position(5, 53) - ), + rangeInSource: $this->range([5, 35], [5, 53]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(5, 36), - new Position(5, 37) - ), + rangeInSource: $this->range([5, 36], [5, 37]), value: TagName::from('em') ), attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(5, 39), - new Position(5, 48) - ), + rangeInSource: $this->range([5, 39], [5, 48]), value: 'emphasized' ), ), isSelfClosing: false ), new TextNode( - rangeInSource: Range::from( - new Position(5, 54), - new Position(5, 58) - ), + rangeInSource: $this->range([5, 54], [5, 58]), value: ' and ' ), new TagNode( - rangeInSource: Range::from( - new Position(5, 59), - new Position(5, 83) - ), + rangeInSource: $this->range([5, 59], [5, 83]), name: new TagNameNode( - rangeInSource: Range::from( - new Position(5, 60), - new Position(5, 65) - ), + rangeInSource: $this->range([5, 60], [5, 65]), value: TagName::from('strong') ), attributes: new AttributeNodes(), children: new ChildNodes( new TextNode( - rangeInSource: Range::from( - new Position(5, 67), - new Position(5, 74) - ), + rangeInSource: $this->range([5, 67], [5, 74]), value: 'boldened' ), ), isSelfClosing: false ), new TextNode( - rangeInSource: Range::from( - new Position(5, 84), - new Position(6, 3) - ), + rangeInSource: $this->range([5, 84], [6, 3]), value: ' text.' ) ), isSelfClosing: false ), new TextNode( - rangeInSource: Range::from( - new Position(6, 8), - new Position(7, 21) - ), + rangeInSource: $this->range([6, 8], [7, 21]), value: 'Some closing text' ), ), diff --git a/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php b/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php index daf3201c..dd757ea8 100644 --- a/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php +++ b/test/Unit/Language/Parser/TemplateLiteral/TemplateLiteralParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/test/Unit/Language/Parser/Text/TextParserTest.php b/test/Unit/Language/Parser/Text/TextParserTest.php index 63da880e..adf41c89 100644 --- a/test/Unit/Language/Parser/Text/TextParserTest.php +++ b/test/Unit/Language/Parser/Text/TextParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,13 +24,9 @@ use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; use PackageFactory\ComponentEngine\Language\Parser\Text\TextParser; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class TextParserTest extends TestCase +final class TextParserTest extends ParserTestCase { /** * @test @@ -38,7 +34,7 @@ final class TextParserTest extends TestCase public function parsesEmptyStringToNull(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(''))->getIterator(); + $tokens = $this->createTokenIterator(''); $this->assertNull( $textParser->parse($tokens) @@ -51,7 +47,7 @@ public function parsesEmptyStringToNull(): void public function parsesTextWithSpacesOnlyToNull(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" \t \n \t "))->getIterator(); + $tokens = $this->createTokenIterator(" \t \n \t "); $this->assertNull($textParser->parse($tokens)); } @@ -62,13 +58,10 @@ public function parsesTextWithSpacesOnlyToNull(): void public function parsesTrivialText(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Hello World'))->getIterator(); + $tokens = $this->createTokenIterator('Hello World'); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 0], [0, 10]), value: 'Hello World' ); @@ -84,13 +77,10 @@ public function parsesTrivialText(): void public function trimsLeadingAndTrailingSpaces(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" \t\t Hello World \t\t "))->getIterator(); + $tokens = $this->createTokenIterator(" \t\t Hello World \t\t "); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), value: 'Hello World' ); @@ -106,13 +96,10 @@ public function trimsLeadingAndTrailingSpaces(): void public function trimsLeadingLineBreak(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("\nHello World"))->getIterator(); + $tokens = $this->createTokenIterator("\nHello World"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 10) - ), + rangeInSource: $this->range([0, 0], [1, 10]), value: 'Hello World' ); @@ -128,13 +115,10 @@ public function trimsLeadingLineBreak(): void public function trimsLeadingLineBreakAndIndentation(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("\n Hello World"))->getIterator(); + $tokens = $this->createTokenIterator("\n Hello World"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 14) - ), + rangeInSource: $this->range([0, 0], [1, 14]), value: 'Hello World' ); @@ -150,13 +134,10 @@ public function trimsLeadingLineBreakAndIndentation(): void public function preservesLeadingSpaceIfFlagIsSet(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" \t\t Hello World \t\t "))->getIterator(); + $tokens = $this->createTokenIterator(" \t\t Hello World \t\t "); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 22) - ), + rangeInSource: $this->range([0, 0], [0, 22]), value: ' Hello World' ); @@ -172,13 +153,10 @@ public function preservesLeadingSpaceIfFlagIsSet(): void public function reducesInnerSpacesToSingleSpaceCharacterEach(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("Hello \t \n \t folks and\t\t\tpeople"))->getIterator(); + $tokens = $this->createTokenIterator("Hello \t \n \t folks and\t\t\tpeople"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 22) - ), + rangeInSource: $this->range([0, 0], [1, 22]), value: 'Hello folks and people' ); @@ -194,13 +172,10 @@ public function reducesInnerSpacesToSingleSpaceCharacterEach(): void public function terminatesAtEmbeddedExpressionAndTrimsLeadingSpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" Hello{"))->getIterator(); + $tokens = $this->createTokenIterator(" Hello{"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 8) - ), + rangeInSource: $this->range([0, 0], [0, 8]), value: 'Hello' ); @@ -216,13 +191,10 @@ public function terminatesAtEmbeddedExpressionAndTrimsLeadingSpace(): void public function terminatesAtEmbeddedExpressionAndKeepsTrailingSpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("Hello \t {foo}!"))->getIterator(); + $tokens = $this->createTokenIterator("Hello \t {foo}!"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 0], [0, 7]), value: 'Hello ' ); @@ -238,13 +210,10 @@ public function terminatesAtEmbeddedExpressionAndKeepsTrailingSpace(): void public function terminatesAtEmbeddedExpressionAndTrimsTrailingSpaceIfItContainsLineBreaks(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t {foo}!"))->getIterator(); + $tokens = $this->createTokenIterator("Hello \n\t {foo}!"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 1) - ), + rangeInSource: $this->range([0, 0], [1, 1]), value: 'Hello' ); @@ -260,7 +229,7 @@ public function terminatesAtEmbeddedExpressionAndTrimsTrailingSpaceIfItContainsL public function returnsNullAtEmbeddedExpressionIfTheresOnlySpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" \n\t {foo}!"))->getIterator(); + $tokens = $this->createTokenIterator(" \n\t {foo}!"); $this->assertNull($textParser->parse($tokens)); } @@ -271,13 +240,10 @@ public function returnsNullAtEmbeddedExpressionIfTheresOnlySpace(): void public function terminatesAtOpeningTagAndTrimsLeadingSpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" Hello"))->getIterator(); + $tokens = $this->createTokenIterator(" Hello"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 8) - ), + rangeInSource: $this->range([0, 0], [0, 8]), value: 'Hello' ); @@ -293,13 +259,10 @@ public function terminatesAtOpeningTagAndTrimsLeadingSpace(): void public function terminatesAtOpeningTagAndKeepsTrailingSpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("Hello \t World"))->getIterator(); + $tokens = $this->createTokenIterator("Hello \t World"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 7) - ), + rangeInSource: $this->range([0, 0], [0, 7]), value: 'Hello ' ); @@ -315,13 +278,10 @@ public function terminatesAtOpeningTagAndKeepsTrailingSpace(): void public function terminatesAtOpeningTagAndTrimsTrailingSpaceIfItContainsLineBreaks(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("Hello \n\t World"))->getIterator(); + $tokens = $this->createTokenIterator("Hello \n\t World"); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 1) - ), + rangeInSource: $this->range([0, 0], [1, 1]), value: 'Hello' ); @@ -337,7 +297,7 @@ public function terminatesAtOpeningTagAndTrimsTrailingSpaceIfItContainsLineBreak public function returnsNullAtOpeningTagIfTheresOnlySpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" \n\t "))->getIterator(); + $tokens = $this->createTokenIterator(" \n\t "); $this->assertNull($textParser->parse($tokens)); } @@ -348,13 +308,10 @@ public function returnsNullAtOpeningTagIfTheresOnlySpace(): void public function terminatesAtClosingTagAndTrimsTrailingSpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString("World \n\t "))->getIterator(); + $tokens = $this->createTokenIterator("World \n\t "); $expectedTextNode = new TextNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(1, 1) - ), + rangeInSource: $this->range([0, 0], [1, 1]), value: 'World' ); @@ -370,7 +327,7 @@ public function terminatesAtClosingTagAndTrimsTrailingSpace(): void public function returnsNullAtClosingTagIfTheresOnlySpace(): void { $textParser = new TextParser(); - $tokens = Tokenizer::fromSource(Source::fromString(" \n\t "))->getIterator(); + $tokens = $this->createTokenIterator(" \n\t "); $this->assertNull($textParser->parse($tokens)); } diff --git a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php index 00c20dc1..d3d460d8 100644 --- a/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php +++ b/test/Unit/Language/Parser/TypeReference/TypeReferenceParserTest.php @@ -32,33 +32,23 @@ use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; use PackageFactory\ComponentEngine\Language\Parser\ParserException; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceCouldNotBeParsed; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class TypeReferenceParserTest extends TestCase +final class TypeReferenceParserTest extends ParserTestCase { /** * @test */ - public function producesAstNodeForSimpleTypeReference(): void + public function parsesSimpleTypeReference(): void { $typeReferenceParser = new TypeReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Foo'))->getIterator(); + $tokens = $this->createTokenIterator('Foo'); $expectedTypeReferenceNode = new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: TypeName::from('Foo') ) ), @@ -75,22 +65,16 @@ public function producesAstNodeForSimpleTypeReference(): void /** * @test */ - public function producesAstNodeForArrayTypeReference(): void + public function parsesArrayTypeReference(): void { $typeReferenceParser = new TypeReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Foo[]'))->getIterator(); + $tokens = $this->createTokenIterator('Foo[]'); $expectedTypeReferenceNode = new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ), + rangeInSource: $this->range([0, 0], [0, 4]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: TypeName::from('Foo') ) ), @@ -107,22 +91,16 @@ public function producesAstNodeForArrayTypeReference(): void /** * @test */ - public function producesAstNodeForOptionalTypeReference(): void + public function parsesOptionalTypeReference(): void { $typeReferenceParser = new TypeReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('?Foo'))->getIterator(); + $tokens = $this->createTokenIterator('?Foo'); $expectedTypeReferenceNode = new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 3) - ), + rangeInSource: $this->range([0, 0], [0, 3]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 1), - new Position(0, 3) - ), + rangeInSource: $this->range([0, 1], [0, 3]), value: TypeName::from('Foo') ) ), @@ -139,36 +117,24 @@ public function producesAstNodeForOptionalTypeReference(): void /** * @test */ - public function producesAstNodeForUnionTypeReference(): void + public function parsesUnionTypeReference(): void { $typeReferenceParser = new TypeReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Foo|Bar|Baz'))->getIterator(); + $tokens = $this->createTokenIterator('Foo|Bar|Baz'); $expectedTypeReferenceNode = new TypeReferenceNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 0], [0, 10]), names: new TypeNameNodes( new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), value: TypeName::from('Foo') ), new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 4), - new Position(0, 6) - ), + rangeInSource: $this->range([0, 4], [0, 6]), value: TypeName::from('Bar') ), new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 8), - new Position(0, 10) - ), + rangeInSource: $this->range([0, 8], [0, 10]), value: TypeName::from('Baz') ) ), @@ -185,20 +151,17 @@ public function producesAstNodeForUnionTypeReference(): void /** * @test */ - public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void + public function throwsIfInvalidTypeReferenceOccurs(): void { $typeReferenceParser = new TypeReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('?Foo[]'))->getIterator(); + $tokens = $this->createTokenIterator('?Foo[]'); $this->expectException(ParserException::class); $this->expectExceptionObject( TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeReferenceNode( cause: InvalidTypeReferenceNode::becauseItWasOptionalAndArrayAtTheSameTime( affectedTypeNames: new TypeNames(TypeName::from('Foo')), - affectedRangeInSource: Range::from( - new Position(0, 0), - new Position(0, 4) - ), + affectedRangeInSource: $this->range([0, 0], [0, 4]), ) ) ); @@ -209,20 +172,17 @@ public function throwsParserExceptionWhenInvalidTypeReferenceOccurs(): void /** * @test */ - public function throwsParserExceptionWhenDuplicatesOccur(): void + public function throwsIfDuplicatesOccurInUnionTypeReference(): void { $typeReferenceParser = new TypeReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('Foo|Bar|Foo|Baz'))->getIterator(); + $tokens = $this->createTokenIterator('Foo|Bar|Foo|Baz'); $this->expectException(ParserException::class); $this->expectExceptionObject( TypeReferenceCouldNotBeParsed::becauseOfInvalidTypeTypeNameNodes( cause: InvalidTypeNameNodes::becauseTheyContainDuplicates( duplicateTypeNameNode: new TypeNameNode( - rangeInSource: Range::from( - new Position(0, 9), - new Position(0, 11) - ), + rangeInSource: $this->range([0, 9], [0, 11]), value: TypeName::from('Foo') ) ) diff --git a/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php b/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php index 72229252..c5d7a2b3 100644 --- a/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php +++ b/test/Unit/Language/Parser/ValueReference/ValueReferenceParserTest.php @@ -2,7 +2,7 @@ /** * PackageFactory.ComponentEngine - Universal View Components for PHP - * Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine + * Copyright (C) 2023 Contributors of PackageFactory.ComponentEngine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,9 @@ use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\Language\Parser\ValueReference\ValueReferenceParser; -use PackageFactory\ComponentEngine\Parser\Source\Range; -use PackageFactory\ComponentEngine\Parser\Source\Position; -use PackageFactory\ComponentEngine\Parser\Source\Source; -use PackageFactory\ComponentEngine\Parser\Tokenizer\Tokenizer; -use PHPUnit\Framework\TestCase; +use PackageFactory\ComponentEngine\Test\Unit\Language\Parser\ParserTestCase; -final class ValueReferenceParserTest extends TestCase +final class ValueReferenceParserTest extends ParserTestCase { /** * @test @@ -39,13 +35,10 @@ final class ValueReferenceParserTest extends TestCase public function parsesValueReference(): void { $valueReferenceParser = new ValueReferenceParser(); - $tokens = Tokenizer::fromSource(Source::fromString('foo'))->getIterator(); + $tokens = $this->createTokenIterator('foo'); $expectedValueReferenceNode = new ValueReferenceNode( - rangeInSource: Range::from( - new Position(0, 0), - new Position(0, 2) - ), + rangeInSource: $this->range([0, 0], [0, 2]), name: VariableName::from('foo') ); From fb4b6c54274f5870f963e7b0f6b753380727d4a2 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sat, 5 Aug 2023 17:16:39 +0200 Subject: [PATCH 56/64] TASK: Turn parsers into singletons where applicable --- src/Framework/PHP/Singleton/Singleton.php | 47 +++++++++++++++++ .../BooleanLiteral/BooleanLiteralParser.php | 3 ++ .../ComponentDeclarationParser.php | 13 ++--- .../EnumDeclaration/EnumDeclarationParser.php | 37 ++++++++++---- src/Language/Parser/Export/ExportParser.php | 17 +++---- .../Parser/Expression/ExpressionParser.php | 41 +++++++++------ src/Language/Parser/Import/ImportParser.php | 10 ++-- .../IntegerLiteral/IntegerLiteralParser.php | 3 ++ src/Language/Parser/Match/MatchParser.php | 3 ++ src/Language/Parser/Module/ModuleParser.php | 15 +++--- .../Parser/NullLiteral/NullLiteralParser.php | 3 ++ .../PropertyDeclarationParser.php | 9 ++-- .../StringLiteral/StringLiteralParser.php | 3 ++ .../StructDeclarationParser.php | 11 ++-- src/Language/Parser/Tag/TagParser.php | 26 ++++++---- .../TemplateLiteral/TemplateLiteralParser.php | 15 +++--- src/Language/Parser/Text/TextParser.php | 3 ++ .../TypeReference/TypeReferenceParser.php | 3 ++ .../ValueReference/ValueReferenceParser.php | 3 ++ .../BooleanLiteralParserTest.php | 4 +- .../ComponentDeclarationParserTest.php | 6 +-- .../EnumDeclarationParserTest.php | 18 +++---- .../Parser/Export/ExportParserTest.php | 8 +-- .../Parser/Import/ImportParserTest.php | 8 +-- .../IntegerLiteralParserTest.php | 12 ++--- .../Language/Parser/Match/MatchParserTest.php | 26 +++++----- .../Parser/Module/ModuleParserTest.php | 10 ++-- .../NullLiteral/NullLiteralParserTest.php | 2 +- .../PropertyDeclarationParserTest.php | 8 +-- .../StringLiteral/StringLiteralParserTest.php | 2 +- .../StructDeclarationParserTest.php | 8 +-- .../Language/Parser/Tag/TagParserTest.php | 50 +++++++++---------- .../TemplateLiteralParserTest.php | 14 +++--- .../Language/Parser/Text/TextParserTest.php | 36 ++++++------- .../TypeReference/TypeReferenceParserTest.php | 12 ++--- .../ValueReferenceParserTest.php | 2 +- 36 files changed, 298 insertions(+), 193 deletions(-) create mode 100644 src/Framework/PHP/Singleton/Singleton.php diff --git a/src/Framework/PHP/Singleton/Singleton.php b/src/Framework/PHP/Singleton/Singleton.php new file mode 100644 index 00000000..58933a05 --- /dev/null +++ b/src/Framework/PHP/Singleton/Singleton.php @@ -0,0 +1,47 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Framework\PHP\Singleton; + +trait Singleton +{ + private static ?self $instance = null; + + private function __construct() + { + } + + final public static function singleton(): static + { + return static::$instance ??= new static(); + } + + final public function __clone() + { + trigger_error('Cloning ' . __CLASS__ . ' is not allowed.', E_USER_ERROR); + } + + final public function __wakeup() + { + trigger_error('Unserializing ' . __CLASS__ . ' is not allowed.', E_USER_ERROR); + } +} diff --git a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php index 300ef04d..f353929b 100644 --- a/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php +++ b/src/Language/Parser/BooleanLiteral/BooleanLiteralParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\BooleanLiteral; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\BooleanLiteral\BooleanLiteralNode; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -29,6 +30,8 @@ final class BooleanLiteralParser { + use Singleton; + /** * @param \Iterator $tokens * @return BooleanLiteralNode diff --git a/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php b/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php index d02db95b..2a3f176d 100644 --- a/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php +++ b/src/Language/Parser/ComponentDeclaration/ComponentDeclarationParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\ComponentDeclaration; use PackageFactory\ComponentEngine\Domain\ComponentName\ComponentName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; @@ -36,13 +37,10 @@ final class ComponentDeclarationParser { - private readonly PropertyDeclarationParser $propertyDeclarationParser; - private ?ExpressionParser $returnParser = null; + use Singleton; - public function __construct() - { - $this->propertyDeclarationParser = new PropertyDeclarationParser(); - } + private ?PropertyDeclarationParser $propertyDeclarationParser = null; + private ?ExpressionParser $returnParser = null; /** * @param \Iterator $tokens @@ -125,8 +123,11 @@ private function skipOpeningBracketToken(\Iterator &$tokens): void */ private function parseProps(\Iterator &$tokens): PropertyDeclarationNodes { + $this->propertyDeclarationParser ??= PropertyDeclarationParser::singleton(); + $items = []; while (Scanner::type($tokens) !== TokenType::KEYWORD_RETURN) { + assert($this->propertyDeclarationParser !== null); $items[] = $this->propertyDeclarationParser->parse($tokens); Scanner::skipSpaceAndComments($tokens); diff --git a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php index 3e0b06e2..2630c0a6 100644 --- a/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php +++ b/src/Language/Parser/EnumDeclaration/EnumDeclarationParser.php @@ -24,12 +24,15 @@ use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; use PackageFactory\ComponentEngine\Domain\EnumName\EnumName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberDeclarationNodes; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumMemberValueNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumNameNode; +use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; +use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral\IntegerLiteralParser; use PackageFactory\ComponentEngine\Language\Parser\StringLiteral\StringLiteralParser; use PackageFactory\ComponentEngine\Parser\Source\Range; @@ -39,14 +42,10 @@ final class EnumDeclarationParser { - private readonly StringLiteralParser $stringLiteralParser; - private readonly IntegerLiteralParser $integerLiteralParser; + use Singleton; - public function __construct() - { - $this->stringLiteralParser = new StringLiteralParser(); - $this->integerLiteralParser = new IntegerLiteralParser(); - } + private ?StringLiteralParser $stringLiteralParser = null; + private ?IntegerLiteralParser $integerLiteralParser = null; /** * @param \Iterator $tokens @@ -213,12 +212,12 @@ private function parseEnumMemberValue(\Iterator &$tokens): ?EnumMemberValueNode $valueToken = $tokens->current(); $value = match ($valueToken->type) { TokenType::STRING_QUOTED => - $this->stringLiteralParser->parse($tokens), + $this->parseStringLiteral($tokens), TokenType::NUMBER_BINARY, TokenType::NUMBER_OCTAL, TokenType::NUMBER_DECIMAL, TokenType::NUMBER_HEXADECIMAL => - $this->integerLiteralParser->parse($tokens), + $this->parseIntegerLiteral($tokens), default => throw new \Exception('@TODO: Unexpected Token ' . Scanner::type($tokens)->value) }; @@ -234,4 +233,24 @@ private function parseEnumMemberValue(\Iterator &$tokens): ?EnumMemberValueNode value: $value ); } + + /** + * @param \Iterator $tokens + * @return StringLiteralNode + */ + private function parseStringLiteral(\Iterator &$tokens): StringLiteralNode + { + $this->stringLiteralParser ??= StringLiteralParser::singleton(); + return $this->stringLiteralParser->parse($tokens); + } + + /** + * @param \Iterator $tokens + * @return IntegerLiteralNode + */ + private function parseIntegerLiteral(\Iterator &$tokens): IntegerLiteralNode + { + $this->integerLiteralParser ??= IntegerLiteralParser::singleton(); + return $this->integerLiteralParser->parse($tokens); + } } diff --git a/src/Language/Parser/Export/ExportParser.php b/src/Language/Parser/Export/ExportParser.php index 795f7fa0..c0fa9ed0 100644 --- a/src/Language/Parser/Export/ExportParser.php +++ b/src/Language/Parser/Export/ExportParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\Export; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\ComponentDeclaration\ComponentDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\EnumDeclaration\EnumDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; @@ -37,16 +38,11 @@ final class ExportParser { - private readonly ComponentDeclarationParser $componentDeclarationParser; - private readonly EnumDeclarationParser $enumDeclarationParser; - private readonly StructDeclarationParser $structDeclarationParser; + use Singleton; - public function __construct() - { - $this->componentDeclarationParser = new ComponentDeclarationParser(); - $this->enumDeclarationParser = new EnumDeclarationParser(); - $this->structDeclarationParser = new StructDeclarationParser(); - } + private ?ComponentDeclarationParser $componentDeclarationParser = null; + private ?EnumDeclarationParser $enumDeclarationParser = null; + private ?StructDeclarationParser $structDeclarationParser = null; /** * @param \Iterator $tokens @@ -99,6 +95,7 @@ private function extractToken(\Iterator &$tokens, TokenType $tokenType): Token */ private function parseComponentDeclaration(\Iterator &$tokens): ComponentDeclarationNode { + $this->componentDeclarationParser ??= ComponentDeclarationParser::singleton(); return $this->componentDeclarationParser->parse($tokens); } @@ -108,6 +105,7 @@ private function parseComponentDeclaration(\Iterator &$tokens): ComponentDeclara */ private function parseEnumDeclaration(\Iterator &$tokens): EnumDeclarationNode { + $this->enumDeclarationParser ??= EnumDeclarationParser::singleton(); return $this->enumDeclarationParser->parse($tokens); } @@ -117,6 +115,7 @@ private function parseEnumDeclaration(\Iterator &$tokens): EnumDeclarationNode */ private function parseStructDeclaration(\Iterator &$tokens): StructDeclarationNode { + $this->structDeclarationParser ??= StructDeclarationParser::singleton(); return $this->structDeclarationParser->parse($tokens); } } diff --git a/src/Language/Parser/Expression/ExpressionParser.php b/src/Language/Parser/Expression/ExpressionParser.php index 0620749e..8e00e814 100644 --- a/src/Language/Parser/Expression/ExpressionParser.php +++ b/src/Language/Parser/Expression/ExpressionParser.php @@ -48,27 +48,19 @@ final class ExpressionParser { - private readonly BooleanLiteralParser $booleanLiteralParser; - private readonly NullLiteralParser $nullLiteralParser; - private readonly StringLiteralParser $stringLiteralParser; - private readonly IntegerLiteralParser $integerLiteralParser; - private readonly ValueReferenceParser $valueReferenceParser; - private readonly TemplateLiteralParser $templateLiteralParser; - private readonly TagParser $tagParser; - private readonly MatchParser $matchParser; + private ?BooleanLiteralParser $booleanLiteralParser = null; + private ?IntegerLiteralParser $integerLiteralParser = null; + private ?MatchParser $matchParser = null; + private ?NullLiteralParser $nullLiteralParser = null; + private ?StringLiteralParser $stringLiteralParser = null; + private ?TagParser $tagParser = null; + private ?TemplateLiteralParser $templateLiteralParser = null; + private ?ValueReferenceParser $valueReferenceParser = null; public function __construct( private ?TokenType $stopAt = null, private Precedence $precedence = Precedence::SEQUENCE ) { - $this->booleanLiteralParser = new BooleanLiteralParser(); - $this->nullLiteralParser = new NullLiteralParser(); - $this->stringLiteralParser = new StringLiteralParser(); - $this->integerLiteralParser = new IntegerLiteralParser(); - $this->valueReferenceParser = new ValueReferenceParser(); - $this->templateLiteralParser = new TemplateLiteralParser(); - $this->tagParser = new TagParser(); - $this->matchParser = new MatchParser(); } /** @@ -267,6 +259,8 @@ private function shouldStop(\Iterator &$tokens): bool */ private function parseBooleanLiteral(\Iterator &$tokens): ExpressionNode { + $this->booleanLiteralParser ??= BooleanLiteralParser::singleton(); + $booleanLiteralNode = $this->booleanLiteralParser->parse($tokens); return new ExpressionNode( @@ -281,6 +275,9 @@ private function parseBooleanLiteral(\Iterator &$tokens): ExpressionNode */ private function parseNullLiteral(\Iterator &$tokens): ExpressionNode { + + $this->nullLiteralParser ??= NullLiteralParser::singleton(); + $nullLiteralNode = $this->nullLiteralParser->parse($tokens); return new ExpressionNode( @@ -295,6 +292,8 @@ private function parseNullLiteral(\Iterator &$tokens): ExpressionNode */ private function parseStringLiteral(\Iterator &$tokens): ExpressionNode { + $this->stringLiteralParser ??= StringLiteralParser::singleton(); + $stringLiteralNode = $this->stringLiteralParser->parse($tokens); return new ExpressionNode( @@ -309,6 +308,8 @@ private function parseStringLiteral(\Iterator &$tokens): ExpressionNode */ private function parseIntegerLiteral(\Iterator &$tokens): ExpressionNode { + $this->integerLiteralParser ??= IntegerLiteralParser::singleton(); + $integerLiteralNode = $this->integerLiteralParser->parse($tokens); return new ExpressionNode( @@ -323,6 +324,8 @@ private function parseIntegerLiteral(\Iterator &$tokens): ExpressionNode */ private function parseValueReference(\Iterator &$tokens): ExpressionNode { + $this->valueReferenceParser ??= ValueReferenceParser::singleton(); + $valueReferenceNode = $this->valueReferenceParser->parse($tokens); return new ExpressionNode( @@ -337,6 +340,8 @@ private function parseValueReference(\Iterator &$tokens): ExpressionNode */ private function parseTag(\Iterator &$tokens): ExpressionNode { + $this->tagParser ??= TagParser::singleton(); + $tagNode = $this->tagParser->parse($tokens); return new ExpressionNode( @@ -351,6 +356,8 @@ private function parseTag(\Iterator &$tokens): ExpressionNode */ private function parseTemplateLiteral(\Iterator &$tokens): ExpressionNode { + $this->templateLiteralParser ??= TemplateLiteralParser::singleton(); + $templateLiteralNode = $this->templateLiteralParser->parse($tokens); return new ExpressionNode( @@ -365,6 +372,8 @@ private function parseTemplateLiteral(\Iterator &$tokens): ExpressionNode */ private function parseMatch(\Iterator &$tokens): ExpressionNode { + $this->matchParser ??= MatchParser::singleton(); + $matchNode = $this->matchParser->parse($tokens); return new ExpressionNode( diff --git a/src/Language/Parser/Import/ImportParser.php b/src/Language/Parser/Import/ImportParser.php index 6551fe8b..b10a2cc4 100644 --- a/src/Language/Parser/Import/ImportParser.php +++ b/src/Language/Parser/Import/ImportParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\Import; use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNode; use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportedNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNode; @@ -36,12 +37,9 @@ final class ImportParser { - private readonly StringLiteralParser $pathParser; + use Singleton; - public function __construct() - { - $this->pathParser = new StringLiteralParser(); - } + private ?StringLiteralParser $pathParser = null; /** * @param \Iterator $tokens @@ -108,6 +106,8 @@ private function skipToken(\Iterator &$tokens, TokenType $tokenType): void */ private function parsePath(\Iterator &$tokens): StringLiteralNode { + $this->pathParser ??= StringLiteralParser::singleton(); + $path = $this->pathParser->parse($tokens); Scanner::skipSpace($tokens); diff --git a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php index cd3745bc..4f34d1be 100644 --- a/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php +++ b/src/Language/Parser/IntegerLiteral/IntegerLiteralParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\IntegerLiteral; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerFormat; use PackageFactory\ComponentEngine\Language\AST\Node\IntegerLiteral\IntegerLiteralNode; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; @@ -31,6 +32,8 @@ final class IntegerLiteralParser { + use Singleton; + /** * @param \Iterator $tokens * @return IntegerLiteralNode diff --git a/src/Language/Parser/Match/MatchParser.php b/src/Language/Parser/Match/MatchParser.php index 5cf689a2..dab66788 100644 --- a/src/Language/Parser/Match/MatchParser.php +++ b/src/Language/Parser/Match/MatchParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\Match; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNodes; use PackageFactory\ComponentEngine\Language\AST\Node\Match\InvalidMatchArmNodes; @@ -36,6 +37,8 @@ final class MatchParser { + use Singleton; + private ?ExpressionParser $subjectParser = null; private ?ExpressionParser $matchArmLeftParser = null; private ?ExpressionParser $matchArmRightParser = null; diff --git a/src/Language/Parser/Module/ModuleParser.php b/src/Language/Parser/Module/ModuleParser.php index 2e5fbfa0..d45f64cf 100644 --- a/src/Language/Parser/Module/ModuleParser.php +++ b/src/Language/Parser/Module/ModuleParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\Module; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\Export\ExportNode; use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNode; use PackageFactory\ComponentEngine\Language\AST\Node\Import\ImportNodes; @@ -36,14 +37,10 @@ final class ModuleParser { - private readonly ImportParser $importParser; - private readonly ExportParser $exportParser; + use Singleton; - public function __construct() - { - $this->importParser = new ImportParser(); - $this->exportParser = new ExportParser(); - } + private ?ImportParser $importParser = null; + private ?ExportParser $exportParser = null; /** * @param \Iterator $tokens @@ -92,6 +89,8 @@ private function parseImports(\Iterator &$tokens): ImportNodes */ private function parseImport(\Iterator &$tokens): ImportNode { + $this->importParser ??= ImportParser::singleton(); + $import = $this->importParser->parse($tokens); Scanner::skipSpaceAndComments($tokens); @@ -104,6 +103,8 @@ private function parseImport(\Iterator &$tokens): ImportNode */ private function parseExport(\Iterator &$tokens): ExportNode { + $this->exportParser ??= ExportParser::singleton(); + $export = $this->exportParser->parse($tokens); Scanner::skipSpaceAndComments($tokens); diff --git a/src/Language/Parser/NullLiteral/NullLiteralParser.php b/src/Language/Parser/NullLiteral/NullLiteralParser.php index baaebbf2..69f17b2f 100644 --- a/src/Language/Parser/NullLiteral/NullLiteralParser.php +++ b/src/Language/Parser/NullLiteral/NullLiteralParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\NullLiteral; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\NullLiteral\NullLiteralNode; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -29,6 +30,8 @@ final class NullLiteralParser { + use Singleton; + /** * @param \Iterator $tokens * @return NullLiteralNode diff --git a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php index 9650e06b..9a41d0ce 100644 --- a/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php +++ b/src/Language/Parser/PropertyDeclaration/PropertyDeclarationParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\PropertyDeclaration; use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyNameNode; use PackageFactory\ComponentEngine\Language\Parser\TypeReference\TypeReferenceParser; @@ -33,12 +34,9 @@ final class PropertyDeclarationParser { - private readonly TypeReferenceParser $typeReferenceParser; + use Singleton; - public function __construct() - { - $this->typeReferenceParser = new TypeReferenceParser(); - } + private ?TypeReferenceParser $typeReferenceParser = null; /** * @param \Iterator $tokens @@ -56,6 +54,7 @@ public function parse(\Iterator &$tokens): PropertyDeclarationNode Scanner::skipSpace($tokens); + $this->typeReferenceParser ??= TypeReferenceParser::singleton(); $typeReferenceNode = $this->typeReferenceParser->parse($tokens); return new PropertyDeclarationNode( diff --git a/src/Language/Parser/StringLiteral/StringLiteralParser.php b/src/Language/Parser/StringLiteral/StringLiteralParser.php index 96ed63e7..fe6f1cb0 100644 --- a/src/Language/Parser/StringLiteral/StringLiteralParser.php +++ b/src/Language/Parser/StringLiteral/StringLiteralParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\StringLiteral; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -29,6 +30,8 @@ final class StringLiteralParser { + use Singleton; + /** * @param \Iterator $tokens * @return StringLiteralNode diff --git a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php index 8c764ca1..37c1496e 100644 --- a/src/Language/Parser/StructDeclaration/StructDeclarationParser.php +++ b/src/Language/Parser/StructDeclaration/StructDeclarationParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\StructDeclaration; use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\PropertyDeclaration\PropertyDeclarationNodes; use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructDeclarationNode; use PackageFactory\ComponentEngine\Language\AST\Node\StructDeclaration\StructNameNode; @@ -34,12 +35,9 @@ final class StructDeclarationParser { - private readonly PropertyDeclarationParser $propertyDeclarationParser; + use Singleton; - public function __construct() - { - $this->propertyDeclarationParser = new PropertyDeclarationParser(); - } + private ?PropertyDeclarationParser $propertyDeclarationParser = null; /** * @param \Iterator $tokens @@ -115,8 +113,11 @@ public function skipOpeningBracketToken(\Iterator &$tokens): void */ public function parsePropertyDeclarations(\Iterator &$tokens): PropertyDeclarationNodes { + $this->propertyDeclarationParser ??= PropertyDeclarationParser::singleton(); + $items = []; while (Scanner::type($tokens) === TokenType::STRING) { + assert($this->propertyDeclarationParser !== null); $items[] = $this->propertyDeclarationParser->parse($tokens); Scanner::skipSpaceAndComments($tokens); } diff --git a/src/Language/Parser/Tag/TagParser.php b/src/Language/Parser/Tag/TagParser.php index c1aec7e7..ce63ed09 100644 --- a/src/Language/Parser/Tag/TagParser.php +++ b/src/Language/Parser/Tag/TagParser.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\Expression\ExpressionNode; use PackageFactory\ComponentEngine\Language\AST\Node\StringLiteral\StringLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\Tag\AttributeNameNode; @@ -43,15 +44,11 @@ final class TagParser { - private readonly StringLiteralParser $stringLiteralParser; - private readonly TextParser $textParser; - private ?ExpressionParser $expressionParser; + use Singleton; - public function __construct() - { - $this->stringLiteralParser = new StringLiteralParser(); - $this->textParser = new TextParser(); - } + private ?StringLiteralParser $stringLiteralParser = null; + private ?TextParser $textParser = null; + private ?ExpressionParser $expressionParser = null; /** * @param \Iterator $tokens @@ -200,7 +197,7 @@ private function parseAttributeValue(\Iterator &$tokens): null|StringLiteralNode return match (Scanner::type($tokens)) { TokenType::STRING_QUOTED => - $this->stringLiteralParser->parse($tokens), + $this->parseString($tokens), TokenType::BRACKET_CURLY_OPEN => $this->parseExpression($tokens), default => throw TagCouldNotBeParsed::becauseOfUnexpectedToken( @@ -216,6 +213,16 @@ private function parseAttributeValue(\Iterator &$tokens): null|StringLiteralNode return null; } + /** + * @param \Iterator $tokens + * @return StringLiteralNode + */ + private function parseString(\Iterator &$tokens): StringLiteralNode + { + $this->stringLiteralParser ??= StringLiteralParser::singleton(); + return $this->stringLiteralParser->parse($tokens); + } + /** * @param \Iterator $tokens * @return ExpressionNode @@ -272,6 +279,7 @@ private function parseChildren(\Iterator &$tokens): ChildNodes $items = []; $preserveLeadingSpace = false; while (Scanner::type($tokens) !== TokenType::TAG_START_CLOSING) { + $this->textParser ??= TextParser::singleton(); if ($textNode = $this->textParser->parse($tokens, $preserveLeadingSpace)) { $items[] = $textNode; } diff --git a/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php b/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php index 8a06c2e3..509f0175 100644 --- a/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php +++ b/src/Language/Parser/TemplateLiteral/TemplateLiteralParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\TemplateLiteral; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralExpressionSegmentNode; use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralNode; use PackageFactory\ComponentEngine\Language\AST\Node\TemplateLiteral\TemplateLiteralSegments; @@ -34,14 +35,9 @@ final class TemplateLiteralParser { - private ?ExpressionParser $expressionParser = null; + use Singleton; - private function initializeExpressionParser(): void - { - $this->expressionParser ??= new ExpressionParser( - stopAt: TokenType::BRACKET_CURLY_CLOSE - ); - } + private ?ExpressionParser $expressionParser = null; /** * @param \Iterator $tokens @@ -108,7 +104,9 @@ public function parseStringSegment(\Iterator &$tokens): TemplateLiteralStringSeg */ public function parseExpressionSegment(\Iterator &$tokens): TemplateLiteralExpressionSegmentNode { - $this->initializeExpressionParser(); + $this->expressionParser ??= new ExpressionParser( + stopAt: TokenType::BRACKET_CURLY_CLOSE + ); Scanner::assertType($tokens, TokenType::DOLLAR); $dollarToken = $tokens->current(); @@ -117,7 +115,6 @@ public function parseExpressionSegment(\Iterator &$tokens): TemplateLiteralExpre Scanner::assertType($tokens, TokenType::BRACKET_CURLY_OPEN); Scanner::skipOne($tokens); - assert($this->expressionParser !== null); $expression = $this->expressionParser->parse($tokens); Scanner::assertType($tokens, TokenType::BRACKET_CURLY_CLOSE); diff --git a/src/Language/Parser/Text/TextParser.php b/src/Language/Parser/Text/TextParser.php index 78c38152..25ef70c8 100644 --- a/src/Language/Parser/Text/TextParser.php +++ b/src/Language/Parser/Text/TextParser.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\Text; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\Text\TextNode; use PackageFactory\ComponentEngine\Parser\Source\Range; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; @@ -30,6 +31,8 @@ final class TextParser { + use Singleton; + private string $value; private ?Token $startingToken; diff --git a/src/Language/Parser/TypeReference/TypeReferenceParser.php b/src/Language/Parser/TypeReference/TypeReferenceParser.php index fe4841a7..f4fa7343 100644 --- a/src/Language/Parser/TypeReference/TypeReferenceParser.php +++ b/src/Language/Parser/TypeReference/TypeReferenceParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\TypeReference; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeNameNodes; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\InvalidTypeReferenceNode; use PackageFactory\ComponentEngine\Language\AST\Node\TypeReference\TypeNameNode; @@ -35,6 +36,8 @@ final class TypeReferenceParser { + use Singleton; + /** * @param \Iterator $tokens * @return TypeReferenceNode diff --git a/src/Language/Parser/ValueReference/ValueReferenceParser.php b/src/Language/Parser/ValueReference/ValueReferenceParser.php index 42c687fc..f955647c 100644 --- a/src/Language/Parser/ValueReference/ValueReferenceParser.php +++ b/src/Language/Parser/ValueReference/ValueReferenceParser.php @@ -23,6 +23,7 @@ namespace PackageFactory\ComponentEngine\Language\Parser\ValueReference; use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner; use PackageFactory\ComponentEngine\Parser\Tokenizer\Token; @@ -30,6 +31,8 @@ final class ValueReferenceParser { + use Singleton; + /** * @param \Iterator $tokens * @return ValueReferenceNode diff --git a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php index 923c4f4f..447c56b3 100644 --- a/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php +++ b/test/Unit/Language/Parser/BooleanLiteral/BooleanLiteralParserTest.php @@ -33,7 +33,7 @@ final class BooleanLiteralParserTest extends ParserTestCase */ public function parsesTrue(): void { - $booleanLiteralParser = new BooleanLiteralParser(); + $booleanLiteralParser = BooleanLiteralParser::singleton(); $tokens = $this->createTokenIterator('true'); $expectedBooleanLiteralNode = new BooleanLiteralNode( @@ -52,7 +52,7 @@ public function parsesTrue(): void */ public function parsesFalse(): void { - $booleanLiteralParser = new BooleanLiteralParser(); + $booleanLiteralParser = BooleanLiteralParser::singleton(); $tokens = $this->createTokenIterator('false'); $expectedBooleanLiteralNode = new BooleanLiteralNode( diff --git a/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php b/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php index 958fd61a..a724ce97 100644 --- a/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php +++ b/test/Unit/Language/Parser/ComponentDeclaration/ComponentDeclarationParserTest.php @@ -55,7 +55,7 @@ final class ComponentDeclarationParserTest extends ParserTestCase */ public function parsesComponentDeclarationWithNoProps(): void { - $componentDeclarationParser = new ComponentDeclarationParser(); + $componentDeclarationParser = ComponentDeclarationParser::singleton(); $tokens = $this->createTokenIterator('component Foo { return "bar" }'); $expectedComponentDeclarationNode = new ComponentDeclarationNode( @@ -85,7 +85,7 @@ public function parsesComponentDeclarationWithNoProps(): void */ public function parsesComponentDeclarationWithOneProp(): void { - $componentDeclarationParser = new ComponentDeclarationParser(); + $componentDeclarationParser = ComponentDeclarationParser::singleton(); $tokens = $this->createTokenIterator('component Foo { bar: string return bar }'); $expectedComponentDeclarationNode = new ComponentDeclarationNode( @@ -134,7 +134,7 @@ public function parsesComponentDeclarationWithOneProp(): void */ public function parsesComponentDeclarationWithMultiplePropsAndComplexReturnStatement(): void { - $componentDeclarationParser = new ComponentDeclarationParser(); + $componentDeclarationParser = ComponentDeclarationParser::singleton(); $componentAsString = <<createTokenIterator('enum Foo { BAR }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -75,7 +75,7 @@ public function parsesEnumDeclarationWithOneValuelessMember(): void */ public function parsesEnumDeclarationWithThreeValuelessMembers(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $tokens = $this->createTokenIterator('enum Foo { BAR BAZ QUX }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -123,7 +123,7 @@ public function parsesEnumDeclarationWithThreeValuelessMembers(): void */ public function parsesEnumDeclarationWithOneStringValueMember(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $tokens = $this->createTokenIterator('enum Foo { BAR("BAR") }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -161,7 +161,7 @@ public function parsesEnumDeclarationWithOneStringValueMember(): void */ public function parsesEnumDeclarationWithSevenStringValueMembers(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $enumAsString = <<createTokenIterator('enum Foo { BAR(0b101) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -333,7 +333,7 @@ public function parsesEnumDeclarationWithOneBinaryIntegerValueMember(): void */ public function parsesEnumDeclarationWithOneOctalIntegerValueMember(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $tokens = $this->createTokenIterator('enum Foo { BAR(0o644) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -372,7 +372,7 @@ public function parsesEnumDeclarationWithOneOctalIntegerValueMember(): void */ public function parsesEnumDeclarationWithOneDecimalIntegerValueMember(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $tokens = $this->createTokenIterator('enum Foo { BAR(42) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -411,7 +411,7 @@ public function parsesEnumDeclarationWithOneDecimalIntegerValueMember(): void */ public function parsesEnumDeclarationWithOneHexadecimalIntegerValueMember(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $tokens = $this->createTokenIterator('enum Foo { BAR(0xABC) }'); $expectedEnumDeclarationNode = new EnumDeclarationNode( @@ -450,7 +450,7 @@ public function parsesEnumDeclarationWithOneHexadecimalIntegerValueMember(): voi */ public function parsesEnumDeclarationWithwelveIntegerValueMembers(): void { - $enumDeclarationParser = new EnumDeclarationParser(); + $enumDeclarationParser = EnumDeclarationParser::singleton(); $enumAsString = <<createTokenIterator( 'export component Foo { return bar }' ); @@ -97,7 +97,7 @@ public function parsesComponentExport(): void */ public function parsesEnumExport(): void { - $exportParser = new ExportParser(); + $exportParser = ExportParser::singleton(); $tokens = $this->createTokenIterator( 'export enum Foo { BAR }' ); @@ -134,7 +134,7 @@ public function parsesEnumExport(): void */ public function parsesStructExport(): void { - $exportParser = new ExportParser(); + $exportParser = ExportParser::singleton(); $tokens = $this->createTokenIterator( 'export struct Foo { bar: baz }' ); @@ -183,7 +183,7 @@ public function throwsIfExportIsNoDeclaration(): void { $this->assertThrowsParserException( function () { - $exportParser = new ExportParser(); + $exportParser = ExportParser::singleton(); $tokens = $this->createTokenIterator('export null'); $exportParser->parse($tokens); diff --git a/test/Unit/Language/Parser/Import/ImportParserTest.php b/test/Unit/Language/Parser/Import/ImportParserTest.php index dce94709..bf7779ed 100644 --- a/test/Unit/Language/Parser/Import/ImportParserTest.php +++ b/test/Unit/Language/Parser/Import/ImportParserTest.php @@ -39,7 +39,7 @@ final class ImportParserTest extends ParserTestCase */ public function parsesImportWithOneName(): void { - $importParser = new ImportParser(); + $importParser = ImportParser::singleton(); $tokens = $this->createTokenIterator( 'from "/some/where/in/the/filesystem" import { Foo }' ); @@ -69,7 +69,7 @@ public function parsesImportWithOneName(): void */ public function parsesImportWithMultipleNames(): void { - $importParser = new ImportParser(); + $importParser = ImportParser::singleton(); $tokens = $this->createTokenIterator( 'from "./some/other.component" import { Foo, Bar, Baz }' ); @@ -109,7 +109,7 @@ public function throwsIfEmptyImportOccurs(): void { $this->assertThrowsParserException( function () { - $importParser = new ImportParser(); + $importParser = ImportParser::singleton(); $tokens = $this->createTokenIterator( 'from "/some/where" import {}' ); @@ -130,7 +130,7 @@ public function throwsIfDuplicateImportsOccur(): void { $this->assertThrowsParserException( function () { - $importParser = new ImportParser(); + $importParser = ImportParser::singleton(); $tokens = $this->createTokenIterator( 'from "/some/where" import { Foo, Bar, Baz, Bar, Qux }' ); diff --git a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php index cc3f8e7e..5831a74a 100644 --- a/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php +++ b/test/Unit/Language/Parser/IntegerLiteral/IntegerLiteralParserTest.php @@ -39,7 +39,7 @@ final class IntegerLiteralParserTest extends ParserTestCase */ public function parsesBinaryInteger(): void { - $integerLiteralParser = new IntegerLiteralParser(); + $integerLiteralParser = IntegerLiteralParser::singleton(); $tokens = $this->createTokenIterator('0b1010110101'); $expectedIntegerLiteralNode = new IntegerLiteralNode( @@ -59,7 +59,7 @@ public function parsesBinaryInteger(): void */ public function parsesOctalInteger(): void { - $integerLiteralParser = new IntegerLiteralParser(); + $integerLiteralParser = IntegerLiteralParser::singleton(); $tokens = $this->createTokenIterator('0o755'); $expectedIntegerLiteralNode = new IntegerLiteralNode( @@ -79,7 +79,7 @@ public function parsesOctalInteger(): void */ public function parsesDecimalInteger(): void { - $integerLiteralParser = new IntegerLiteralParser(); + $integerLiteralParser = IntegerLiteralParser::singleton(); $tokens = $this->createTokenIterator('1234567890'); $expectedIntegerLiteralNode = new IntegerLiteralNode( @@ -99,7 +99,7 @@ public function parsesDecimalInteger(): void */ public function parsesHexadecimalInteger(): void { - $integerLiteralParser = new IntegerLiteralParser(); + $integerLiteralParser = IntegerLiteralParser::singleton(); $tokens = $this->createTokenIterator('0x123456789ABCDEF'); $expectedIntegerLiteralNode = new IntegerLiteralNode( @@ -121,7 +121,7 @@ public function throwsIfTokenStreamEndsUnexpectedly(): void { $this->assertThrowsParserException( function () { - $integerLiteralParser = new IntegerLiteralParser(); + $integerLiteralParser = IntegerLiteralParser::singleton(); $tokens = $this->createTokenIterator(''); $integerLiteralParser->parse($tokens); @@ -137,7 +137,7 @@ public function throwsIfUnexpectedTokenIsEncountered(): void { $this->assertThrowsParserException( function () { - $integerLiteralParser = new IntegerLiteralParser(); + $integerLiteralParser = IntegerLiteralParser::singleton(); $tokens = $this->createTokenIterator('foo1234'); $integerLiteralParser->parse($tokens); diff --git a/test/Unit/Language/Parser/Match/MatchParserTest.php b/test/Unit/Language/Parser/Match/MatchParserTest.php index 168d8d34..a3c43936 100644 --- a/test/Unit/Language/Parser/Match/MatchParserTest.php +++ b/test/Unit/Language/Parser/Match/MatchParserTest.php @@ -41,7 +41,7 @@ final class MatchParserTest extends ParserTestCase */ public function parsesMatchWithOneArm(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { b -> c }' ); @@ -89,7 +89,7 @@ public function parsesMatchWithOneArm(): void */ public function parsesMatchWithMultipleArms(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { b -> c d -> e f -> g }' ); @@ -175,7 +175,7 @@ public function parsesMatchWithMultipleArms(): void */ public function parsesMatchWithOneSummarizedArm(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { b, c, d -> e }' ); @@ -237,7 +237,7 @@ public function parsesMatchWithOneSummarizedArm(): void */ public function parsesMatchWithMultipleSummarizedArms(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { b, c, d -> e f, g, h -> i j, k, l -> m }' ); @@ -365,7 +365,7 @@ public function parsesMatchWithMultipleSummarizedArms(): void */ public function parsesMatchWithOnlyDefaultArm(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { default -> b }' ); @@ -405,7 +405,7 @@ public function parsesMatchWithOnlyDefaultArm(): void */ public function parsesMatchWithOneArmAndDefaultArm(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { b -> c default -> d }' ); @@ -464,7 +464,7 @@ public function parsesMatchWithOneArmAndDefaultArm(): void */ public function parsesMatchWithOneSummarizedArmAndDefaultArm(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator( 'match (a) { b, c, d -> e default -> f }' ); @@ -537,7 +537,7 @@ public function parsesMatchWithOneSummarizedArmAndDefaultArm(): void */ public function parsesMatchWithMixedArms(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $matchAsString = << c @@ -681,7 +681,7 @@ public function parsesMatchWithMixedArms(): void */ public function parsesNestedMatchAsSubject(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $matchAsString = << d default -> e }) { d, e -> f @@ -796,7 +796,7 @@ public function parsesNestedMatchAsSubject(): void */ public function parsesNestedMatchAsArmLeft(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $matchAsString = << e default -> f } -> g @@ -1004,7 +1004,7 @@ public function parsesNestedMatchAsArmLeft(): void */ public function parsesNestedMatchAsArmRight(): void { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $matchAsString = << match (c) { d, e -> f default -> g } @@ -1114,7 +1114,7 @@ public function throwsIfMatchArmsAreEmpty(): void { $this->assertThrowsParserException( function () { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $tokens = $this->createTokenIterator('match (a) {}'); $matchParser->parse($tokens); @@ -1133,7 +1133,7 @@ public function throwsIfMultipleDefaultArmsOccur(): void { $this->assertThrowsParserException( function () { - $matchParser = new MatchParser(); + $matchParser = MatchParser::singleton(); $matchAsString = << d diff --git a/test/Unit/Language/Parser/Module/ModuleParserTest.php b/test/Unit/Language/Parser/Module/ModuleParserTest.php index 34f4d956..a54ae774 100644 --- a/test/Unit/Language/Parser/Module/ModuleParserTest.php +++ b/test/Unit/Language/Parser/Module/ModuleParserTest.php @@ -48,7 +48,7 @@ final class ModuleParserTest extends ParserTestCase */ public function parsesModuleWithNoImports(): void { - $moduleParser = new ModuleParser(); + $moduleParser = ModuleParser::singleton(); $moduleAsString = <<assertThrowsParserException( function () { - $moduleParser = new ModuleParser(); + $moduleParser = ModuleParser::singleton(); $moduleAsString = <<createTokenIterator('null'); $expectedNullLiteralNode = new NullLiteralNode( diff --git a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php index 5aa59e14..720d6360 100644 --- a/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php +++ b/test/Unit/Language/Parser/PropertyDeclaration/PropertyDeclarationParserTest.php @@ -39,7 +39,7 @@ final class PropertyDeclarationParserTest extends ParserTestCase */ public function parsesPropertyDeclarationWithSimpleType(): void { - $propertyDeclarationParser = new PropertyDeclarationParser(); + $propertyDeclarationParser = PropertyDeclarationParser::singleton(); $tokens = $this->createTokenIterator('foo: Bar'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( @@ -72,7 +72,7 @@ public function parsesPropertyDeclarationWithSimpleType(): void */ public function parsesPropertyDeclarationWithOptionalType(): void { - $propertyDeclarationParser = new PropertyDeclarationParser(); + $propertyDeclarationParser = PropertyDeclarationParser::singleton(); $tokens = $this->createTokenIterator('foo: ?Bar'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( @@ -105,7 +105,7 @@ public function parsesPropertyDeclarationWithOptionalType(): void */ public function parsesPropertyDeclarationWithArrayType(): void { - $propertyDeclarationParser = new PropertyDeclarationParser(); + $propertyDeclarationParser = PropertyDeclarationParser::singleton(); $tokens = $this->createTokenIterator('foo: Bar[]'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( @@ -138,7 +138,7 @@ public function parsesPropertyDeclarationWithArrayType(): void */ public function parsesPropertyDeclarationWithUnionType(): void { - $propertyDeclarationParser = new PropertyDeclarationParser(); + $propertyDeclarationParser = PropertyDeclarationParser::singleton(); $tokens = $this->createTokenIterator('foo: Bar|Baz|Qux'); $expectedPropertyDeclarationNode = new PropertyDeclarationNode( diff --git a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php index 1da49710..bfee07ec 100644 --- a/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php +++ b/test/Unit/Language/Parser/StringLiteral/StringLiteralParserTest.php @@ -33,7 +33,7 @@ final class StringLiteralParserTest extends ParserTestCase */ public function parsesString(): void { - $stringLiteralParser = new StringLiteralParser(); + $stringLiteralParser = StringLiteralParser::singleton(); $tokens = $this->createTokenIterator('"Hello World"'); $expectedStringLiteralNode = new StringLiteralNode( diff --git a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php index 76ae04f9..87fff6e8 100644 --- a/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php +++ b/test/Unit/Language/Parser/StructDeclaration/StructDeclarationParserTest.php @@ -43,7 +43,7 @@ final class StructDeclarationParserTest extends ParserTestCase */ public function parsesStructDeclarationWithOneProperty(): void { - $structDeclarationParser = new StructDeclarationParser(); + $structDeclarationParser = StructDeclarationParser::singleton(); $tokens = $this->createTokenIterator('struct Foo { bar: Baz }'); $expectedStructDeclarationNode = new StructDeclarationNode( @@ -85,7 +85,7 @@ public function parsesStructDeclarationWithOneProperty(): void */ public function parsesStructDeclarationWithMultipleProperties(): void { - $structDeclarationParser = new StructDeclarationParser(); + $structDeclarationParser = StructDeclarationParser::singleton(); $tokens = $this->createTokenIterator('struct Foo { bar: Baz qux: Quux corge: Grault }'); $expectedStructDeclarationNode = new StructDeclarationNode( @@ -163,7 +163,7 @@ public function parsesStructDeclarationWithMultipleProperties(): void */ public function parsesStructDeclarationWithMultiplePropertiesAndSpaceAndComments(): void { - $structDeclarationParser = new StructDeclarationParser(); + $structDeclarationParser = StructDeclarationParser::singleton(); $structAsString = <<createTokenIterator(''); $expectedTagNode = new TagNode( @@ -71,7 +71,7 @@ public function parsesSelfClosingTagWithoutAttributes(): void */ public function parsesSelfClosingTagWithValuelessAttribute(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( @@ -105,7 +105,7 @@ public function parsesSelfClosingTagWithValuelessAttribute(): void */ public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( @@ -155,7 +155,7 @@ public function parsesSelfClosingTagWithMultipleValuelessAttributes(): void */ public function parsesSelfClosingTagWithStringAttribute(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -192,7 +192,7 @@ public function parsesSelfClosingTagWithStringAttribute(): void */ public function parsesSelfClosingTagWithMultipleStringAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( @@ -251,7 +251,7 @@ public function parsesSelfClosingTagWithMultipleStringAttributes(): void */ public function parsesSelfClosingTagWithExpressionAttribute(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -291,7 +291,7 @@ public function parsesSelfClosingTagWithExpressionAttribute(): void */ public function parsesSelfClosingTagWithMultipleExpressionAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('
'); $expectedTagNode = new TagNode( @@ -359,7 +359,7 @@ public function parsesSelfClosingTagWithMultipleExpressionAttributes(): void */ public function parsesTagWithEmptyContentAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -386,7 +386,7 @@ public function throwsIfClosingTagNameDoesNotMatchOpeningTagName(): void { $this->assertThrowsParserException( function () { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $tagParser->parse($tokens); @@ -404,7 +404,7 @@ function () { */ public function parsesTagWithEmptyContentAndValuelessAttribute(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -438,7 +438,7 @@ public function parsesTagWithEmptyContentAndValuelessAttribute(): void */ public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -488,7 +488,7 @@ public function parsesTagWithEmptyContentAndMultipleValuelessAttributes(): void */ public function parsesTagWithEmptyContentAndStringAttribute(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -525,7 +525,7 @@ public function parsesTagWithEmptyContentAndStringAttribute(): void */ public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -584,7 +584,7 @@ public function parsesTagWithEmptyContentAndMultipleStringAttributes(): void */ public function parsesTagWithEmptyContentAndExpressionAttribute(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -624,7 +624,7 @@ public function parsesTagWithEmptyContentAndExpressionAttribute(): void */ public function parsesTagWithEmptyContentAndMultipleExpressionAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -692,7 +692,7 @@ public function parsesTagWithEmptyContentAndMultipleExpressionAttributes(): void */ public function parsesTagWithTextContentAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('Lorem ipsum...'); $expectedTagNode = new TagNode( @@ -722,7 +722,7 @@ public function parsesTagWithTextContentAndWithoutAttributes(): void */ public function parsesTagWithExpressionContentAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('{someExpression}'); $expectedTagNode = new TagNode( @@ -755,7 +755,7 @@ public function parsesTagWithExpressionContentAndWithoutAttributes(): void */ public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -791,7 +791,7 @@ public function parsesTagWithNestedSelfClosingTagContentAndWithoutAttributes(): */ public function parsesTagWithNestedTagAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -827,7 +827,7 @@ public function parsesTagWithNestedTagAndWithoutAttributes(): void */ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -885,7 +885,7 @@ public function parsesTagWithNestedTagsOnMultipleLevelsAndWithoutAttributes(): v */ public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(' '); $expectedTagNode = new TagNode( @@ -921,7 +921,7 @@ public function parsesTagWithNestedTagInBetweenSpacesAndWithoutAttributes(): voi */ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundTheNestedTag(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('Something important happened.'); $expectedTagNode = new TagNode( @@ -970,7 +970,7 @@ public function parsesTagWithNestedTagInBetweenTextContentPreservingSpaceAroundT */ public function parsesTagWithExpressionInBetweenTextContentPreservingSpaceAroundTheExpression(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator('Something {variable} happened.'); $expectedTagNode = new TagNode( @@ -1011,7 +1011,7 @@ public function parsesTagWithExpressionInBetweenTextContentPreservingSpaceAround */ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tokens = $this->createTokenIterator(''); $expectedTagNode = new TagNode( @@ -1067,7 +1067,7 @@ public function parsesTagWithMultipleNestedTagsAsImmediateChildren(): void */ public function parsesTagWithMultipleNestedTagsOnMultipleLevelsAllHavingAttributesAndContentsThemselves(): void { - $tagParser = new TagParser(); + $tagParser = TagParser::singleton(); $tagAsString = <<
} EOT; - $componentDeclarationNode = ComponentDeclarationNode::fromString($componentDeclarationAsString); + $componentDeclarationNode = ASTNodeFixtures::ComponentDeclaration( + $componentDeclarationAsString + ); $componentScope = new ComponentScope( componentDeclarationNode: $componentDeclarationNode, - parentScope: new DummyScope([], [ - 'SomeEnum' => $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( - ModuleId::fromString("module-a"), - EnumDeclarationNode::fromString( - 'enum SomeEnum { A B C }' - ) - ) - ]) + parentScope: new DummyScope([$enumStaticType->toEnumInstanceType()]) ); $expectedType = $enumStaticType->toEnumInstanceType(); - $actualType = $componentScope->lookupTypeFor('foo'); + $actualType = $componentScope->getTypeOf(VariableName::from('foo')); $this->assertNotNull($actualType); @@ -116,14 +117,19 @@ public function fallsBackToParentScope(): void return
{foo}
} EOT; - $componentDeclarationNode = ComponentDeclarationNode::fromString($componentDeclarationAsString); + $componentDeclarationNode = ASTNodeFixtures::ComponentDeclaration( + $componentDeclarationAsString + ); $componentScope = new ComponentScope( componentDeclarationNode: $componentDeclarationNode, - parentScope: new DummyScope(['bar' => IntegerType::get()], []) + parentScope: new DummyScope( + [IntegerType::get()], + ['bar' => IntegerType::get()] + ) ); $expectedType = IntegerType::get(); - $actualType = $componentScope->lookupTypeFor('bar'); + $actualType = $componentScope->getTypeOf(VariableName::from('bar')); $this->assertNotNull($actualType); @@ -146,16 +152,16 @@ public function resolvesTypeReferencesUsingParentScope(): void return
{foo}
} EOT; - $componentDeclarationNode = ComponentDeclarationNode::fromString($componentDeclarationAsString); + $componentDeclarationNode = ASTNodeFixtures::ComponentDeclaration( + $componentDeclarationAsString + ); $componentScope = new ComponentScope( componentDeclarationNode: $componentDeclarationNode, - parentScope: new DummyScope([], ['StringAlias' => StringType::get()]) + parentScope: new DummyScope([StringType::get()]) ); $expectedType = StringType::get(); - $actualType = $componentScope->resolveTypeReference( - TypeReferenceNode::fromString('StringAlias') - ); + $actualType = $componentScope->getType(TypeName::from('string')); $this->assertTrue( $expectedType->is($actualType), diff --git a/test/Unit/TypeSystem/Scope/Fixtures/DummyScope.php b/test/Unit/TypeSystem/Scope/Fixtures/DummyScope.php index 954a1f3c..166d8dce 100644 --- a/test/Unit/TypeSystem/Scope/Fixtures/DummyScope.php +++ b/test/Unit/TypeSystem/Scope/Fixtures/DummyScope.php @@ -22,33 +22,47 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\Fixtures; -use PackageFactory\ComponentEngine\Parser\Ast\TypeReferenceNode; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; final class DummyScope implements ScopeInterface { /** - * @param array $identifierToTypeMap - * @param array $typeNameToTypeMap + * @var array + */ + private readonly array $typeNameToTypeMap; + + /** + * @param AtomicTypeInterface[] $knownTypes + * @param array $identifierToTypeReferenceMap */ public function __construct( - private readonly array $identifierToTypeMap = [], - private readonly array $typeNameToTypeMap = [] + array $knownTypes = [], + private readonly array $identifierToTypeReferenceMap = [], ) { - } + $typeNameToTypeMap = []; + foreach ($knownTypes as $type) { + /** @var AtomicTypeInterface $type */ + $typeNameToTypeMap[$type->getName()->value] = $type; + } - public function lookupTypeFor(string $name): ?TypeInterface - { - return $this->identifierToTypeMap[$name] ?? null; + $this->typeNameToTypeMap = $typeNameToTypeMap; } - public function resolveTypeReference(TypeReferenceNode $typeReferenceNode): TypeInterface + public function getType(TypeName $typeName): AtomicTypeInterface { - if ($type = $this->typeNameToTypeMap[$typeReferenceNode->name] ?? null) { + if ($type = $this->typeNameToTypeMap[$typeName->value] ?? null) { return $type; } - throw new \Exception('DummyScope: Unknown type ' . $typeReferenceNode->name); + throw new \Exception('DummyScope: Unknown type ' . $typeName->value); + } + + public function getTypeOf(VariableName $variableName): ?TypeInterface + { + return $this->identifierToTypeReferenceMap[$variableName->value] ?? null; } } diff --git a/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php b/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php index f145e7da..c06194cd 100644 --- a/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php +++ b/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php @@ -22,7 +22,8 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\GlobalScope; -use PackageFactory\ComponentEngine\Parser\Ast\TypeReferenceNode; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; use PackageFactory\ComponentEngine\TypeSystem\Scope\GlobalScope\GlobalScope; use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; @@ -30,18 +31,6 @@ final class GlobalScopeTest extends TestCase { - /** - * @test - * @return void - */ - public function isSingleton(): void - { - $globalScope1 = GlobalScope::get(); - $globalScope2 = GlobalScope::get(); - - $this->assertSame($globalScope1, $globalScope2); - } - /** * @return array */ @@ -55,16 +44,14 @@ public static function primitiveTypeExamples(): array /** * @dataProvider primitiveTypeExamples * @test - * @param string $typeReferenceAsString + * @param string $typeNameAsString * @param TypeInterface $expectedType * @return void */ - public function resolvesPrimitiveTypes(string $typeReferenceAsString, TypeInterface $expectedType): void + public function resolvesPrimitiveTypes(string $typeNameAsString, TypeInterface $expectedType): void { $globalScope = GlobalScope::get(); - $typeReferenceNode = TypeReferenceNode::fromString($typeReferenceAsString); - - $actualType = $globalScope->resolveTypeReference($typeReferenceNode); + $actualType = $globalScope->getType(TypeName::from($typeNameAsString)); $this->assertTrue( $expectedType->is($actualType), @@ -80,6 +67,6 @@ public function knowsNoLocalNames(): void { $globalScope = GlobalScope::get(); - $this->assertNull($globalScope->lookupTypeFor('someVariable')); + $this->assertNull($globalScope->getTypeOf(VariableName::from('someVariable'))); } } diff --git a/test/Unit/TypeSystem/Scope/ModuleScope/ModuleScopeTest.php b/test/Unit/TypeSystem/Scope/ModuleScope/ModuleScopeTest.php index 27c68069..6d5a9b6f 100644 --- a/test/Unit/TypeSystem/Scope/ModuleScope/ModuleScopeTest.php +++ b/test/Unit/TypeSystem/Scope/ModuleScope/ModuleScopeTest.php @@ -22,16 +22,38 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\ModuleScope; -use PackageFactory\ComponentEngine\Parser\Ast\ModuleNode; -use PackageFactory\ComponentEngine\Parser\Ast\TypeReferenceNode; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Test\Unit\Language\ASTNodeFixtures; use PackageFactory\ComponentEngine\Test\Unit\Module\Loader\Fixtures\DummyLoader; use PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\Fixtures\DummyScope; +use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\Scope\ModuleScope\ModuleScope; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; use PHPUnit\Framework\TestCase; final class ModuleScopeTest extends TestCase { + private function mockAtomicType(string $name): AtomicTypeInterface + { + return new class($name) implements AtomicTypeInterface + { + public function __construct(private readonly string $name) + { + } + + public function getName(): TypeName + { + return TypeName::from($this->name); + } + + public function is(TypeInterface $other): bool + { + return $other === $this; + } + }; + } + /** * @test * @return void @@ -41,16 +63,18 @@ public function resolvesTypeReferencesForModuleImports(): void $moduleAsString = << [ - 'Foo' => $typeOfFoo = $this->createStub(TypeInterface::class), + 'Foo' => $typeOfFoo = $this->createStub(AtomicTypeInterface::class), ], './Bar.afx' => [ - 'Bar' => $typeOfBar = $this->createStub(TypeInterface::class), - 'Baz' => $typeOfBaz = $this->createStub(TypeInterface::class) + 'Bar' => $typeOfBar = $this->createStub(AtomicTypeInterface::class), + 'Baz' => $typeOfBaz = $this->createStub(AtomicTypeInterface::class) ], ]), moduleNode: $moduleNode, @@ -59,23 +83,17 @@ public function resolvesTypeReferencesForModuleImports(): void $this->assertSame( $typeOfFoo, - $moduleScope->resolveTypeReference( - TypeReferenceNode::fromString('Foo') - ) + $moduleScope->getType(TypeName::from('Foo')) ); $this->assertSame( $typeOfBar, - $moduleScope->resolveTypeReference( - TypeReferenceNode::fromString('Bar') - ) + $moduleScope->getType(TypeName::from('Bar')) ); $this->assertSame( $typeOfBaz, - $moduleScope->resolveTypeReference( - TypeReferenceNode::fromString('Baz') - ) + $moduleScope->getType(TypeName::from('Baz')) ); } @@ -85,18 +103,23 @@ public function resolvesTypeReferencesForModuleImports(): void */ public function fallsBackToParentScopeWhenProvidingTypesForValues(): void { - $moduleNode = ModuleNode::fromString('from "y" import { y }'); + $moduleNode = ASTNodeFixtures::Module('from "y" import { y } export struct Qux {}'); $moduleScope = new ModuleScope( loader: new DummyLoader(), moduleNode: $moduleNode, - parentScope: new DummyScope([ - 'foo' => $typeOfFoo = $this->createStub(TypeInterface::class), - ]) + parentScope: new DummyScope( + [ + $typeOfFoo = $this->mockAtomicType('Foo') + ], + [ + 'foo' => $typeOfFoo + ] + ) ); $this->assertSame( $typeOfFoo, - $moduleScope->lookupTypeFor('foo') + $moduleScope->getTypeOf(VariableName::from('foo')) ); } } diff --git a/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php b/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php index b49b51d6..bdfe23a4 100644 --- a/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php +++ b/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php @@ -22,12 +22,22 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\BooleanType; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\TypeSystem\Type\BooleanType\BooleanType; use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; use PHPUnit\Framework\TestCase; final class BooleanTypeTest extends TestCase { + /** + * @test + * @return void + */ + public function providesItsTypeName(): void + { + $this->assertEquals(TypeName::from('boolean'), BooleanType::get()->getName()); + } + /** * @test */ diff --git a/test/Unit/TypeSystem/Type/ComponentType/ComponentTypeTest.php b/test/Unit/TypeSystem/Type/ComponentType/ComponentTypeTest.php index af7ecffc..4aff9a8c 100644 --- a/test/Unit/TypeSystem/Type/ComponentType/ComponentTypeTest.php +++ b/test/Unit/TypeSystem/Type/ComponentType/ComponentTypeTest.php @@ -22,7 +22,8 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\ComponentType; -use PackageFactory\ComponentEngine\Parser\Ast\ComponentDeclarationNode; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Test\Unit\Language\ASTNodeFixtures; use PackageFactory\ComponentEngine\TypeSystem\Type\ComponentType\ComponentType; use PHPUnit\Framework\TestCase; @@ -34,8 +35,8 @@ final class ComponentTypeTest extends TestCase */ public function canBeCreatedFromComponentDeclarationNode(): void { - $componentDeclarationNode = ComponentDeclarationNode::fromString( - 'component Foo { a : string b : number return
{a} and {b}
}' + $componentDeclarationNode = ASTNodeFixtures::ComponentDeclaration( + 'component Foo { a: string b: number return
{a} and {b}
}' ); $componentType = ComponentType::fromComponentDeclarationNode( $componentDeclarationNode @@ -50,14 +51,17 @@ public function canBeCreatedFromComponentDeclarationNode(): void */ public function providesNameOfTheComponent(): void { - $componentDeclarationNode = ComponentDeclarationNode::fromString( + $componentDeclarationNode = ASTNodeFixtures::ComponentDeclaration( 'component SomeComponent { return "" }' ); $componentType = ComponentType::fromComponentDeclarationNode( $componentDeclarationNode ); - $this->assertEquals('SomeComponent', $componentType->componentName); + $this->assertEquals( + TypeName::from('SomeComponent'), + $componentType->getName() + ); } /** @@ -66,7 +70,7 @@ public function providesNameOfTheComponent(): void */ public function isEquivalentToItself(): void { - $componentDeclarationNode = ComponentDeclarationNode::fromString( + $componentDeclarationNode = ASTNodeFixtures::ComponentDeclaration( 'component SomeComponent { return "" }' ); $componentType = ComponentType::fromComponentDeclarationNode( diff --git a/test/Unit/TypeSystem/Type/EnumType/EnumStaticTypeTest.php b/test/Unit/TypeSystem/Type/EnumType/EnumStaticTypeTest.php index 6b630e01..4357b382 100644 --- a/test/Unit/TypeSystem/Type/EnumType/EnumStaticTypeTest.php +++ b/test/Unit/TypeSystem/Type/EnumType/EnumStaticTypeTest.php @@ -22,8 +22,10 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\EnumType; +use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Module\ModuleId; -use PackageFactory\ComponentEngine\Parser\Ast\EnumDeclarationNode; +use PackageFactory\ComponentEngine\Test\Unit\Language\ASTNodeFixtures; use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumInstanceType; use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType; use PHPUnit\Framework\TestCase; @@ -36,7 +38,7 @@ final class EnumStaticTypeTest extends TestCase */ public function canBeCreatedFromEnumDeclarationNode(): void { - $enumDeclarationNode = EnumDeclarationNode::fromString( + $enumDeclarationNode = ASTNodeFixtures::EnumDeclaration( 'enum Foo { BAR BAZ }' ); $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( @@ -53,7 +55,7 @@ public function canBeCreatedFromEnumDeclarationNode(): void */ public function providesNameOfTheEnum(): void { - $enumDeclarationNode = EnumDeclarationNode::fromString( + $enumDeclarationNode = ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum {}' ); $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( @@ -61,7 +63,10 @@ public function providesNameOfTheEnum(): void $enumDeclarationNode ); - $this->assertEquals('SomeEnum', $enumStaticType->enumName); + $this->assertEquals( + TypeName::from('SomeEnum'), + $enumStaticType->getName() + ); } /** @@ -71,7 +76,7 @@ public function providesMemberNames(): void { $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( ModuleId::fromString("module-a"), - EnumDeclarationNode::fromString( + ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A B C }' ) ); @@ -86,16 +91,16 @@ public function providesMemberType(): void { $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( ModuleId::fromString("module-a"), - EnumDeclarationNode::fromString( + ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A B C }' ) ); - $enumMemberType = $enumStaticType->getMemberType('A'); + $enumMemberType = $enumStaticType->getMemberType(EnumMemberName::from('A')); $this->assertInstanceOf(EnumInstanceType::class, $enumMemberType); - $this->assertSame($enumStaticType, $enumMemberType->enumStaticType); - $this->assertSame('A', $enumMemberType->getMemberName()); + $this->assertEquals($enumStaticType, $enumMemberType->enumStaticType); + $this->assertEquals(EnumMemberName::from('A'), $enumMemberType->getMemberName()); } /** @@ -107,12 +112,12 @@ public function canOnlyAccessValidMemberType(): void $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( ModuleId::fromString("module-a"), - EnumDeclarationNode::fromString( + ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A B C }' ) ); - $enumStaticType->getMemberType('NonExistent'); + $enumStaticType->getMemberType(EnumMemberName::from('NonExistent')); } /** @@ -121,7 +126,7 @@ public function canOnlyAccessValidMemberType(): void */ public function canBeTransformedIntoInstanceType(): void { - $enumDeclarationNode = EnumDeclarationNode::fromString( + $enumDeclarationNode = ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A }' ); $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( @@ -144,7 +149,7 @@ public function canBeTransformedIntoInstanceType(): void */ public function isEquivalentToItself(): void { - $enumDeclarationNode = EnumDeclarationNode::fromString( + $enumDeclarationNode = ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A }' ); $enumStaticType = EnumStaticType::fromModuleIdAndDeclaration( @@ -161,14 +166,14 @@ public function isEquivalentToItself(): void */ public function canBeComparedToOther(): void { - $enumDeclarationNode1 = EnumDeclarationNode::fromString( + $enumDeclarationNode1 = ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A }' ); $enumStaticType1 = EnumStaticType::fromModuleIdAndDeclaration( ModuleId::fromString("module-a"), $enumDeclarationNode1 ); - $enumDeclarationNode2 = EnumDeclarationNode::fromString( + $enumDeclarationNode2 = ASTNodeFixtures::EnumDeclaration( 'enum SomeEnum { A }' ); $enumStaticType2 = EnumStaticType::fromModuleIdAndDeclaration( diff --git a/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php b/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php index 2c67e3cd..6df23bb5 100644 --- a/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php +++ b/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php @@ -22,12 +22,22 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\IntegerType; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\TypeSystem\Type\IntegerType\IntegerType; use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; use PHPUnit\Framework\TestCase; final class IntegerTypeTest extends TestCase { + /** + * @test + * @return void + */ + public function providesItsTypeName(): void + { + $this->assertEquals(TypeName::from('number'), IntegerType::get()->getName()); + } + /** * @test */ diff --git a/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php b/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php index b5b82d8c..f011c952 100644 --- a/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php +++ b/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php @@ -22,12 +22,22 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\NullType; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\TypeSystem\Type\NullType\NullType; use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; use PHPUnit\Framework\TestCase; final class NullTypeTest extends TestCase { + /** + * @test + * @return void + */ + public function providesItsTypeName(): void + { + $this->assertEquals(TypeName::from('null'), NullType::get()->getName()); + } + /** * @test */ diff --git a/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php b/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php index d2c7e5c7..9d3d1d13 100644 --- a/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php +++ b/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php @@ -22,12 +22,22 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\SlotType; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\TypeSystem\Type\IntegerType\IntegerType; use PackageFactory\ComponentEngine\TypeSystem\Type\SlotType\SlotType; use PHPUnit\Framework\TestCase; final class SlotTypeTest extends TestCase { + /** + * @test + * @return void + */ + public function providesItsTypeName(): void + { + $this->assertEquals(TypeName::from('slot'), SlotType::get()->getName()); + } + /** * @test */ diff --git a/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php b/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php index 44c6e812..21a1b5a6 100644 --- a/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php +++ b/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php @@ -22,12 +22,22 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\StringType; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\TypeSystem\Type\IntegerType\IntegerType; use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; use PHPUnit\Framework\TestCase; final class StringTypeTest extends TestCase { + /** + * @test + * @return void + */ + public function providesItsTypeName(): void + { + $this->assertEquals(TypeName::from('string'), StringType::get()->getName()); + } + /** * @test */ diff --git a/test/Unit/TypeSystem/Type/StructType/StructTypeTest.php b/test/Unit/TypeSystem/Type/StructType/StructTypeTest.php index 23313e95..99c85267 100644 --- a/test/Unit/TypeSystem/Type/StructType/StructTypeTest.php +++ b/test/Unit/TypeSystem/Type/StructType/StructTypeTest.php @@ -22,8 +22,15 @@ namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Type\StructType; -use PackageFactory\ComponentEngine\Parser\Ast\StructDeclarationNode; +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PackageFactory\ComponentEngine\Domain\StructName\StructName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; +use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; +use PackageFactory\ComponentEngine\TypeSystem\Type\StructType\Properties; +use PackageFactory\ComponentEngine\TypeSystem\Type\StructType\Property; use PackageFactory\ComponentEngine\TypeSystem\Type\StructType\StructType; +use PackageFactory\ComponentEngine\TypeSystem\TypeReference; use PHPUnit\Framework\TestCase; final class StructTypeTest extends TestCase @@ -32,45 +39,56 @@ final class StructTypeTest extends TestCase * @test * @return void */ - public function canBeCreatedFromStructDeclarationNode(): void + public function providesNameOfTheStruct(): void { - $structDeclarationNode = StructDeclarationNode::fromString( - 'struct Foo { a : string b : number }' + $structType = new StructType( + name: StructName::from('SomeStruct'), + properties: new Properties() ); - $structType = StructType::fromStructDeclarationNode($structDeclarationNode); - $this->assertInstanceOf(StructType::class, $structType); + $this->assertEquals( + TypeName::from('SomeStruct'), + $structType->getName() + ); } /** * @test * @return void */ - public function providesNameOfTheStruct(): void + public function isEquivalentToItself(): void { - $structDeclarationNode = StructDeclarationNode::fromString( - 'struct SomeStruct {}' - ); - $structStaticType = StructType::fromStructDeclarationNode( - $structDeclarationNode + $structType = new StructType( + name: StructName::from('SomeStruct'), + properties: new Properties() ); - $this->assertEquals('SomeStruct', $structStaticType->structName); + $this->assertTrue($structType->is($structType)); } /** * @test * @return void */ - public function isEquivalentToItself(): void + public function providesTypeOfProperty(): void { - $structDeclarationNode = StructDeclarationNode::fromString( - 'struct SomeStruct {}' - ); - $structStaticType = StructType::fromStructDeclarationNode( - $structDeclarationNode + $structType = new StructType( + name: StructName::from('SomeStruct'), + properties: new Properties( + new Property( + name: PropertyName::from('foo'), + type: $typeOfFoo = new TypeReference( + names: new TypeNames(TypeName::from('string')), + isOptional: false, + isArray: false + ) + ) + ) ); - $this->assertTrue($structStaticType->is($structStaticType)); + $this->assertEquals( + $typeOfFoo, + $structType->getTypeOfProperty(PropertyName::from('foo')) + ); } } diff --git a/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php b/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php index 3604ae66..edbdec17 100644 --- a/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php +++ b/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php @@ -42,14 +42,6 @@ public function staticOfResolvesToGivenTypeIfOnlyOneTypeIsGiven(): void $unionType = UnionType::of(IntegerType::get()); $this->assertTrue($unionType->is(IntegerType::get())); $this->assertTrue(IntegerType::get()->is($unionType)); - - $unionType = UnionType::of(UnionType::of(StringType::get())); - $this->assertTrue($unionType->is(StringType::get())); - $this->assertTrue(StringType::get()->is($unionType)); - - $unionType = UnionType::of(UnionType::of(IntegerType::get())); - $this->assertTrue($unionType->is(IntegerType::get())); - $this->assertTrue(IntegerType::get()->is($unionType)); } /** @@ -57,11 +49,7 @@ public function staticOfResolvesToGivenTypeIfOnlyOneTypeIsGiven(): void */ public function staticOfResolvesToGivenTypeIfAllGivenTypesAreIdentical(): void { - $unionType = UnionType::of(StringType::get(), StringType::get()); - $this->assertTrue($unionType->is(StringType::get())); - $this->assertTrue(StringType::get()->is($unionType)); - - $unionType = UnionType::of(StringType::get(), StringType::get(), UnionType::of(StringType::get(), StringType::get())); + $unionType = UnionType::of(StringType::get(), StringType::get(), StringType::get()); $this->assertTrue($unionType->is(StringType::get())); $this->assertTrue(StringType::get()->is($unionType)); } From 30e2600c3829a75d017163abede683d731d7e250 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sun, 6 Aug 2023 22:52:56 +0200 Subject: [PATCH 59/64] TASK: Remove leftover AST and Token snapshots --- test/Integration/Examples/Comment/Comment.afx | 3 - .../Examples/Comment/Comment.ast.alt.json | 1 - .../Examples/Comment/Comment.ast.json | 7 - .../Examples/Comment/Comment.tokens.json | 26 - .../Examples/Component/Component.ast.alt.json | 1 - .../Examples/Component/Component.ast.json | 80 -- .../Examples/Component/Component.tokens.json | 222 ------ .../ComponentEmpty/ComponentEmpty.tokens.json | 58 -- .../ComponentWithKeywords.ast.json | 31 - .../ComponentWithKeywords.tokens.json | 186 ----- .../ComponentWithNesting.ast.json | 138 ---- .../ComponentWithNesting.tokens.json | 394 ---------- test/Integration/Examples/Enum/Enum.ast.json | 44 -- .../Examples/Enum/Enum.tokens.json | 126 ---- .../EnumWithNumberValue.ast.json | 46 -- .../EnumWithNumberValue.tokens.json | 114 --- .../EnumWithStringValue.ast.json | 30 - .../EnumWithStringValue.tokens.json | 90 --- .../Examples/Expression/Expression.ast.json | 109 --- .../Expression/Expression.tokens.json | 218 ------ .../ImportExport/ImportExport.ast.json | 122 ---- .../ImportExport/ImportExport.tokens.json | 109 --- .../Integration/Examples/Match/Match.ast.json | 276 ------- .../Examples/Match/Match.tokens.json | 683 ------------------ .../Examples/Numbers/Numbers.ast.json | 173 ----- .../Examples/Numbers/Numbers.tokens.json | 326 --------- .../Examples/Struct/Struct.ast.json | 30 - .../Examples/Struct/Struct.tokens.json | 90 --- .../StructWithOptionals.ast.json | 37 - .../StructWithOptionals.tokens.json | 118 --- .../TemplateLiteral/TemplateLiteral.ast.json | 177 ----- .../TemplateLiteral.tokens.json | 490 ------------- 32 files changed, 4555 deletions(-) delete mode 100644 test/Integration/Examples/Comment/Comment.afx delete mode 100644 test/Integration/Examples/Comment/Comment.ast.alt.json delete mode 100644 test/Integration/Examples/Comment/Comment.ast.json delete mode 100644 test/Integration/Examples/Comment/Comment.tokens.json delete mode 100644 test/Integration/Examples/Component/Component.ast.alt.json delete mode 100644 test/Integration/Examples/Component/Component.ast.json delete mode 100644 test/Integration/Examples/Component/Component.tokens.json delete mode 100644 test/Integration/Examples/ComponentEmpty/ComponentEmpty.tokens.json delete mode 100644 test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.ast.json delete mode 100644 test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.tokens.json delete mode 100644 test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.ast.json delete mode 100644 test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.tokens.json delete mode 100644 test/Integration/Examples/Enum/Enum.ast.json delete mode 100644 test/Integration/Examples/Enum/Enum.tokens.json delete mode 100644 test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.ast.json delete mode 100644 test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.tokens.json delete mode 100644 test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.ast.json delete mode 100644 test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.tokens.json delete mode 100644 test/Integration/Examples/Expression/Expression.ast.json delete mode 100644 test/Integration/Examples/Expression/Expression.tokens.json delete mode 100644 test/Integration/Examples/ImportExport/ImportExport.ast.json delete mode 100644 test/Integration/Examples/ImportExport/ImportExport.tokens.json delete mode 100644 test/Integration/Examples/Match/Match.ast.json delete mode 100644 test/Integration/Examples/Match/Match.tokens.json delete mode 100644 test/Integration/Examples/Numbers/Numbers.ast.json delete mode 100644 test/Integration/Examples/Numbers/Numbers.tokens.json delete mode 100644 test/Integration/Examples/Struct/Struct.ast.json delete mode 100644 test/Integration/Examples/Struct/Struct.tokens.json delete mode 100644 test/Integration/Examples/StructWithOptionals/StructWithOptionals.ast.json delete mode 100644 test/Integration/Examples/StructWithOptionals/StructWithOptionals.tokens.json delete mode 100644 test/Integration/Examples/TemplateLiteral/TemplateLiteral.ast.json delete mode 100644 test/Integration/Examples/TemplateLiteral/TemplateLiteral.tokens.json diff --git a/test/Integration/Examples/Comment/Comment.afx b/test/Integration/Examples/Comment/Comment.afx deleted file mode 100644 index 6f738014..00000000 --- a/test/Integration/Examples/Comment/Comment.afx +++ /dev/null @@ -1,3 +0,0 @@ -# This is a comment. -# The only way to have comments is to prefix them with '#'. -# A comment alwas ends at an END_OF_LINE token. diff --git a/test/Integration/Examples/Comment/Comment.ast.alt.json b/test/Integration/Examples/Comment/Comment.ast.alt.json deleted file mode 100644 index 1cfb3f65..00000000 --- a/test/Integration/Examples/Comment/Comment.ast.alt.json +++ /dev/null @@ -1 +0,0 @@ -[1,[2,[],[]]] diff --git a/test/Integration/Examples/Comment/Comment.ast.json b/test/Integration/Examples/Comment/Comment.ast.json deleted file mode 100644 index 99bbf0b4..00000000 --- a/test/Integration/Examples/Comment/Comment.ast.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": {} - } -} diff --git a/test/Integration/Examples/Comment/Comment.tokens.json b/test/Integration/Examples/Comment/Comment.tokens.json deleted file mode 100644 index 4badfb1a..00000000 --- a/test/Integration/Examples/Comment/Comment.tokens.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "type": "COMMENT", - "value": "# This is a comment." - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "COMMENT", - "value": "# The only way to have comments is to prefix them with '#'." - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "COMMENT", - "value": "# A comment alwas ends at an END_OF_LINE token." - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/Component/Component.ast.alt.json b/test/Integration/Examples/Component/Component.ast.alt.json deleted file mode 100644 index 7bbbeb61..00000000 --- a/test/Integration/Examples/Component/Component.ast.alt.json +++ /dev/null @@ -1 +0,0 @@ -[1,[2,[],[[3,["Image",[["src",[4,"string",0]],["alt",[4,"string",0]],["title",[4,"string",0]]],["Tag","img",[["src",[5,"src",0]],["alt",[5,"alt",0]],["title",[5,"title",0]]],[]]]]]]] diff --git a/test/Integration/Examples/Component/Component.ast.json b/test/Integration/Examples/Component/Component.ast.json deleted file mode 100644 index 3998cab8..00000000 --- a/test/Integration/Examples/Component/Component.ast.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "Image", - "propertyDeclarations": [ - { - "name": "src", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "alt", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "title", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - } - ], - "returnExpression": { - "type": "TagNode", - "payload": { - "tagName": "img", - "attributes": [ - { - "name": "src", - "value": { - "type": "Identifier", - "payload": "src" - } - }, - { - "name": "alt", - "value": { - "type": "Identifier", - "payload": "alt" - } - }, - { - "name": "title", - "value": { - "type": "Identifier", - "payload": "title" - } - } - ], - "children": [], - "isSelfClosing": true - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/Component/Component.tokens.json b/test/Integration/Examples/Component/Component.tokens.json deleted file mode 100644 index 5f6e33ab..00000000 --- a/test/Integration/Examples/Component/Component.tokens.json +++ /dev/null @@ -1,222 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Image" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "img" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_SELF_CLOSE", - "value": "/>" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] \ No newline at end of file diff --git a/test/Integration/Examples/ComponentEmpty/ComponentEmpty.tokens.json b/test/Integration/Examples/ComponentEmpty/ComponentEmpty.tokens.json deleted file mode 100644 index 977cc0a3..00000000 --- a/test/Integration/Examples/ComponentEmpty/ComponentEmpty.tokens.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Empty" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING_QUOTED", - "value": "" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.ast.json b/test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.ast.json deleted file mode 100644 index 42e92b84..00000000 --- a/test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.ast.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "ComponentWithKeywords", - "propertyDeclarations": [], - "returnExpression": { - "type": "TagNode", - "payload": { - "tagName": "div", - "attributes": [], - "children": [ - { - "type": "TextNode", - "payload": { - "value": "Keywords like import or export or component are allowed in here." - } - } - ], - "isSelfClosing": false - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.tokens.json b/test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.tokens.json deleted file mode 100644 index d94f0049..00000000 --- a/test/Integration/Examples/ComponentWithKeywords/ComponentWithKeywords.tokens.json +++ /dev/null @@ -1,186 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ComponentWithKeywords" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "div" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Keywords" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "like" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "import" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "or" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "or" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "component" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "are" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "allowed" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "in" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "here." - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.ast.json b/test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.ast.json deleted file mode 100644 index 5b27badd..00000000 --- a/test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.ast.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "TextWithImage", - "propertyDeclarations": [ - { - "name": "src", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "alt", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "title", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "text", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - } - ], - "returnExpression": { - "type": "TagNode", - "payload": { - "tagName": "div", - "attributes": [ - { - "name": "class", - "value": { - "type": "StringLiteralNode", - "payload": "text-with-image" - } - } - ], - "children": [ - { - "type": "TagNode", - "payload": { - "tagName": "img", - "attributes": [ - { - "name": "class", - "value": { - "type": "StringLiteralNode", - "payload": "image" - } - }, - { - "name": "src", - "value": { - "type": "Identifier", - "payload": "src" - } - }, - { - "name": "alt", - "value": { - "type": "Identifier", - "payload": "alt" - } - }, - { - "name": "title", - "value": { - "type": "Identifier", - "payload": "title" - } - } - ], - "children": [], - "isSelfClosing": true - } - }, - { - "type": "TagNode", - "payload": { - "tagName": "p", - "attributes": [ - { - "name": "class", - "value": { - "type": "StringLiteralNode", - "payload": "text" - } - } - ], - "children": [ - { - "type": "Identifier", - "payload": "text" - } - ], - "isSelfClosing": false - } - } - ], - "isSelfClosing": false - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.tokens.json b/test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.tokens.json deleted file mode 100644 index ce21e02f..00000000 --- a/test/Integration/Examples/ComponentWithNesting/ComponentWithNesting.tokens.json +++ /dev/null @@ -1,394 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "TextWithImage" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "text" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "div" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "class" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "text-with-image" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "img" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "class" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "image" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_SELF_CLOSE", - "value": "/>" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "p" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "class" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "text" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "text" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/Enum/Enum.ast.json b/test/Integration/Examples/Enum/Enum.ast.json deleted file mode 100644 index e41fea27..00000000 --- a/test/Integration/Examples/Enum/Enum.ast.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "EnumDeclarationNode", - "payload": { - "enumName": "DayOfWeek", - "memberDeclarations": { - "MONDAY": { - "name": "MONDAY", - "value": null - }, - "TUESDAY": { - "name": "TUESDAY", - "value": null - }, - "WEDNESDAY": { - "name": "WEDNESDAY", - "value": null - }, - "THURSDAY": { - "name": "THURSDAY", - "value": null - }, - "FRIDAY": { - "name": "FRIDAY", - "value": null - }, - "SATURDAY": { - "name": "SATURDAY", - "value": null - }, - "SUNDAY": { - "name": "SUNDAY", - "value": null - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/Enum/Enum.tokens.json b/test/Integration/Examples/Enum/Enum.tokens.json deleted file mode 100644 index c08c9f24..00000000 --- a/test/Integration/Examples/Enum/Enum.tokens.json +++ /dev/null @@ -1,126 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_ENUM", - "value": "enum" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "DayOfWeek" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "MONDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "TUESDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "WEDNESDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "THURSDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "FRIDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "SATURDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "SUNDAY" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.ast.json b/test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.ast.json deleted file mode 100644 index 8633cd3d..00000000 --- a/test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.ast.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "EnumDeclarationNode", - "payload": { - "enumName": "TrafficLight", - "memberDeclarations": { - "RED": { - "name": "RED", - "value": { - "type": "IntegerLiteralNode", - "payload": { - "value": "1", - "format": "DECIMAL" - } - } - }, - "YELLOW": { - "name": "YELLOW", - "value": { - "type": "IntegerLiteralNode", - "payload": { - "value": "2", - "format": "DECIMAL" - } - } - }, - "GREEN": { - "name": "GREEN", - "value": { - "type": "IntegerLiteralNode", - "payload": { - "value": "3", - "format": "DECIMAL" - } - } - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.tokens.json b/test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.tokens.json deleted file mode 100644 index 808397a6..00000000 --- a/test/Integration/Examples/EnumWithNumberValue/EnumWithNumberValue.tokens.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_ENUM", - "value": "enum" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "TrafficLight" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "RED" - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "NUMBER_DECIMAL", - "value": "1" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "YELLOW" - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "NUMBER_DECIMAL", - "value": "2" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "GREEN" - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "NUMBER_DECIMAL", - "value": "3" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.ast.json b/test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.ast.json deleted file mode 100644 index 70fcfabd..00000000 --- a/test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.ast.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "EnumDeclarationNode", - "payload": { - "enumName": "ImageLoadingMethod", - "memberDeclarations": { - "EAGER": { - "name": "EAGER", - "value": { - "type": "StringLiteralNode", - "payload": "eager" - } - }, - "LAZY": { - "name": "LAZY", - "value": { - "type": "StringLiteralNode", - "payload": "lazy" - } - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.tokens.json b/test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.tokens.json deleted file mode 100644 index c5462f1f..00000000 --- a/test/Integration/Examples/EnumWithStringValue/EnumWithStringValue.tokens.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_ENUM", - "value": "enum" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ImageLoadingMethod" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "EAGER" - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "STRING_QUOTED", - "value": "eager" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "LAZY" - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "STRING_QUOTED", - "value": "lazy" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/Expression/Expression.ast.json b/test/Integration/Examples/Expression/Expression.ast.json deleted file mode 100644 index a2055f1d..00000000 --- a/test/Integration/Examples/Expression/Expression.ast.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "Expression", - "propertyDeclarations": [ - { - "name": "a", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "number", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "b", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "number", - "isArray": false, - "isOptional": false - } - } - } - ], - "returnExpression": { - "type": "TernaryOperationNode", - "payload": { - "condition": { - "type": "BinaryOperationNode", - "payload": { - "operator": "LESS_THAN_OR_EQUAL", - "operands": [ - { - "type": "Identifier", - "payload": "a" - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "120", - "format": "DECIMAL" - } - } - ] - } - }, - "true": { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "Identifier", - "payload": "b" - }, - { - "type": "Identifier", - "payload": "a" - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "17", - "format": "DECIMAL" - } - } - ] - } - }, - "false": { - "type": "BinaryOperationNode", - "payload": { - "operator": "AND", - "operands": [ - { - "type": "Identifier", - "payload": "b" - }, - { - "type": "Identifier", - "payload": "a" - } - ] - } - } - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/Expression/Expression.tokens.json b/test/Integration/Examples/Expression/Expression.tokens.json deleted file mode 100644 index 0ff447a1..00000000 --- a/test/Integration/Examples/Expression/Expression.tokens.json +++ /dev/null @@ -1,218 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Expression" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "a" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "number" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "b" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "number" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "a" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COMPARATOR_LESS_THAN_OR_EQUAL", - "value": "<=" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "120" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "QUESTIONMARK", - "value": "?" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "b" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "a" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "17" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "b" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_AND", - "value": "&&" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "a" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/ImportExport/ImportExport.ast.json b/test/Integration/Examples/ImportExport/ImportExport.ast.json deleted file mode 100644 index 26289c46..00000000 --- a/test/Integration/Examples/ImportExport/ImportExport.ast.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": [ - { - "path": "../Struct/Struct.afx", - "name": { - "type": "Identifier", - "payload": "Link" - } - }, - { - "path": "./Button.afx", - "name": { - "type": "Identifier", - "payload": "Button" - } - } - ], - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "Card", - "propertyDeclarations": [ - { - "name": "title", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "link", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "Link", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "button", - "type": { - "type": "TypeReferenceNode", - "payload": { "name": "Button", "isArray": false, "isOptional": false } - } - } - ], - "returnExpression": { - "type": "TagNode", - "payload": { - "tagName": "div", - "attributes": [ - { - "name": "class", - "value": { "type": "StringLiteralNode", "payload": "card" } - } - ], - "children": [ - { - "type": "TagNode", - "payload": { - "tagName": "a", - "attributes": [ - { - "name": "href", - "value": { - "type": "AccessNode", - "payload": { - "root": { "type": "Identifier", "payload": "link" }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "href" - } - } - ] - } - } - }, - { - "name": "target", - "value": { - "type": "AccessNode", - "payload": { - "root": { "type": "Identifier", "payload": "link" }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "target" - } - } - ] - } - } - } - ], - "children": [{ "type": "Identifier", "payload": "title" }], - "isSelfClosing": false - } - }, - { "type": "Identifier", "payload": "button" } - ], - "isSelfClosing": false - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/ImportExport/ImportExport.tokens.json b/test/Integration/Examples/ImportExport/ImportExport.tokens.json deleted file mode 100644 index 303dd861..00000000 --- a/test/Integration/Examples/ImportExport/ImportExport.tokens.json +++ /dev/null @@ -1,109 +0,0 @@ -[ - { "type": "KEYWORD_FROM", "value": "from" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING_QUOTED", "value": "../Struct/Struct.afx" }, - { "type": "SPACE", "value": " " }, - { "type": "KEYWORD_IMPORT", "value": "import" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "Link" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "KEYWORD_FROM", "value": "from" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING_QUOTED", "value": "./Button.afx" }, - { "type": "SPACE", "value": " " }, - { "type": "KEYWORD_IMPORT", "value": "import" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "Button" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "KEYWORD_EXPORT", "value": "export" }, - { "type": "SPACE", "value": " " }, - { "type": "KEYWORD_COMPONENT", "value": "component" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "Card" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "title" }, - { "type": "COLON", "value": ":" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "string" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "link" }, - { "type": "COLON", "value": ":" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "Link" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "button" }, - { "type": "COLON", "value": ":" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "Button" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "KEYWORD_RETURN", "value": "return" }, - { "type": "SPACE", "value": " " }, - { "type": "TAG_START_OPENING", "value": "<" }, - { "type": "STRING", "value": "div" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "class" }, - { "type": "EQUALS", "value": "=" }, - { "type": "STRING_QUOTED", "value": "card" }, - { "type": "TAG_END", "value": ">" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "TAG_START_OPENING", "value": "<" }, - { "type": "STRING", "value": "a" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "href" }, - { "type": "EQUALS", "value": "=" }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "STRING", "value": "link" }, - { "type": "PERIOD", "value": "." }, - { "type": "STRING", "value": "href" }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "target" }, - { "type": "EQUALS", "value": "=" }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "STRING", "value": "link" }, - { "type": "PERIOD", "value": "." }, - { "type": "STRING", "value": "target" }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "TAG_END", "value": ">" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "STRING", "value": "title" }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "TAG_START_CLOSING", "value": "" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "STRING", "value": "button" }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "SPACE", "value": " " }, - { "type": "TAG_START_CLOSING", "value": "" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "END_OF_LINE", "value": "\n" } -] diff --git a/test/Integration/Examples/Match/Match.ast.json b/test/Integration/Examples/Match/Match.ast.json deleted file mode 100644 index bd3a1cb2..00000000 --- a/test/Integration/Examples/Match/Match.ast.json +++ /dev/null @@ -1,276 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": [ - { - "path": "./ButtonType.afx", - "name": { - "type": "Identifier", - "payload": "ButtonType" - } - } - ], - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "Button", - "propertyDeclarations": [ - { - "name": "type", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "ButtonType", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "content", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "slot", - "isArray": false, - "isOptional": false - } - } - } - ], - "returnExpression": { - "type": "MatchNode", - "payload": { - "subject": { - "type": "Identifier", - "payload": "type" - }, - "arms": [ - { - "type": "MatchArmNode", - "payload": { - "left": [ - { - "type": "AccessNode", - "payload": { - "root": { - "type": "Identifier", - "payload": "ButtonType" - }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "LINK" - } - } - ] - } - } - ], - "right": { - "type": "TagNode", - "payload": { - "tagName": "a", - "attributes": [ - { - "name": "class", - "value": { - "type": "StringLiteralNode", - "payload": "btn" - } - }, - { - "name": "href", - "value": { - "type": "StringLiteralNode", - "payload": "#" - } - } - ], - "children": [ - { - "type": "Identifier", - "payload": "content" - } - ], - "isSelfClosing": false - } - } - } - }, - { - "type": "MatchArmNode", - "payload": { - "left": [ - { - "type": "AccessNode", - "payload": { - "root": { - "type": "Identifier", - "payload": "ButtonType" - }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "BUTTON" - } - } - ] - } - }, - { - "type": "AccessNode", - "payload": { - "root": { - "type": "Identifier", - "payload": "ButtonType" - }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "SUBMIT" - } - } - ] - } - } - ], - "right": { - "type": "TagNode", - "payload": { - "tagName": "button", - "attributes": [ - { - "name": "class", - "value": { - "type": "StringLiteralNode", - "payload": "btn" - } - }, - { - "name": "type", - "value": { - "type": "MatchNode", - "payload": { - "subject": { - "type": "Identifier", - "payload": "type" - }, - "arms": [ - { - "type": "MatchArmNode", - "payload": { - "left": [ - { - "type": "AccessNode", - "payload": { - "root": { - "type": "Identifier", - "payload": "ButtonType" - }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "SUBMIT" - } - } - ] - } - } - ], - "right": { - "type": "StringLiteralNode", - "payload": "submit" - } - } - }, - { - "type": "MatchArmNode", - "payload": { - "left": null, - "right": { - "type": "StringLiteralNode", - "payload": "button" - } - } - } - ] - } - } - } - ], - "children": [ - { - "type": "Identifier", - "payload": "content" - } - ], - "isSelfClosing": false - } - } - } - }, - { - "type": "MatchArmNode", - "payload": { - "left": [ - { - "type": "AccessNode", - "payload": { - "root": { - "type": "Identifier", - "payload": "ButtonType" - }, - "chain": [ - { - "accessType": "MANDATORY", - "accessor": { - "type": "Identifier", - "payload": "NONE" - } - } - ] - } - } - ], - "right": { - "type": "TagNode", - "payload": { - "tagName": "div", - "attributes": [ - { - "name": "class", - "value": { - "type": "StringLiteralNode", - "payload": "btn" - } - } - ], - "children": [ - { - "type": "Identifier", - "payload": "content" - } - ], - "isSelfClosing": false - } - } - } - } - ] - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/Match/Match.tokens.json b/test/Integration/Examples/Match/Match.tokens.json deleted file mode 100644 index 49d15d46..00000000 --- a/test/Integration/Examples/Match/Match.tokens.json +++ /dev/null @@ -1,683 +0,0 @@ -[ - { "type": "KEYWORD_FROM", "value": "from" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING_QUOTED", "value": "./ButtonType.afx" }, - { "type": "SPACE", "value": " " }, - { "type": "KEYWORD_IMPORT", "value": "import" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_OPEN", "value": "{" }, - { "type": "SPACE", "value": " " }, - { "type": "STRING", "value": "ButtonType" }, - { "type": "SPACE", "value": " " }, - { "type": "BRACKET_CURLY_CLOSE", "value": "}" }, - { "type": "END_OF_LINE", "value": "\n" }, - { "type": "END_OF_LINE", "value": "\n" }, - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Button" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "type" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ButtonType" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "content" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "slot" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_MATCH", - "value": "match" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "STRING", - "value": "type" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ButtonType" - }, - { - "type": "PERIOD", - "value": "." - }, - { - "type": "STRING", - "value": "LINK" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "ARROW_SINGLE", - "value": "->" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "a" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "class" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "btn" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "href" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "#" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "content" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ButtonType" - }, - { - "type": "PERIOD", - "value": "." - }, - { - "type": "STRING", - "value": "BUTTON" - }, - { - "type": "COMMA", - "value": "," - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ButtonType" - }, - { - "type": "PERIOD", - "value": "." - }, - { - "type": "STRING", - "value": "SUBMIT" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "ARROW_SINGLE", - "value": "->" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "button" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "class" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "btn" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "type" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "KEYWORD_MATCH", - "value": "match" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "STRING", - "value": "type" - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ButtonType" - }, - { - "type": "PERIOD", - "value": "." - }, - { - "type": "STRING", - "value": "SUBMIT" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "ARROW_SINGLE", - "value": "->" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING_QUOTED", - "value": "submit" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_DEFAULT", - "value": "default" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "ARROW_SINGLE", - "value": "->" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING_QUOTED", - "value": "button" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "content" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "ButtonType" - }, - { - "type": "PERIOD", - "value": "." - }, - { - "type": "STRING", - "value": "NONE" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "ARROW_SINGLE", - "value": "->" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_OPEN", - "value": "(" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "div" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "class" - }, - { - "type": "EQUALS", - "value": "=" - }, - { - "type": "STRING_QUOTED", - "value": "btn" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "content" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_ROUND_CLOSE", - "value": ")" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/Numbers/Numbers.ast.json b/test/Integration/Examples/Numbers/Numbers.ast.json deleted file mode 100644 index 6ba7112c..00000000 --- a/test/Integration/Examples/Numbers/Numbers.ast.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": [], - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "Numbers", - "propertyDeclarations": [], - "returnExpression": { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "BinaryOperationNode", - "payload": { - "operator": "OR", - "operands": [ - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0", - "format": "DECIMAL" - } - }, - - { - "type": "IntegerLiteralNode", - "payload": { - "value": "1234567890", - "format": "DECIMAL" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "42", - "format": "DECIMAL" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0b10000000000000000000000000000000", - "format": "BINARY" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0b01111111100000000000000000000000", - "format": "BINARY" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0B00000000011111111111111111111111", - "format": "BINARY" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0o755", - "format": "OCTAL" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0o644", - "format": "OCTAL" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0xFFFFFFFFFFFFFFFFF", - "format": "HEXADECIMAL" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0x123456789ABCDEF", - "format": "HEXADECIMAL" - } - } - ] - } - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "0xA", - "format": "HEXADECIMAL" - } - } - ] - } - } - } - } - ] - } -} diff --git a/test/Integration/Examples/Numbers/Numbers.tokens.json b/test/Integration/Examples/Numbers/Numbers.tokens.json deleted file mode 100644 index c36ec52e..00000000 --- a/test/Integration/Examples/Numbers/Numbers.tokens.json +++ /dev/null @@ -1,326 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Numbers" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COMMENT", - "value": "# Decimal" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "0" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "1234567890" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "42" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COMMENT", - "value": "# Binary" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_BINARY", - "value": "0b10000000000000000000000000000000" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_BINARY", - "value": "0b01111111100000000000000000000000" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_BINARY", - "value": "0B00000000011111111111111111111111" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COMMENT", - "value": "# Octal" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_OCTAL", - "value": "0o755" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_OCTAL", - "value": "0o644" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COMMENT", - "value": "# Hexadecimal" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_HEXADECIMAL", - "value": "0xFFFFFFFFFFFFFFFFF" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_HEXADECIMAL", - "value": "0x123456789ABCDEF" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "OPERATOR_BOOLEAN_OR", - "value": "||" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_HEXADECIMAL", - "value": "0xA" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/Struct/Struct.ast.json b/test/Integration/Examples/Struct/Struct.ast.json deleted file mode 100644 index dfe87bdc..00000000 --- a/test/Integration/Examples/Struct/Struct.ast.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "Struct", - "payload": { - "structName": "Link", - "propertyDeclarations": [ - { - "name": "href", - "type": { - "type": "TypeReferenceNode", - "payload": { "name": "string", "isArray": false, "isOptional": false } - } - }, - { - "name": "target", - "type": { - "type": "TypeReferenceNode", - "payload": { "name": "string", "isArray": false, "isOptional": false } - } - } - ] - } - } - ] - } -} diff --git a/test/Integration/Examples/Struct/Struct.tokens.json b/test/Integration/Examples/Struct/Struct.tokens.json deleted file mode 100644 index 8fabd0f5..00000000 --- a/test/Integration/Examples/Struct/Struct.tokens.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_STRUCT", - "value": "struct" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Link" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "href" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "target" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/StructWithOptionals/StructWithOptionals.ast.json b/test/Integration/Examples/StructWithOptionals/StructWithOptionals.ast.json deleted file mode 100644 index bee5e1c2..00000000 --- a/test/Integration/Examples/StructWithOptionals/StructWithOptionals.ast.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "Struct", - "payload": { - "structName": "Image", - "propertyDeclarations": [ - { - "name": "src", - "type": { - "type": "TypeReferenceNode", - "payload": { "name": "string", "isArray": false, "isOptional": false } - } - }, - { - "name": "alt", - "type": { - "type": "TypeReferenceNode", - "payload": { "name": "string", "isArray": false, "isOptional": false } - } - }, - { - "name": "title", - "type": { - "type": "TypeReferenceNode", - "payload": { "name": "string", "isArray": false, "isOptional": true } - } - } - ] - } - } - ] - } -} diff --git a/test/Integration/Examples/StructWithOptionals/StructWithOptionals.tokens.json b/test/Integration/Examples/StructWithOptionals/StructWithOptionals.tokens.json deleted file mode 100644 index 33d7292d..00000000 --- a/test/Integration/Examples/StructWithOptionals/StructWithOptionals.tokens.json +++ /dev/null @@ -1,118 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_STRUCT", - "value": "struct" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "Image" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "src" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "alt" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "title" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "QUESTIONMARK", - "value": "?" - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] diff --git a/test/Integration/Examples/TemplateLiteral/TemplateLiteral.ast.json b/test/Integration/Examples/TemplateLiteral/TemplateLiteral.ast.json deleted file mode 100644 index b477685b..00000000 --- a/test/Integration/Examples/TemplateLiteral/TemplateLiteral.ast.json +++ /dev/null @@ -1,177 +0,0 @@ -{ - "type": "ModuleNode", - "payload": { - "imports": {}, - "exports": [ - { - "type": "ComponentDeclarationNode", - "payload": { - "componentName": "TemplateLiteral", - "propertyDeclarations": [ - { - "name": "expression", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "string", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "isActive", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "boolean", - "isArray": false, - "isOptional": false - } - } - }, - { - "name": "someNumber", - "type": { - "type": "TypeReferenceNode", - "payload": { - "name": "number", - "isArray": false, - "isOptional": false - } - } - } - ], - "returnExpression": { - "type": "TemplateLiteralNode", - "payload": [ - { - "type": "StringLiteralNode", - "payload": "A template literal may contain " - }, - { - "type": "Identifier", - "payload": "expression" - }, - { - "type": "StringLiteralNode", - "payload": "s.\n\n It can span multiple lines.\n\n Interpolated Expressions can be arbitrarily complex:\n " - }, - { - "type": "TernaryOperationNode", - "payload": { - "condition": { - "type": "Identifier", - "payload": "isActive" - }, - "true": { - "type": "IntegerLiteralNode", - "payload": { "value": "27", "format": "DECIMAL" } - }, - "false": { - "type": "IntegerLiteralNode", - "payload": { "value": "17", "format": "DECIMAL" } - } - } - }, - { - "type": "StringLiteralNode", - "payload": "\n\n They can also contain other template literals:\n " - }, - { - "type": "TernaryOperationNode", - "payload": { - "condition": { - "type": "Identifier", - "payload": "isActive" - }, - "true": { - "type": "TemplateLiteralNode", - "payload": [ - { "type": "StringLiteralNode", "payload": "Is 27? " }, - { - "type": "TernaryOperationNode", - "payload": { - "condition": { - "type": "BinaryOperationNode", - "payload": { - "operator": "EQUAL", - "operands": [ - { - "type": "Identifier", - "payload": "someNumber" - }, - { - "type": "IntegerLiteralNode", - "payload": { - "value": "27", - "format": "DECIMAL" - } - } - ] - } - }, - "true": { - "type": "StringLiteralNode", - "payload": "yes" - }, - "false": { - "type": "StringLiteralNode", - "payload": "no" - } - } - } - ] - }, - "false": { - "type": "TemplateLiteralNode", - "payload": [ - { "type": "StringLiteralNode", "payload": "Number is " }, - { - "type": "IntegerLiteralNode", - "payload": { "value": "27", "format": "DECIMAL" } - } - ] - } - } - }, - { - "type": "StringLiteralNode", - "payload": "\n\n Even markup:\n " - }, - { - "type": "TagNode", - "payload": { - "tagName": "header", - "attributes": [], - "children": [ - { - "type": "TagNode", - "payload": { - "tagName": "h1", - "attributes": [], - "children": [ - { - "type": "TextNode", - "payload": { "value": "Number is " } - }, - { - "type": "Identifier", - "payload": "someNumber" - } - ], - "isSelfClosing": false - } - } - ], - "isSelfClosing": false - } - }, - { "type": "StringLiteralNode", "payload": "\n " } - ] - } - } - } - ] - } -} diff --git a/test/Integration/Examples/TemplateLiteral/TemplateLiteral.tokens.json b/test/Integration/Examples/TemplateLiteral/TemplateLiteral.tokens.json deleted file mode 100644 index a2d2c635..00000000 --- a/test/Integration/Examples/TemplateLiteral/TemplateLiteral.tokens.json +++ /dev/null @@ -1,490 +0,0 @@ -[ - { - "type": "KEYWORD_EXPORT", - "value": "export" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_COMPONENT", - "value": "component" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "TemplateLiteral" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "expression" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "string" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "isActive" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "boolean" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "someNumber" - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "number" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "KEYWORD_RETURN", - "value": "return" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TEMPLATE_LITERAL_START", - "value": "`" - }, - { - "type": "STRING_QUOTED", - "value": "A template literal may contain " - }, - { - "type": "DOLLAR", - "value": "$" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "expression" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "STRING_QUOTED", - "value": "s.\n\n It can span multiple lines.\n\n Interpolated Expressions can be arbitrarily complex:\n " - }, - { - "type": "DOLLAR", - "value": "$" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "isActive" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "QUESTIONMARK", - "value": "?" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "27" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "17" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "STRING_QUOTED", - "value": "\n\n They can also contain other template literals:\n " - }, - { - "type": "DOLLAR", - "value": "$" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "isActive" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "QUESTIONMARK", - "value": "?" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TEMPLATE_LITERAL_START", - "value": "`" - }, - { - "type": "STRING_QUOTED", - "value": "Is 27? " - }, - { - "type": "DOLLAR", - "value": "$" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "someNumber" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COMPARATOR_EQUAL", - "value": "===" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "NUMBER_DECIMAL", - "value": "27" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "QUESTIONMARK", - "value": "?" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING_QUOTED", - "value": "yes" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING_QUOTED", - "value": "no" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "TEMPLATE_LITERAL_END", - "value": "`" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "COLON", - "value": ":" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TEMPLATE_LITERAL_START", - "value": "`" - }, - { - "type": "STRING_QUOTED", - "value": "Number is " - }, - { - "type": "DOLLAR", - "value": "$" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "NUMBER_DECIMAL", - "value": "27" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "TEMPLATE_LITERAL_END", - "value": "`" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "STRING_QUOTED", - "value": "\n\n Even markup:\n " - }, - { - "type": "DOLLAR", - "value": "$" - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "header" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_OPENING", - "value": "<" - }, - { - "type": "STRING", - "value": "h1" - }, - { - "type": "TAG_END", - "value": ">" - }, - { - "type": "STRING", - "value": "Number" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "STRING", - "value": "is" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_OPEN", - "value": "{" - }, - { - "type": "STRING", - "value": "someNumber" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "TAG_START_CLOSING", - "value": "" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "SPACE", - "value": " " - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "STRING_QUOTED", - "value": "\n " - }, - { - "type": "TEMPLATE_LITERAL_END", - "value": "`" - }, - { - "type": "END_OF_LINE", - "value": "\n" - }, - { - "type": "BRACKET_CURLY_CLOSE", - "value": "}" - }, - { - "type": "END_OF_LINE", - "value": "\n" - } -] From c0dbaceea31eb070f1c97a0af331b32cafcd29a8 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sun, 6 Aug 2023 23:23:22 +0200 Subject: [PATCH 60/64] !!!TASK: Rename IdentifierTypeResolver -> ValueReferenceTypeResolver --- .../Expression/ExpressionTypeResolver.php | 4 ++-- .../ValueReferenceTypeResolver.php} | 4 ++-- .../ValueReferenceTypeResolverTest.php} | 17 +++++++---------- 3 files changed, 11 insertions(+), 14 deletions(-) rename src/TypeSystem/Resolver/{Identifier/IdentifierTypeResolver.php => ValueReference/ValueReferenceTypeResolver.php} (92%) rename test/Unit/TypeSystem/Resolver/{Identifier/IdentifierTypeResolverTest.php => ValueReference/ValueReferenceTypeResolverTest.php} (76%) diff --git a/src/TypeSystem/Resolver/Expression/ExpressionTypeResolver.php b/src/TypeSystem/Resolver/Expression/ExpressionTypeResolver.php index 8456da5a..2a273d63 100644 --- a/src/TypeSystem/Resolver/Expression/ExpressionTypeResolver.php +++ b/src/TypeSystem/Resolver/Expression/ExpressionTypeResolver.php @@ -37,7 +37,7 @@ use PackageFactory\ComponentEngine\TypeSystem\Resolver\Access\AccessTypeResolver; use PackageFactory\ComponentEngine\TypeSystem\Resolver\BinaryOperation\BinaryOperationTypeResolver; use PackageFactory\ComponentEngine\TypeSystem\Resolver\BooleanLiteral\BooleanLiteralTypeResolver; -use PackageFactory\ComponentEngine\TypeSystem\Resolver\Identifier\IdentifierTypeResolver; +use PackageFactory\ComponentEngine\TypeSystem\Resolver\ValueReference\ValueReferenceTypeResolver; use PackageFactory\ComponentEngine\TypeSystem\Resolver\Match\MatchTypeResolver; use PackageFactory\ComponentEngine\TypeSystem\Resolver\NullLiteral\NullLiteralTypeResolver; use PackageFactory\ComponentEngine\TypeSystem\Resolver\IntegerLiteral\IntegerLiteralTypeResolver; @@ -64,7 +64,7 @@ public function resolveTypeOf(ExpressionNode $expressionNode): TypeInterface ))->resolveTypeOf($rootNode), BooleanLiteralNode::class => (new BooleanLiteralTypeResolver()) ->resolveTypeOf($rootNode), - ValueReferenceNode::class => (new IdentifierTypeResolver( + ValueReferenceNode::class => (new ValueReferenceTypeResolver( scope: $this->scope ))->resolveTypeOf($rootNode), MatchNode::class => (new MatchTypeResolver( diff --git a/src/TypeSystem/Resolver/Identifier/IdentifierTypeResolver.php b/src/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolver.php similarity index 92% rename from src/TypeSystem/Resolver/Identifier/IdentifierTypeResolver.php rename to src/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolver.php index 15d9130b..ae9c4594 100644 --- a/src/TypeSystem/Resolver/Identifier/IdentifierTypeResolver.php +++ b/src/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolver.php @@ -20,13 +20,13 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\TypeSystem\Resolver\Identifier; +namespace PackageFactory\ComponentEngine\TypeSystem\Resolver\ValueReference; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; -final class IdentifierTypeResolver +final class ValueReferenceTypeResolver { public function __construct(private readonly ScopeInterface $scope) { diff --git a/test/Unit/TypeSystem/Resolver/Identifier/IdentifierTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php similarity index 76% rename from test/Unit/TypeSystem/Resolver/Identifier/IdentifierTypeResolverTest.php rename to test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php index 90ca70b5..0d2bb785 100644 --- a/test/Unit/TypeSystem/Resolver/Identifier/IdentifierTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php @@ -20,27 +20,24 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Resolver\Identifier; +namespace PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Resolver\ValueReference; -use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; -use PackageFactory\ComponentEngine\Domain\TypeName\TypeNames; use PackageFactory\ComponentEngine\Test\Unit\Language\ASTNodeFixtures; use PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\Fixtures\DummyScope; -use PackageFactory\ComponentEngine\TypeSystem\Resolver\Identifier\IdentifierTypeResolver; +use PackageFactory\ComponentEngine\TypeSystem\Resolver\ValueReference\ValueReferenceTypeResolver; use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; -use PackageFactory\ComponentEngine\TypeSystem\TypeReference; use PHPUnit\Framework\TestCase; -final class IdentifierTypeResolverTest extends TestCase +final class ValueReferenceTypeResolverTest extends TestCase { /** * @test * @return void */ - public function resolvesKnownIdentifierToItsType(): void + public function resolvesKnownValueReferenceToItsType(): void { $scope = new DummyScope([StringType::get()], ['foo' => StringType::get()]); - $identifierTypeResolver = new IdentifierTypeResolver(scope: $scope); + $identifierTypeResolver = new ValueReferenceTypeResolver(scope: $scope); $identifierNode = ASTNodeFixtures::ValueReference('foo'); $expectedType = StringType::get(); @@ -56,10 +53,10 @@ public function resolvesKnownIdentifierToItsType(): void * @test * @return void */ - public function throwsIfGivenIdentifierIsUnknown(): void + public function throwsIfGivenValueReferenceIsUnknown(): void { $scope = new DummyScope(); - $identifierTypeResolver = new IdentifierTypeResolver(scope: $scope); + $identifierTypeResolver = new ValueReferenceTypeResolver(scope: $scope); $identifierNode = ASTNodeFixtures::ValueReference('foo'); $this->expectExceptionMessageMatches('/unknown identifier/i'); From b2c75cb0b813488078cfcbf7cc5c043d4c8f8df0 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sun, 6 Aug 2023 23:26:18 +0200 Subject: [PATCH 61/64] !!!TASK: Rename IdentifierTranspiler -> ValueReferenceTranspiler --- .../Transpiler/Expression/ExpressionTranspiler.php | 4 ++-- .../ValueReferenceTranspiler.php} | 4 ++-- .../ValueReferenceTranspilerTest.php} | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) rename src/Target/Php/Transpiler/{Identifier/IdentifierTranspiler.php => ValueReference/ValueReferenceTranspiler.php} (93%) rename test/Unit/Target/Php/Transpiler/{Identifier/IdentifierTranspilerTest.php => ValueReference/ValueReferenceTranspilerTest.php} (85%) diff --git a/src/Target/Php/Transpiler/Expression/ExpressionTranspiler.php b/src/Target/Php/Transpiler/Expression/ExpressionTranspiler.php index fddc5459..50c27f9a 100644 --- a/src/Target/Php/Transpiler/Expression/ExpressionTranspiler.php +++ b/src/Target/Php/Transpiler/Expression/ExpressionTranspiler.php @@ -38,7 +38,7 @@ use PackageFactory\ComponentEngine\Target\Php\Transpiler\Access\AccessTranspiler; use PackageFactory\ComponentEngine\Target\Php\Transpiler\BinaryOperation\BinaryOperationTranspiler; use PackageFactory\ComponentEngine\Target\Php\Transpiler\BooleanLiteral\BooleanLiteralTranspiler; -use PackageFactory\ComponentEngine\Target\Php\Transpiler\Identifier\IdentifierTranspiler; +use PackageFactory\ComponentEngine\Target\Php\Transpiler\ValueReference\ValueReferenceTranspiler; use PackageFactory\ComponentEngine\Target\Php\Transpiler\Match\MatchTranspiler; use PackageFactory\ComponentEngine\Target\Php\Transpiler\NullLiteral\NullLiteralTranspiler; use PackageFactory\ComponentEngine\Target\Php\Transpiler\IntegerLiteral\IntegerLiteralTranspiler; @@ -63,7 +63,7 @@ public function transpile(ExpressionNode $expressionNode): string AccessNode::class => new AccessTranspiler( scope: $this->scope ), - ValueReferenceNode::class => new IdentifierTranspiler( + ValueReferenceNode::class => new ValueReferenceTranspiler( scope: $this->scope ), TernaryOperationNode::class => new TernaryOperationTranspiler( diff --git a/src/Target/Php/Transpiler/Identifier/IdentifierTranspiler.php b/src/Target/Php/Transpiler/ValueReference/ValueReferenceTranspiler.php similarity index 93% rename from src/Target/Php/Transpiler/Identifier/IdentifierTranspiler.php rename to src/Target/Php/Transpiler/ValueReference/ValueReferenceTranspiler.php index b2f1db2a..7e535ee3 100644 --- a/src/Target/Php/Transpiler/Identifier/IdentifierTranspiler.php +++ b/src/Target/Php/Transpiler/ValueReference/ValueReferenceTranspiler.php @@ -20,13 +20,13 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Target\Php\Transpiler\Identifier; +namespace PackageFactory\ComponentEngine\Target\Php\Transpiler\ValueReference; use PackageFactory\ComponentEngine\Language\AST\Node\ValueReference\ValueReferenceNode; use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface; use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType; -final class IdentifierTranspiler +final class ValueReferenceTranspiler { public function __construct(private readonly ScopeInterface $scope) { diff --git a/test/Unit/Target/Php/Transpiler/Identifier/IdentifierTranspilerTest.php b/test/Unit/Target/Php/Transpiler/ValueReference/ValueReferenceTranspilerTest.php similarity index 85% rename from test/Unit/Target/Php/Transpiler/Identifier/IdentifierTranspilerTest.php rename to test/Unit/Target/Php/Transpiler/ValueReference/ValueReferenceTranspilerTest.php index 1e2e9691..f6245c54 100644 --- a/test/Unit/Target/Php/Transpiler/Identifier/IdentifierTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/ValueReference/ValueReferenceTranspilerTest.php @@ -20,24 +20,24 @@ declare(strict_types=1); -namespace PackageFactory\ComponentEngine\Test\Unit\Target\Php\Transpiler\Identifier; +namespace PackageFactory\ComponentEngine\Test\Unit\Target\Php\Transpiler\ValueReference; use PackageFactory\ComponentEngine\Module\ModuleId; use PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\Fixtures\DummyScope; -use PackageFactory\ComponentEngine\Target\Php\Transpiler\Identifier\IdentifierTranspiler; +use PackageFactory\ComponentEngine\Target\Php\Transpiler\ValueReference\ValueReferenceTranspiler; use PackageFactory\ComponentEngine\Test\Unit\Language\ASTNodeFixtures; use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType; use PHPUnit\Framework\TestCase; -final class IdentifierTranspilerTest extends TestCase +final class ValueReferenceTranspilerTest extends TestCase { /** * @test * @return void */ - public function transpilesIdentifierNodes(): void + public function transpilesValueReferenceNodes(): void { - $identifierTranspiler = new IdentifierTranspiler( + $identifierTranspiler = new ValueReferenceTranspiler( scope: new DummyScope() ); $identifierNode = ASTNodeFixtures::ValueReference('foo'); @@ -57,9 +57,9 @@ public function transpilesIdentifierNodes(): void * @test * @return void */ - public function transpilesIdentifierNodesReferringToEnums(): void + public function transpilesValueReferenceNodesReferringToEnums(): void { - $identifierTranspiler = new IdentifierTranspiler( + $identifierTranspiler = new ValueReferenceTranspiler( scope: new DummyScope( [ $someEnumType = EnumStaticType::fromModuleIdAndDeclaration( From 68f4fa2666f4f04ef9c8fd7ab0d4415762efac6f Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sun, 6 Aug 2023 23:43:02 +0200 Subject: [PATCH 62/64] TASK: Turn all Domain\* name objects into flyweights --- src/Domain/AttributeName/AttributeName.php | 7 +++- src/Domain/ComponentName/ComponentName.php | 7 +++- src/Domain/EnumMemberName/EnumMemberName.php | 7 +++- src/Domain/EnumName/EnumName.php | 7 +++- src/Domain/PropertyName/PropertyName.php | 7 +++- src/Domain/StructName/StructName.php | 7 +++- src/Domain/TagName/TagName.php | 7 +++- src/Domain/TypeName/TypeName.php | 7 +++- src/Domain/VariableName/VariableName.php | 7 +++- .../AttributeName/AttributeNameTest.php | 41 +++++++++++++++++++ .../ComponentName/ComponentNameTest.php | 10 +++++ .../EnumMemberName/EnumMemberNameTest.php | 41 +++++++++++++++++++ test/Unit/Domain/EnumName/EnumNameTest.php | 12 ++++++ .../Domain/PropertyName/PropertyNameTest.php | 41 +++++++++++++++++++ .../Unit/Domain/StructName/StructNameTest.php | 12 ++++++ test/Unit/Domain/TagName/TagNameTest.php | 41 +++++++++++++++++++ test/Unit/Domain/TypeName/TypeNameTest.php | 12 ++++++ .../Domain/VariableName/VariableNameTest.php | 41 +++++++++++++++++++ 18 files changed, 305 insertions(+), 9 deletions(-) create mode 100644 test/Unit/Domain/AttributeName/AttributeNameTest.php create mode 100644 test/Unit/Domain/EnumMemberName/EnumMemberNameTest.php create mode 100644 test/Unit/Domain/PropertyName/PropertyNameTest.php create mode 100644 test/Unit/Domain/TagName/TagNameTest.php create mode 100644 test/Unit/Domain/VariableName/VariableNameTest.php diff --git a/src/Domain/AttributeName/AttributeName.php b/src/Domain/AttributeName/AttributeName.php index d85dba68..fe01569d 100644 --- a/src/Domain/AttributeName/AttributeName.php +++ b/src/Domain/AttributeName/AttributeName.php @@ -24,6 +24,11 @@ final class AttributeName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -31,6 +36,6 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } } diff --git a/src/Domain/ComponentName/ComponentName.php b/src/Domain/ComponentName/ComponentName.php index fe76e3ae..5b021d99 100644 --- a/src/Domain/ComponentName/ComponentName.php +++ b/src/Domain/ComponentName/ComponentName.php @@ -26,6 +26,11 @@ final class ComponentName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -33,7 +38,7 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } public function toTypeName(): TypeName diff --git a/src/Domain/EnumMemberName/EnumMemberName.php b/src/Domain/EnumMemberName/EnumMemberName.php index 39040656..dc65ddb7 100644 --- a/src/Domain/EnumMemberName/EnumMemberName.php +++ b/src/Domain/EnumMemberName/EnumMemberName.php @@ -24,6 +24,11 @@ final class EnumMemberName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -31,6 +36,6 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } } diff --git a/src/Domain/EnumName/EnumName.php b/src/Domain/EnumName/EnumName.php index 57808fe3..c814f824 100644 --- a/src/Domain/EnumName/EnumName.php +++ b/src/Domain/EnumName/EnumName.php @@ -26,6 +26,11 @@ final class EnumName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -33,7 +38,7 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } public function toTypeName(): TypeName diff --git a/src/Domain/PropertyName/PropertyName.php b/src/Domain/PropertyName/PropertyName.php index 0f36b782..e07fc050 100644 --- a/src/Domain/PropertyName/PropertyName.php +++ b/src/Domain/PropertyName/PropertyName.php @@ -26,6 +26,11 @@ final class PropertyName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -33,7 +38,7 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } public function toEnumMemberName(): EnumMemberName diff --git a/src/Domain/StructName/StructName.php b/src/Domain/StructName/StructName.php index 5967cf41..df5eb7a1 100644 --- a/src/Domain/StructName/StructName.php +++ b/src/Domain/StructName/StructName.php @@ -26,6 +26,11 @@ final class StructName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -33,7 +38,7 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } public function toTypeName(): TypeName diff --git a/src/Domain/TagName/TagName.php b/src/Domain/TagName/TagName.php index 137f01a6..cc456689 100644 --- a/src/Domain/TagName/TagName.php +++ b/src/Domain/TagName/TagName.php @@ -24,6 +24,11 @@ final class TagName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -31,6 +36,6 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } } diff --git a/src/Domain/TypeName/TypeName.php b/src/Domain/TypeName/TypeName.php index cb63b5dd..12d91d9c 100644 --- a/src/Domain/TypeName/TypeName.php +++ b/src/Domain/TypeName/TypeName.php @@ -26,6 +26,11 @@ final class TypeName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -33,7 +38,7 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } public function toVariableName(): VariableName diff --git a/src/Domain/VariableName/VariableName.php b/src/Domain/VariableName/VariableName.php index 75592494..bad9b091 100644 --- a/src/Domain/VariableName/VariableName.php +++ b/src/Domain/VariableName/VariableName.php @@ -24,6 +24,11 @@ final class VariableName { + /** + * @var array + */ + private static array $instances = []; + private function __construct( public readonly string $value ) { @@ -31,6 +36,6 @@ private function __construct( public static function from(string $string): self { - return new self($string); + return self::$instances[$string] ??= new self($string); } } diff --git a/test/Unit/Domain/AttributeName/AttributeNameTest.php b/test/Unit/Domain/AttributeName/AttributeNameTest.php new file mode 100644 index 00000000..d7f11554 --- /dev/null +++ b/test/Unit/Domain/AttributeName/AttributeNameTest.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Domain\AttributeName; + +use PackageFactory\ComponentEngine\Domain\AttributeName\AttributeName; +use PHPUnit\Framework\TestCase; + +final class AttributeNameTest extends TestCase +{ + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(AttributeName::from('foo'), AttributeName::from('foo')); + $this->assertSame(AttributeName::from('bar'), AttributeName::from('bar')); + $this->assertSame(AttributeName::from('data-baz'), AttributeName::from('data-baz')); + + $this->assertNotSame(AttributeName::from('foo'), AttributeName::from('bar')); + } +} diff --git a/test/Unit/Domain/ComponentName/ComponentNameTest.php b/test/Unit/Domain/ComponentName/ComponentNameTest.php index 2d9562a3..30eb1fd3 100644 --- a/test/Unit/Domain/ComponentName/ComponentNameTest.php +++ b/test/Unit/Domain/ComponentName/ComponentNameTest.php @@ -28,6 +28,16 @@ final class ComponentNameTest extends TestCase { + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(ComponentName::from('Foo'), ComponentName::from('Foo')); + $this->assertSame(ComponentName::from('Bar'), ComponentName::from('Bar')); + $this->assertSame(ComponentName::from('FooBar'), ComponentName::from('FooBar')); + } + /** * @test */ diff --git a/test/Unit/Domain/EnumMemberName/EnumMemberNameTest.php b/test/Unit/Domain/EnumMemberName/EnumMemberNameTest.php new file mode 100644 index 00000000..515aacb6 --- /dev/null +++ b/test/Unit/Domain/EnumMemberName/EnumMemberNameTest.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Domain\EnumMemberName; + +use PackageFactory\ComponentEngine\Domain\EnumMemberName\EnumMemberName; +use PHPUnit\Framework\TestCase; + +final class EnumMemberNameTest extends TestCase +{ + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(EnumMemberName::from('foo'), EnumMemberName::from('foo')); + $this->assertSame(EnumMemberName::from('bar'), EnumMemberName::from('bar')); + $this->assertSame(EnumMemberName::from('foobar'), EnumMemberName::from('foobar')); + + $this->assertNotSame(EnumMemberName::from('foo'), EnumMemberName::from('bar')); + } +} diff --git a/test/Unit/Domain/EnumName/EnumNameTest.php b/test/Unit/Domain/EnumName/EnumNameTest.php index 1eef9a60..d4ef70ca 100644 --- a/test/Unit/Domain/EnumName/EnumNameTest.php +++ b/test/Unit/Domain/EnumName/EnumNameTest.php @@ -28,6 +28,18 @@ final class EnumNameTest extends TestCase { + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(EnumName::from('Foo'), EnumName::from('Foo')); + $this->assertSame(EnumName::from('Bar'), EnumName::from('Bar')); + $this->assertSame(EnumName::from('FooBar'), EnumName::from('FooBar')); + + $this->assertNotSame(EnumName::from('Foo'), EnumName::from('Bar')); + } + /** * @test */ diff --git a/test/Unit/Domain/PropertyName/PropertyNameTest.php b/test/Unit/Domain/PropertyName/PropertyNameTest.php new file mode 100644 index 00000000..cb8040e6 --- /dev/null +++ b/test/Unit/Domain/PropertyName/PropertyNameTest.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Domain\PropertyName; + +use PackageFactory\ComponentEngine\Domain\PropertyName\PropertyName; +use PHPUnit\Framework\TestCase; + +final class PropertyNameTest extends TestCase +{ + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(PropertyName::from('foo'), PropertyName::from('foo')); + $this->assertSame(PropertyName::from('bar'), PropertyName::from('bar')); + $this->assertSame(PropertyName::from('foobar'), PropertyName::from('foobar')); + + $this->assertNotSame(PropertyName::from('foo'), PropertyName::from('bar')); + } +} diff --git a/test/Unit/Domain/StructName/StructNameTest.php b/test/Unit/Domain/StructName/StructNameTest.php index 56674e79..8c24b791 100644 --- a/test/Unit/Domain/StructName/StructNameTest.php +++ b/test/Unit/Domain/StructName/StructNameTest.php @@ -28,6 +28,18 @@ final class StructNameTest extends TestCase { + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(StructName::from('Foo'), StructName::from('Foo')); + $this->assertSame(StructName::from('Bar'), StructName::from('Bar')); + $this->assertSame(StructName::from('FooBar'), StructName::from('FooBar')); + + $this->assertNotSame(StructName::from('Foo'), StructName::from('Bar')); + } + /** * @test */ diff --git a/test/Unit/Domain/TagName/TagNameTest.php b/test/Unit/Domain/TagName/TagNameTest.php new file mode 100644 index 00000000..6da2faa6 --- /dev/null +++ b/test/Unit/Domain/TagName/TagNameTest.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Domain\TagName; + +use PackageFactory\ComponentEngine\Domain\TagName\TagName; +use PHPUnit\Framework\TestCase; + +final class TagNameTest extends TestCase +{ + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(TagName::from('div'), TagName::from('div')); + $this->assertSame(TagName::from('a'), TagName::from('a')); + $this->assertSame(TagName::from('vendor-component'), TagName::from('vendor-component')); + + $this->assertNotSame(TagName::from('pre'), TagName::from('table')); + } +} diff --git a/test/Unit/Domain/TypeName/TypeNameTest.php b/test/Unit/Domain/TypeName/TypeNameTest.php index e8426fba..9ee597bc 100644 --- a/test/Unit/Domain/TypeName/TypeNameTest.php +++ b/test/Unit/Domain/TypeName/TypeNameTest.php @@ -28,6 +28,18 @@ final class TypeNameTest extends TestCase { + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(TypeName::from('Foo'), TypeName::from('Foo')); + $this->assertSame(TypeName::from('Bar'), TypeName::from('Bar')); + $this->assertSame(TypeName::from('FooBar'), TypeName::from('FooBar')); + + $this->assertNotSame(TypeName::from('Foo'), TypeName::from('Bar')); + } + /** * @test */ diff --git a/test/Unit/Domain/VariableName/VariableNameTest.php b/test/Unit/Domain/VariableName/VariableNameTest.php new file mode 100644 index 00000000..1868b158 --- /dev/null +++ b/test/Unit/Domain/VariableName/VariableNameTest.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + +namespace PackageFactory\ComponentEngine\Test\Unit\Domain\VariableName; + +use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PHPUnit\Framework\TestCase; + +final class VariableNameTest extends TestCase +{ + /** + * @test + */ + public function isFlyweight(): void + { + $this->assertSame(VariableName::from('foo'), VariableName::from('foo')); + $this->assertSame(VariableName::from('bar'), VariableName::from('bar')); + $this->assertSame(VariableName::from('foobar'), VariableName::from('foobar')); + + $this->assertNotSame(VariableName::from('foo'), VariableName::from('bar')); + } +} From 3bac790377d505210abbe478ca9e195273f18fb5 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sun, 6 Aug 2023 23:44:58 +0200 Subject: [PATCH 63/64] TASK: Reform GlobalScope to use explicit type names --- src/TypeSystem/Scope/GlobalScope/GlobalScope.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/TypeSystem/Scope/GlobalScope/GlobalScope.php b/src/TypeSystem/Scope/GlobalScope/GlobalScope.php index 3ed02c89..47ca11ef 100644 --- a/src/TypeSystem/Scope/GlobalScope/GlobalScope.php +++ b/src/TypeSystem/Scope/GlobalScope/GlobalScope.php @@ -47,11 +47,11 @@ public static function get(): self public function getType(TypeName $typeName): AtomicTypeInterface { - return match ($typeName->value) { - 'string' => StringType::get(), - 'number' => IntegerType::get(), - 'boolean' => BooleanType::get(), - 'slot' => SlotType::get(), + return match ($typeName) { + StringType::get()->getName() => StringType::get(), + IntegerType::get()->getName() => IntegerType::get(), + BooleanType::get()->getName() => BooleanType::get(), + SlotType::get()->getName() => SlotType::get(), default => throw new \Exception('@TODO: Unknown Type ' . $typeName->value) }; } From 5b3f7ca36987d65805ae1027276611af5de6f849 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Sun, 6 Aug 2023 23:55:07 +0200 Subject: [PATCH 64/64] !!!TASK: Refactor all remaining Singletons with Singleton Trait --- .../ComponentDeclarationTranspiler.php | 2 +- .../BinaryOperationTypeResolver.php | 2 +- .../BooleanLiteralTypeResolver.php | 2 +- .../IntegerLiteralTypeResolver.php | 2 +- .../Resolver/Match/MatchTypeResolver.php | 2 +- .../NullLiteral/NullLiteralTypeResolver.php | 2 +- .../StringLiteralTypeResolver.php | 2 +- .../Resolver/Tag/TagTypeResolver.php | 2 +- .../TemplateLiteralTypeResolver.php | 2 +- .../Scope/GlobalScope/GlobalScope.php | 20 ++---- .../Type/BooleanType/BooleanType.php | 12 +--- .../Type/IntegerType/IntegerType.php | 12 +--- src/TypeSystem/Type/NullType/NullType.php | 12 +--- src/TypeSystem/Type/SlotType/SlotType.php | 12 +--- src/TypeSystem/Type/StringType/StringType.php | 12 +--- src/TypeSystem/TypeReference.php | 2 +- .../PhpTranspilerIntegrationTest.php | 2 +- .../ComponentDeclarationTranspilerTest.php | 2 +- .../Module/ModuleTranspilerTest.php | 6 +- .../StructDeclarationTranspilerTest.php | 2 +- .../Php/Transpiler/Tag/TagTranspilerTest.php | 2 +- .../TagContent/TagContentTranspilerTest.php | 2 +- .../TernaryOperationTranspilerTest.php | 4 +- .../TypeReferenceTranspilerTest.php | 6 +- .../UnaryOperationTranspilerTest.php | 2 +- .../Access/AccessTypeResolverTest.php | 4 +- .../BinaryOperationTypeResolverTest.php | 28 ++++---- .../BooleanLiteralTypeResolverTest.php | 2 +- .../Expression/ExpressionTypeResolverTest.php | 64 +++++++++---------- .../IntegerLiteralTypeResolverTest.php | 2 +- .../Resolver/Match/MatchTypeResolverTest.php | 24 +++---- .../NullLiteralTypeResolverTest.php | 2 +- .../StringLiteralTypeResolverTest.php | 2 +- .../Resolver/Tag/TagTypeResolverTest.php | 2 +- .../TemplateLiteralTypeResolverTest.php | 2 +- .../TernaryOperationTypeResolverTest.php | 14 ++-- .../ValueReferenceTypeResolverTest.php | 4 +- .../ComponentScope/ComponentScopeTest.php | 14 ++-- .../Scope/GlobalScope/GlobalScopeTest.php | 6 +- .../Type/BooleanType/BooleanTypeTest.php | 8 +-- .../Type/IntegerType/IntegerTypeTest.php | 8 +-- .../TypeSystem/Type/NullType/NullTypeTest.php | 8 +-- .../TypeSystem/Type/SlotType/SlotTypeTest.php | 8 +-- .../Type/StringType/StringTypeTest.php | 8 +-- .../Type/UnionType/UnionTypeTest.php | 36 +++++------ 45 files changed, 163 insertions(+), 211 deletions(-) diff --git a/src/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspiler.php b/src/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspiler.php index 80be2490..059d8659 100644 --- a/src/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspiler.php +++ b/src/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspiler.php @@ -124,7 +124,7 @@ public function writeReturnExpression(ComponentDeclarationNode $componentDeclara ); $returnExpression = $componentDeclarationNode->return; - $returnTypeIsString = StringType::get()->is( + $returnTypeIsString = StringType::singleton()->is( $expressionTypeResolver->resolveTypeOf($returnExpression) ); $transpiledReturnExpression = $expressionTranspiler->transpile($returnExpression); diff --git a/src/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolver.php b/src/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolver.php index d589651e..b81798cd 100644 --- a/src/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolver.php +++ b/src/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolver.php @@ -48,7 +48,7 @@ public function resolveTypeOf(BinaryOperationNode $binaryOperationNode): TypeInt BinaryOperator::GREATER_THAN, BinaryOperator::GREATER_THAN_OR_EQUAL, BinaryOperator::LESS_THAN, - BinaryOperator::LESS_THAN_OR_EQUAL => BooleanType::get() + BinaryOperator::LESS_THAN_OR_EQUAL => BooleanType::singleton() }; } diff --git a/src/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolver.php b/src/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolver.php index 69b6e84d..7cfe1b65 100644 --- a/src/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolver.php +++ b/src/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolver.php @@ -30,6 +30,6 @@ final class BooleanLiteralTypeResolver { public function resolveTypeOf(BooleanLiteralNode $booleanLiteralNode): TypeInterface { - return BooleanType::get(); + return BooleanType::singleton(); } } diff --git a/src/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolver.php b/src/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolver.php index 3caa5a35..21951e09 100644 --- a/src/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolver.php +++ b/src/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolver.php @@ -30,6 +30,6 @@ final class IntegerLiteralTypeResolver { public function resolveTypeOf(IntegerLiteralNode $IntegerLiteralNode): TypeInterface { - return IntegerType::get(); + return IntegerType::singleton(); } } diff --git a/src/TypeSystem/Resolver/Match/MatchTypeResolver.php b/src/TypeSystem/Resolver/Match/MatchTypeResolver.php index aab21425..6e7fd609 100644 --- a/src/TypeSystem/Resolver/Match/MatchTypeResolver.php +++ b/src/TypeSystem/Resolver/Match/MatchTypeResolver.php @@ -138,7 +138,7 @@ public function resolveTypeOf(MatchNode $matchNode): TypeInterface ); return match (true) { - BooleanType::get()->is($typeOfSubject) => $this->resolveTypeOfBooleanMatch($matchNode), + BooleanType::singleton()->is($typeOfSubject) => $this->resolveTypeOfBooleanMatch($matchNode), $typeOfSubject instanceof EnumInstanceType => $this->resolveTypeOfEnumMatch($matchNode, $typeOfSubject), default => throw new \Exception('@TODO: Not handled ' . $typeOfSubject::class) }; diff --git a/src/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolver.php b/src/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolver.php index e5b0ab10..03acdb99 100644 --- a/src/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolver.php +++ b/src/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolver.php @@ -30,6 +30,6 @@ final class NullLiteralTypeResolver { public function resolveTypeOf(NullLiteralNode $nullLiteralNode): TypeInterface { - return NullType::get(); + return NullType::singleton(); } } diff --git a/src/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolver.php b/src/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolver.php index c536f28e..6cf9a83a 100644 --- a/src/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolver.php +++ b/src/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolver.php @@ -30,6 +30,6 @@ final class StringLiteralTypeResolver { public function resolveTypeOf(StringLiteralNode $stringLiteralNode): TypeInterface { - return StringType::get(); + return StringType::singleton(); } } diff --git a/src/TypeSystem/Resolver/Tag/TagTypeResolver.php b/src/TypeSystem/Resolver/Tag/TagTypeResolver.php index fa9f02a6..d8ec6f98 100644 --- a/src/TypeSystem/Resolver/Tag/TagTypeResolver.php +++ b/src/TypeSystem/Resolver/Tag/TagTypeResolver.php @@ -30,6 +30,6 @@ final class TagTypeResolver { public function resolveTypeOf(TagNode $tagNode): TypeInterface { - return StringType::get(); + return StringType::singleton(); } } diff --git a/src/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolver.php b/src/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolver.php index 626e91ca..7ba43acf 100644 --- a/src/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolver.php +++ b/src/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolver.php @@ -30,6 +30,6 @@ final class TemplateLiteralTypeResolver { public function resolveTypeOf(TemplateLiteralNode $templateLiteralNode): TypeInterface { - return StringType::get(); + return StringType::singleton(); } } diff --git a/src/TypeSystem/Scope/GlobalScope/GlobalScope.php b/src/TypeSystem/Scope/GlobalScope/GlobalScope.php index 47ca11ef..6025584b 100644 --- a/src/TypeSystem/Scope/GlobalScope/GlobalScope.php +++ b/src/TypeSystem/Scope/GlobalScope/GlobalScope.php @@ -24,6 +24,7 @@ use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; use PackageFactory\ComponentEngine\Domain\VariableName\VariableName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface; use PackageFactory\ComponentEngine\TypeSystem\Type\BooleanType\BooleanType; @@ -34,24 +35,15 @@ final class GlobalScope implements ScopeInterface { - private static null|self $instance = null; - - private function __construct() - { - } - - public static function get(): self - { - return self::$instance ??= new self(); - } + use Singleton; public function getType(TypeName $typeName): AtomicTypeInterface { return match ($typeName) { - StringType::get()->getName() => StringType::get(), - IntegerType::get()->getName() => IntegerType::get(), - BooleanType::get()->getName() => BooleanType::get(), - SlotType::get()->getName() => SlotType::get(), + StringType::singleton()->getName() => StringType::singleton(), + IntegerType::singleton()->getName() => IntegerType::singleton(), + BooleanType::singleton()->getName() => BooleanType::singleton(), + SlotType::singleton()->getName() => SlotType::singleton(), default => throw new \Exception('@TODO: Unknown Type ' . $typeName->value) }; } diff --git a/src/TypeSystem/Type/BooleanType/BooleanType.php b/src/TypeSystem/Type/BooleanType/BooleanType.php index a303488f..f0f8af55 100644 --- a/src/TypeSystem/Type/BooleanType/BooleanType.php +++ b/src/TypeSystem/Type/BooleanType/BooleanType.php @@ -23,21 +23,13 @@ namespace PackageFactory\ComponentEngine\TypeSystem\Type\BooleanType; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; final class BooleanType implements AtomicTypeInterface { - private static null|self $instance = null; - - private function __construct() - { - } // @codeCoverageIgnore - - public static function get(): self - { - return self::$instance ??= new self(); - } + use Singleton; public function getName(): TypeName { diff --git a/src/TypeSystem/Type/IntegerType/IntegerType.php b/src/TypeSystem/Type/IntegerType/IntegerType.php index 1fc10e96..cf293caf 100644 --- a/src/TypeSystem/Type/IntegerType/IntegerType.php +++ b/src/TypeSystem/Type/IntegerType/IntegerType.php @@ -23,21 +23,13 @@ namespace PackageFactory\ComponentEngine\TypeSystem\Type\IntegerType; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; final class IntegerType implements AtomicTypeInterface { - private static null|self $instance = null; - - private function __construct() - { - } // @codeCoverageIgnore - - public static function get(): self - { - return self::$instance ??= new self(); - } + use Singleton; public function getName(): TypeName { diff --git a/src/TypeSystem/Type/NullType/NullType.php b/src/TypeSystem/Type/NullType/NullType.php index cf25a91f..848be2bc 100644 --- a/src/TypeSystem/Type/NullType/NullType.php +++ b/src/TypeSystem/Type/NullType/NullType.php @@ -23,21 +23,13 @@ namespace PackageFactory\ComponentEngine\TypeSystem\Type\NullType; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; final class NullType implements AtomicTypeInterface { - private static null|self $instance = null; - - private function __construct() - { - } - - public static function get(): self - { - return self::$instance ??= new self(); - } + use Singleton; public function getName(): TypeName { diff --git a/src/TypeSystem/Type/SlotType/SlotType.php b/src/TypeSystem/Type/SlotType/SlotType.php index c0bee7c6..db2b98b1 100644 --- a/src/TypeSystem/Type/SlotType/SlotType.php +++ b/src/TypeSystem/Type/SlotType/SlotType.php @@ -23,21 +23,13 @@ namespace PackageFactory\ComponentEngine\TypeSystem\Type\SlotType; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; final class SlotType implements AtomicTypeInterface { - private static null|self $instance = null; - - private function __construct() - { - } - - public static function get(): self - { - return self::$instance ??= new self(); - } + use Singleton; public function getName(): TypeName { diff --git a/src/TypeSystem/Type/StringType/StringType.php b/src/TypeSystem/Type/StringType/StringType.php index 5dc2369c..869b1e31 100644 --- a/src/TypeSystem/Type/StringType/StringType.php +++ b/src/TypeSystem/Type/StringType/StringType.php @@ -23,21 +23,13 @@ namespace PackageFactory\ComponentEngine\TypeSystem\Type\StringType; use PackageFactory\ComponentEngine\Domain\TypeName\TypeName; +use PackageFactory\ComponentEngine\Framework\PHP\Singleton\Singleton; use PackageFactory\ComponentEngine\TypeSystem\AtomicTypeInterface; use PackageFactory\ComponentEngine\TypeSystem\TypeInterface; final class StringType implements AtomicTypeInterface { - private static null|self $instance = null; - - private function __construct() - { - } // @codeCoverageIgnore - - public static function get(): self - { - return self::$instance ??= new self(); - } + use Singleton; public function getName(): TypeName { diff --git a/src/TypeSystem/TypeReference.php b/src/TypeSystem/TypeReference.php index 57e9a278..a05bddf6 100644 --- a/src/TypeSystem/TypeReference.php +++ b/src/TypeSystem/TypeReference.php @@ -40,7 +40,7 @@ public function toType(ScopeInterface $scope): TypeInterface $types = []; if ($this->isOptional) { - $types[] = NullType::get(); + $types[] = NullType::singleton(); } foreach ($this->names->items as $name) { diff --git a/test/Integration/PhpTranspilerIntegrationTest.php b/test/Integration/PhpTranspilerIntegrationTest.php index 1c5a797e..12346c4e 100644 --- a/test/Integration/PhpTranspilerIntegrationTest.php +++ b/test/Integration/PhpTranspilerIntegrationTest.php @@ -78,7 +78,7 @@ public function testTranspiler(string $example): void loader: new ModuleFileLoader( sourcePath: $sourcePath ), - globalScope: GlobalScope::get(), + globalScope: GlobalScope::singleton(), strategy: new ModuleTestStrategy() ); diff --git a/test/Unit/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspilerTest.php index 99ffcb2e..87616253 100644 --- a/test/Unit/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/ComponentDeclaration/ComponentDeclarationTranspilerTest.php @@ -45,7 +45,7 @@ public function transpilesComponentDeclarationNodes(): void EOT; $moduleNode = ASTNodeFixtures::Module($componentModuleAsString); $componentDeclarationTranspiler = new ComponentDeclarationTranspiler( - scope: GlobalScope::get(), + scope: GlobalScope::singleton(), module: $moduleNode, strategy: new ComponentDeclarationTestStrategy() ); diff --git a/test/Unit/Target/Php/Transpiler/Module/ModuleTranspilerTest.php b/test/Unit/Target/Php/Transpiler/Module/ModuleTranspilerTest.php index 72d28124..ad3ad3fb 100644 --- a/test/Unit/Target/Php/Transpiler/Module/ModuleTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/Module/ModuleTranspilerTest.php @@ -44,7 +44,7 @@ public function transpilesModuleNodesThatContainComponentDeclarations(): void EOT; $moduleTranspiler = new ModuleTranspiler( loader: new DummyLoader(), - globalScope: GlobalScope::get(), + globalScope: GlobalScope::singleton(), strategy: new ModuleTestStrategy() ); $moduleNode = ASTNodeFixtures::Module($moduleNodeAsString); @@ -92,7 +92,7 @@ public function transpilesModuleNodesThatContainEnumDeclarations(): void EOT; $moduleTranspiler = new ModuleTranspiler( loader: new DummyLoader(), - globalScope: GlobalScope::get(), + globalScope: GlobalScope::singleton(), strategy: new ModuleTestStrategy() ); $moduleNode = ASTNodeFixtures::Module($moduleNodeAsString); @@ -137,7 +137,7 @@ public function transpilesModuleNodesThatContainStructDeclarations(): void EOT; $moduleTranspiler = new ModuleTranspiler( loader: new DummyLoader(), - globalScope: GlobalScope::get(), + globalScope: GlobalScope::singleton(), strategy: new ModuleTestStrategy() ); $moduleNode = ASTNodeFixtures::Module($moduleNodeAsString); diff --git a/test/Unit/Target/Php/Transpiler/StructDeclaration/StructDeclarationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/StructDeclaration/StructDeclarationTranspilerTest.php index cc0656a2..2510f492 100644 --- a/test/Unit/Target/Php/Transpiler/StructDeclaration/StructDeclarationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/StructDeclaration/StructDeclarationTranspilerTest.php @@ -43,7 +43,7 @@ public function transpilesStructDeclarationNodes(): void } EOT; $structDeclarationTranspiler = new StructDeclarationTranspiler( - scope: new DummyScope([StringType::get()]), + scope: new DummyScope([StringType::singleton()]), strategy: new StructDeclarationTestStrategy() ); $structDeclarationNode = ASTNodeFixtures::StructDeclaration($structDeclarationAsString); diff --git a/test/Unit/Target/Php/Transpiler/Tag/TagTranspilerTest.php b/test/Unit/Target/Php/Transpiler/Tag/TagTranspilerTest.php index 4e2920ef..7e6bb1ad 100644 --- a/test/Unit/Target/Php/Transpiler/Tag/TagTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/Tag/TagTranspilerTest.php @@ -61,7 +61,7 @@ public static function tagExamples(): array public function transpilesTagNodes(string $tagAsString, string $expectedTranspilationResult): void { $tagTranspiler = new TagTranspiler( - scope: new DummyScope([StringType::get()], ['someValue' => StringType::get()]) + scope: new DummyScope([StringType::singleton()], ['someValue' => StringType::singleton()]) ); $tagNode = ASTNodeFixtures::Tag($tagAsString); diff --git a/test/Unit/Target/Php/Transpiler/TagContent/TagContentTranspilerTest.php b/test/Unit/Target/Php/Transpiler/TagContent/TagContentTranspilerTest.php index bc5165c7..1f12df51 100644 --- a/test/Unit/Target/Php/Transpiler/TagContent/TagContentTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/TagContent/TagContentTranspilerTest.php @@ -62,7 +62,7 @@ public static function tagContentExamples(): array public function transpilesTagContentNodes(string $tagContentAsString, string $expectedTranspilationResult): void { $tagContentTranspiler = new TagContentTranspiler( - scope: new DummyScope([StringType::get()], ['someValue' => StringType::get()]) + scope: new DummyScope([StringType::singleton()], ['someValue' => StringType::singleton()]) ); $tagContentNode = ASTNodeFixtures::TagContent($tagContentAsString); assert($tagContentNode !== null); diff --git a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php index 4709ec3f..ec89074d 100644 --- a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php @@ -83,7 +83,7 @@ public function transpilesTernaryOperationNodes(string $ternaryOperationAsString $ternaryOperationTranspiler = new TernaryOperationTranspiler( scope: new DummyScope( [ - StringType::get(), + StringType::singleton(), $someStructType = new StructType( name: StructName::from('SomeStruct'), properties: new Properties( @@ -107,7 +107,7 @@ public function transpilesTernaryOperationNodes(string $ternaryOperationAsString ) ], [ - 'someString' => StringType::get(), + 'someString' => StringType::singleton(), 'someStruct' => $someStructType ] ) diff --git a/test/Unit/Target/Php/Transpiler/TypeReference/TypeReferenceTranspilerTest.php b/test/Unit/Target/Php/Transpiler/TypeReference/TypeReferenceTranspilerTest.php index 85478511..92979f06 100644 --- a/test/Unit/Target/Php/Transpiler/TypeReference/TypeReferenceTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/TypeReference/TypeReferenceTranspilerTest.php @@ -65,9 +65,9 @@ protected function getTypeReferenceTranspiler(): TypeReferenceTranspiler { return new TypeReferenceTranspiler( scope: new DummyScope([ - StringType::get(), - BooleanType::get(), - IntegerType::get(), + StringType::singleton(), + BooleanType::singleton(), + IntegerType::singleton(), ComponentType::fromComponentDeclarationNode( ASTNodeFixtures::ComponentDeclaration('component Button { return "" }') ), diff --git a/test/Unit/Target/Php/Transpiler/UnaryOperation/UnaryOperationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/UnaryOperation/UnaryOperationTranspilerTest.php index 8059a9ec..2bbb7b32 100644 --- a/test/Unit/Target/Php/Transpiler/UnaryOperation/UnaryOperationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/UnaryOperation/UnaryOperationTranspilerTest.php @@ -50,7 +50,7 @@ public static function unaryOperationExamples(): array public function transpilesUnaryOperationNodes(string $unaryOperationAsString, string $expectedTranspilationResult): void { $transpiler = new UnaryOperationTranspiler( - scope: new DummyScope([StringType::get()], ['foo' => StringType::get()]) + scope: new DummyScope([StringType::singleton()], ['foo' => StringType::singleton()]) ); $node = ASTNodeFixtures::UnaryOperation($unaryOperationAsString); diff --git a/test/Unit/TypeSystem/Resolver/Access/AccessTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/Access/AccessTypeResolverTest.php index 5a2c56be..19483ab2 100644 --- a/test/Unit/TypeSystem/Resolver/Access/AccessTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/Access/AccessTypeResolverTest.php @@ -105,7 +105,7 @@ public function invalidAccessResultsInError(string $accessAsString, string $expe $scope = new DummyScope( [ - StringType::get(), + StringType::singleton(), $someEnum = EnumStaticType::fromModuleIdAndDeclaration( ModuleId::fromString("module-a"), ASTNodeFixtures::EnumDeclaration( @@ -114,7 +114,7 @@ public function invalidAccessResultsInError(string $accessAsString, string $expe ) ], [ - 'someString' => StringType::get(), + 'someString' => StringType::singleton(), 'SomeEnum' => $someEnum, 'someEnumValue' => $someEnum->toEnumInstanceType() ] diff --git a/test/Unit/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolverTest.php index fc1b4013..d88e62bf 100644 --- a/test/Unit/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/BinaryOperation/BinaryOperationTypeResolverTest.php @@ -40,22 +40,22 @@ final class BinaryOperationTypeResolverTest extends TestCase public static function binaryOperationExamples(): array { return [ - 'true && false' => ['true && false', BooleanType::get()], - 'true || false' => ['true || false', BooleanType::get()], - 'true && "foo"' => ['true && "foo"', UnionType::of(BooleanType::get(), StringType::get())], - 'true || "foo"' => ['true || "foo"', UnionType::of(BooleanType::get(), StringType::get())], - 'true && 42' => ['true && 42', UnionType::of(BooleanType::get(), IntegerType::get())], - 'true || 42' => ['true || 42', UnionType::of(BooleanType::get(), IntegerType::get())], + 'true && false' => ['true && false', BooleanType::singleton()], + 'true || false' => ['true || false', BooleanType::singleton()], + 'true && "foo"' => ['true && "foo"', UnionType::of(BooleanType::singleton(), StringType::singleton())], + 'true || "foo"' => ['true || "foo"', UnionType::of(BooleanType::singleton(), StringType::singleton())], + 'true && 42' => ['true && 42', UnionType::of(BooleanType::singleton(), IntegerType::singleton())], + 'true || 42' => ['true || 42', UnionType::of(BooleanType::singleton(), IntegerType::singleton())], - '4 === 2' => ['4 === 2', BooleanType::get()], - '4 !== 2' => ['4 !== 2', BooleanType::get()], - '4 > 2' => ['4 > 2', BooleanType::get()], - '4 >= 2' => ['4 >= 2', BooleanType::get()], - '4 < 2' => ['4 < 2', BooleanType::get()], - '4 <= 2' => ['4 <= 2', BooleanType::get()], + '4 === 2' => ['4 === 2', BooleanType::singleton()], + '4 !== 2' => ['4 !== 2', BooleanType::singleton()], + '4 > 2' => ['4 > 2', BooleanType::singleton()], + '4 >= 2' => ['4 >= 2', BooleanType::singleton()], + '4 < 2' => ['4 < 2', BooleanType::singleton()], + '4 <= 2' => ['4 <= 2', BooleanType::singleton()], - 'true && true && true' => ['true && true && true', BooleanType::get()], - '1 === 1 === true' => ['1 === 1 === true', BooleanType::get()], + 'true && true && true' => ['true && true && true', BooleanType::singleton()], + '1 === 1 === true' => ['1 === 1 === true', BooleanType::singleton()], ]; } diff --git a/test/Unit/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolverTest.php index 73fd64a6..107d54a4 100644 --- a/test/Unit/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/BooleanLiteral/BooleanLiteralTypeResolverTest.php @@ -37,7 +37,7 @@ public function resolvesBooleanLiteralToBooleanType(): void $booleanLiteralTypeResolver = new BooleanLiteralTypeResolver(); $booleanLiteralNode = ASTNodeFixtures::BooleanLiteral('true'); - $expectedType = BooleanType::get(); + $expectedType = BooleanType::singleton(); $actualType = $booleanLiteralTypeResolver->resolveTypeOf($booleanLiteralNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Resolver/Expression/ExpressionTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/Expression/ExpressionTypeResolverTest.php index a5298d70..e5d7f9dd 100644 --- a/test/Unit/TypeSystem/Resolver/Expression/ExpressionTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/Expression/ExpressionTypeResolverTest.php @@ -41,19 +41,19 @@ final class ExpressionTypeResolverTest extends TestCase public static function binaryOperationExamples(): array { return [ - 'true && false' => ['true && false', BooleanType::get()], - 'true || false' => ['true || false', BooleanType::get()], - 'true && "foo"' => ['true && "foo"', UnionType::of(BooleanType::get(), StringType::get())], - 'true || "foo"' => ['true || "foo"', UnionType::of(BooleanType::get(), StringType::get())], - 'true && 42' => ['true && 42', UnionType::of(BooleanType::get(), IntegerType::get())], - 'true || 42' => ['true || 42', UnionType::of(BooleanType::get(), IntegerType::get())], - - '4 === 2' => ['4 === 2', BooleanType::get()], - '4 !== 2' => ['4 !== 2', BooleanType::get()], - '4 > 2' => ['4 > 2', BooleanType::get()], - '4 >= 2' => ['4 >= 2', BooleanType::get()], - '4 < 2' => ['4 < 2', BooleanType::get()], - '4 <= 2' => ['4 <= 2', BooleanType::get()], + 'true && false' => ['true && false', BooleanType::singleton()], + 'true || false' => ['true || false', BooleanType::singleton()], + 'true && "foo"' => ['true && "foo"', UnionType::of(BooleanType::singleton(), StringType::singleton())], + 'true || "foo"' => ['true || "foo"', UnionType::of(BooleanType::singleton(), StringType::singleton())], + 'true && 42' => ['true && 42', UnionType::of(BooleanType::singleton(), IntegerType::singleton())], + 'true || 42' => ['true || 42', UnionType::of(BooleanType::singleton(), IntegerType::singleton())], + + '4 === 2' => ['4 === 2', BooleanType::singleton()], + '4 !== 2' => ['4 !== 2', BooleanType::singleton()], + '4 > 2' => ['4 > 2', BooleanType::singleton()], + '4 >= 2' => ['4 >= 2', BooleanType::singleton()], + '4 < 2' => ['4 < 2', BooleanType::singleton()], + '4 <= 2' => ['4 <= 2', BooleanType::singleton()], ]; } @@ -88,7 +88,7 @@ public function resolvesBooleanLiteralToBooleanType(): void $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression('true'); - $expectedType = BooleanType::get(); + $expectedType = BooleanType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -103,11 +103,11 @@ public function resolvesBooleanLiteralToBooleanType(): void */ public function resolvesKnownIdentifierToItsType(): void { - $scope = new DummyScope([StringType::get()], ['foo' => StringType::get()]); + $scope = new DummyScope([StringType::singleton()], ['foo' => StringType::singleton()]); $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression('foo'); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -124,19 +124,19 @@ public static function matchExamples(): array return [ 'match (true) { true -> 42 false -> "foo" }' => [ 'match (true) { true -> 42 false -> "foo" }', - IntegerType::get() + IntegerType::singleton() ], 'match (false) { true -> 42 false -> "foo" }' => [ 'match (false) { true -> 42 false -> "foo" }', - StringType::get() + StringType::singleton() ], 'match (variableOfTypeBoolean) { true -> 42 false -> "foo" }' => [ 'match (variableOfTypeBoolean) { true -> 42 false -> "foo" }', - UnionType::of(IntegerType::get(), StringType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton()) ], 'match (variableOfTypeBoolean) { true -> variableOfTypeNumber false -> variableOfTypeString }' => [ 'match (variableOfTypeBoolean) { true -> variableOfTypeNumber false -> variableOfTypeString }', - UnionType::of(IntegerType::get(), StringType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton()) ], ]; } @@ -151,11 +151,11 @@ public static function matchExamples(): array public function resolvesMatchToResultingType(string $matchAsString, TypeInterface $expectedType): void { $scope = new DummyScope( - [BooleanType::get(), StringType::get(), IntegerType::get()], + [BooleanType::singleton(), StringType::singleton(), IntegerType::singleton()], [ - 'variableOfTypeBoolean' => BooleanType::get(), - 'variableOfTypeString' => StringType::get(), - 'variableOfTypeNumber' => IntegerType::get() + 'variableOfTypeBoolean' => BooleanType::singleton(), + 'variableOfTypeString' => StringType::singleton(), + 'variableOfTypeNumber' => IntegerType::singleton() ] ); $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); @@ -179,7 +179,7 @@ public function resolvesNullLiteralToNullType(): void $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression('null'); - $expectedType = NullType::get(); + $expectedType = NullType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -198,7 +198,7 @@ public function resolvesNumberLiteralToIntegerType(): void $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression('42'); - $expectedType = IntegerType::get(); + $expectedType = IntegerType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -217,7 +217,7 @@ public function resolvesStringLiteralToStringType(): void $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression('"foo"'); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -236,7 +236,7 @@ public function resolvesTagToStringType(): void $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression('
'); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -270,7 +270,7 @@ public function resolvesTemplateLiteralToStringType(string $templateLiteralAsStr $expressionTypeResolver = new ExpressionTypeResolver(scope: $scope); $expressionNode = ASTNodeFixtures::Expression($templateLiteralAsString); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $expressionTypeResolver->resolveTypeOf($expressionNode); $this->assertTrue( @@ -285,9 +285,9 @@ public function resolvesTemplateLiteralToStringType(string $templateLiteralAsStr public static function ternaryOperationExamples(): array { return [ - 'true ? 42 : "foo"' => ['true ? 42 : "foo"', IntegerType::get()], - 'false ? 42 : "foo"' => ['false ? 42 : "foo"', StringType::get()], - '1 < 2 ? 42 : "foo"' => ['1 < 2 ? 42 : "foo"', UnionType::of(IntegerType::get(), StringType::get())] + 'true ? 42 : "foo"' => ['true ? 42 : "foo"', IntegerType::singleton()], + 'false ? 42 : "foo"' => ['false ? 42 : "foo"', StringType::singleton()], + '1 < 2 ? 42 : "foo"' => ['1 < 2 ? 42 : "foo"', UnionType::of(IntegerType::singleton(), StringType::singleton())] ]; } diff --git a/test/Unit/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolverTest.php index 6ffe9352..dd763f1b 100644 --- a/test/Unit/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/IntegerLiteral/IntegerLiteralTypeResolverTest.php @@ -37,7 +37,7 @@ public function resolvesIntegerLiteralToIntegerType(): void $integerLiteralTypeResolver = new IntegerLiteralTypeResolver(); $integerLiteralNode = ASTNodeFixtures::IntegerLiteral('42'); - $expectedType = IntegerType::get(); + $expectedType = IntegerType::singleton(); $actualType = $integerLiteralTypeResolver->resolveTypeOf($integerLiteralNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Resolver/Match/MatchTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/Match/MatchTypeResolverTest.php index a2795e90..94aa8751 100644 --- a/test/Unit/TypeSystem/Resolver/Match/MatchTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/Match/MatchTypeResolverTest.php @@ -44,19 +44,19 @@ public static function matchExamples(): array return [ 'match (true) { true -> 42 false -> "foo" }' => [ 'match (true) { true -> 42 false -> "foo" }', - IntegerType::get() + IntegerType::singleton() ], 'match (false) { true -> 42 false -> "foo" }' => [ 'match (false) { true -> 42 false -> "foo" }', - StringType::get() + StringType::singleton() ], 'match (variableOfTypeBoolean) { true -> 42 false -> "foo" }' => [ 'match (variableOfTypeBoolean) { true -> 42 false -> "foo" }', - UnionType::of(IntegerType::get(), StringType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton()) ], 'match (variableOfTypeBoolean) { true -> variableOfTypeNumber false -> variableOfTypeString }' => [ 'match (variableOfTypeBoolean) { true -> variableOfTypeNumber false -> variableOfTypeString }', - UnionType::of(IntegerType::get(), StringType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton()) ], 'match enum with all declared members' => [ << variableOfTypeBoolean } EOF, - UnionType::of(IntegerType::get(), StringType::get(), BooleanType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton(), BooleanType::singleton()) ], 'match enum with some declared members and default' => [ << variableOfTypeBoolean } EOF, - UnionType::of(IntegerType::get(), StringType::get(), BooleanType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton(), BooleanType::singleton()) ], ]; } @@ -92,9 +92,9 @@ public function resolvesMatchToResultingType(string $matchAsString, TypeInterfac { $scope = new DummyScope( [ - BooleanType::get(), - StringType::get(), - IntegerType::get(), + BooleanType::singleton(), + StringType::singleton(), + IntegerType::singleton(), $someStaticEnumType = EnumStaticType::fromModuleIdAndDeclaration( ModuleId::fromString("module-a"), ASTNodeFixtures::EnumDeclaration( @@ -103,9 +103,9 @@ public function resolvesMatchToResultingType(string $matchAsString, TypeInterfac ) ], [ - 'variableOfTypeBoolean' => BooleanType::get(), - 'variableOfTypeString' => StringType::get(), - 'variableOfTypeNumber' => IntegerType::get(), + 'variableOfTypeBoolean' => BooleanType::singleton(), + 'variableOfTypeString' => StringType::singleton(), + 'variableOfTypeNumber' => IntegerType::singleton(), 'someEnumValue' => $someStaticEnumType->toEnumInstanceType(), 'SomeEnum' => $someStaticEnumType ] diff --git a/test/Unit/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolverTest.php index e2c1f08f..f4a4c2f9 100644 --- a/test/Unit/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/NullLiteral/NullLiteralTypeResolverTest.php @@ -37,7 +37,7 @@ public function resolvesNullLiteralToNullType(): void $nullLiteralTypeResolver = new NullLiteralTypeResolver(); $nullLiteralNode = ASTNodeFixtures::NullLiteral('null'); - $expectedType = NullType::get(); + $expectedType = NullType::singleton(); $actualType = $nullLiteralTypeResolver->resolveTypeOf($nullLiteralNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolverTest.php index 4345534a..caeb4ab2 100644 --- a/test/Unit/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/StringLiteral/StringLiteralTypeResolverTest.php @@ -38,7 +38,7 @@ public function resolvesStringLiteralToStringType(): void $stringLiteralTypeResolver = new StringLiteralTypeResolver(); $stringLiteralNode = ASTNodeFixtures::StringLiteral('"foo"'); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $stringLiteralTypeResolver->resolveTypeOf($stringLiteralNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Resolver/Tag/TagTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/Tag/TagTypeResolverTest.php index ea435c9f..48402cce 100644 --- a/test/Unit/TypeSystem/Resolver/Tag/TagTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/Tag/TagTypeResolverTest.php @@ -38,7 +38,7 @@ public function resolvesTagToStringType(): void $tagTypeResolver = new TagTypeResolver(); $tagNode = ASTNodeFixtures::Tag('
'); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $tagTypeResolver->resolveTypeOf($tagNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolverTest.php index 79e170a3..29137094 100644 --- a/test/Unit/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/TemplateLiteral/TemplateLiteralTypeResolverTest.php @@ -53,7 +53,7 @@ public function resolvesTemplateLiteralToStringType(string $templateLiteralAsStr $templateLiteralTypeResolver = new TemplateLiteralTypeResolver(); $templateLiteralNode = ASTNodeFixtures::TemplateLiteral($templateLiteralAsString); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $templateLiteralTypeResolver->resolveTypeOf($templateLiteralNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Resolver/TernaryOperation/TernaryOperationTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/TernaryOperation/TernaryOperationTypeResolverTest.php index 280268b0..ec6ddc56 100644 --- a/test/Unit/TypeSystem/Resolver/TernaryOperation/TernaryOperationTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/TernaryOperation/TernaryOperationTypeResolverTest.php @@ -39,12 +39,12 @@ final class TernaryOperationTypeResolverTest extends TestCase public static function ternaryOperationExamples(): array { return [ - 'true ? 42 : "foo"' => ['true ? 42 : "foo"', IntegerType::get()], - 'false ? 42 : "foo"' => ['false ? 42 : "foo"', StringType::get()], - '1 < 2 ? 42 : "foo"' => ['1 < 2 ? 42 : "foo"', UnionType::of(IntegerType::get(), StringType::get())], + 'true ? 42 : "foo"' => ['true ? 42 : "foo"', IntegerType::singleton()], + 'false ? 42 : "foo"' => ['false ? 42 : "foo"', StringType::singleton()], + '1 < 2 ? 42 : "foo"' => ['1 < 2 ? 42 : "foo"', UnionType::of(IntegerType::singleton(), StringType::singleton())], '1 < 2 ? variableOfTypeString : variableOfTypeNumber' => [ '1 < 2 ? variableOfTypeString : variableOfTypeNumber', - UnionType::of(IntegerType::get(), StringType::get()) + UnionType::of(IntegerType::singleton(), StringType::singleton()) ] ]; } @@ -59,10 +59,10 @@ public static function ternaryOperationExamples(): array public function resolvesTernaryOperationToResultingType(string $ternaryExpressionAsString, TypeInterface $expectedType): void { $scope = new DummyScope( - [StringType::get(), IntegerType::get()], + [StringType::singleton(), IntegerType::singleton()], [ - 'variableOfTypeString' => StringType::get(), - 'variableOfTypeNumber' => IntegerType::get() + 'variableOfTypeString' => StringType::singleton(), + 'variableOfTypeNumber' => IntegerType::singleton() ] ); $ternaryOperationTypeResolver = new TernaryOperationTypeResolver( diff --git a/test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php b/test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php index 0d2bb785..3de632d4 100644 --- a/test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php +++ b/test/Unit/TypeSystem/Resolver/ValueReference/ValueReferenceTypeResolverTest.php @@ -36,11 +36,11 @@ final class ValueReferenceTypeResolverTest extends TestCase */ public function resolvesKnownValueReferenceToItsType(): void { - $scope = new DummyScope([StringType::get()], ['foo' => StringType::get()]); + $scope = new DummyScope([StringType::singleton()], ['foo' => StringType::singleton()]); $identifierTypeResolver = new ValueReferenceTypeResolver(scope: $scope); $identifierNode = ASTNodeFixtures::ValueReference('foo'); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $identifierTypeResolver->resolveTypeOf($identifierNode); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Scope/ComponentScope/ComponentScopeTest.php b/test/Unit/TypeSystem/Scope/ComponentScope/ComponentScopeTest.php index 045d70bc..67b120a8 100644 --- a/test/Unit/TypeSystem/Scope/ComponentScope/ComponentScopeTest.php +++ b/test/Unit/TypeSystem/Scope/ComponentScope/ComponentScopeTest.php @@ -54,10 +54,10 @@ public function providesTheTypesOfComponentApiMembers(): void ); $componentScope = new ComponentScope( componentDeclarationNode: $componentDeclarationNode, - parentScope: GlobalScope::get() + parentScope: GlobalScope::singleton() ); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $componentScope->getTypeOf(VariableName::from('foo')); $this->assertNotNull($actualType); @@ -123,12 +123,12 @@ public function fallsBackToParentScope(): void $componentScope = new ComponentScope( componentDeclarationNode: $componentDeclarationNode, parentScope: new DummyScope( - [IntegerType::get()], - ['bar' => IntegerType::get()] + [IntegerType::singleton()], + ['bar' => IntegerType::singleton()] ) ); - $expectedType = IntegerType::get(); + $expectedType = IntegerType::singleton(); $actualType = $componentScope->getTypeOf(VariableName::from('bar')); $this->assertNotNull($actualType); @@ -157,10 +157,10 @@ public function resolvesTypeReferencesUsingParentScope(): void ); $componentScope = new ComponentScope( componentDeclarationNode: $componentDeclarationNode, - parentScope: new DummyScope([StringType::get()]) + parentScope: new DummyScope([StringType::singleton()]) ); - $expectedType = StringType::get(); + $expectedType = StringType::singleton(); $actualType = $componentScope->getType(TypeName::from('string')); $this->assertTrue( diff --git a/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php b/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php index c06194cd..42501d6f 100644 --- a/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php +++ b/test/Unit/TypeSystem/Scope/GlobalScope/GlobalScopeTest.php @@ -37,7 +37,7 @@ final class GlobalScopeTest extends TestCase public static function primitiveTypeExamples(): array { return [ - 'string' => ['string', StringType::get()] + 'string' => ['string', StringType::singleton()] ]; } @@ -50,7 +50,7 @@ public static function primitiveTypeExamples(): array */ public function resolvesPrimitiveTypes(string $typeNameAsString, TypeInterface $expectedType): void { - $globalScope = GlobalScope::get(); + $globalScope = GlobalScope::singleton(); $actualType = $globalScope->getType(TypeName::from($typeNameAsString)); $this->assertTrue( @@ -65,7 +65,7 @@ public function resolvesPrimitiveTypes(string $typeNameAsString, TypeInterface $ */ public function knowsNoLocalNames(): void { - $globalScope = GlobalScope::get(); + $globalScope = GlobalScope::singleton(); $this->assertNull($globalScope->getTypeOf(VariableName::from('someVariable'))); } diff --git a/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php b/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php index bdfe23a4..354a4f52 100644 --- a/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php +++ b/test/Unit/TypeSystem/Type/BooleanType/BooleanTypeTest.php @@ -35,7 +35,7 @@ final class BooleanTypeTest extends TestCase */ public function providesItsTypeName(): void { - $this->assertEquals(TypeName::from('boolean'), BooleanType::get()->getName()); + $this->assertEquals(TypeName::from('boolean'), BooleanType::singleton()->getName()); } /** @@ -43,7 +43,7 @@ public function providesItsTypeName(): void */ public function booleanTypeIsSingleton(): void { - $this->assertSame(BooleanType::get(), BooleanType::get()); + $this->assertSame(BooleanType::singleton(), BooleanType::singleton()); } /** @@ -51,7 +51,7 @@ public function booleanTypeIsSingleton(): void */ public function isReturnsTrueIfGivenTypeIsBooleanType(): void { - $this->assertTrue(BooleanType::get()->is(BooleanType::get())); + $this->assertTrue(BooleanType::singleton()->is(BooleanType::singleton())); } /** @@ -59,6 +59,6 @@ public function isReturnsTrueIfGivenTypeIsBooleanType(): void */ public function isReturnsFalseIfGivenTypeIsNotBooleanType(): void { - $this->assertFalse(BooleanType::get()->is(StringType::get())); + $this->assertFalse(BooleanType::singleton()->is(StringType::singleton())); } } diff --git a/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php b/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php index 6df23bb5..a31d5d6c 100644 --- a/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php +++ b/test/Unit/TypeSystem/Type/IntegerType/IntegerTypeTest.php @@ -35,7 +35,7 @@ final class IntegerTypeTest extends TestCase */ public function providesItsTypeName(): void { - $this->assertEquals(TypeName::from('number'), IntegerType::get()->getName()); + $this->assertEquals(TypeName::from('number'), IntegerType::singleton()->getName()); } /** @@ -43,7 +43,7 @@ public function providesItsTypeName(): void */ public function integerTypeIsSingleton(): void { - $this->assertSame(IntegerType::get(), IntegerType::get()); + $this->assertSame(IntegerType::singleton(), IntegerType::singleton()); } /** @@ -51,7 +51,7 @@ public function integerTypeIsSingleton(): void */ public function isReturnsTrueIfGivenTypeIsIntegerType(): void { - $this->assertTrue(IntegerType::get()->is(IntegerType::get())); + $this->assertTrue(IntegerType::singleton()->is(IntegerType::singleton())); } /** @@ -59,6 +59,6 @@ public function isReturnsTrueIfGivenTypeIsIntegerType(): void */ public function isReturnsFalseIfGivenTypeIsNotIntegerType(): void { - $this->assertFalse(IntegerType::get()->is(StringType::get())); + $this->assertFalse(IntegerType::singleton()->is(StringType::singleton())); } } diff --git a/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php b/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php index f011c952..706ec820 100644 --- a/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php +++ b/test/Unit/TypeSystem/Type/NullType/NullTypeTest.php @@ -35,7 +35,7 @@ final class NullTypeTest extends TestCase */ public function providesItsTypeName(): void { - $this->assertEquals(TypeName::from('null'), NullType::get()->getName()); + $this->assertEquals(TypeName::from('null'), NullType::singleton()->getName()); } /** @@ -43,7 +43,7 @@ public function providesItsTypeName(): void */ public function nullTypeIsSingleton(): void { - $this->assertSame(NullType::get(), NullType::get()); + $this->assertSame(NullType::singleton(), NullType::singleton()); } /** @@ -51,7 +51,7 @@ public function nullTypeIsSingleton(): void */ public function isReturnsTrueIfGivenTypeIsNullType(): void { - $this->assertTrue(NullType::get()->is(NullType::get())); + $this->assertTrue(NullType::singleton()->is(NullType::singleton())); } /** @@ -59,6 +59,6 @@ public function isReturnsTrueIfGivenTypeIsNullType(): void */ public function isReturnsFalseIfGivenTypeIsNotNullType(): void { - $this->assertFalse(NullType::get()->is(StringType::get())); + $this->assertFalse(NullType::singleton()->is(StringType::singleton())); } } diff --git a/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php b/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php index 9d3d1d13..9a0cb27d 100644 --- a/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php +++ b/test/Unit/TypeSystem/Type/SlotType/SlotTypeTest.php @@ -35,7 +35,7 @@ final class SlotTypeTest extends TestCase */ public function providesItsTypeName(): void { - $this->assertEquals(TypeName::from('slot'), SlotType::get()->getName()); + $this->assertEquals(TypeName::from('slot'), SlotType::singleton()->getName()); } /** @@ -43,7 +43,7 @@ public function providesItsTypeName(): void */ public function stringTypeIsSingleton(): void { - $this->assertSame(SlotType::get(), SlotType::get()); + $this->assertSame(SlotType::singleton(), SlotType::singleton()); } /** @@ -51,7 +51,7 @@ public function stringTypeIsSingleton(): void */ public function isReturnsTrueIfGivenTypeIsSlotType(): void { - $this->assertTrue(SlotType::get()->is(SlotType::get())); + $this->assertTrue(SlotType::singleton()->is(SlotType::singleton())); } /** @@ -59,6 +59,6 @@ public function isReturnsTrueIfGivenTypeIsSlotType(): void */ public function isReturnsFalseIfGivenTypeIsNotSlotType(): void { - $this->assertFalse(SlotType::get()->is(IntegerType::get())); + $this->assertFalse(SlotType::singleton()->is(IntegerType::singleton())); } } diff --git a/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php b/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php index 21a1b5a6..9359f92e 100644 --- a/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php +++ b/test/Unit/TypeSystem/Type/StringType/StringTypeTest.php @@ -35,7 +35,7 @@ final class StringTypeTest extends TestCase */ public function providesItsTypeName(): void { - $this->assertEquals(TypeName::from('string'), StringType::get()->getName()); + $this->assertEquals(TypeName::from('string'), StringType::singleton()->getName()); } /** @@ -43,7 +43,7 @@ public function providesItsTypeName(): void */ public function stringTypeIsSingleton(): void { - $this->assertSame(StringType::get(), StringType::get()); + $this->assertSame(StringType::singleton(), StringType::singleton()); } /** @@ -51,7 +51,7 @@ public function stringTypeIsSingleton(): void */ public function isReturnsTrueIfGivenTypeIsStringType(): void { - $this->assertTrue(StringType::get()->is(StringType::get())); + $this->assertTrue(StringType::singleton()->is(StringType::singleton())); } /** @@ -59,6 +59,6 @@ public function isReturnsTrueIfGivenTypeIsStringType(): void */ public function isReturnsFalseIfGivenTypeIsNotStringType(): void { - $this->assertFalse(StringType::get()->is(IntegerType::get())); + $this->assertFalse(StringType::singleton()->is(IntegerType::singleton())); } } diff --git a/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php b/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php index edbdec17..437af0eb 100644 --- a/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php +++ b/test/Unit/TypeSystem/Type/UnionType/UnionTypeTest.php @@ -35,13 +35,13 @@ final class UnionTypeTest extends TestCase */ public function staticOfResolvesToGivenTypeIfOnlyOneTypeIsGiven(): void { - $unionType = UnionType::of(StringType::get()); - $this->assertTrue($unionType->is(StringType::get())); - $this->assertTrue(StringType::get()->is($unionType)); + $unionType = UnionType::of(StringType::singleton()); + $this->assertTrue($unionType->is(StringType::singleton())); + $this->assertTrue(StringType::singleton()->is($unionType)); - $unionType = UnionType::of(IntegerType::get()); - $this->assertTrue($unionType->is(IntegerType::get())); - $this->assertTrue(IntegerType::get()->is($unionType)); + $unionType = UnionType::of(IntegerType::singleton()); + $this->assertTrue($unionType->is(IntegerType::singleton())); + $this->assertTrue(IntegerType::singleton()->is($unionType)); } /** @@ -49,9 +49,9 @@ public function staticOfResolvesToGivenTypeIfOnlyOneTypeIsGiven(): void */ public function staticOfResolvesToGivenTypeIfAllGivenTypesAreIdentical(): void { - $unionType = UnionType::of(StringType::get(), StringType::get(), StringType::get()); - $this->assertTrue($unionType->is(StringType::get())); - $this->assertTrue(StringType::get()->is($unionType)); + $unionType = UnionType::of(StringType::singleton(), StringType::singleton(), StringType::singleton()); + $this->assertTrue($unionType->is(StringType::singleton())); + $this->assertTrue(StringType::singleton()->is($unionType)); } /** @@ -59,8 +59,8 @@ public function staticOfResolvesToGivenTypeIfAllGivenTypesAreIdentical(): void */ public function isReturnsTrueIfGivenTypeIsCongruentUnionType(): void { - $unionType = UnionType::of(StringType::get(), IntegerType::get()); - $otherUnionType = UnionType::of(IntegerType::get(), StringType::get()); + $unionType = UnionType::of(StringType::singleton(), IntegerType::singleton()); + $otherUnionType = UnionType::of(IntegerType::singleton(), StringType::singleton()); $this->assertTrue($unionType->is($otherUnionType)); } @@ -70,8 +70,8 @@ public function isReturnsTrueIfGivenTypeIsCongruentUnionType(): void */ public function isReturnsTrueIfGivenTypeIsCongruentUnionTypeWithRedundantMembers(): void { - $unionType = UnionType::of(StringType::get(), IntegerType::get()); - $otherUnionType = UnionType::of(IntegerType::get(), StringType::get(), IntegerType::get(), StringType::get()); + $unionType = UnionType::of(StringType::singleton(), IntegerType::singleton()); + $otherUnionType = UnionType::of(IntegerType::singleton(), StringType::singleton(), IntegerType::singleton(), StringType::singleton()); $this->assertTrue($unionType->is($otherUnionType)); } @@ -81,10 +81,10 @@ public function isReturnsTrueIfGivenTypeIsCongruentUnionTypeWithRedundantMembers */ public function isReturnsFalseIfGivenTypeIsNotAUnionType(): void { - $unionType = UnionType::of(StringType::get(), IntegerType::get()); + $unionType = UnionType::of(StringType::singleton(), IntegerType::singleton()); - $this->assertFalse($unionType->is(IntegerType::get())); - $this->assertFalse($unionType->is(StringType::get())); + $this->assertFalse($unionType->is(IntegerType::singleton())); + $this->assertFalse($unionType->is(StringType::singleton())); } /** @@ -92,8 +92,8 @@ public function isReturnsFalseIfGivenTypeIsNotAUnionType(): void */ public function isReturnsFalseIfGivenTypeIsANonCongruentUnionType(): void { - $unionType = UnionType::of(StringType::get(), IntegerType::get()); - $otherUnionType = UnionType::of(StringType::get(), BooleanType::get()); + $unionType = UnionType::of(StringType::singleton(), IntegerType::singleton()); + $otherUnionType = UnionType::of(StringType::singleton(), BooleanType::singleton()); $this->assertFalse($unionType->is($otherUnionType)); }