feat(php): 添加对trait的支持和优化函数调用处理

- 在AstNodeType中添加isNull方法用于检查null值
- 更新CompilerBase中的参数默认值处理逻辑,支持引用参数的null默认值
- 将FuncCallOptimizer中的函数移动到合适位置并修复逻辑
- 重命名Preprocessor中的命名空间准备方法
- 在Translator中添加对trait语句的支持并抛出异常
- 添加对func_get_args和func_get_arg函数的优化实现
pull/1/head
韩天峰 5 months ago
parent ddeceec91f
commit 21b7de3905
  1. 5
      src/Php/AstNodeType.php
  2. 9
      src/Php/CompilerBase.php
  3. 71
      src/Php/FuncCallOptimizer.php
  4. 4
      src/Php/Preprocessor.php
  5. 9
      src/Php/Translator.php

@ -142,4 +142,9 @@ trait AstNodeType
{
return $expr instanceof Expr\Array_ && count($expr->items) === 0;
}
protected function isNull(NodeAbstract $expr): bool
{
return $expr instanceof Node\Expr\ConstFetch && $expr->name->toString() === 'null';
}
}

@ -1055,11 +1055,14 @@ class CompilerBase extends \PhpAot\Core\Translator
}
if ($param->default) {
if ($param->byRef) {
if (!$this->isEmptyArray($param->default)) {
$this->fatalError($param, 'Default value for parameters passed by reference must be an empty array');
} else {
if ($this->isEmptyArray($param->default)) {
$argInfo->default = 'php::getEmptyArrayRef()';
$argInfo->defaultValue = null;
} elseif ($this->isNull($param->default)) {
$argInfo->default = 'nullptr';
$argInfo->defaultValue = null;
} else {
$this->fatalError($param, 'Only null and empty array can be used as default value for reference parameter');
}
} else {
$argInfo->default = $this->parseParamDefaultValue($param->default);

@ -12,6 +12,42 @@ use PhpParser\Node;
trait FuncCallOptimizer
{
public function genFuncGetArgs(string $name, Node\Expr\FuncCall $expr): string
{
$funcDef = $this->functionDef;
$list = [];
foreach ($funcDef->argInfoList as $i => $argInfo) {
if ($argInfo->variadic) {
$tmpVar = $this->addTmpVar(self::TYPE_ARRAY);
$this->context->beforeStmtLines[] = $this->genArray($list) . ';';
$this->context->beforeStmtLines[] = $tmpVar . '.merge(' . $argInfo->name . ');';
return $tmpVar;
}
$list[] = $argInfo->name;
}
return $this->genArray($list);
}
public function genFuncGetArg(string $name, Node\Expr\FuncCall $expr)
{
$position = $expr->args[0]->value;
if ($this->isScalarInt($position)) {
$funcDef = $this->functionDef;
$posInt = intval($position->value);
foreach ($funcDef->argInfoList as $i => $argInfo) {
if ($argInfo->variadic) {
return $argInfo->name . '.offsetGet(' . ($posInt - $i) . ')';
}
if ($i == $posInt) {
return $argInfo->name;
}
}
$this->fatalError($expr, 'wrong parameter position `' . $posInt . '`');
} else {
$this->fatalError($expr, 'func_get_arg() only support scalar int');
}
}
protected function parseFuncCallWithOptimizer(string $name, Node\Expr\FuncCall $expr): string|false
{
$getArg = function ($i) use ($expr) {
@ -71,41 +107,6 @@ trait FuncCallOptimizer
return false;
}
public function genFuncGetArgs(string $name, Node\Expr\FuncCall $expr): string
{
$funcDef = $this->functionDef;
$list = [];
foreach ($funcDef->argInfoList as $i => $argInfo) {
if ($argInfo->variadic) {
$tmpVar = $this->addTmpVar(self::TYPE_ARRAY);
$this->context->beforeStmtLines[] = $this->genArray($list) . ';';
$this->context->beforeStmtLines[] = $tmpVar . '.merge(' . $argInfo->name . ');';
return $tmpVar;
}
$list[] = $argInfo->name;
}
return $this->genArray($list);
}
public function genFuncGetArg(string $name, Node\Expr\FuncCall $expr)
{
$position = $expr->args[0]->value;
if ($this->isScalarInt($position)) {
$funcDef = $this->functionDef;
$posInt = intval($position->value);
foreach ($funcDef->argInfoList as $i => $argInfo) {
if ($argInfo->variadic) {
return $argInfo->name . '.offsetGet(' . ($posInt - $i) . ')';
} elseif ($i == $posInt) {
return $argInfo->name;
}
}
$this->fatalError($expr, 'wrong parameter position `' . $posInt . '`');
} else {
$this->fatalError($expr, 'func_get_arg() only support scalar int');
}
}
protected function genFuncNumArgs(string $name, Node\Expr\FuncCall $expr): string
{
$funcDef = $this->functionDef;

@ -106,7 +106,7 @@ class Preprocessor extends CompilerBase
$type = $v->getType();
switch ($type) {
case 'Stmt_Namespace':
$this->prepareNamespaceDef($v);
$this->prepareNamespace($v);
break;
case 'Stmt_Enum':
case 'Stmt_Class':
@ -161,7 +161,7 @@ class Preprocessor extends CompilerBase
$this->symbolCallInFile[$this->file] = array_unique($this->symbolCallInFile[$this->file]);
}
protected function prepareNamespaceDef(Node\Stmt\Namespace_ $node): void
protected function prepareNamespace(Node\Stmt\Namespace_ $node): void
{
$this->resetNamespace();
$this->namespace = $node->name ? $this->parseIdentifier($node->name) : '';

@ -17,6 +17,7 @@ use PhpAot\Php\Entity\InterfaceDef;
use PhpAot\Php\Entity\MethodDef;
use PhpAot\Php\Entity\PropertyDef;
use PhpAot\Php\Exception\Redo;
use PhpAot\Php\Exception\Unsupported;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Stmt\Foreach_;
@ -825,6 +826,9 @@ class Translator extends Preprocessor
case 'Stmt_Interface':
$code .= $this->parseInterface($v2) . PHP_EOL;
break;
case 'Stmt_Trait':
$code .= $this->parseTrait($v2) . PHP_EOL;
break;
default:
abort($v2);
}
@ -1363,4 +1367,9 @@ class Translator extends Preprocessor
return $code;
}
protected function parseTrait(Node\Stmt\Trait_ $trait)
{
throw new Unsupported('Unsupported Trait ');
}
}

Loading…
Cancel
Save