pull/1/head
韩天峰 8 months ago
parent bb10e4c6f2
commit 35e17771d7
  1. 0
      bin/linker.php
  2. 17
      examples/fib.php
  3. 10
      src/Php/ArgInfo.php
  4. 11
      src/Php/FunctionDef.php
  5. 110
      src/Php/Translator.php

@ -1,4 +1,12 @@
<?php <?php
function fib(int $n): int
{
if ($n == 1 || $n == 2) {
return 1;
} else {
return fib($n - 1) + fib($n - 2);
}
}
function main() function main()
{ {
@ -8,12 +16,3 @@ function main()
echo fib($n) . "\n"; echo fib($n) . "\n";
echo "Time: " . (microtime(true) - $begin) . "\n"; echo "Time: " . (microtime(true) - $begin) . "\n";
} }
function fib(int $n): int
{
if ($n == 1 || $n == 2) {
return 1;
} else {
return fib($n - 1) + fib($n - 2);
}
}

@ -0,0 +1,10 @@
<?php
namespace PhpAot\Php;
class ArgInfo
{
public string $name;
public string $type;
public string $default;
}

@ -0,0 +1,11 @@
<?php
namespace PhpAot\Php;
class FunctionDef
{
public string $name;
public array $arguments;
public string $returnType;
public int $argumentCountRequired = 0;
}

@ -14,22 +14,27 @@ use PhpParser\PrettyPrinter;
class Translator extends \PhpAot\Core\Translator class Translator extends \PhpAot\Core\Translator
{ {
const TYPE_VAR = 'php::Variant'; const TYPE_VAR = 'php::Variant';
const TYPE_BOOL = 'bool';
const TYPE_INT = 'php::Int'; const TYPE_INT = 'php::Int';
const TYPE_FLOAT = 'php::Float'; const TYPE_FLOAT = 'php::Float';
const TYPE_BOOL = 'bool'; const TYPE_OBJECT = 'php::Object';
const TYPE_ARRAY = 'php::Array';
protected string $phpxDir = '~/workspace/projects/phpx'; protected string $phpxDir = '~/workspace/projects/phpx';
protected string $lang = 'PHP'; protected string $lang = 'PHP';
protected array $typeMap = []; protected array $scope = [];
protected array $zendTypeMap = [ protected array $zendTypeMap = [
'int' => self::TYPE_INT, 'int' => self::TYPE_INT,
'float' => self::TYPE_FLOAT, 'float' => self::TYPE_FLOAT,
'bool' => 'bool', 'bool' => 'bool',
]; ];
protected array $headers = [ protected array $headers = [
'phpx.h', 'phpx.h',
]; ];
protected array $internalFunctions = [];
protected int $optimizeLevel = 5; protected int $optimizeLevel = 5;
protected string $namespace = ''; protected string $namespace = '';
@ -109,7 +114,7 @@ class Translator extends \PhpAot\Core\Translator
protected function getDetectedType($name) protected function getDetectedType($name)
{ {
return $this->typeMap[$name] ?? 'php::Variant'; return $this->scope[$name] ?? 'php::Variant';
} }
public function getZendType(string $type): string public function getZendType(string $type): string
@ -117,8 +122,15 @@ class Translator extends \PhpAot\Core\Translator
return $this->zendTypeMap[$type] ?? 'zval *'; return $this->zendTypeMap[$type] ?? 'zval *';
} }
public function isInternalFunction(string $name): bool
{
return isset($this->internalFunctions[$name]);
}
private function parseFunctionDef($v): string private function parseFunctionDef($v): string
{ {
$this->scope = [];
$def = new FunctionDef();
$names[] = $this->parseIdentifier($v->name); $names[] = $this->parseIdentifier($v->name);
if ($this->class) { if ($this->class) {
$names[] = strtolower($this->class); $names[] = strtolower($this->class);
@ -135,7 +147,11 @@ class Translator extends \PhpAot\Core\Translator
$this->returnType = 'void'; $this->returnType = 'void';
} }
$params = $this->parseParams($v->params); $def->name = $name;
$def->returnType = $this->returnType;
$this->internalFunctions[$name] = $def;
$params = $this->parseParams($v->params, $def);
$code = $this->returnType . ' ' . self::PREFIX . $name . '(' . $params . ') {' . PHP_EOL; $code = $this->returnType . ' ' . self::PREFIX . $name . '(' . $params . ') {' . PHP_EOL;
$this->indentLevel++; $this->indentLevel++;
$stmts = $this->parseStmts($v->stmts); $stmts = $this->parseStmts($v->stmts);
@ -170,14 +186,24 @@ class Translator extends \PhpAot\Core\Translator
} }
} }
private function parseParams($params) private function parseParams($params, FunctionDef $def): string
{ {
$list = []; $list = [];
$def->argumentCountRequired = count($params);
foreach ($params as $param) { foreach ($params as $param) {
$type = $this->parseType($param->type); $type = $this->parseType($param->type);
$name = $this->parseIdentifier($param->var); $name = $this->parseIdentifier($param->var);
$list[] = $type . ' ' . $name; $list[] = $type . ' ' . $name;
$this->typeMap[$name] = $type; $this->scope[$name] = $type;
$argInfo = new ArgInfo();
$argInfo->name = $name;
$argInfo->type = $type;
if (isset($param->default)) {
$def->argumentCountRequired = count($list) - 1;
$argInfo->default = $param->default->getAttribute('rawValue');
}
$def->arguments[] = $argInfo;
} }
return implode(', ', $list); return implode(', ', $list);
} }
@ -345,9 +371,9 @@ class Translator extends \PhpAot\Core\Translator
$var = $this->parseIdentifier($v->var); $var = $this->parseIdentifier($v->var);
$expr = $this->parseExpr($v->expr); $expr = $this->parseExpr($v->expr);
if (!isset($this->typeMap[$var])) { if (!$this->hasVar($var)) {
$type = $this->detectType($v->var, $v->expr); $type = $this->detectType($v->expr);
$this->typeMap[$var] = $type; $this->addVar($var, $type);
return $type . ' ' . $var . ' = ' . $expr; return $type . ' ' . $var . ' = ' . $expr;
} else { } else {
return $var . ' = ' . $expr; return $var . ' = ' . $expr;
@ -389,6 +415,16 @@ class Translator extends \PhpAot\Core\Translator
return '(' . $left . ') * (' . $right . ')'; return '(' . $left . ') * (' . $right . ')';
} }
protected function addVar(string $name, string $type): void
{
$this->scope[$name] = $type;
}
protected function hasVar(string $name)
{
return isset($this->scope[$name]);
}
private function detectType($expr): string private function detectType($expr): string
{ {
$exprType = $expr->getType(); $exprType = $expr->getType();
@ -404,6 +440,7 @@ class Translator extends \PhpAot\Core\Translator
case 'Expr_Array': case 'Expr_Array':
return 'php::Array'; return 'php::Array';
case 'Expr_BinaryOp_Plus': case 'Expr_BinaryOp_Plus':
case 'Expr_BinaryOp_Minus':
$leftType = $this->detectType($expr->left); $leftType = $this->detectType($expr->left);
$rightType = $this->detectType($expr->right); $rightType = $this->detectType($expr->right);
if ($leftType === self::TYPE_INT || $rightType === self::TYPE_INT) { if ($leftType === self::TYPE_INT || $rightType === self::TYPE_INT) {
@ -411,6 +448,13 @@ class Translator extends \PhpAot\Core\Translator
} else { } else {
return self::TYPE_VAR; return self::TYPE_VAR;
} }
case 'Expr_FuncCall':
$name = $this->parseIdentifier($expr->name);
if ($this->isInternalFunction($name)) {
return $this->internalFunctions[$name]->returnType;
} else {
return self::TYPE_VAR;
}
case 'Scalar_String': case 'Scalar_String':
default: default:
return self::TYPE_VAR; return self::TYPE_VAR;
@ -438,14 +482,19 @@ class Translator extends \PhpAot\Core\Translator
private function parseType($type) private function parseType($type)
{ {
if ($type == null) {
return self::TYPE_VAR;
}
$name = $type->name; $name = $type->name;
switch ($name) { switch ($name) {
case 'int': case 'int':
return 'php::Int'; return self::TYPE_INT;
case 'array': case 'array':
return 'php::Array'; return 'php::Array';
case 'float': case 'float':
return 'php::Float'; return self::TYPE_FLOAT;
case 'bool':
return self::TYPE_BOOL;
default: default:
debug($type); debug($type);
} }
@ -621,18 +670,27 @@ class Translator extends \PhpAot\Core\Translator
private function parseFuncCall(mixed $expr): string private function parseFuncCall(mixed $expr): string
{ {
$name = $this->parseIdentifier($expr->name); $name = $this->parseIdentifier($expr->name);
if ($this->isInternalFunction($name)) {
return self::PREFIX . $name . '(' . $this->parseArgs($expr->args, $name) . ')';
}
if (empty($expr->args)) { if (empty($expr->args)) {
return 'php::call("' . $name . '")'; return 'php::call("' . $name . '")';
} else { } else {
return 'php::call("' . $name . '", {' . $this->parseArgs($expr->args) . '})'; return 'php::call("' . $name . '", {' . $this->parseArgs($expr->args, $name) . '})';
} }
} }
private function parseArgs($args): string private function parseArgs($args, string $funcName): string
{ {
$internalFunction = $this->isInternalFunction($funcName);
$list_args = []; $list_args = [];
foreach ($args as $arg) { foreach ($args as $i => $arg) {
$list_args[] = $this->parseArg($arg); if ($internalFunction) {
$argInfo = $this->getArgInfo($funcName, $i);
$list_args[] = $this->getTypeConvertedArg($arg, $argInfo);
} else {
$list_args[] = $this->parseArg($arg);
}
} }
return implode(', ', $list_args); return implode(', ', $list_args);
} }
@ -994,4 +1052,26 @@ class Translator extends \PhpAot\Core\Translator
} }
return implode(PHP_EOL . $this->getIndent(), $out); return implode(PHP_EOL . $this->getIndent(), $out);
} }
private function getArgInfo(string $funcName, int $index): ArgInfo
{
$funcDef = $this->internalFunctions[$funcName];
return $funcDef->arguments[$index];
}
private function getTypeConvertedArg($arg, $argInfo): string
{
$expr = $this->parseArg($arg);
$type = $this->detectType($arg->value);
if ($argInfo->type === self::TYPE_INT && $type !== self::TYPE_INT) {
return '(' . $expr . ').toInt()';
}
if ($argInfo->type === self::TYPE_FLOAT && $type !== self::TYPE_FLOAT) {
return '(' . $expr . ').toFloat()';
}
if ($argInfo->type === self::TYPE_BOOL && $type !== self::TYPE_BOOL) {
return '(' . $expr . ').toBool()';
}
return $expr;
}
} }

Loading…
Cancel
Save