Native 常量处理

pull/1/head
韩天峰 8 months ago
parent 4dd4b61218
commit 5f14139ace
  1. 7
      main.cc
  2. 124
      src/Php/Translator.php
  3. 50
      tests/aot/const.phpt

@ -8,7 +8,9 @@ void php_main();
extern php::Var argc; extern php::Var argc;
extern php::Var argv; extern php::Var argv;
extern void php_unset_all_global_vars();
extern void php_init_constant_vars();
extern void php_unset_global_vars();
static void throw_exception(zend_object *ex) { static void throw_exception(zend_object *ex) {
zend_bailout(); zend_bailout();
@ -33,6 +35,7 @@ int main(int cpp_argc, char **cpp_argv) {
zend_first_try { zend_first_try {
argc = php::global("argc"); argc = php::global("argc");
argv = php::global("argv"); argv = php::global("argv");
php_init_constant_vars();
php_main(); php_main();
} }
zend_catch { zend_catch {
@ -45,7 +48,7 @@ int main(int cpp_argc, char **cpp_argv) {
#if PPROF_ON #if PPROF_ON
ProfilerStop(); ProfilerStop();
#endif #endif
php_unset_all_global_vars(); php_unset_global_vars();
php::request_shutdown(); php::request_shutdown();
php_embed_shutdown(); php_embed_shutdown();
return rc; return rc;

@ -13,6 +13,7 @@ use PhpParser\NodeTraverser;
use PhpParser\ParserFactory; use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter; use PhpParser\PrettyPrinter;
use SimplePie\Exception; use SimplePie\Exception;
use stdClass;
class Translator extends \PhpAot\Core\Translator class Translator extends \PhpAot\Core\Translator
{ {
@ -99,6 +100,7 @@ class Translator extends \PhpAot\Core\Translator
private array $nativeFunctions = []; private array $nativeFunctions = [];
private array $internalFunctions = []; private array $internalFunctions = [];
private array $nativeConstants = [];
private int $optimizeLevel = 0; private int $optimizeLevel = 0;
private int $floatPrecision = 17; private int $floatPrecision = 17;
private bool $debugInfo = true; private bool $debugInfo = true;
@ -293,6 +295,9 @@ class Translator extends \PhpAot\Core\Translator
case 'Stmt_Function': case 'Stmt_Function':
$cppCode .= $this->parseFunctionDef($v) . PHP_EOL; $cppCode .= $this->parseFunctionDef($v) . PHP_EOL;
break; break;
case 'Stmt_Const':
$this->parseConstDef($v) . PHP_EOL;
break;
default: default:
abort($v); abort($v);
} }
@ -499,6 +504,7 @@ class Translator extends \PhpAot\Core\Translator
$this->beforeStmtLines = []; $this->beforeStmtLines = [];
$this->afterStmtLines = []; $this->afterStmtLines = [];
$this->writeLog('Line ' . $this->getLine($v) . ': ' . $class); $this->writeLog('Line ' . $this->getLine($v) . ': ' . $class);
$lines[] = $this->getIndent() . '// ' . $class . ' [' . $v->getStartLine() . ':' . $v->getEndLine() . ']';
switch ($class) { switch ($class) {
case 'Stmt_Expression': case 'Stmt_Expression':
$result = $this->parseExpr($v->expr) . ';'; $result = $this->parseExpr($v->expr) . ';';
@ -819,14 +825,19 @@ class Translator extends \PhpAot\Core\Translator
return implode("\n" . $this->getIndent(), $lines); return implode("\n" . $this->getIndent(), $lines);
} }
private function isFloatStr(string $str) private function isFloatStr(string $str): bool
{
return filter_var($str, FILTER_VALIDATE_FLOAT) !== false;
}
private function isIntStr(string $str): bool
{ {
return filter_var($str, FILTER_VALIDATE_FLOAT); return filter_var($str, FILTER_VALIDATE_INT) !== false;
} }
private function isIntStr(string $str) private function isBoolStr(string $str): bool
{ {
return filter_var($str, FILTER_VALIDATE_INT); return $str === 'true' || $str === 'false';
} }
private function isInternalFunction(string $fname): bool private function isInternalFunction(string $fname): bool
@ -1172,7 +1183,7 @@ class Translator extends \PhpAot\Core\Translator
if ($expr->getType() === 'Expr_Assign') { if ($expr->getType() === 'Expr_Assign') {
$left = $expr->var; $left = $expr->var;
$name = $this->parseIdentifier($left); $name = $this->parseIdentifier($left);
if (!$this->hasGlobalVar($name)) { if ($this->hasGlobalVar($name)) {
$this->fatalError($left, 'Cannot assign to global variable in for loop'); $this->fatalError($left, 'Cannot assign to global variable in for loop');
} }
if (!$this->hasVar($name)) { if (!$this->hasVar($name)) {
@ -1755,6 +1766,9 @@ class Translator extends \PhpAot\Core\Translator
case 'Stmt_Class': case 'Stmt_Class':
$code .= $this->parseClassDef($v2); $code .= $this->parseClassDef($v2);
break; break;
case 'Stmt_Const':
$this->parseConstDef($v2) . PHP_EOL;
break;
case 'Stmt_Function': case 'Stmt_Function':
$code .= $this->parseFunctionDef($v2) . PHP_EOL; $code .= $this->parseFunctionDef($v2) . PHP_EOL;
break; break;
@ -1815,7 +1829,13 @@ class Translator extends \PhpAot\Core\Translator
private function parseConstFetch(Node $expr): string private function parseConstFetch(Node $expr): string
{ {
if ($expr->name->getType() != 'Name') {
abort($expr);
}
$name = $this->parseIdentifier($expr->name); $name = $this->parseIdentifier($expr->name);
if ($this->hasConstant($name)) {
return $this->getConstant($name);
}
if ($name === 'null') { if ($name === 'null') {
return 'nullptr'; return 'nullptr';
} elseif ($name === 'true') { } elseif ($name === 'true') {
@ -2049,6 +2069,9 @@ class Translator extends \PhpAot\Core\Translator
private function detectConstType($expr): string private function detectConstType($expr): string
{ {
$name = $this->parseIdentifier($expr->name); $name = $this->parseIdentifier($expr->name);
if ($this->hasConstant($name)) {
return $this->getConstantType($name);
}
if ($name === 'true') { if ($name === 'true') {
return self::TYPE_BOOL; return self::TYPE_BOOL;
} }
@ -2219,20 +2242,52 @@ class Translator extends \PhpAot\Core\Translator
$this->indentLevel--; $this->indentLevel--;
$code .= '};' . PHP_EOL; $code .= '};' . PHP_EOL;
// 生成全局常量
$this->indentLevel++;
foreach ($this->nativeConstants as $name => $constant) {
$code .= $constant->type . ' ' . $name . ';' . PHP_EOL;
}
$this->indentLevel--;
$code .= PHP_EOL; $code .= PHP_EOL;
$code .= 'void ' . self::PREFIX . 'unset_all_global_vars() {' . PHP_EOL; $this->indentLevel++;
$lines = []; $lines = [];
foreach ($this->nativeConstants as $name => $constant) {
$lines[] = $this->getIndent() . $name . ' = ' . $constant->value . ';';
}
$this->indentLevel--;
$code .= $this->genFunction(self::PREFIX . 'init_constant_vars', 'void', [], $lines);
$code .= PHP_EOL;
$this->indentLevel++; $this->indentLevel++;
$lines = [];
foreach ($this->globalVars as $name => $type) { foreach ($this->globalVars as $name => $type) {
$lines[] = $this->getIndent() . $name . '.unset();'; $lines[] = $this->getIndent() . $name . '.unset();';
} }
foreach ($this->nativeConstants as $name => $constant) {
if ($constant->type !== self::TYPE_VAR) {
continue;
}
$lines[] = $this->getIndent() . $name . '.unset();';
}
$this->indentLevel--; $this->indentLevel--;
$code .= implode(PHP_EOL, $lines) . PHP_EOL; $code .= $this->genFunction(self::PREFIX . 'unset_global_vars', 'void', [], $lines);
$code .= '}' . PHP_EOL;
file_put_contents($file, $code); file_put_contents($file, $code);
} }
private function genFunction(string $name, string $returnType, array $args = [], array $lines = []): string
{
$_args = [];
foreach ($args as $arg => $type) {
$_args[] = $type . ' ' . $arg;
}
$code = $returnType . ' ' . $name . '(' . implode(', ', $_args) . ') {' . PHP_EOL;
$code .= implode(PHP_EOL, $lines) . PHP_EOL;
$code .= '}' . PHP_EOL;
return $code;
}
private function parseCastDouble(mixed $expr): string private function parseCastDouble(mixed $expr): string
{ {
return $this->convertFloatExpr($this->parseIdentifier($expr->expr)); return $this->convertFloatExpr($this->parseIdentifier($expr->expr));
@ -2312,6 +2367,12 @@ class Translator extends \PhpAot\Core\Translator
} }
$code .= ');' . PHP_EOL; $code .= ');' . PHP_EOL;
} }
$code .= PHP_EOL;
foreach ($this->nativeConstants as $name => $constant) {
$code .= 'extern ' . $constant->type . ' ' . $name . ';' . PHP_EOL;
}
file_put_contents($file, $code); file_put_contents($file, $code);
} }
@ -2461,4 +2522,51 @@ class Translator extends \PhpAot\Core\Translator
$this->fatalError($v, 'Label statement is not supported'); $this->fatalError($v, 'Label statement is not supported');
return $v->name->name . ':'; return $v->name->name . ':';
} }
private function parseConstDef(mixed $v2): string
{
foreach($v2->consts as $const) {
$name = $this->parseIdentifier($const->name);
$value = $this->parseIdentifier($const->value);
$this->addConstant($name, $value);
}
return '';
}
private function addConstant(string $name, string $value): void
{
$constInfo = new stdClass();
$constInfo->value = $value;
$constInfo->type = $this->detectStrValueType($value);
$this->nativeConstants[$name] = $constInfo;
}
private function hasConstant(string $name)
{
return isset($this->nativeConstants[$name]);
}
private function getConstant(string $name): string
{
return $this->nativeConstants[$name]->value;
}
private function getConstantType(string $name): string
{
return $this->nativeConstants[$name]->type;
}
private function detectStrValueType(mixed $constant): string
{
if ($this->isIntStr($constant)) {
return self::TYPE_INT;
}
if ($this->isFloatStr($constant)) {
return self::TYPE_FLOAT;
}
if ($this->isBoolStr($constant)) {
return self::TYPE_BOOL;
}
return self::TYPE_VAR;
}
} }

@ -0,0 +1,50 @@
--TEST--
consts
--FILE--
<?php
const C_I = 11;
const C_F = 1.1;
const C_S = "str";
const C_B = true;
const C_N = null;
const C_A = [1,2,3];
const C_O = new stdClass();
const C_I2 = -C_I;
const C_F2 = C_F * 2;
const C_S2 = C_S . "hello";
function main() {
var_dump(C_I);
var_dump(C_F);
var_dump(C_S);
var_dump(C_B);
var_dump(C_N);
var_dump(C_A);
var_dump(C_O);
var_dump(C_I2);
var_dump(C_F2);
var_dump(C_S2);
}
?>
--EXPECTF--
int(11)
float(1.1)
string(3) "str"
bool(true)
NULL
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
object(stdClass)#%d (0) {
}
int(-11)
float(2.2)
string(8) "strhello"
Loading…
Cancel
Save