feat(compiler): 添加类常量获取支持并优化参数信息处理

- 在 CompilerBase.php 中添加对 Expr_ClassConstFetch 类型的支持
- 修改 getArgInfo 方法签名以接收 Node 参数并添加参数不存在时的错误处理
- 修复三元运算符解析逻辑以正确处理省略中间表达式的情况
- 将 null 常量映射从 nullptr 改为 php::null
- 扩展 hasVar 方法以支持更多变量类型包括静态属性和对象属性
- 添加 parseClassConstFetch 方法用于处理类常量获取表达式
- 在 gen_stub.php 中修复缺少可见性修饰符和参数类型的处理
- 跳过生成 ext_functions 条目当类名不存在时
- 在 Translator.php 中添加存根文件生成的状态检查和错误报告
pull/1/head
韩天峰 7 months ago
parent e1bb057420
commit 9702529c0f
  1. 2
      .gitignore
  2. 9
      bin/gen_stub.php
  3. 39
      src/Php/CompilerBase.php
  4. 6
      src/Php/Translator.php

2
.gitignore vendored

@ -1,4 +1,6 @@
/.idea
/.cproject
/.project
/logs
/build
/vendor

@ -4420,7 +4420,7 @@ class FileInfo {
}
} else if ($classStmt instanceof Stmt\Property) {
if (!($classStmt->flags & Class_::VISIBILITY_MODIFIER_MASK)) {
throw new Exception("Visibility modifier is required");
$classStmt->flags |= Modifiers::PUBLIC;
}
foreach ($classStmt->props as $property) {
$propertyInfos[] = parseProperty(
@ -4776,7 +4776,7 @@ function parseFunctionLike(
$type = $param->type ? Type::fromNode($param->type) : null;
if ($type === null && !isset($docParamTypes[$varName])) {
throw new Exception("Missing parameter type");
$type = Type::fromString("mixed");
}
if ($param->default instanceof Expr\ConstFetch &&
@ -5269,10 +5269,13 @@ function generateFunctionEntries(?Name $className, array $funcInfos, ?string $co
return '';
}
$functionEntryName = "ext_functions";
if ($className) {
$underscoreName = implode("_", $className->getParts());
$functionEntryName = "class_{$underscoreName}_methods";
} else {
// 跳过生成 ext_functions
$functionEntryName = "ext_functions";
return '';
}
$code = "\nstatic const zend_function_entry {$functionEntryName}[] = {\n";

@ -585,6 +585,8 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->parseStaticCall($expr);
case 'Expr_StaticPropertyFetch':
return $this->parseStaticPropertyFetch($expr);
case 'Expr_ClassConstFetch':
return $this->parseClassConstFetch($expr);
case 'Expr_Include':
return $this->parseInclude($expr);
case 'Expr_Eval':
@ -1366,7 +1368,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->fatalError($arg, "The syntax for variable parameter expansion is not supported");
}
if ($nativeFunction) {
$argInfo = $this->getArgInfo($funcName, $i);
$argInfo = $this->getArgInfo($arg, $funcName, $i);
$list_args[] = $this->getTypeConvertedArg($arg, $argInfo);
} else {
$list_args[] = $this->parseArg($arg);
@ -1395,7 +1397,12 @@ class CompilerBase extends \PhpAot\Core\Translator
$cond = $expr->cond;
$if = $expr->if;
$else = $expr->else;
return '(' . $this->parseExpr($cond) . ') ? (' . $this->parseExpr($if) . ') : (' . $this->parseExpr($else) . ')';
if ($if === null) {
$cond = $this->parseExpr($cond);
return '(' . $cond . ') ? (' . $cond . ') : (' . $this->parseExpr($else) . ')';
} else {
return '(' . $this->parseExpr($cond) . ') ? (' . $this->parseExpr($if) . ') : (' . $this->parseExpr($else) . ')';
}
}
protected function parseBinaryOpGreater(mixed $expr): string
@ -1716,7 +1723,7 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->getConstant($name);
}
if ($name === 'null') {
return 'nullptr';
return 'php::null';
} elseif ($name === 'true') {
return 'true';
} elseif ($name === 'false') {
@ -1811,9 +1818,12 @@ class CompilerBase extends \PhpAot\Core\Translator
return '';
}
protected function getArgInfo(string $funcName, int $index): ArgInfo
protected function getArgInfo(Node $arg, string $funcName, int $index): ArgInfo
{
$funcDef = $this->nativeFunctions[$funcName];
if (!array_key_exists($index, $funcDef->argInfoList)) {
$this->fatalError($arg, "Argument `$index` of function `$funcName` not found");
}
return $funcDef->argInfoList[$index];
}
@ -2091,11 +2101,19 @@ class CompilerBase extends \PhpAot\Core\Translator
{
$vars = $expr->vars;
foreach ($vars as $var) {
$type = $var->getType();
if ($type === self::EXPR_VARIABLE) {
if ($var instanceof Node\Expr\Variable) {
return $this->hasVar($var->name) ? 'true' : 'false';
} elseif ($type === self::EXPR_ARRAY_DIM_FETCH) {
} elseif ($var instanceof Node\Expr\ArrayDimFetch) {
return $this->parseIdentifier($var->var) . ".offsetExists(" . $this->parseIdentifier($var->dim) . ')';
} elseif ($var instanceof Node\Expr\StaticPropertyFetch) {
$class = $this->parseIdentifier($var->class);
$prop = $var->name;
$class = $class === 'self' ? $this->class : $class;
return 'php::hasStaticProperty("' . $class . '", ' . $this->identifierToStr($prop) . ')';
} elseif ($var instanceof Node\Expr\PropertyFetch) {
$object = $var->var;
$prop = $var->name;
return $this->parseIdentifier($object) . '.propertyExists(' . $this->identifierToStr($prop) . ')';
} else {
abort($var);
}
@ -2242,6 +2260,13 @@ class CompilerBase extends \PhpAot\Core\Translator
return 'php::getStaticProperty(' . $this->identifierToStr($expr->class) . ', ' . $this->identifierToStr($expr->name) . ')';
}
protected function parseClassConstFetch(Node\Expr\ClassConstFetch $expr): string
{
$class = $this->parseIdentifier($expr->class);
$const = $this->parseIdentifier($expr->name);
return 'php::constant("' . $class . '::' . $const . '")';
}
protected function parseThrow(mixed $expr): string
{
if ($expr->expr->getType() != self::EXPR_VARIABLE and $expr->expr->getType() != self::EXPR_NEW) {

@ -363,10 +363,14 @@ class Translator extends Preprocessor
$this->class = $this->parseIdentifier($class->name);
if (!$this->stubFileIncluded) {
$genStubCmd = PHP_BINARY. ' ' . $this->rootPath . '/bin/gen_stub.php -f ' . $this->file;
shell_exec($genStubCmd);
$output = shell_exec($genStubCmd);
$this->climate->info('generate stub file: ' . $this->file);
$this->climate->comment($genStubCmd);
$stubFilenameWithoutExtension = str_replace([".stub.php", '.php'], "", $this->file);
$headerFile = $this->getArgInfoHeaderFile($stubFilenameWithoutExtension, true);
if (!str_starts_with($output, "Saved")) {
$this->fatalError($class, "failed to generate arginfo header file: `$headerFile`, output: $output");
}
$this->localHeaders[] = $headerFile;
$this->stubFileIncluded = true;
}

Loading…
Cancel
Save