TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.9 KiB
114 lines
3.9 KiB
<?php
|
|
/**
|
|
* This file is part of TypePHP.
|
|
*
|
|
* @link https://www.swoole.com/
|
|
* @contact service@swoole.com
|
|
*/
|
|
|
|
namespace TypePhp\Transform;
|
|
|
|
use PhpParser\Modifiers;
|
|
use PhpParser\Node;
|
|
use PhpParser\Node\Expr;
|
|
use PhpParser\Node\Param;
|
|
use PhpParser\Node\Stmt;
|
|
use TypePhp\Exception\SyntaxError;
|
|
|
|
final class PropertyMethodLowering
|
|
{
|
|
private const ATTRIBUTES = ['Setter', 'With'];
|
|
|
|
public static function validateTarget(Node $node): void
|
|
{
|
|
foreach (self::ATTRIBUTES as $attribute) {
|
|
if (!CompileTimeAttribute::has($node, $attribute)) {
|
|
continue;
|
|
}
|
|
if ($node instanceof Stmt\Property && !$node->isStatic()) {
|
|
continue;
|
|
}
|
|
if ($node instanceof Param && $node->isPromoted()) {
|
|
continue;
|
|
}
|
|
throw new SyntaxError($attribute . ' can only be applied to instance properties');
|
|
}
|
|
}
|
|
|
|
/** @return list<Stmt\ClassMethod> */
|
|
public static function lowerProperty(Stmt\Property $property): array
|
|
{
|
|
$setter = CompileTimeAttribute::consume($property, 'Setter');
|
|
$with = CompileTimeAttribute::consume($property, 'With');
|
|
if (!$setter && !$with) {
|
|
return [];
|
|
}
|
|
|
|
$methods = [];
|
|
foreach ($property->props as $prop) {
|
|
$name = $prop->name->toString();
|
|
if ($setter) {
|
|
$methods[] = self::createSetter($name, $property->type, $property->getAttributes());
|
|
}
|
|
if ($with) {
|
|
$methods[] = self::createWith($name, $property->type, $property->getAttributes());
|
|
}
|
|
}
|
|
return $methods;
|
|
}
|
|
|
|
/** @return list<Stmt\ClassMethod> */
|
|
public static function lowerPromotedProperty(Param $param): array
|
|
{
|
|
if (!$param->isPromoted() || !is_string($param->var->name)) {
|
|
return [];
|
|
}
|
|
$setter = CompileTimeAttribute::consume($param, 'Setter');
|
|
$with = CompileTimeAttribute::consume($param, 'With');
|
|
if (!$setter && !$with) {
|
|
return [];
|
|
}
|
|
|
|
$methods = [];
|
|
if ($setter) {
|
|
$methods[] = self::createSetter($param->var->name, $param->type, $param->getAttributes());
|
|
}
|
|
if ($with) {
|
|
$methods[] = self::createWith($param->var->name, $param->type, $param->getAttributes());
|
|
}
|
|
return $methods;
|
|
}
|
|
|
|
private static function createSetter(string $property, ?Node $type, array $attributes): Stmt\ClassMethod
|
|
{
|
|
return new Stmt\ClassMethod('set' . ucfirst($property), [
|
|
'flags' => Modifiers::PUBLIC,
|
|
'params' => [new Param(new Expr\Variable($property), type: $type === null ? null : clone $type)],
|
|
'returnType' => new Node\Identifier('void'),
|
|
'stmts' => [new Stmt\Expression(new Expr\Assign(
|
|
new Expr\PropertyFetch(new Expr\Variable('this'), $property),
|
|
new Expr\Variable($property),
|
|
))],
|
|
], $attributes);
|
|
}
|
|
|
|
private static function createWith(string $property, ?Node $type, array $attributes): Stmt\ClassMethod
|
|
{
|
|
return new Stmt\ClassMethod('with' . ucfirst($property), [
|
|
'flags' => Modifiers::PUBLIC,
|
|
'params' => [new Param(new Expr\Variable($property), type: $type === null ? null : clone $type)],
|
|
'returnType' => new Node\Name('static'),
|
|
'stmts' => [
|
|
new Stmt\Expression(new Expr\Assign(
|
|
new Expr\Variable('clone'),
|
|
new Expr\Clone_(new Expr\Variable('this')),
|
|
)),
|
|
new Stmt\Expression(new Expr\Assign(
|
|
new Expr\PropertyFetch(new Expr\Variable('clone'), $property),
|
|
new Expr\Variable($property),
|
|
)),
|
|
new Stmt\Return_(new Expr\Variable('clone')),
|
|
],
|
|
], $attributes);
|
|
}
|
|
}
|
|
|