diff --git a/.gitignore b/.gitignore index d46d61f6..9fd71973 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /.idea +/.cproject +/.project /logs /build /vendor diff --git a/bin/gen_stub.php b/bin/gen_stub.php index 4c040623..4c85073c 100644 --- a/bin/gen_stub.php +++ b/bin/gen_stub.php @@ -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"; diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index c14162d9..2b556303 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -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) { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 50bd51cc..3e6d12d7 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -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; }