From 192c1da52c1e7d3640205be715c2dde22afa6bd6 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Sat, 8 Apr 2023 12:12:02 +0200 Subject: [PATCH 1/4] WIP: BUGFIX: Ternary with nested variable access in condition --- src/Parser/Ast/ExpressionNode.php | 3 ++ .../TernaryOperationTranspilerTest.php | 28 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Parser/Ast/ExpressionNode.php b/src/Parser/Ast/ExpressionNode.php index 5c09d7a1..c8f50399 100644 --- a/src/Parser/Ast/ExpressionNode.php +++ b/src/Parser/Ast/ExpressionNode.php @@ -111,6 +111,9 @@ public static function fromTokens(\Iterator $tokens, Precedence $precedence = Pr break; default: $root = IdentifierNode::fromTokens($tokens); + if (!Scanner::isEnd($tokens) && Scanner::type($tokens) === TokenType::PERIOD) { + $root = AccessNode::fromTokens(new self(root: $root), $tokens); + } break; } diff --git a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php index 1a44e3d3..0e104892 100644 --- a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php @@ -23,9 +23,12 @@ namespace PackageFactory\ComponentEngine\Test\Unit\Target\Php\Transpiler\TernaryOperation; use PackageFactory\ComponentEngine\Parser\Ast\ExpressionNode; +use PackageFactory\ComponentEngine\Parser\Ast\StructDeclarationNode; use PackageFactory\ComponentEngine\Parser\Ast\TernaryOperationNode; use PackageFactory\ComponentEngine\Test\Unit\TypeSystem\Scope\Fixtures\DummyScope; use PackageFactory\ComponentEngine\Target\Php\Transpiler\TernaryOperation\TernaryOperationTranspiler; +use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType; +use PackageFactory\ComponentEngine\TypeSystem\Type\StructType\StructType; use PHPUnit\Framework\TestCase; final class TernaryOperationTranspilerTest extends TestCase @@ -46,8 +49,19 @@ public function ternaryOperationExamples(): array ]; } + public function ternaryOperationWithVariablesInConditionExamples() + { + return [ + 'true === someString ? "a" : "foo"' => ['true === someString ? "a" : "foo"', '((true === $this->someString) ? \'a\' : \'foo\')'], + 'true === someStruct.foo ? "a" : "foo"' => ['true === someStruct.foo ? "a" : "foo"', '((true === $this->someStruct->foo) ? \'a\' : \'foo\')'], + 'true === someStruct.deep.foo ? "a" : "foo"' => ['true === someStruct.deep.foo ? "a" : "foo"', '((true === $this->someStruct->deep->foo) ? \'a\' : \'foo\')'], + 'someStruct.foo === true ? "a" : "foo"' => ['someStruct.foo === true ? "a" : "foo"', '(($this->someStruct->foo === true) ? \'a\' : \'foo\')'], + ]; + } + /** * @dataProvider ternaryOperationExamples + * @dataProvider ternaryOperationWithVariablesInConditionExamples * @test * @param string $ternaryOperationAsString * @param string $expectedTranspilationResult @@ -56,7 +70,17 @@ public function ternaryOperationExamples(): array public function transpilesTernaryOperationNodes(string $ternaryOperationAsString, string $expectedTranspilationResult): void { $ternaryOperationTranspiler = new TernaryOperationTranspiler( - scope: new DummyScope() + scope: new DummyScope([ + "someString" => StringType::get(), + "someStruct" => StructType::fromStructDeclarationNode( + StructDeclarationNode::fromString(<<<'AFX' + struct SomeStruct { + foo: string + deep: ?SomeStruct + } + AFX) + ) + ]) ); $ternaryOperationNode = ExpressionNode::fromString($ternaryOperationAsString)->root; assert($ternaryOperationNode instanceof TernaryOperationNode); @@ -70,4 +94,4 @@ public function transpilesTernaryOperationNodes(string $ternaryOperationAsString $actualTranspilationResult ); } -} \ No newline at end of file +} From a7b9ece3a4f42edc2bb4e38fc6955d7f3aaa80ec Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Mon, 24 Apr 2023 10:28:59 +0200 Subject: [PATCH 2/4] BUGFIX: check $precedence in expression parsing loop I have the feeling it's the right way. It just fell like this into place. Cant 100% explain why but after debugging it i think it is right. --- src/Parser/Ast/ExpressionNode.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Parser/Ast/ExpressionNode.php b/src/Parser/Ast/ExpressionNode.php index c8f50399..fb70b0af 100644 --- a/src/Parser/Ast/ExpressionNode.php +++ b/src/Parser/Ast/ExpressionNode.php @@ -111,9 +111,6 @@ public static function fromTokens(\Iterator $tokens, Precedence $precedence = Pr break; default: $root = IdentifierNode::fromTokens($tokens); - if (!Scanner::isEnd($tokens) && Scanner::type($tokens) === TokenType::PERIOD) { - $root = AccessNode::fromTokens(new self(root: $root), $tokens); - } break; } @@ -122,15 +119,8 @@ public static function fromTokens(\Iterator $tokens, Precedence $precedence = Pr } Scanner::skipSpaceAndComments($tokens); - if (Scanner::isEnd($tokens) || $precedence->mustStopAt(Scanner::type($tokens))) { - return new self( - root: $root - ); - } - - while ($tokens->valid()) { - Scanner::skipSpaceAndComments($tokens); + while (!Scanner::isEnd($tokens) && !$precedence->mustStopAt(Scanner::type($tokens))) { switch (Scanner::type($tokens)) { case TokenType::OPERATOR_BOOLEAN_AND: case TokenType::OPERATOR_BOOLEAN_OR: @@ -157,6 +147,8 @@ public static function fromTokens(\Iterator $tokens, Precedence $precedence = Pr default: break 2; } + + Scanner::skipSpaceAndComments($tokens); } return new self( From 04f16913f719a104542e1f773bc30e8e6d3c5b6b Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 5 Jun 2023 14:09:00 +0200 Subject: [PATCH 3/4] TASK: Add return type to ternary operation examples --- .../TernaryOperation/TernaryOperationTranspilerTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php index 0e104892..db627d2b 100644 --- a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php @@ -49,7 +49,10 @@ public function ternaryOperationExamples(): array ]; } - public function ternaryOperationWithVariablesInConditionExamples() + /** + * @return array + */ + public function ternaryOperationWithVariablesInConditionExamples(): array { return [ 'true === someString ? "a" : "foo"' => ['true === someString ? "a" : "foo"', '((true === $this->someString) ? \'a\' : \'foo\')'], From 480e62e99c87663d262203ce7f4d0714754788aa Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Mon, 5 Jun 2023 14:09:39 +0200 Subject: [PATCH 4/4] TASK: Add more ternary operation with variables in condition examples --- .../TernaryOperation/TernaryOperationTranspilerTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php index db627d2b..dd8a6dcb 100644 --- a/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php +++ b/test/Unit/Target/Php/Transpiler/TernaryOperation/TernaryOperationTranspilerTest.php @@ -59,9 +59,11 @@ public function ternaryOperationWithVariablesInConditionExamples(): array 'true === someStruct.foo ? "a" : "foo"' => ['true === someStruct.foo ? "a" : "foo"', '((true === $this->someStruct->foo) ? \'a\' : \'foo\')'], 'true === someStruct.deep.foo ? "a" : "foo"' => ['true === someStruct.deep.foo ? "a" : "foo"', '((true === $this->someStruct->deep->foo) ? \'a\' : \'foo\')'], 'someStruct.foo === true ? "a" : "foo"' => ['someStruct.foo === true ? "a" : "foo"', '(($this->someStruct->foo === true) ? \'a\' : \'foo\')'], + 'someStruct.foo === true || false ? "a" : "foo"' => ['someStruct.foo === true || false ? "a" : "foo"', '(($this->someStruct->foo === true || false) ? \'a\' : \'foo\')'], + '1 + 2 + 3 === a || 5 * b || c === true && false ? "a" : "foo"' => ['1 + 2 + 3 === a || 5 * b || c === true && false ? "a" : "foo"', '((1 + 2 + 3 === $this->a || 5 * $this->b || $this->c === true && false) ? \'a\' : \'foo\')'], ]; } - + /** * @dataProvider ternaryOperationExamples * @dataProvider ternaryOperationWithVariablesInConditionExamples @@ -74,7 +76,7 @@ public function transpilesTernaryOperationNodes(string $ternaryOperationAsString { $ternaryOperationTranspiler = new TernaryOperationTranspiler( scope: new DummyScope([ - "someString" => StringType::get(), + "someString" => StringType::get(), "someStruct" => StructType::fromStructDeclarationNode( StructDeclarationNode::fromString(<<<'AFX' struct SomeStruct {