Skip to content

Commit e228154

Browse files
committed
Implement Transpilation for Expression example
1 parent 2ae4e9f commit e228154

3 files changed

Lines changed: 103 additions & 16 deletions

File tree

src/Transpiler/Php/Transpiler.php

Lines changed: 99 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,25 @@
2222

2323
namespace PackageFactory\ComponentEngine\Transpiler\Php;
2424

25+
use PackageFactory\ComponentEngine\Definition\BinaryOperator;
2526
use PackageFactory\ComponentEngine\Parser\Ast\AttributeNode;
27+
use PackageFactory\ComponentEngine\Parser\Ast\BinaryOperationNode;
2628
use PackageFactory\ComponentEngine\Parser\Ast\ComponentDeclarationNode;
2729
use PackageFactory\ComponentEngine\Parser\Ast\EnumDeclarationNode;
2830
use PackageFactory\ComponentEngine\Parser\Ast\ExpressionNode;
2931
use PackageFactory\ComponentEngine\Parser\Ast\IdentifierNode;
3032
use PackageFactory\ComponentEngine\Parser\Ast\ModuleNode;
33+
use PackageFactory\ComponentEngine\Parser\Ast\NumberLiteralNode;
3134
use PackageFactory\ComponentEngine\Parser\Ast\PropertyDeclarationNodes;
3235
use PackageFactory\ComponentEngine\Parser\Ast\StringLiteralNode;
3336
use PackageFactory\ComponentEngine\Parser\Ast\TagContentNode;
3437
use PackageFactory\ComponentEngine\Parser\Ast\TagNode;
38+
use PackageFactory\ComponentEngine\Parser\Ast\TernaryOperationNode;
3539
use PackageFactory\ComponentEngine\Parser\Ast\TextNode;
40+
use PackageFactory\ComponentEngine\Parser\Ast\TypeReferenceNode;
41+
use PackageFactory\ComponentEngine\TypeSystem\Resolver\ExpressionTypeResolver\ExpressionTypeResolver;
42+
use PackageFactory\ComponentEngine\TypeSystem\Scope\ComponentScope\ComponentScope;
43+
use PackageFactory\ComponentEngine\TypeSystem\Type\StringType\StringType;
3644

3745
final class Transpiler
3846
{
@@ -74,7 +82,7 @@ public function transpileComponentDeclaration(ComponentDeclarationNode $componen
7482

7583
$lines[] = ' public function render(): string';
7684
$lines[] = ' {';
77-
$lines[] = $this->writeReturnExpression($componentDeclaration->returnExpression);
85+
$lines[] = $this->writeReturnExpression($componentDeclaration);
7886
$lines[] = ' }';
7987
$lines[] = '}';
8088
$lines[] = '';
@@ -110,7 +118,7 @@ public function writeConstructorPropertyDeclarations(PropertyDeclarationNodes $p
110118
$lines = [];
111119

112120
foreach ($propertyDeclarations->items as $propertyDeclaration) {
113-
$lines[] = ' public readonly ' . $propertyDeclaration->type->name . ' $' . $propertyDeclaration->name . ',';
121+
$lines[] = ' public readonly ' . $this->transpileTypeReference($propertyDeclaration->type) . ' $' . $propertyDeclaration->name . ',';
114122
}
115123

116124
if ($length = count($lines)) {
@@ -120,16 +128,20 @@ public function writeConstructorPropertyDeclarations(PropertyDeclarationNodes $p
120128
return join("\n", $lines);
121129
}
122130

123-
public function writeReturnExpression(ExpressionNode $returnExpression): string
131+
public function writeReturnExpression(ComponentDeclarationNode $componentDeclarationNode): string
124132
{
125-
$transpiledReturnExpression = match ($returnExpression->root::class) {
126-
TagNode::class => sprintf(
127-
'\'%s\'',
128-
$this->transpileTag($returnExpression->root)
129-
),
130-
IdentifierNode::class => $this->transpileIdentifier($returnExpression->root),
131-
default => throw new \Exception('@TODO: Transpile ' . $returnExpression->root::class)
132-
};
133+
$returnExpression = $componentDeclarationNode->returnExpression;
134+
$transpiledReturnExpression = $this->transpileReturnExpression($returnExpression);
135+
$expressionTypeResolver = new ExpressionTypeResolver(
136+
scope: new ComponentScope($componentDeclarationNode)
137+
);
138+
$returnTypeIsString = StringType::get()->is(
139+
$expressionTypeResolver->resolveTypeOf($returnExpression)
140+
);
141+
142+
if (!$returnTypeIsString) {
143+
$transpiledReturnExpression = '(string) ' . $transpiledReturnExpression;
144+
}
133145

134146
return ' return ' . $transpiledReturnExpression . ';';
135147
}
@@ -139,10 +151,27 @@ public function transpileExpression(ExpressionNode $expression): string
139151
return match ($expression->root::class) {
140152
TagNode::class => $this->transpileTag($expression->root),
141153
IdentifierNode::class => $this->transpileIdentifier($expression->root),
154+
TernaryOperationNode::class => $this->transpileTernaryOperation($expression->root),
155+
BinaryOperationNode::class => $this->transpileBinaryOperation($expression->root),
156+
NumberLiteralNode::class => $this->transpileNumberLiteral($expression->root),
142157
default => throw new \Exception('@TODO: Transpile ' . $expression->root::class)
143158
};
144159
}
145160

161+
public function transpileReturnExpression(ExpressionNode $returnExpression): string
162+
{
163+
return match ($returnExpression->root::class) {
164+
TagNode::class => sprintf(
165+
'\'%s\'',
166+
$this->transpileTag($returnExpression->root)
167+
),
168+
IdentifierNode::class => $this->transpileIdentifier($returnExpression->root),
169+
TernaryOperationNode::class => $this->transpileTernaryReturnExpression($returnExpression->root),
170+
BinaryOperationNode::class => $this->transpileBinaryOperation($returnExpression->root),
171+
default => throw new \Exception('@TODO: Transpile ' . $returnExpression->root::class)
172+
};
173+
}
174+
146175
public function transpileTag(TagNode $tag): string
147176
{
148177
$result = sprintf('<%s', $tag->tagName);
@@ -207,4 +236,63 @@ public function transpileText(TextNode $textNode): string
207236
{
208237
return $textNode->value;
209238
}
239+
240+
public function transpileTernaryOperation(TernaryOperationNode $ternaryOperation): string
241+
{
242+
return sprintf(
243+
'(%s ? %s : %s)',
244+
$this->transpileExpression($ternaryOperation->condition),
245+
$this->transpileExpression($ternaryOperation->true),
246+
$this->transpileExpression($ternaryOperation->false)
247+
);
248+
}
249+
250+
public function transpileTernaryReturnExpression(TernaryOperationNode $ternaryOperation): string
251+
{
252+
return sprintf(
253+
'(%s ? %s : %s)',
254+
$this->transpileReturnExpression($ternaryOperation->condition),
255+
$this->transpileReturnExpression($ternaryOperation->true),
256+
$this->transpileReturnExpression($ternaryOperation->false)
257+
);
258+
}
259+
260+
public function transpileBinaryOperation(BinaryOperationNode $binaryOperation): string
261+
{
262+
$result = $this->transpileExpression($binaryOperation->operands->first);
263+
$operator = sprintf(' %s ', $this->transpileBinaryOperator($binaryOperation->operator));
264+
265+
foreach ($binaryOperation->operands->rest as $operandNode) {
266+
$result .= $operator;
267+
$result .= $this->transpileExpression($operandNode);
268+
}
269+
270+
return sprintf('(%s)', $result);
271+
}
272+
273+
public function transpileBinaryOperator(BinaryOperator $binaryOperator): string
274+
{
275+
return match ($binaryOperator) {
276+
BinaryOperator::LESS_THAN_OR_EQUAL => '<=',
277+
BinaryOperator::MULTIPLY_BY => '*',
278+
BinaryOperator::PLUS => '+',
279+
BinaryOperator::MODULO => '%',
280+
BinaryOperator::DIVIDE_BY => '/',
281+
default => throw new \Exception('@TODO: Transpile binary operator ' . $binaryOperator->name)
282+
};
283+
}
284+
285+
public function transpileTypeReference(TypeReferenceNode $typeReference): string
286+
{
287+
if ($typeReference->name === 'number') {
288+
return 'int|float';
289+
}
290+
291+
return $typeReference->name;
292+
}
293+
294+
public function transpileNumberLiteral(NumberLiteralNode $numberLiteral): string
295+
{
296+
return $numberLiteral->value;
297+
}
210298
}

test/Integration/Examples/Expression/Expression.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@
99
final class Expression extends BaseClass
1010
{
1111
public function __construct(
12-
private readonly int|float $a,
13-
private readonly int|float $b
12+
public readonly int|float $a,
13+
public readonly int|float $b
1414
) {
1515
}
1616

1717
public function render(): string
1818
{
19-
return (string) ($this->a <= 120
20-
? $this->b * $this->a + (17 % $this->b)
21-
: $this->b / $this->a);
19+
return (string) (($this->a <= 120) ? (($this->b * $this->a) + (17 % $this->b)) : ($this->b / $this->a));
2220
}
2321
}

test/Integration/IntegrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ public function transpilerExamples(): array
119119
'ComponentWithKeywords' => ["ComponentWithKeywords"],
120120
'ComponentWithNesting' => ["ComponentWithNesting"],
121121
'Enum' => ["Enum"],
122+
'Expression' => ["Expression"],
122123
];
123124
}
124125

0 commit comments

Comments
 (0)