From 780b360e7d60c121c385751be65aee5831c97ebe Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sat, 8 Apr 2023 12:56:05 +0200 Subject: [PATCH] FEATURE: Implement optchain previously TokenType::OPTCHAIN was dead code --- src/Definition/Precedence.php | 1 + src/Parser/Ast/ExpressionNode.php | 1 + src/Parser/Tokenizer/Tokenizer.php | 1 + .../Php/Transpiler/Access/AccessTranspiler.php | 3 +++ .../Php/Transpiler/Access/AccessTranspilerTest.php | 12 ++++++++++++ 5 files changed, 18 insertions(+) diff --git a/src/Definition/Precedence.php b/src/Definition/Precedence.php index 18ed2598..49da1b56 100644 --- a/src/Definition/Precedence.php +++ b/src/Definition/Precedence.php @@ -50,6 +50,7 @@ public static function forTokenType(TokenType $tokenType): self TokenType::BRACKET_ROUND_CLOSE, TokenType::BRACKET_SQUARE_OPEN, TokenType::BRACKET_SQUARE_CLOSE, + TokenType::OPTCHAIN, TokenType::PERIOD => self::ACCESS, TokenType::OPERATOR_BOOLEAN_NOT => self::UNARY, diff --git a/src/Parser/Ast/ExpressionNode.php b/src/Parser/Ast/ExpressionNode.php index 5c09d7a1..6331f5ab 100644 --- a/src/Parser/Ast/ExpressionNode.php +++ b/src/Parser/Ast/ExpressionNode.php @@ -145,6 +145,7 @@ public static function fromTokens(\Iterator $tokens, Precedence $precedence = Pr $root = BinaryOperationNode::fromTokens(new self(root: $root), $tokens); break; case TokenType::PERIOD: + case TokenType::OPTCHAIN: $root = AccessNode::fromTokens(new self(root: $root), $tokens); break; case TokenType::QUESTIONMARK: diff --git a/src/Parser/Tokenizer/Tokenizer.php b/src/Parser/Tokenizer/Tokenizer.php index c11fa077..a1af26cd 100644 --- a/src/Parser/Tokenizer/Tokenizer.php +++ b/src/Parser/Tokenizer/Tokenizer.php @@ -292,6 +292,7 @@ public static function symbol(\Iterator $fragments, ?Buffer $buffer = null): \It '!==' => $buffer->flush(TokenType::COMPARATOR_NOT_EQUAL), '->' => $buffer->flush(TokenType::ARROW_SINGLE), ':' => $buffer->flush(TokenType::COLON), + '?.' => $buffer->flush(TokenType::OPTCHAIN), '.' => $buffer->flush(TokenType::PERIOD), ',' => $buffer->flush(TokenType::COMMA), '=' => $buffer->flush(TokenType::EQUALS), diff --git a/src/Target/Php/Transpiler/Access/AccessTranspiler.php b/src/Target/Php/Transpiler/Access/AccessTranspiler.php index 891fa46d..d1e5ef46 100644 --- a/src/Target/Php/Transpiler/Access/AccessTranspiler.php +++ b/src/Target/Php/Transpiler/Access/AccessTranspiler.php @@ -22,6 +22,7 @@ namespace PackageFactory\ComponentEngine\Target\Php\Transpiler\Access; +use PackageFactory\ComponentEngine\Definition\AccessType; use PackageFactory\ComponentEngine\Parser\Ast\AccessNode; use PackageFactory\ComponentEngine\Target\Php\Transpiler\Expression\ExpressionTranspiler; use PackageFactory\ComponentEngine\TypeSystem\Resolver\Expression\ExpressionTypeResolver; @@ -49,6 +50,8 @@ public function transpile(AccessNode $accessNode): string foreach ($accessNode->chain->items as $accessChainNode) { if ($typeOfRoot instanceof EnumStaticType && $isFirstElement) { $result .= '::'; + } elseif ($accessChainNode->accessType === AccessType::OPTIONAL) { + $result .= '?->'; } else { $result .= '->'; } diff --git a/test/Unit/Target/Php/Transpiler/Access/AccessTranspilerTest.php b/test/Unit/Target/Php/Transpiler/Access/AccessTranspilerTest.php index 267514fc..ee785fd5 100644 --- a/test/Unit/Target/Php/Transpiler/Access/AccessTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/Access/AccessTranspilerTest.php @@ -43,6 +43,9 @@ public function accessExamples(): array 'a.b' => ['a.b', '$this->a->b'], 'a.b.c' => ['a.b.c', '$this->a->b->c'], 'SomeEnum.A' => ['SomeEnum.A', 'SomeEnum::A'], + 'someStruct.foo' => ['someStruct.foo', '$this->someStruct->foo'], + 'someStruct?.foo' => ['someStruct?.foo', '$this->someStruct?->foo'], + 'someStruct.deep?.foo' => ['someStruct.deep?.foo', '$this->someStruct->deep?->foo'] ]; } @@ -66,6 +69,15 @@ public function transpilesAccessNodes(string $accessAsString, string $expectedTr EnumDeclarationNode::fromString( 'enum SomeEnum { A B C }' ) + ), + 'someStruct' => StructType::fromStructDeclarationNode( + StructDeclarationNode::fromString(<<<'AFX' + struct SomeStruct { + foo: string + deep: ?SomeStruct + } + AFX + ) ) ]) );