2222
2323namespace PackageFactory \ComponentEngine \Transpiler \Php ;
2424
25+ use PackageFactory \ComponentEngine \Definition \BinaryOperator ;
2526use PackageFactory \ComponentEngine \Parser \Ast \AttributeNode ;
27+ use PackageFactory \ComponentEngine \Parser \Ast \BinaryOperationNode ;
2628use PackageFactory \ComponentEngine \Parser \Ast \ComponentDeclarationNode ;
2729use PackageFactory \ComponentEngine \Parser \Ast \EnumDeclarationNode ;
2830use PackageFactory \ComponentEngine \Parser \Ast \ExpressionNode ;
2931use PackageFactory \ComponentEngine \Parser \Ast \IdentifierNode ;
3032use PackageFactory \ComponentEngine \Parser \Ast \ModuleNode ;
33+ use PackageFactory \ComponentEngine \Parser \Ast \NumberLiteralNode ;
3134use PackageFactory \ComponentEngine \Parser \Ast \PropertyDeclarationNodes ;
3235use PackageFactory \ComponentEngine \Parser \Ast \StringLiteralNode ;
3336use PackageFactory \ComponentEngine \Parser \Ast \TagContentNode ;
3437use PackageFactory \ComponentEngine \Parser \Ast \TagNode ;
38+ use PackageFactory \ComponentEngine \Parser \Ast \TernaryOperationNode ;
3539use 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
3745final 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}
0 commit comments