pull/1/head
韩天峰 8 months ago
parent f072f944b2
commit a25fe02e09
  1. 4
      bin/arg_info.php
  2. 8
      examples/div.php
  3. 17
      src/Php/Reflection.php
  4. 47
      src/Php/Translator.php
  5. 196
      tests/aot/arrays.phpt
  6. 48
      tests/aot/basic_variables.phpt

@ -0,0 +1,4 @@
<?php
require __DIR__ . '/bootstrap.php';
$r = \PhpAot\Php\Reflection::getFunctionParameter('array_push', 0);
var_dump($r->isPassedByReference());

@ -0,0 +1,8 @@
<?php
function main()
{
$array = [1, 232, 333, 4, 35];
sort($array);
var_dump($array);
}

@ -3,6 +3,8 @@
namespace PhpAot\Php;
use ReflectionFunction;
use ReflectionParameter;
use ReflectionUnionType;
class Reflection
{
@ -31,9 +33,22 @@ class Reflection
if (!$returnType) {
return null;
}
if ($returnType instanceof \ReflectionUnionType) {
if ($returnType instanceof ReflectionUnionType) {
return null;
}
return $returnType->getName();
}
public static function getFunctionParameter(string $fn, int $index): ?ReflectionParameter
{
$func = self::getFunction($fn);
if (!$func) {
return null;
}
$args = $func->getParameters();
if ($index >= count($args)) {
return null;
}
return $args[$index];
}
}

@ -114,6 +114,8 @@ class Translator extends \PhpAot\Core\Translator
private int $debugLine = 0;
private CLImate $climate;
private array $definedFunctions = [];
private array $beforeStmtLines = [];
private array $afterStmtLines = [];
public function __construct(string $rootPath)
{
@ -237,6 +239,7 @@ class Translator extends \PhpAot\Core\Translator
private function doConvert(string $phpCode)
{
$this->climate->info('do convert');
$parser = (new ParserFactory())->createForNewestSupportedVersion();
$ast = $parser->parse($phpCode);
@ -397,10 +400,11 @@ class Translator extends \PhpAot\Core\Translator
{
$type = $expr->getType();
switch ($type) {
case 'Name':
case 'Identifier':
case 'Expr_Variable':
return $this->escapeVarName($expr->name);
case 'Name':
case 'Identifier':
return $expr->name;
case 'Scalar_Int':
return $expr->value . 'L';
case 'Scalar_Float':
@ -440,9 +444,10 @@ class Translator extends \PhpAot\Core\Translator
private function parseStmts(array $stmts): string
{
$lines = [];
foreach ($stmts as $v) {
$class = $v->getType();
$this->beforeStmtLines = [];
$this->afterStmtLines = [];
$this->writeLog('Line ' . $this->getLine($v) . ': ' . $class);
switch ($class) {
case 'Stmt_Expression':
@ -493,7 +498,9 @@ class Translator extends \PhpAot\Core\Translator
default:
abort($v);
}
$lines = array_merge($lines, $this->beforeStmtLines);
$lines[] = $result;
$lines = array_merge($lines, $this->afterStmtLines);
}
$code = '';
@ -837,6 +844,7 @@ class Translator extends \PhpAot\Core\Translator
case 'Scalar_Int':
return self::TYPE_INT;
case 'Expr_Cast_Float':
case 'Expr_Cast_Double':
case 'Scalar_Float':
return self::TYPE_FLOAT;
case 'Expr_Cast_Bool':
@ -1169,6 +1177,7 @@ class Translator extends \PhpAot\Core\Translator
break;
}
}
if (empty($expr->args)) {
return 'php::call(' . $fn . ')';
} else {
@ -1181,20 +1190,30 @@ class Translator extends \PhpAot\Core\Translator
$internalFunction = $this->isInternalFunction($funcName);
$list_args = [];
foreach ($args as $i => $arg) {
if ($internalFunction) {
$argInfo = $this->getArgInfo($funcName, $i);
$list_args[] = $this->getTypeConvertedArg($arg, $argInfo);
} else {
$list_args[] = $this->parseArg($arg);
}
// 调用了不存在的变量,可能是引用
if ($arg->value->getType() === 'Expr_Variable') {
$name = $this->parseIdentifier($arg->value);
// 调用了不存在的变量,可能是引用
if (!$this->hasVar($name)) {
$this->addLocalVar($name, self::TYPE_REF);
} else {
$funcArg = Reflection::getFunctionParameter($funcName, 0);
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
if ($funcArg and $funcArg->isPassedByReference()) {
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_REF);
$this->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();';
$this->afterStmtLines[] = $name . ' = *' . $tmpVar . ';';
$list_args[] = $tmpVar;
continue;
}
}
}
if ($internalFunction) {
$argInfo = $this->getArgInfo($funcName, $i);
$list_args[] = $this->getTypeConvertedArg($arg, $argInfo);
} else {
$list_args[] = $this->parseArg($arg);
}
}
return implode(', ', $list_args);
}
@ -1670,7 +1689,7 @@ class Translator extends \PhpAot\Core\Translator
}
$valueVar = $this->parseIdentifier($node->valueVar);
$iteratorVar = $this->addTmpVar();
$iteratorVar = $this->genTmpVarName();
$stmts = $node->stmts;
$code = '';
@ -1712,7 +1731,7 @@ class Translator extends \PhpAot\Core\Translator
shell_exec($cmd);
}
private function addTmpVar(): string
private function genTmpVarName(): string
{
return 'tmp_var_' . $this->tmpVarIndex++;
}
@ -1735,7 +1754,7 @@ class Translator extends \PhpAot\Core\Translator
private function parseSwitch(mixed $v): string
{
$cond = $v->cond;
$tmp_var = $this->addTmpVar();
$tmp_var = $this->genTmpVarName();
$type = $this->detectExprType($cond);
$var_def = $type . ' ' . $tmp_var . ' = ' . $this->parseExpr($cond) . ';' . PHP_EOL;

@ -0,0 +1,196 @@
--TEST--
Arrays - Indexed, Associative, and Multidimensional
--FILE--
<?php
// Test indexed arrays
$indexed = [1, 2, 3, 4, 5];
var_dump($indexed);
// Test associative arrays
$assoc = [
"name" => "John",
"age" => 30,
"city" => "New York"
];
var_dump($assoc);
// Test array access
$first_element = $indexed[0];
var_dump($first_element);
$name = $assoc["name"];
var_dump($name);
// Test array modification
$indexed[0] = 10;
var_dump($indexed[0]);
$assoc["age"] = 35;
var_dump($assoc["age"]);
// Test array functions
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];
sort($numbers);
var_dump($numbers);
$assoc2 = [
"product" => "Laptop",
"price" => 999.99,
"in_stock" => true
];
$keys = array_keys($assoc2);
var_dump($keys);
$values = array_values($assoc2);
var_dump($values);
// Test multidimensional array
$multi = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
var_dump($multi);
// Access multidimensional array
$element = $multi[1][2]; // Should be 6
var_dump($element);
// Test array push
$stack = [];
array_push($stack, "first");
array_push($stack, "second");
array_push($stack, "third");
var_dump($stack);
// Test foreach loop with arrays
$output = [];
foreach ($indexed as $value) {
$output[] = $value * 2;
}
var_dump($output);
$assoc_output = [];
foreach ($assoc as $key => $value) {
$assoc_output[$key] = "Value: " . $value;
}
var_dump($assoc_output);
?>
--EXPECT--
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
array(3) {
["name"]=>
string(4) "John"
["age"]=>
int(30)
["city"]=>
string(8) "New York"
}
int(1)
string(4) "John"
int(10)
int(35)
array(8) {
[0]=>
int(1)
[1]=>
int(1)
[2]=>
int(2)
[3]=>
int(3)
[4]=>
int(4)
[5]=>
int(5)
[6]=>
int(6)
[7]=>
int(9)
}
array(3) {
[0]=>
string(7) "product"
[1]=>
string(5) "price"
[2]=>
string(8) "in_stock"
}
array(3) {
[0]=>
string(6) "Laptop"
[1]=>
float(999.99)
[2]=>
bool(true)
}
array(3) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
[1]=>
array(3) {
[0]=>
int(4)
[1]=>
int(5)
[2]=>
int(6)
}
[2]=>
array(3) {
[0]=>
int(7)
[1]=>
int(8)
[2]=>
int(9)
}
}
int(6)
array(3) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
[2]=>
string(5) "third"
}
array(5) {
[0]=>
int(20)
[1]=>
int(4)
[2]=>
int(6)
[3]=>
int(8)
[4]=>
int(10)
}
array(3) {
["name"]=>
string(11) "Value: John"
["age"]=>
string(9) "Value: 35"
["city"]=>
string(15) "Value: New York"
}

@ -0,0 +1,48 @@
--TEST--
Basic Variables and Data Types
--FILE--
<?php
// Test scalar types
$int_var = 42;
$float_var = 3.14;
$bool_var = true;
$string_var = "Hello, World!";
var_dump($int_var);
var_dump($float_var);
var_dump($bool_var);
var_dump($string_var);
// Test variable assignment and operations
$a = 10;
$b = 3;
$sum = $a + $b;
$diff = $a - $b;
$product = $a * $b;
$quotient = $a / (float) $b;
$remainder = $a % $b;
var_dump($sum);
var_dump($diff);
var_dump($product);
var_dump($quotient);
var_dump($remainder);
// Test string operations
$str1 = "Hello";
$str2 = "World";
$concat = $str1 . " " . $str2;
var_dump($concat);
?>
--EXPECT--
int(42)
float(3.14)
bool(true)
string(13) "Hello, World!"
int(13)
int(7)
int(30)
float(3.3333333333333335)
int(1)
string(11) "Hello World"
Loading…
Cancel
Save