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.
117 lines
4.0 KiB
117 lines
4.0 KiB
<?php
|
|
/**
|
|
* This file is part of TypePHP.
|
|
*
|
|
* @link https://www.swoole.com/
|
|
* @contact service@swoole.com
|
|
*/
|
|
|
|
namespace TypePhp\Transform;
|
|
|
|
use PhpParser\Node\Expr;
|
|
use PhpParser\Node\NullableType;
|
|
use PhpParser\Node\Param;
|
|
use PhpParser\Node\Stmt;
|
|
use PhpParser\Node\UnionType;
|
|
use TypePhp\Exception\CompileTimeAttributeError;
|
|
use TypePhp\Exception\SyntaxError;
|
|
|
|
final class ParameterValidationLowering
|
|
{
|
|
public static function lowerFunction(
|
|
Stmt\Function_|Stmt\ClassMethod|Expr\Closure $function,
|
|
?callable $warning = null,
|
|
): void
|
|
{
|
|
$checks = [];
|
|
foreach ($function->params as $param) {
|
|
if (!is_string($param->var->name)) {
|
|
continue;
|
|
}
|
|
$name = $param->var->name;
|
|
$notNull = CompileTimeAttribute::find($param, 'NotNull');
|
|
if ($notNull !== null) {
|
|
if ($notNull->args !== []) {
|
|
throw new CompileTimeAttributeError(
|
|
'NotNull does not accept arguments',
|
|
$param,
|
|
'NotNull',
|
|
$notNull,
|
|
);
|
|
}
|
|
if ($warning !== null && self::isExplicitlyNullable($param)) {
|
|
$warning($param, 'NotNull is applied to nullable parameter `$' . $name . '`');
|
|
}
|
|
$checks[] = NotNullLowering::createCheck($name);
|
|
}
|
|
$notEmpty = CompileTimeAttribute::find($param, 'NotEmpty');
|
|
if ($notEmpty !== null) {
|
|
if ($notEmpty->args !== []) {
|
|
throw new CompileTimeAttributeError(
|
|
'NotEmpty does not accept arguments',
|
|
$param,
|
|
'NotEmpty',
|
|
$notEmpty,
|
|
);
|
|
}
|
|
$checks[] = NotEmptyLowering::createCheck($name);
|
|
}
|
|
$validate = CompileTimeAttribute::find($param, 'Validate');
|
|
if ($validate !== null) {
|
|
try {
|
|
$checks[] = ValidateLowering::createCheck($param, $validate);
|
|
} catch (SyntaxError $error) {
|
|
throw new CompileTimeAttributeError(
|
|
$error->getMessage(),
|
|
$param,
|
|
'Validate',
|
|
$validate,
|
|
previous: $error,
|
|
);
|
|
}
|
|
}
|
|
CompileTimeAttribute::remove($param, 'NotNull');
|
|
CompileTimeAttribute::remove($param, 'NotEmpty');
|
|
CompileTimeAttribute::remove($param, 'Validate');
|
|
}
|
|
if ($checks !== []) {
|
|
if ($function->stmts === null) {
|
|
throw new SyntaxError('Parameter validation requires a concrete function or method');
|
|
}
|
|
$function->stmts = [...$checks, ...$function->stmts];
|
|
}
|
|
}
|
|
|
|
private static function isExplicitlyNullable(Param $param): bool
|
|
{
|
|
if ($param->type instanceof NullableType) {
|
|
return true;
|
|
}
|
|
if (!$param->type instanceof UnionType) {
|
|
return false;
|
|
}
|
|
foreach ($param->type->types as $type) {
|
|
if (strcasecmp($type->toString(), 'null') === 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static function rejectArrowFunction(Expr\ArrowFunction $function): void
|
|
{
|
|
foreach ($function->params as $param) {
|
|
foreach (['NotNull', 'NotEmpty', 'Validate'] as $name) {
|
|
$attribute = CompileTimeAttribute::find($param, $name);
|
|
if ($attribute !== null) {
|
|
throw new CompileTimeAttributeError(
|
|
$name . ' is not supported on arrow function parameters',
|
|
$param,
|
|
$name,
|
|
$attribute,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|