Skip to content

Commit 22a282c

Browse files
committed
Implement Transpilation for Match example
1 parent 7d8dc5b commit 22a282c

57 files changed

Lines changed: 1411 additions & 356 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/Module/ModuleId.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/**
4+
* PackageFactory.ComponentEngine - Universal View Components for PHP
5+
* Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
namespace PackageFactory\ComponentEngine\Module;
24+
25+
use PackageFactory\ComponentEngine\Parser\Source\Source;
26+
27+
final class ModuleId
28+
{
29+
/**
30+
* @var array<string,ModuleId>
31+
*/
32+
private static array $instances;
33+
34+
private function __construct(private readonly string $value)
35+
{
36+
}
37+
38+
public static function fromString(string $moduleIdAsString): self
39+
{
40+
return self::$instances[$moduleIdAsString] ??= new self($moduleIdAsString);
41+
}
42+
43+
public static function fromSource(Source $source): self
44+
{
45+
if ($source->path->isMemory()) {
46+
return self::fromString(
47+
sprintf(
48+
'%s#%s',
49+
$source->path,
50+
hash('sha256', $source->contents)
51+
)
52+
);
53+
} else {
54+
return self::fromString((string) $source->path);
55+
}
56+
}
57+
58+
public function __toString(): string
59+
{
60+
return $this->value;
61+
}
62+
}

src/Parser/Ast/AccessChainSegmentNodes.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222

2323
namespace PackageFactory\ComponentEngine\Parser\Ast;
2424

25-
use PackageFactory\ComponentEngine\Definition\AccessType;
26-
use PackageFactory\ComponentEngine\Definition\BinaryOperator;
2725
use PackageFactory\ComponentEngine\Parser\Tokenizer\Scanner;
2826
use PackageFactory\ComponentEngine\Parser\Tokenizer\Token;
2927
use PackageFactory\ComponentEngine\Parser\Tokenizer\TokenType;
@@ -52,6 +50,10 @@ public static function fromTokens(\Iterator $tokens): self
5250
while (true) {
5351
Scanner::skipSpaceAndComments($tokens);
5452

53+
if (Scanner::isEnd($tokens)) {
54+
break;
55+
}
56+
5557
switch (Scanner::type($tokens)) {
5658
case TokenType::PERIOD:
5759
case TokenType::OPTCHAIN:

src/Parser/Source/Source.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
*/
2828
final class Source implements \IteratorAggregate
2929
{
30-
private function __construct(
30+
public function __construct(
3131
public readonly Path $path,
3232
public readonly string $contents
3333
) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
/**
4+
* PackageFactory.ComponentEngine - Universal View Components for PHP
5+
* Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
namespace PackageFactory\ComponentEngine\Transpiler\Php\Access;
24+
25+
use PackageFactory\ComponentEngine\Parser\Ast\AccessNode;
26+
use PackageFactory\ComponentEngine\Transpiler\Php\Expression\ExpressionTranspiler;
27+
use PackageFactory\ComponentEngine\TypeSystem\Resolver\Expression\ExpressionTypeResolver;
28+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
29+
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType;
30+
31+
final class AccessTranspiler
32+
{
33+
public function __construct(private readonly ScopeInterface $scope)
34+
{
35+
}
36+
37+
public function transpile(AccessNode $accessNode): string
38+
{
39+
$expressionTranspiler = new ExpressionTranspiler(
40+
scope: $this->scope
41+
);
42+
$expressionTypeResolver = new ExpressionTypeResolver(
43+
scope: $this->scope
44+
);
45+
$typeOfRoot = $expressionTypeResolver->resolveTypeOf($accessNode->root);
46+
$result = $expressionTranspiler->transpile($accessNode->root);
47+
48+
$isFirstElement = true;
49+
foreach ($accessNode->chain->items as $accessChainNode) {
50+
if ($typeOfRoot instanceof EnumStaticType && $isFirstElement) {
51+
$result .= '::';
52+
} else {
53+
$result .= '->';
54+
}
55+
$result .= $accessChainNode->accessor->value;
56+
$isFirstElement = false;
57+
}
58+
59+
return $result;
60+
}
61+
}

src/Transpiler/Php/Attribute/AttributeTranspiler.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@
2727
use PackageFactory\ComponentEngine\Parser\Ast\StringLiteralNode;
2828
use PackageFactory\ComponentEngine\Transpiler\Php\Expression\ExpressionTranspiler;
2929
use PackageFactory\ComponentEngine\Transpiler\Php\StringLiteral\StringLiteralTranspiler;
30+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
3031

3132
final class AttributeTranspiler
3233
{
34+
public function __construct(private readonly ScopeInterface $scope)
35+
{
36+
}
37+
3338
public function transpile(AttributeNode $attributeNode): string
3439
{
3540
return sprintf(
@@ -38,7 +43,9 @@ public function transpile(AttributeNode $attributeNode): string
3843
match ($attributeNode->value::class) {
3944
ExpressionNode::class => sprintf(
4045
'\' . %s . \'',
41-
(new ExpressionTranspiler())->transpile($attributeNode->value)
46+
(new ExpressionTranspiler(
47+
scope: $this->scope
48+
))->transpile($attributeNode->value)
4249
),
4350
StringLiteralNode::class => (new StringLiteralTranspiler())->transpile($attributeNode->value)
4451
}

src/Transpiler/Php/BinaryOperation/BinaryOperationTranspiler.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@
2525
use PackageFactory\ComponentEngine\Definition\BinaryOperator;
2626
use PackageFactory\ComponentEngine\Parser\Ast\BinaryOperationNode;
2727
use PackageFactory\ComponentEngine\Transpiler\Php\Expression\ExpressionTranspiler;
28+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
2829

2930
final class BinaryOperationTranspiler
3031
{
32+
public function __construct(private readonly ScopeInterface $scope)
33+
{
34+
}
35+
3136
private function transpileBinaryOperator(BinaryOperator $binaryOperator): string
3237
{
3338
return match ($binaryOperator) {
@@ -50,6 +55,7 @@ private function transpileBinaryOperator(BinaryOperator $binaryOperator): string
5055
public function transpile(BinaryOperationNode $binaryOperationNode): string
5156
{
5257
$expressionTranspiler = new ExpressionTranspiler(
58+
scope: $this->scope,
5359
shouldAddQuotesIfNecessary: true
5460
);
5561

src/Transpiler/Php/ComponentDeclaration/ComponentDeclarationTranspiler.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@
2828
use PackageFactory\ComponentEngine\Transpiler\Php\TypeReference\TypeReferenceTranspiler;
2929
use PackageFactory\ComponentEngine\TypeSystem\Resolver\Expression\ExpressionTypeResolver;
3030
use PackageFactory\ComponentEngine\TypeSystem\Scope\ComponentScope\ComponentScope;
31+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
3132
use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType;
3233

3334
final class ComponentDeclarationTranspiler
3435
{
36+
public function __construct(private readonly ScopeInterface $scope)
37+
{
38+
}
39+
3540
public function transpile(ComponentDeclarationNode $componentDeclarationNode): string
3641
{
3742
$lines = [];
@@ -83,10 +88,15 @@ public function writeConstructorPropertyDeclarations(PropertyDeclarationNodes $p
8388

8489
public function writeReturnExpression(ComponentDeclarationNode $componentDeclarationNode): string
8590
{
91+
$componentScope = new ComponentScope(
92+
componentDeclarationNode: $componentDeclarationNode,
93+
parentScope: $this->scope
94+
);
8695
$expressionTypeResolver = new ExpressionTypeResolver(
87-
scope: new ComponentScope($componentDeclarationNode)
96+
scope: $componentScope
8897
);
8998
$expressionTranspiler = new ExpressionTranspiler(
99+
scope: $componentScope,
90100
shouldAddQuotesIfNecessary: true
91101
);
92102

src/Transpiler/Php/Expression/ExpressionTranspiler.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,60 @@
2222

2323
namespace PackageFactory\ComponentEngine\Transpiler\Php\Expression;
2424

25+
use PackageFactory\ComponentEngine\Parser\Ast\AccessNode;
2526
use PackageFactory\ComponentEngine\Parser\Ast\BinaryOperationNode;
2627
use PackageFactory\ComponentEngine\Parser\Ast\BooleanLiteralNode;
2728
use PackageFactory\ComponentEngine\Parser\Ast\ExpressionNode;
2829
use PackageFactory\ComponentEngine\Parser\Ast\IdentifierNode;
30+
use PackageFactory\ComponentEngine\Parser\Ast\MatchNode;
2931
use PackageFactory\ComponentEngine\Parser\Ast\NumberLiteralNode;
3032
use PackageFactory\ComponentEngine\Parser\Ast\StringLiteralNode;
3133
use PackageFactory\ComponentEngine\Parser\Ast\TagNode;
3234
use PackageFactory\ComponentEngine\Parser\Ast\TernaryOperationNode;
35+
use PackageFactory\ComponentEngine\Transpiler\Php\Access\AccessTranspiler;
3336
use PackageFactory\ComponentEngine\Transpiler\Php\BinaryOperation\BinaryOperationTranspiler;
3437
use PackageFactory\ComponentEngine\Transpiler\Php\BooleanLiteral\BooleanLiteralTranspiler;
3538
use PackageFactory\ComponentEngine\Transpiler\Php\Identifier\IdentifierTranspiler;
39+
use PackageFactory\ComponentEngine\Transpiler\Php\Match\MatchTranspiler;
3640
use PackageFactory\ComponentEngine\Transpiler\Php\NumberLiteral\NumberLiteralTranspiler;
3741
use PackageFactory\ComponentEngine\Transpiler\Php\StringLiteral\StringLiteralTranspiler;
3842
use PackageFactory\ComponentEngine\Transpiler\Php\Tag\TagTranspiler;
3943
use PackageFactory\ComponentEngine\Transpiler\Php\TernaryOperation\TernaryOperationTranspiler;
44+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
4045

4146
final class ExpressionTranspiler
4247
{
4348
public function __construct(
44-
private bool $shouldAddQuotesIfNecessary = false
49+
private readonly ScopeInterface $scope,
50+
private readonly bool $shouldAddQuotesIfNecessary = false
4551
) {
4652
}
4753

4854
public function transpile(ExpressionNode $expressionNode): string
4955
{
5056
$rootTranspiler = match ($expressionNode->root::class) {
51-
IdentifierNode::class => new IdentifierTranspiler(),
52-
TernaryOperationNode::class => new TernaryOperationTranspiler(),
53-
BinaryOperationNode::class => new BinaryOperationTranspiler(),
57+
AccessNode::class => new AccessTranspiler(
58+
scope: $this->scope
59+
),
60+
IdentifierNode::class => new IdentifierTranspiler(
61+
scope: $this->scope
62+
),
63+
TernaryOperationNode::class => new TernaryOperationTranspiler(
64+
scope: $this->scope
65+
),
66+
BinaryOperationNode::class => new BinaryOperationTranspiler(
67+
scope: $this->scope
68+
),
5469
BooleanLiteralNode::class => new BooleanLiteralTranspiler(),
70+
MatchNode::class => new MatchTranspiler(
71+
scope: $this->scope
72+
),
5573
NumberLiteralNode::class => new NumberLiteralTranspiler(),
5674
StringLiteralNode::class => new StringLiteralTranspiler(
5775
shouldAddQuotes: $this->shouldAddQuotesIfNecessary
5876
),
5977
TagNode::class => new TagTranspiler(
78+
scope: $this->scope,
6079
shouldAddQuotes: $this->shouldAddQuotesIfNecessary
6180
),
6281
default => throw new \Exception('@TODO: Transpile ' . $expressionNode->root::class)

src/Transpiler/Php/Identifier/IdentifierTranspiler.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,22 @@
2323
namespace PackageFactory\ComponentEngine\Transpiler\Php\Identifier;
2424

2525
use PackageFactory\ComponentEngine\Parser\Ast\IdentifierNode;
26+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
27+
use PackageFactory\ComponentEngine\TypeSystem\Type\EnumType\EnumStaticType;
2628

2729
final class IdentifierTranspiler
2830
{
31+
public function __construct(private readonly ScopeInterface $scope)
32+
{
33+
}
34+
2935
public function transpile(IdentifierNode $identifierNode): string
3036
{
31-
return '$this->' . $identifierNode->value;
37+
$typeOfIdentifiedValue = $this->scope->lookupTypeFor($identifierNode->value);
38+
39+
return match (true) {
40+
$typeOfIdentifiedValue instanceof EnumStaticType => $identifierNode->value,
41+
default => '$this->' . $identifierNode->value
42+
};
3243
}
3344
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/**
4+
* PackageFactory.ComponentEngine - Universal View Components for PHP
5+
* Copyright (C) 2022 Contributors of PackageFactory.ComponentEngine
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
namespace PackageFactory\ComponentEngine\Transpiler\Php\Match;
24+
25+
use PackageFactory\ComponentEngine\Parser\Ast\MatchNode;
26+
use PackageFactory\ComponentEngine\Transpiler\Php\Expression\ExpressionTranspiler;
27+
use PackageFactory\ComponentEngine\TypeSystem\ScopeInterface;
28+
29+
final class MatchTranspiler
30+
{
31+
public function __construct(private readonly ScopeInterface $scope)
32+
{
33+
}
34+
35+
public function transpile(MatchNode $matchNode): string
36+
{
37+
$expressionTranspiler = new ExpressionTranspiler(
38+
scope: $this->scope,
39+
shouldAddQuotesIfNecessary: true
40+
);
41+
42+
$transpiledSubject = $expressionTranspiler->transpile($matchNode->subject);
43+
$transpiledArms = [];
44+
45+
foreach ($matchNode->arms->items as $matchArmNode) {
46+
$left = [];
47+
if ($matchArmNode->left === null) {
48+
$left = ['default'];
49+
} else {
50+
foreach ($matchArmNode->left->items as $leftNode) {
51+
$left[] = $expressionTranspiler->transpile($leftNode);
52+
}
53+
}
54+
$transpiledArms[] = sprintf(
55+
'%s => %s',
56+
join(', ', $left),
57+
$expressionTranspiler->transpile($matchArmNode->right)
58+
);
59+
}
60+
61+
return sprintf(
62+
'match (%s) { %s }',
63+
$transpiledSubject,
64+
join(', ', $transpiledArms)
65+
);
66+
}
67+
}

0 commit comments

Comments
 (0)