diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index c607faf6..265a8316 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -273,6 +273,11 @@ class CompilerBase extends \PhpAot\Core\Translator $this->formatCppCode($file); } + public function isScalarInt(Node\Expr $position): bool + { + return $position instanceof Node\Scalar\LNumber; + } + public function getLine($node): int { return $node->getLine(); @@ -908,7 +913,7 @@ class CompilerBase extends \PhpAot\Core\Translator return self::LITERAL_STRINGS . '[' . $index . ']'; } - protected function parseScalar(Node\Scalar $expr) + protected function parseScalar(Node\Scalar $expr): string { $type = $expr->getType(); switch ($type) { diff --git a/src/Php/Constants.php b/src/Php/Constants.php index 1b41e3de..f199ca77 100644 --- a/src/Php/Constants.php +++ b/src/Php/Constants.php @@ -59,7 +59,5 @@ class Constants public const UNSUPPORTED_FUNCTIONS = [ 'compact', 'extract', - 'func_get_arg', - 'func_get_args', ]; } diff --git a/src/Php/FuncCallOptimizer.php b/src/Php/FuncCallOptimizer.php index c1b330fa..00f74a06 100644 --- a/src/Php/FuncCallOptimizer.php +++ b/src/Php/FuncCallOptimizer.php @@ -56,27 +56,74 @@ trait FuncCallOptimizer if ($name === 'array_key_exists') { return $getArg(1) . '.offsetExists(' . $getArg(0) . ')'; } + if ($name === 'func_get_arg') { + return $this->genFuncGetArg($name, $expr); + } if ($name === 'func_get_args') { - + return $this->genFuncGetArgs($name, $expr); } if ($name === 'func_num_args') { + return $this->genFuncNumArgs($name, $expr); + } + if ($name === 'function_exists') { + return $this->genFunctionExists($name, $expr); + } + 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 . '.count() + ' . $i . ')'; + return $argInfo->name . '.offsetGet(' . ($posInt - $i) . ')'; + } elseif ($i == $posInt) { + return $argInfo->name; } } - return count($funcDef->argInfoList); + $this->fatalError($expr, 'wrong parameter position `' . $posInt . '`'); + } else { + $this->fatalError($expr, 'func_get_arg() only support scalar int'); } - if ($name === 'function_exists') { - $funcName = $expr->args[0]->value; - if ($this->isScalarString($funcName)) { - $funcName = $this->getLiteralString(strtolower(trim($funcName->value, '\\'))); - return 'php::fn::function_exists(' . $funcName . ', true)'; + } + + protected function genFuncNumArgs(string $name, Node\Expr\FuncCall $expr): string + { + $funcDef = $this->functionDef; + foreach ($funcDef->argInfoList as $i => $argInfo) { + if ($argInfo->variadic) { + return '(' . $argInfo->name . '.count() + ' . $i . ')'; } - return 'php::fn::function_exists(' . $this->parseIdentifier($funcName) . ')'; } + return count($funcDef->argInfoList); + } - return false; + protected function genFunctionExists(string $name, Node\Expr\FuncCall $expr): string + { + $funcName = $expr->args[0]->value; + if ($this->isScalarString($funcName)) { + $funcName = $this->getLiteralString(strtolower(trim($funcName->value, '\\'))); + return 'php::fn::function_exists(' . $funcName . ', true)'; + } + return 'php::fn::function_exists(' . $this->parseIdentifier($funcName) . ')'; } } diff --git a/tests/aot/functions/func_get_arg.phpt b/tests/aot/functions/func_get_arg.phpt new file mode 100644 index 00000000..73e2d5a1 --- /dev/null +++ b/tests/aot/functions/func_get_arg.phpt @@ -0,0 +1,29 @@ +--TEST-- +func_get_arg +--FILE-- + +--EXPECT-- +int(10) +int(8) +int(10) \ No newline at end of file diff --git a/tests/aot/functions/func_get_args.phpt b/tests/aot/functions/func_get_args.phpt new file mode 100644 index 00000000..6219fc7a --- /dev/null +++ b/tests/aot/functions/func_get_args.phpt @@ -0,0 +1,54 @@ +--TEST-- +func_get_args +--FILE-- + +--EXPECT-- +array(3) { + [0]=> + float(2.5) + [1]=> + int(3) + [2]=> + int(10) +} +array(5) { + [0]=> + int(1) + [1]=> + int(3) + [2]=> + int(5) + [3]=> + int(8) + [4]=> + int(10) +} +array(3) { + [0]=> + int(8) + [1]=> + int(10) + [2]=> + int(12) +} \ No newline at end of file