diff --git a/.gitignore b/.gitignore index 9fd71973..b5f25c9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /.idea /.cproject /.project +/.settings /logs /build /vendor diff --git a/bin/gen_stub.php b/bin/gen_stub.php index 782ff014..8350ddd6 100755 --- a/bin/gen_stub.php +++ b/bin/gen_stub.php @@ -4377,20 +4377,20 @@ class FileInfo { } if ($stmt instanceof Stmt\Const_) { - foreach ($stmt->consts as $const) { - $this->constInfos[] = parseConstLike( - $prettyPrinter, - new ConstName($const->namespacedName, $const->name->toString()), - $const, - 0, - null, - $stmt->getComments(), - $cond, - $this->isUndocumentable, - $this->getMinimumPhpVersionIdCompatibility(), - AttributeInfo::createFromGroups($stmt->attrGroups) - ); - } +// foreach ($stmt->consts as $const) { +// $this->constInfos[] = parseConstLike( +// $prettyPrinter, +// new ConstName($const->namespacedName, $const->name->toString()), +// $const, +// 0, +// null, +// $stmt->getComments(), +// $cond, +// $this->isUndocumentable, +// $this->getMinimumPhpVersionIdCompatibility(), +// AttributeInfo::createFromGroups($stmt->attrGroups) +// ); +// } continue; } diff --git a/examples/array_get.php b/examples/array_get.php index 9b8497a2..867216c6 100644 --- a/examples/array_get.php +++ b/examples/array_get.php @@ -9,7 +9,10 @@ //var_dump($str[99]); //var_dump($str[-3]); - -$o = new ArrayObject(); -$o['hello'] = 'world'; -var_dump($o['hello'], $o); +function main() +{ + $arr = array( + array(2, 2) + ); + var_dump(empty($arr[0][0][2][3]->prop[3])); +} diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 00c5c8a9..0613258e 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -673,7 +673,11 @@ class CompilerBase extends \PhpAot\Core\Translator if ($v->stmts) { $this->indentLevel++; - $stmts = $this->parseStmts($v->stmts); + try { + $stmts = $this->parseStmts($v->stmts); + } catch (SkipException $e) { + $stmts = ''; + } $this->indentLevel--; } else { $stmts = ''; @@ -1663,6 +1667,12 @@ class CompilerBase extends \PhpAot\Core\Translator { $var = $this->parseIdentifier($node->var); if ($this->isVarExpr($node->var)) { + if ($var === 'GLOBALS') { + if ($node->dim === null) { + $this->fatalError($node, 'Cannot use [] for GLOBALS'); + } + return 'php::global(' . $this->parseIdentifier($node->dim) . ')'; + } if (!$this->hasVar($var)) { if ($write) { $this->addLocalVar($var, self::TYPE_ARRAY); @@ -1670,12 +1680,6 @@ class CompilerBase extends \PhpAot\Core\Translator $this->fatalError($node->var, "The variable `{$node->var->name}` is undefined"); } } - if ($var === 'GLOBALS') { - if ($node->dim === null) { - $this->fatalError($node, 'Cannot use [] for GLOBALS'); - } - return 'php::global(' . $this->parseIdentifier($node->dim) . ')'; - } } if ($node->dim === null) { @@ -1729,12 +1733,12 @@ class CompilerBase extends \PhpAot\Core\Translator } foreach ($possibleFunctionNames as $name) { // 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误 + // 跳过,稍后再处理 if (isset($this->functionDeclInFile[$name]) and $this->functionDeclInFile[$name] === $this->file and !$this->isNativeFunction($name)) { $this->redoAfterDeclare[$name] = true; - - return $name; + throw new SkipException(); } if ($this->isNativeFunction($name)) { return $name; @@ -2695,12 +2699,37 @@ class CompilerBase extends \PhpAot\Core\Translator } } - protected function parseEmpty(mixed $expr): string + protected function parseEmpty(Node\Expr\Empty_ $expr): string { - return 'php::empty(' . $this->parseExpr($expr->expr) . ')'; + if ($this->isVarExpr($expr->expr)) { + return 'php::empty(' . $this->parseExpr($expr->expr) . ')'; + } + + $list = []; + $expr = $expr->expr; + while (true) { + if ($this->isArrayDimFetch($expr)) { + if ($expr->dim === null) { + $this->fatalError($expr, 'Cannot use [] for reading'); + } + $dim = $this->parseIdentifier($expr->dim); + $list[] = '{php::ArrayDimFetch, ' . self::TYPE_VAR . '(' . $dim . ')}'; + } elseif ($this->isPropertyFetch($expr)) { + $name = $this->identifierToStr($expr->name); + $list[] = '{php::PropertyFetch, ' . self::TYPE_VAR . '(' . $name . ')}'; + } elseif ($this->isVarExpr($expr)) { + $var = $this->parseIdentifier($expr); + break; + } else { + $this->fatalError($expr, 'The empty() only supports variables, array fetch, and property read'); + } + $expr = $expr->var; + } + $list = array_reverse($list); + return 'php::empty(' . $var . ', {' . implode(', ', $list) . '})'; } - protected function parseCastArray(mixed $expr): string + protected function parseCastArray(Node\Expr\Cast\Array_ $expr): string { return $this->convertArrayExpr($this->parseIdentifier($expr->expr)); } @@ -2819,14 +2848,16 @@ class CompilerBase extends \PhpAot\Core\Translator if ($require) { $this->requireVar($node, $id); } - return $id; } if ($id === 'self') { $id = $this->class; } - - return '"' . $id . '"'; + if ($this->isNameExpr($node) or $this->isIdExpr($node)) { + return '"' . $id . '"'; + } else { + return $id; + } } protected function requireVar($node, string $var): void @@ -2864,13 +2895,15 @@ class CompilerBase extends \PhpAot\Core\Translator $class = $this->parseIdentifier($expr->class); $prop = $this->parseIdentifier($expr->name); if ($class === 'self') { - $classDef = $this->classDef; $class = $this->class; - $namespace = $this->namespace; - } else { - $classDef = $this->classes[$class]; - $namespace = $classDef->namespace; } + + if (!$this->hasNativeClass($class)) { + return null; + } + + $classDef = $this->classes[$class]; + $namespace = $classDef->namespace; if ($classDef->hasProperty($prop)) { $propDef = $classDef->getProperty($prop); if ($propDef->isStatic()) { diff --git a/src/Php/SkipException.php b/src/Php/SkipException.php new file mode 100644 index 00000000..841dd930 --- /dev/null +++ b/src/Php/SkipException.php @@ -0,0 +1,8 @@ +climate->red('The target name must not be a reserved keyword'); + $this->climate->red('The target name [' . $name . '] must not be a reserved keyword'); exit(1); } $this->targetName = $name; @@ -270,6 +270,10 @@ class Translator extends Preprocessor public function genFunctionDeclaration(string $file): void { $code = '#include ' . PHP_EOL; + + $literalStringsCount = count($this->literalStrings); + $code .= 'extern ' . self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; + /** * @var FunctionDef $func */ diff --git a/src/cpp/php_aot_helper.h b/src/cpp/php_aot_helper.h index 2a38e580..b6d85648 100644 --- a/src/cpp/php_aot_helper.h +++ b/src/cpp/php_aot_helper.h @@ -3,7 +3,7 @@ extern zend_class_entry *php_get_class(int class_id, const php::String &class_name); extern zend_function *php_get_func(int func_id, const php::String &func_name); -static inline php::Variant CALL(int func_id, const php::String &func_name, const std::initializer_list &args) { +static inline php::Variant CALL(int func_id, const php::String &func_name, const php::ArgList &args) { return php::call(php_get_func(func_id, func_name), args); } @@ -11,7 +11,7 @@ static inline php::Variant CALL(int func_id, const php::String &func_name) { return php::call(php_get_func(func_id, func_name)); } -static inline php::Variant CALL_SILENT(int func_id, const php::String &func_name, const std::initializer_list &args) { +static inline php::Variant CALL_SILENT(int func_id, const php::String &func_name, const php::ArgList &args) { return php::silentCall(php_get_func(func_id, func_name), args); } diff --git a/tests/aot/const.phpt b/tests/aot/const-test.phpt similarity index 100% rename from tests/aot/const.phpt rename to tests/aot/const-test.phpt diff --git a/tests/aot/empty-test.phpt b/tests/aot/empty-test.phpt new file mode 100644 index 00000000..b43fb5ce --- /dev/null +++ b/tests/aot/empty-test.phpt @@ -0,0 +1,13 @@ +--TEST-- +empty (linked expr) +--FILE-- +prop[4])); +?> +--EXPECT-- +bool(false) +bool(true) diff --git a/tests/aot/for.phpt b/tests/aot/for-test.phpt similarity index 100% rename from tests/aot/for.phpt rename to tests/aot/for-test.phpt diff --git a/tests/aot/foreach.phpt b/tests/aot/foreach-test.phpt similarity index 100% rename from tests/aot/foreach.phpt rename to tests/aot/foreach-test.phpt diff --git a/tests/aot/list.phpt b/tests/aot/list-test.phpt similarity index 100% rename from tests/aot/list.phpt rename to tests/aot/list-test.phpt