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 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) {
zend_bailout();
@ -33,6 +35,7 @@ int main(int cpp_argc, char **cpp_argv) {
zend_first_try {
argc = php::global("argc");
argv = php::global("argv");
php_init_constant_vars();
php_main();
}
zend_catch {
@ -45,7 +48,7 @@ int main(int cpp_argc, char **cpp_argv) {
#if PPROF_ON
ProfilerStop();
#endif
php_unset_all_global_vars();
php_unset_global_vars();
php::request_shutdown();
php_embed_shutdown();
return rc;

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