refactor(core): 优化代码结构和性能

- 调整 import 语句顺序,将 Node 相关引入规范化
- 规范化字符串拼接操作,统一使用点号连接
- 统一比较运算符写法,调整变量与常量的比较顺序
- 移除多余空行和分号,精简代码结构
- 标准化缩进和代码格式,提升可读性
- 优化循环和条件判断逻辑,使用前置递增递减
- 修复类定义和方法定义的格式一致性
- 更新依赖管理方式,优化编译器配置加载
pull/1/head
韩天峰 7 months ago
parent 1c074d140e
commit 8c20fd18c8
  1. 3
      src/Php/AstNodeType.php
  2. 8
      src/Php/ClassLikeDef.php
  3. 900
      src/Php/CompilerBase.php
  4. 2
      src/Php/Constants.php
  5. 82
      src/Php/Encryptor.php
  6. 119
      src/Php/Extractor.php
  7. 8
      src/Php/FileScanner.php
  8. 10
      src/Php/FileSorter.php
  9. 14
      src/Php/FuncCallOptimizer.php
  10. 1
      src/Php/FunctionDef.php
  11. 14
      src/Php/MagicMethodDetector.php
  12. 22
      src/Php/Preprocessor.php
  13. 15
      src/Php/Reflection.php
  14. 1
      src/Php/SyntaxError.php
  15. 265
      src/Php/Translator.php
  16. 17
      src/template/extension.cc.php

@ -2,9 +2,9 @@
namespace PhpAot\Php;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\NodeAbstract;
use PhpParser\Node;
trait AstNodeType
{
@ -12,6 +12,7 @@ trait AstNodeType
{
return $expr instanceof Expr\ArrayDimFetch;
}
protected function isVarExpr(NodeAbstract $expr): bool
{
return $expr instanceof Expr\Variable;

@ -8,7 +8,6 @@ class ClassLikeDef
public string $namespace;
public string $extends = '';
public function __construct(string $name, string $namespace = '')
{
$this->name = $name;
@ -17,12 +16,13 @@ class ClassLikeDef
public function getNamespacedName(bool $symbolic = true): string
{
if ($this->namespace === '') {
if ('' === $this->namespace) {
return $this->name;
}
if ($symbolic) {
return str_replace('\\', '_', $this->namespace . '_' . $this->name);
return str_replace('\\', '_', $this->namespace.'_'.$this->name);
}
return $this->namespace . '\\\\' . $this->name;
return $this->namespace.'\\\\'.$this->name;
}
}

File diff suppressed because it is too large Load Diff

@ -4,7 +4,7 @@ namespace PhpAot\Php;
class Constants
{
const array CPP_RESERVED_NAMES = [
public const array CPP_RESERVED_NAMES = [
'auto',
'break',
'case',

@ -2,9 +2,6 @@
namespace PhpAot\Php;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\PrettyPrinter\Standard;
class Encryptor extends \PhpAot\Core\Translator
@ -22,20 +19,21 @@ class Encryptor extends \PhpAot\Core\Translator
public function __construct(array $stmts)
{
$confDir = __DIR__ . '/../../config';
$confDir = __DIR__.'/../../config';
$this->stmts = $stmts;
$this->encodeMap = require $confDir . '/functions.php';
$this->encodeMap = require $confDir.'/functions.php';
$this->decodeMap = array_flip($this->encodeMap);
$this->constants = require $confDir . '/constants.php';
$this->constants = require $confDir.'/constants.php';
}
public function parseHeaders(): string
{
$lines = [];
foreach ($this->headers as $header) {
$lines[] = '#include <' . $header . '>';
$lines[] = '#include <'.$header.'>';
}
return implode(PHP_EOL, $lines) . PHP_EOL . PHP_EOL;
return implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL;
}
public function setPhpxDir($dir): void
@ -47,6 +45,7 @@ class Encryptor extends \PhpAot\Core\Translator
{
$this->parseStmts($this->stmts);
$prettyPrinter = new Standard();
return $prettyPrinter->prettyPrintFile($this->stmts);
}
@ -55,7 +54,6 @@ class Encryptor extends \PhpAot\Core\Translator
file_put_contents($file, $code);
}
public function getLine($node): int
{
return $node->getLine();
@ -86,12 +84,12 @@ class Encryptor extends \PhpAot\Core\Translator
$params = '';
}
$code = $return . ' ' . $name . '(' . $params . ') {' . PHP_EOL;
$this->indentLevel++;
$code = $return.' '.$name.'('.$params.') {'.PHP_EOL;
++$this->indentLevel;
$stmts = $this->parseStmts($v->stmts);
$this->indentLevel--;
--$this->indentLevel;
$code .= $stmts;
$code .= "}";
$code .= '}';
return $code;
}
@ -107,7 +105,7 @@ class Encryptor extends \PhpAot\Core\Translator
case 'Scalar_Float':
return $node->value;
case 'Scalar_String':
return '"' . $node->value . '"';
return '"'.$node->value.'"';
case 'Expr_Array':
return $this->parseArray($node);
case 'Expr_FuncCall':
@ -129,16 +127,16 @@ class Encryptor extends \PhpAot\Core\Translator
}
}
private function parseParams($params)
{
$list = [];
foreach ($params as $param) {
$type = $param->type ? $this->parseType($param->type) : '';
$name = $param->var ? $this->parseIdentifier($param->var) : '';
$list[] = $type . ' ' . $name;
$list[] = $type.' '.$name;
$this->typeMap[$name] = $type;
}
return implode(', ', $list);
}
@ -152,10 +150,10 @@ class Encryptor extends \PhpAot\Core\Translator
$lines[] = $this->parseFunctionDef($v);
break;
case 'Stmt_Expression':
$lines[] = $this->parseExpr($v->expr) . ';';
$lines[] = $this->parseExpr($v->expr).';';
break;
case 'Stmt_Echo':
$lines[] = $this->parseEcho($v) . ';';
$lines[] = $this->parseEcho($v).';';
break;
case 'Stmt_Return':
$this->parseReturn($v);
@ -177,8 +175,9 @@ class Encryptor extends \PhpAot\Core\Translator
}
$code = '';
foreach ($lines as $line) {
$code .= $this->getIndent() . $line . PHP_EOL;
$code .= $this->getIndent().$line.PHP_EOL;
}
return $code;
}
@ -230,7 +229,7 @@ class Encryptor extends \PhpAot\Core\Translator
private function parseEcho(mixed $v)
{
return 'php::echo(' . $this->parseExprs($v->exprs) . ')';
return 'php::echo('.$this->parseExprs($v->exprs).')';
}
private function parseExprs($exprs)
@ -239,6 +238,7 @@ class Encryptor extends \PhpAot\Core\Translator
foreach ($exprs as $expr) {
$code .= $this->parseExpr($expr);
}
return $code;
}
@ -247,12 +247,12 @@ class Encryptor extends \PhpAot\Core\Translator
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' + ' . $right;
return $left.' + '.$right;
}
private function parseReturn(mixed $v)
{
return 'return ' . $this->parseExpr($v->expr);
return 'return '.$this->parseExpr($v->expr);
}
private function parseBinaryOpMul(mixed $expr)
@ -260,7 +260,7 @@ class Encryptor extends \PhpAot\Core\Translator
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' * ' . $right;
return $left.' * '.$right;
}
private function detectType($var, $expr)
@ -284,18 +284,19 @@ class Encryptor extends \PhpAot\Core\Translator
{
$items = $node->items;
$list = [];
$this->indentLevel++;
++$this->indentLevel;
foreach ($items as $item) {
if ($item->key) {
$list[] = $this->getIndent() . '{ php::Variant(' . $this->parseIdentifier($item->key) . '), php::Variant(' . $this->parseIdentifier($item->value) . ') }';
$list[] = $this->getIndent().'{ php::Variant('.$this->parseIdentifier($item->key).'), php::Variant('.$this->parseIdentifier($item->value).') }';
} else {
$list[] = $this->getIndent() . 'php::Variant(' . $this->parseIdentifier($item->value) . ')';
$list[] = $this->getIndent().'php::Variant('.$this->parseIdentifier($item->value).')';
}
}
$this->indentLevel--;
return '{' . PHP_EOL .
implode(', ' . PHP_EOL, $list) . PHP_EOL .
$this->getIndent() .
--$this->indentLevel;
return '{'.PHP_EOL.
implode(', '.PHP_EOL, $list).PHP_EOL.
$this->getIndent().
'}';
}
@ -317,12 +318,13 @@ class Encryptor extends \PhpAot\Core\Translator
private function parseIncludes()
{
$list = [
$this->phpxDir . '/include',
$this->phpxDir.'/include',
];
$out = '$(php-config --includes) ';
foreach ($list as $li) {
$out .= '-I ' . $li . ' ';
$out .= '-I '.$li.' ';
}
return $out;
}
@ -330,12 +332,13 @@ class Encryptor extends \PhpAot\Core\Translator
{
$list = [
'$(php-config --prefix)/lib',
$this->phpxDir . '/lib',
$this->phpxDir.'/lib',
];
$out = '';
foreach ($list as $li) {
$out .= '-L ' . $li . ' ';
$out .= '-L '.$li.' ';
}
return $out;
}
@ -347,15 +350,16 @@ class Encryptor extends \PhpAot\Core\Translator
];
$out = '';
foreach ($list as $li) {
$out .= '-l' . $li . ' ';
$out .= '-l'.$li.' ';
}
return $out;
}
public function compileFile($file)
{
$cmd = 'g++ -c ' . $file . ' -o ' . $file . '.o ' . $this->parseIncludes() . $this->parseLdflags() . $this->parseLibs();
echo $cmd . PHP_EOL;
$cmd = 'g++ -c '.$file.' -o '.$file.'.o '.$this->parseIncludes().$this->parseLdflags().$this->parseLibs();
echo $cmd.PHP_EOL;
shell_exec($cmd);
}
@ -364,7 +368,7 @@ class Encryptor extends \PhpAot\Core\Translator
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' + ' . $right;
return $left.' + '.$right;
}
private function parseFuncCall($expr)
@ -372,6 +376,7 @@ class Encryptor extends \PhpAot\Core\Translator
if (isset($this->decodeMap[$expr->name])) {
$expr->name = $this->decodeMap[$expr->name];
}
return $expr;
}
@ -425,7 +430,6 @@ class Encryptor extends \PhpAot\Core\Translator
{
$name = $expr->name->name;
if (isset($this->constants[$name])) {
}
}
}

@ -13,28 +13,29 @@ class Extractor
}
/**
* 检查 ctags 是否可用
* 检查 ctags 是否可用.
*/
private function checkCtags(): void
{
$output = shell_exec("{$this->ctagsPath} --version 2>&1");
if ($output === null) {
if (null === $output) {
$this->error("未找到 ctags 命令\n安装: sudo apt install universal-ctags");
}
$this->isUniversalCtags = stripos($output, 'Universal Ctags') !== false;
$this->isUniversalCtags = false !== stripos($output, 'Universal Ctags');
if (!$this->isUniversalCtags) {
$this->warn("建议使用 Universal Ctags 以获得更好的支持");
$this->warn('建议使用 Universal Ctags 以获得更好的支持');
}
}
/**
* 提取函数定义
* 提取函数定义.
*
* @param string $filename 文件路径
* @param array $prefixes 函数名前缀列表
*
* @return array 函数列表
*/
public function extractFunctions(string $filename, array $prefixes = ['php_']): array
@ -44,7 +45,7 @@ class Extractor
}
$this->info("分析文件: {$filename}");
$this->info("函数前缀: " . implode(', ', $prefixes));
$this->info('函数前缀: '.implode(', ', $prefixes));
// 运行 ctags
$tags = $this->runCtags($filename);
@ -52,7 +53,7 @@ class Extractor
// 过滤和解析函数
$functions = [];
foreach ($tags as $tag) {
if ($tag['kind'] !== 'function') {
if ('function' !== $tag['kind']) {
continue;
}
@ -78,13 +79,13 @@ class Extractor
}
}
$this->info("找到 " . count($functions) . " 个函数");
$this->info('找到 '.count($functions).' 个函数');
return $functions;
}
/**
* 运行 ctags 命令
* 运行 ctags 命令.
*/
private function runCtags(string $filename): array
{
@ -96,8 +97,8 @@ class Extractor
$output = shell_exec($cmd);
if ($output === null) {
throw new RuntimeException("ctags 执行失败");
if (null === $output) {
throw new RuntimeException('ctags 执行失败');
}
// 解析 JSON 输出
@ -110,7 +111,7 @@ class Extractor
}
$tag = json_decode($line, true);
if ($tag === null) {
if (null === $tag) {
continue;
}
@ -121,7 +122,7 @@ class Extractor
}
/**
* 解析单个函数的详细信息
* 解析单个函数的详细信息.
*/
private function parseFunction(string $filename, array $tag): ?array
{
@ -152,21 +153,21 @@ class Extractor
'parameters' => $parameters,
'location' => [
'file' => $filename,
'line' => $lineNum
'line' => $lineNum,
],
'scope' => $tag['scope'] ?? null,
'scopeKind' => $tag['scopeKind'] ?? null
'scopeKind' => $tag['scopeKind'] ?? null,
];
}
/**
* 从源文件中提取完整的函数签名
* 从源文件中提取完整的函数签名.
*/
private function extractSignature(string $filename, int $lineNum, string $funcName): string
{
$lines = file($filename, FILE_IGNORE_NEW_LINES);
if ($lines === false || $lineNum > count($lines)) {
if (false === $lines || $lineNum > count($lines)) {
return '';
}
@ -174,12 +175,12 @@ class Extractor
$signatureLines = [];
$maxLines = min($lineNum + 20, count($lines));
for ($i = $lineNum - 1; $i < $maxLines; $i++) {
for ($i = $lineNum - 1; $i < $maxLines; ++$i) {
$line = $lines[$i];
$signatureLines[] = $line;
// 检查是否到达函数体或声明结束
if (strpos($line, '{') !== false || strpos($line, ';') !== false) {
if (false !== strpos($line, '{') || false !== strpos($line, ';')) {
break;
}
}
@ -200,12 +201,12 @@ class Extractor
}
/**
* 解析返回类型
* 解析返回类型.
*/
private function parseReturnType(string $signature, string $funcName): string
{
// 匹配: <返回类型> <函数名>(
$pattern = '/^(.+?)\s+' . preg_quote($funcName, '/') . '\s*\(/';
$pattern = '/^(.+?)\s+'.preg_quote($funcName, '/').'\s*\(/';
if (preg_match($pattern, $signature, $matches)) {
$returnType = trim($matches[1]);
@ -222,12 +223,12 @@ class Extractor
}
/**
* 解析参数列表
* 解析参数列表.
*/
private function parseParameters(string $signature, string $funcName): array
{
// 提取括号内的参数
$pattern = '/' . preg_quote($funcName, '/') . '\s*\((.*?)\)/s';
$pattern = '/'.preg_quote($funcName, '/').'\s*\((.*?)\)/s';
if (!preg_match($pattern, $signature, $matches)) {
return [];
@ -236,7 +237,7 @@ class Extractor
$paramsStr = trim($matches[1]);
// 空参数或 void
if (empty($paramsStr) || $paramsStr === 'void') {
if (empty($paramsStr) || 'void' === $paramsStr) {
return [];
}
@ -261,7 +262,7 @@ class Extractor
}
/**
* 智能分割参数(处理嵌套的模板和括号)
* 智能分割参数(处理嵌套的模板和括号).
*/
private function splitParameters(string $paramsStr): array
{
@ -270,16 +271,16 @@ class Extractor
$depth = 0;
$length = strlen($paramsStr);
for ($i = 0; $i < $length; $i++) {
for ($i = 0; $i < $length; ++$i) {
$char = $paramsStr[$i];
if ($char === '<' || $char === '(' || $char === '[') {
$depth++;
if ('<' === $char || '(' === $char || '[' === $char) {
++$depth;
$current .= $char;
} elseif ($char === '>' || $char === ')' || $char === ']') {
$depth--;
} elseif ('>' === $char || ')' === $char || ']' === $char) {
--$depth;
$current .= $char;
} elseif ($char === ',' && $depth === 0) {
} elseif (',' === $char && 0 === $depth) {
$params[] = $current;
$current = '';
} else {
@ -295,7 +296,7 @@ class Extractor
}
/**
* 解析单个参数
* 解析单个参数.
*/
private function parseParameter(string $param): ?array
{
@ -309,19 +310,19 @@ class Extractor
if (preg_match('/^(.+?)\s+(\w+)\s*$/', $param, $matches)) {
return [
'type' => trim($matches[1]),
'name' => trim($matches[2])
'name' => trim($matches[2]),
];
}
// 只有类型,没有名称
return [
'type' => $param,
'name' => ''
'name' => '',
];
}
/**
* 批量提取多个文件
* 批量提取多个文件.
*/
public function extractFromFiles(array $files, array $prefixes = ['php_']): array
{
@ -332,7 +333,7 @@ class Extractor
$functions = $this->extractFunctions($file, $prefixes);
$allFunctions = array_merge($allFunctions, $functions);
} catch (Exception $e) {
$this->error("处理文件 {$file} 失败: " . $e->getMessage());
$this->error("处理文件 {$file} 失败: ".$e->getMessage());
}
}
@ -340,7 +341,7 @@ class Extractor
}
/**
* 输出信息
* 输出信息.
*/
private function info(string $message): void
{
@ -348,7 +349,7 @@ class Extractor
}
/**
* 输出警告
* 输出警告.
*/
private function warn(string $message): void
{
@ -356,7 +357,7 @@ class Extractor
}
/**
* 输出错误并退出
* 输出错误并退出.
*/
private function error(string $message): void
{
@ -365,7 +366,7 @@ class Extractor
}
/**
* 提取函数并添加额外信息
* 提取函数并添加额外信息.
*/
public function extractWithMetadata(string $filename, array $prefixes = ['php_']): array
{
@ -380,7 +381,7 @@ class Extractor
}
/**
* 提取函数的元数据(注释、属性等)
* 提取函数的元数据(注释、属性等).
*/
private function extractMetadata(string $filename, array $func): array
{
@ -404,8 +405,8 @@ class Extractor
// 检测修饰符
$signature = $func['signature'];
$metadata['isStatic'] = strpos($signature, 'static') !== false;
$metadata['isInline'] = strpos($signature, 'inline') !== false;
$metadata['isStatic'] = false !== strpos($signature, 'static');
$metadata['isInline'] = false !== strpos($signature, 'inline');
// 提取文档注释中的标签
$metadata['docTags'] = $this->parseDocTags($comments);
@ -414,7 +415,7 @@ class Extractor
}
/**
* 提取函数前的注释
* 提取函数前的注释.
*/
private function extractComments(array $lines, int $lineNum): array
{
@ -427,21 +428,21 @@ class Extractor
// 空行
if (empty($line)) {
$i--;
--$i;
continue;
}
// C++ 风格注释
if (str_starts_with($line, '//')) {
array_unshift($comments, substr($line, 2));
$i--;
--$i;
continue;
}
// C 风格注释结束
if (str_ends_with($line, '*/')) {
$commentLines = [$line];
$i--;
--$i;
// 继续向上查找注释开始
while ($i >= 0) {
@ -451,7 +452,7 @@ class Extractor
if (str_starts_with($commentLine, '/*')) {
break;
}
$i--;
--$i;
}
// 解析多行注释
@ -461,7 +462,7 @@ class Extractor
$comment = preg_replace('#^\s*\*\s?#m', '', $comment);
array_unshift($comments, trim($comment));
$i--;
--$i;
continue;
}
@ -473,7 +474,7 @@ class Extractor
}
/**
* 检测是否是 PHP 函数宏定义
* 检测是否是 PHP 函数宏定义.
*/
private function isPHPFunction(string $signature): bool
{
@ -485,7 +486,7 @@ class Extractor
];
foreach ($phpMacros as $macro) {
if (strpos($signature, $macro) !== false) {
if (false !== strpos($signature, $macro)) {
return true;
}
}
@ -494,7 +495,7 @@ class Extractor
}
/**
* 解析文档注释标签
* 解析文档注释标签.
*/
private function parseDocTags(array $comments): array
{
@ -520,7 +521,7 @@ class Extractor
}
/**
* 生成函数统计信息
* 生成函数统计信息.
*/
public function generateStatistics(array $functions): array
{
@ -552,12 +553,12 @@ class Extractor
// 有注释的函数
if (!empty($func['metadata']['comments'])) {
$stats['withComments']++;
++$stats['withComments'];
}
// PHP 函数宏
if ($func['metadata']['isPHPFunction'] ?? false) {
$stats['isPHPFunction']++;
++$stats['isPHPFunction'];
}
}
@ -565,13 +566,13 @@ class Extractor
}
/**
* 导出为 Markdown 文档
* 导出为 Markdown 文档.
*/
public function exportToMarkdown(array $functions, string $title = 'API 文档'): string
{
$md = "# {$title}\n\n";
$md .= "生成时间: " . date('Y-m-d H:i:s') . "\n\n";
$md .= "总计: " . count($functions) . " 个函数\n\n";
$md .= '生成时间: '.date('Y-m-d H:i:s')."\n\n";
$md .= '总计: '.count($functions)." 个函数\n\n";
$md .= "---\n\n";
foreach ($functions as $func) {
@ -599,7 +600,7 @@ class Extractor
if (!empty($func['metadata']['comments'])) {
$md .= "**说明**:\n\n";
foreach ($func['metadata']['comments'] as $comment) {
$md .= $comment . "\n\n";
$md .= $comment."\n\n";
}
}

@ -2,8 +2,6 @@
namespace PhpAot\Php;
use FilesystemIterator;
class FileScanner
{
private string $directory;
@ -45,12 +43,14 @@ class FileScanner
public function addExcludePattern(string $pattern): self
{
$this->excludePatterns[] = $pattern;
return $this;
}
public function setExcludePatterns(array $patterns): self
{
$this->excludePatterns = $patterns;
return $this;
}
@ -68,6 +68,7 @@ class FileScanner
break;
}
}
return $excluded;
}
@ -75,7 +76,7 @@ class FileScanner
{
$files = [];
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->directory, FilesystemIterator::SKIP_DOTS)
new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
@ -92,6 +93,7 @@ class FileScanner
}
}
}
return $files;
}

@ -22,13 +22,13 @@ class FileSorter
$inDegree = array_fill_keys($allFiles, 0);
foreach ($dependencies as $deps) {
foreach ($deps as $dep) {
$inDegree[$dep]++;
++$inDegree[$dep];
}
}
$queue = [];
foreach ($inDegree as $file => $degree) {
if ($degree === 0) {
if (0 === $degree) {
$queue[] = $file;
}
}
@ -40,8 +40,8 @@ class FileSorter
if (isset($dependencies[$current])) {
foreach ($dependencies[$current] as $dep) {
$inDegree[$dep]--;
if ($inDegree[$dep] === 0) {
--$inDegree[$dep];
if (0 === $inDegree[$dep]) {
$queue[] = $dep;
}
}
@ -49,7 +49,7 @@ class FileSorter
}
if (count($sorted) !== count($allFiles)) {
throw new \RuntimeException("Circular dependency of function call detected");
throw new \RuntimeException('Circular dependency of function call detected');
}
return array_reverse($sorted);

@ -8,10 +8,10 @@ trait FuncCallOptimizer
{
protected function parseFuncCallWithOptimizer(string $name, Node\Expr\FuncCall $expr): string|false
{
if ($name === 'strlen' or $name === 'sizeof' or $name === 'count') {
return 'php::len(' . $this->parseIdentifier($expr->args[0]->value) . ')';
if ('strlen' === $name or 'sizeof' === $name or 'count' === $name) {
return 'php::len('.$this->parseIdentifier($expr->args[0]->value).')';
}
if (count($expr->args) == 1) {
if (1 == count($expr->args)) {
switch ($name) {
case 'intval':
return $this->convertIntExpr($this->parseExpr($expr->args[0]->value));
@ -24,19 +24,21 @@ trait FuncCallOptimizer
default:
break;
}
} elseif (count($expr->args) == 2) {
} elseif (2 == count($expr->args)) {
switch ($name) {
case 'objval':
$arg1 = $expr->args[0]->value;
$arg2 = $expr->args[1]->value;
return $this->convertObjectExpr($this->parseExpr($arg1), $this->parseExpr($arg2));
default:
break;
}
}
if ($name === 'abs') {
return 'php::math::abs(' . $this->parseIdentifier($expr->args[0]->value) . ')';
if ('abs' === $name) {
return 'php::math::abs('.$this->parseIdentifier($expr->args[0]->value).')';
}
return false;
}
}

@ -14,7 +14,6 @@ class FunctionDef
public string $params = '';
public bool $method = false;
public function __construct(string $name, string $returnType)
{
$this->name = $name;

@ -6,15 +6,15 @@ use PhpParser\NodeAbstract;
trait MagicMethodDetector
{
function checkRequiredArgNum(string $name, MethodDef $methodDef, NodeAbstract $v): void
public function checkRequiredArgNum(string $name, MethodDef $methodDef, NodeAbstract $v): void
{
if ($name == '__call' or $name == '__callStatic' or $name == '__set') {
if (count($methodDef->functionDef->argInfoList) != 2) {
$this->fatalError($v, 'Method ' . $this->class . "::$name() must take exactly 2 arguments");
if ('__call' == $name or '__callStatic' == $name or '__set' == $name) {
if (2 != count($methodDef->functionDef->argInfoList)) {
$this->fatalError($v, 'Method '.$this->class."::$name() must take exactly 2 arguments");
}
} elseif ($name == '__get') {
if (count($methodDef->functionDef->argInfoList) != 1) {
$this->fatalError($v, 'Method ' . $this->class . "::$name() must take exactly 1 argument");
} elseif ('__get' == $name) {
if (1 != count($methodDef->functionDef->argInfoList)) {
$this->fatalError($v, 'Method '.$this->class."::$name() must take exactly 1 argument");
}
}
}

@ -39,7 +39,7 @@ class Preprocessor extends CompilerBase
$this->prepareClass($v2);
break;
case 'Stmt_Function':
$this->prepareFunction($v2) . PHP_EOL;
$this->prepareFunction($v2).PHP_EOL;
break;
case 'Stmt_Use':
case 'Stmt_Const':
@ -54,13 +54,15 @@ class Preprocessor extends CompilerBase
public function getCppFile(string $file): string
{
$info = pathinfo($file);
return $this->buildDir . '/' . $this->removeCommonPrefix($this->buildDir, $info['dirname'] . '/' . $info['filename'] . '.cc');
return $this->buildDir.'/'.$this->removeCommonPrefix($this->buildDir, $info['dirname'].'/'.$info['filename'].'.cc');
}
public function getObjectFile(string $cppFile): string
{
$info = pathinfo($cppFile);
return $info['dirname'] . '/' . $info['filename'] . '.o';
return $info['dirname'].'/'.$info['filename'].'.o';
}
public function hasCppFileCache(string $file): bool
@ -72,19 +74,21 @@ class Preprocessor extends CompilerBase
if (file_exists($cppFile) and filemtime($cppFile) > filemtime($file)) {
return true;
}
return false;
}
public function prepare(string $file): void
{
if ($this->hasCppFileCache($file)) {
$this->climate->darkGray('skip: ' . $file . ', cache exists');
$this->climate->darkGray('skip: '.$file.', cache exists');
return;
}
$phpCode = $this->loadFile($file);
$this->climate->info('prepare: ' . $this->file);
$this->climate->info('prepare: '.$this->file);
try {
$ast = $this->parser->parse($phpCode);
} catch (\PhpParser\Error $e) {
@ -107,7 +111,7 @@ class Preprocessor extends CompilerBase
$this->prepareClass($v);
break;
case 'Stmt_Function':
$this->prepareFunction($v) . PHP_EOL;
$this->prepareFunction($v).PHP_EOL;
break;
case 'Stmt_Declare':
case 'Stmt_Use':
@ -116,7 +120,7 @@ class Preprocessor extends CompilerBase
case 'Stmt_Nop':
break;
default:
$this->fatalError($v, 'Unsupported statement: ' . $type);
$this->fatalError($v, 'Unsupported statement: '.$type);
break;
}
}
@ -146,7 +150,6 @@ class Preprocessor extends CompilerBase
}
}
protected function prepareClass(Node\Stmt\Class_|Node\Stmt\Trait_ $class): string
{
$this->class = $this->parseIdentifier($class->name);
@ -160,13 +163,14 @@ class Preprocessor extends CompilerBase
case 'Stmt_TraitUse':
break;
case 'Stmt_ClassMethod':
$code .= $this->prepareFunction($v) . PHP_EOL;
$code .= $this->prepareFunction($v).PHP_EOL;
break;
default:
abort($v);
}
}
$this->class = '';
return $code;
}
}

@ -2,10 +2,6 @@
namespace PhpAot\Php;
use ReflectionFunction;
use ReflectionParameter;
use ReflectionUnionType;
class Reflection
{
private static array $functions = [];
@ -14,13 +10,13 @@ class Reflection
{
if (!isset(self::$functions[$fn])) {
try {
$ref = new ReflectionFunction($fn);
;
$ref = new \ReflectionFunction($fn);
} catch (\ReflectionException $e) {
return null;
}
self::$functions[$fn] = $ref;
}
return self::$functions[$fn];
}
@ -34,13 +30,14 @@ 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
public static function getFunctionParameter(string $fn, int $index): ?\ReflectionParameter
{
$func = self::getFunction($fn);
if (!$func) {
@ -50,6 +47,7 @@ class Reflection
if ($index >= count($args)) {
return null;
}
return $args[$index];
}
@ -59,6 +57,7 @@ class Reflection
if (!$param) {
return null;
}
return $param->isPassedByReference() ? $param->getName() : null;
}
}

@ -4,5 +4,4 @@ namespace PhpAot\Php;
class SyntaxError extends \RuntimeException
{
}

@ -3,12 +3,11 @@
namespace PhpAot\Php;
use MJS\TopSort\Implementations\StringSort;
use Symfony\Component\Yaml\Yaml;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\NodeAbstract;
use PhpParser\NodeTraverser;
use Symfony\Component\Yaml\Yaml;
class Translator extends Preprocessor
{
@ -30,14 +29,14 @@ class Translator extends Preprocessor
public function __construct(string $rootPath)
{
parent::__construct($rootPath);
$this->climate->arguments->add(require __DIR__ . '/../config/compiler_options.php');
$this->climate->arguments->add(require __DIR__.'/../config/compiler_options.php');
$this->preprocessArgvAdvanced();
$this->climate->arguments->parse();
$this->optimizeLevel = $this->climate->arguments->get('optimize');
$this->buildMode = $this->climate->arguments->get('mode');
$this->debugLine = intval($this->climate->arguments->get('debug-line'));
// $this->noLiteralStrings = $this->climate->arguments->get('noLiteralStrings');
// $this->noLiteralStrings = $this->climate->arguments->get('noLiteralStrings');
$this->noLiteralStrings = true;
$this->enableProfiler = $this->climate->arguments->defined('profile');
$this->internalFunctions = array_flip(get_defined_functions()['internal']);
@ -84,7 +83,8 @@ class Translator extends Preprocessor
public function convert(string $file): string
{
if ($this->hasCppFileCache($file)) {
$this->climate->darkGray('skip: ' . $file . ', cache exists');
$this->climate->darkGray('skip: '.$file.', cache exists');
return $this->getCppFile($file);
}
$phpCode = $this->loadFile($file);
@ -96,6 +96,7 @@ class Translator extends Preprocessor
$cppFile = $this->getCppFile($file);
$this->save($cppCode, $cppFile);
$this->phpSrcFiles[] = $file;
return $cppFile;
} catch (RedoException $e) {
continue;
@ -105,14 +106,14 @@ class Translator extends Preprocessor
protected function getRegisterClassFunction(string $name): string
{
return self::PREFIX . 'register_class_' . $name;
return self::PREFIX.'register_class_'.$name;
}
protected function getRegisterClassFunctionCeList(ClassDef|InterfaceDef $classDef): array
{
$list = [];
$parentCe = $this->getParentClassCe($classDef);
if ($parentCe !== '') {
if ('' !== $parentCe) {
$list = [$parentCe];
}
// interface 没有 implements
@ -120,6 +121,7 @@ class Translator extends Preprocessor
return $list;
}
$implements = $this->getImplementCe($classDef);
return array_merge($list, $implements);
}
@ -134,12 +136,13 @@ class Translator extends Preprocessor
if (empty($depsCeList)) {
return '';
}
return 'zend_class_entry *' . implode(', zend_class_entry *', $depsCeList);
return 'zend_class_entry *'.implode(', zend_class_entry *', $depsCeList);
}
protected function getClassCe(ClassLikeDef $classDef): string
{
return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName();
return self::PREFIX.'class_entry_'.$classDef->getNamespacedName();
}
public function setTargetName(string $name): void
@ -162,6 +165,7 @@ class Translator extends Preprocessor
protected function getFilesFromDir(string $path): array
{
$scanner = new FileScanner($path);
return $scanner->scan();
}
@ -175,14 +179,14 @@ class Translator extends Preprocessor
$list = [];
foreach ($sources as $src) {
$src = trim($src);
if ($src[0] != '/') {
$absPath = $projectDir . '/' . $src;
if ('/' != $src[0]) {
$absPath = $projectDir.'/'.$src;
} else {
$absPath = $src;
}
$realPath = realpath($absPath);
if (!$realPath) {
$this->error('Source file not exists: `' . $src . '`');
$this->error('Source file not exists: `'.$src.'`');
}
if (is_file($realPath)) {
$list[] = $realPath;
@ -198,27 +202,28 @@ class Translator extends Preprocessor
if (is_array($cfg['cxxflags'])) {
$this->cxxflags = implode(' ', $cfg['cxxflags']);
} else {
$this->cxxflags = str_replace("\n", " ", $cfg['cxxflags']);
$this->cxxflags = str_replace("\n", ' ', $cfg['cxxflags']);
}
}
if (!empty($cfg['ldflags'])) {
if (is_array($cfg['ldflags'])) {
$this->ldflags = implode(' ', $cfg['ldflags']);
} else {
$this->ldflags = str_replace("\n", " ", $cfg['ldflags']);
$this->ldflags = str_replace("\n", ' ', $cfg['ldflags']);
}
}
if (!empty($cfg['name'])) {
$this->setTargetName($cfg['name']);
}
return $list;
}
public function getFiles(string $path): array
{
$realpath = realpath($path);
if ($realpath === false) {
die("path not exists: $path\n");
if (false === $realpath) {
exit("path not exists: $path\n");
}
$path = $realpath;
@ -228,16 +233,17 @@ class Translator extends Preprocessor
$this->setTargetName($targetName);
} else {
$ext = pathinfo($path, PATHINFO_EXTENSION);
if ($ext === 'yml') {
if ('yml' === $ext) {
$list = $this->parseProjectYaml($path);
} elseif ($ext === 'php') {
} elseif ('php' === $ext) {
$list = [$path];
$targetName = FileScanner::getFileName($path);
$this->setTargetName($targetName);
} else {
$this->error('Unsupported file type: ' . $path);
$this->error('Unsupported file type: '.$path);
}
}
return $list;
}
@ -245,7 +251,7 @@ class Translator extends Preprocessor
{
return [
'func' => 'php::getClassEntry',
'args' => '"' . substr($ce, strlen(self::PREFIX . 'class_entry_')) . '"',
'args' => '"'.substr($ce, strlen(self::PREFIX.'class_entry_')).'"',
];
}
@ -254,21 +260,23 @@ class Translator extends Preprocessor
if (!$classDef->extends) {
return '';
}
return self::PREFIX . 'class_entry_' . $classDef->extends;
return self::PREFIX.'class_entry_'.$classDef->extends;
}
private function getImplementCe(ClassDef $classDef): array
{
$list = [];
foreach ($classDef->implements as $interface) {
$list[] = self::PREFIX . 'class_entry_' . $interface;
$list[] = self::PREFIX.'class_entry_'.$interface;
}
return $list;
}
protected function doConvert(string $phpCode): string
{
$this->climate->info('convert: ' . $this->file);
$this->climate->info('convert: '.$this->file);
$ast = $this->parser->parse($phpCode);
$traverser = new NodeTraverser();
@ -296,16 +304,16 @@ class Translator extends Preprocessor
$cppCode .= $this->parseClass($v);
break;
case 'Stmt_Use':
$cppCode .= $this->parseUse($v) . PHP_EOL;
$cppCode .= $this->parseUse($v).PHP_EOL;
break;
case 'Stmt_Function':
$cppCode .= $this->parseFunction($v) . PHP_EOL;
$cppCode .= $this->parseFunction($v).PHP_EOL;
break;
case 'Stmt_Const':
$this->parseConstDef($v) . PHP_EOL;
$this->parseConstDef($v).PHP_EOL;
break;
case 'Stmt_Interface':
$this->parseInterface($v) . PHP_EOL;
$this->parseInterface($v).PHP_EOL;
break;
case 'Stmt_Nop':
break;
@ -326,7 +334,7 @@ class Translator extends Preprocessor
$cppCode .= $this->genFunctionWrapper($functionDef);
}
return $this->genIncludeHeaderFiles() . $cppCode;
return $this->genIncludeHeaderFiles().$cppCode;
}
public function preprocessArgvAdvanced(): void
@ -334,7 +342,7 @@ class Translator extends Preprocessor
global $argv;
$processed = [$argv[0]];
for ($i = 1; $i < count($argv); $i++) {
for ($i = 1; $i < count($argv); ++$i) {
$arg = $argv[$i];
if (preg_match('/^-([a-zA-Z])(.+)$/', $arg, $matches)) {
$option = $matches[1];
@ -358,26 +366,31 @@ class Translator extends Preprocessor
$lines[] = '#include <phpx.h>';
$lines[] = PHP_EOL;
foreach ($this->globalVars as $name => $type) {
$lines[] = 'extern ' . self::TYPE_VAR . ' ' . $name . ';';
$lines[] = 'extern '.self::TYPE_VAR.' '.$name.';';
}
// property offset
foreach ($this->classes as $classDef) {
foreach ($classDef->properties as $propertyDef) {
$lines[] = 'extern uint32_t ' . self::PREFIX . $this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace) . ';';
$lines[] = 'extern uint32_t '.self::PREFIX.$this->getPropertyOffset($propertyDef->name, $classDef->name, $classDef->namespace).';';
}
}
$literalStringsCount = count($this->literalStrings);
$lines[] = 'extern php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
$code = implode(PHP_EOL, $lines) . PHP_EOL . PHP_EOL;
$lines[] = 'extern php::Var '.self::LITERAL_STRINGS.'['.$literalStringsCount.'];'.PHP_EOL;
$classEntryCount = count($this->classMap);
$lines[] = 'extern zend_class_entry *'.self::PREFIX.self::CLASS_ENTRY_MAP.'['.$classEntryCount.'];'.PHP_EOL;
$code = implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL;
$this->writeFile($file, $code);
}
private function render(string $template): string
{
ob_start();
include __DIR__ . '/../template/' . $template;
include __DIR__.'/../template/'.$template;
return ob_get_clean();
}
@ -428,7 +441,7 @@ class Translator extends Preprocessor
$implements = $classDef->implements;
if ($implements) {
foreach ($implements as $interface) {
$tmpCe = self::PREFIX . 'class_entry_' . $interface;
$tmpCe = self::PREFIX.'class_entry_'.$interface;
if (!isset($this->interfaces[$interface])) {
$sorter->add($tmpCe);
}
@ -450,7 +463,7 @@ class Translator extends Preprocessor
public function genExtension(string $file): void
{
if ($this->buildMode == 'bin') {
if ('bin' == $this->buildMode) {
if (!isset($this->nativeFunctions['main'])) {
$this->climate->red('When the build mode is a binary executable file, the `main()` function must be defined');
exit(1);
@ -473,16 +486,18 @@ class Translator extends Preprocessor
if (file_exists($objectFile) and filemtime($objectFile) > filemtime($cppFile)) {
return true;
}
return false;
}
public function compileFile(string $cppFile, string $objectFile): void
{
if ($this->hasObjectFileCache($cppFile)) {
$this->climate->darkGray('skip: ' . $cppFile . ', cache exists');
$this->climate->darkGray('skip: '.$cppFile.', cache exists');
return;
}
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
$cmd = $this->cppCompiler.' -c '.$cppFile.' -o '.$objectFile;
$this->addCompilationOption($cmd, false);
$this->climate->comment($cmd);
shell_exec($cmd);
@ -492,10 +507,10 @@ class Translator extends Preprocessor
{
$objectList = implode(' ', $objectFiles);
$targetFile = $this->targetName;
if ($this->buildMode == 'ext' and !str_ends_with($targetFile, '.so')) {
if ('ext' == $this->buildMode and !str_ends_with($targetFile, '.so')) {
$targetFile .= '.so';
}
$linkCmd = $this->cppCompiler . ' ' . $objectList . ' -o ' . $targetFile;
$linkCmd = $this->cppCompiler.' '.$objectList.' -o '.$targetFile;
$this->addCompilationOption($linkCmd, true);
$this->climate->comment($linkCmd);
shell_exec($linkCmd);
@ -503,12 +518,12 @@ class Translator extends Preprocessor
public function genFunctionDeclaration(string $file): void
{
$code = '#include <phpx.h>' . PHP_EOL;
$code = '#include <phpx.h>'.PHP_EOL;
/**
* @var FunctionDef $func
*/
foreach ($this->nativeFunctions as $name => $func) {
$code .= 'extern ' . $func->returnType . ' ' . self::PREFIX . $name . '(';
$code .= 'extern '.$func->returnType.' '.self::PREFIX.$name.'(';
$argInfoList = $func->argInfoList;
if ($argInfoList) {
$list = [];
@ -516,22 +531,24 @@ class Translator extends Preprocessor
$list[] = 'php::Object &this_';
}
foreach ($argInfoList as $argInfo) {
$arg = $argInfo->type . ' ' . $argInfo->name;
$arg = $argInfo->type.' '.$argInfo->name;
if ($argInfo->default) {
$arg .= ' = ' . $argInfo->default;
$arg .= ' = '.$argInfo->default;
}
$list[] = $arg;
}
$code .= implode(', ', $list);
}
$code .= ');' . PHP_EOL;
$code .= ');'.PHP_EOL;
}
$code .= PHP_EOL;
foreach ($this->nativeConstants as $name => $constant) {
$code .= 'extern ' . $constant->type . ' ' . $name . ';' . PHP_EOL;
$code .= 'extern '.$constant->type.' '.$name.';'.PHP_EOL;
}
$code .= 'extern zend_class_entry *php_get_class_entry(int class_id, const char *class_name);'.PHP_EOL;
$this->writeFile($file, $code);
}
@ -555,10 +572,10 @@ class Translator extends Preprocessor
if ($this->useCppNamespace) {
$ns = explode('\\', $ns);
$ns = array_filter($ns, function ($v) {
return $v !== '';
return '' !== $v;
});
foreach ($ns as $name) {
$code .= 'namespace ' . $name . ' {' . PHP_EOL;
$code .= 'namespace '.$name.' {'.PHP_EOL;
}
$ns_end = str_repeat('}', count($ns));
$this->namespace = implode('::', $ns);
@ -574,13 +591,13 @@ class Translator extends Preprocessor
$code .= $this->parseClass($v2);
break;
case 'Stmt_Const':
$this->parseConstDef($v2) . PHP_EOL;
$this->parseConstDef($v2).PHP_EOL;
break;
case 'Stmt_Function':
$code .= $this->parseFunction($v2) . PHP_EOL;
$code .= $this->parseFunction($v2).PHP_EOL;
break;
case 'Stmt_Use':
$code .= $this->parseUse($v2) . PHP_EOL;
$code .= $this->parseUse($v2).PHP_EOL;
break;
default:
abort($v2);
@ -588,18 +605,19 @@ class Translator extends Preprocessor
}
$code .= $ns_end;
$this->resetNamespace();
return $code;
}
protected function genStubFile(string $file): void
{
$genStubCmd = PHP_BINARY. ' ' . $this->rootPath . '/bin/gen_stub.php -f ' . $file;
$genStubCmd = PHP_BINARY.' '.$this->rootPath.'/bin/gen_stub.php -f '.$file;
$output = shell_exec($genStubCmd);
$this->climate->info('generate stub file: ' . $file);
$this->climate->info('generate stub file: '.$file);
$this->climate->comment($genStubCmd);
$stubFilenameWithoutExtension = str_replace([".stub.php", '.php'], "", $file);
$stubFilenameWithoutExtension = str_replace(['.stub.php', '.php'], '', $file);
$headerFile = $this->getArgInfoHeaderFile($stubFilenameWithoutExtension, true);
if (!str_contains($output, "Saved")) {
if (!str_contains($output, 'Saved')) {
$this->error("failed to generate arginfo header file: `$headerFile`, output: $output");
}
$this->argInfoHeaderFiles[] = $headerFile;
@ -649,6 +667,7 @@ class Translator extends Preprocessor
$this->fatalError($class, "Class `{$this->class}` uses a non-empty array as the default value for an property, and the constructor must be set.");
}
$this->resetClass();
return $code;
}
@ -659,8 +678,8 @@ class Translator extends Preprocessor
public function getArgInfoHeaderFile(string $stubFilenameWithoutExtension, bool $relative = false): string
{
$basename = self::PREFIX . basename($stubFilenameWithoutExtension);
$absPath = $this->getIncludeDir() . "/{$basename}_arginfo.h";
$basename = self::PREFIX.basename($stubFilenameWithoutExtension);
$absPath = $this->getIncludeDir()."/{$basename}_arginfo.h";
if ($relative) {
return ltrim($this->removeCommonPrefix($this->getIncludeDir(), $absPath), '/');
} else {
@ -673,7 +692,7 @@ class Translator extends Preprocessor
$code = '';
$classDef = $this->classDef;
foreach ($classDef->methods as $method) {
$code .= $methodCodes[$method->name] . PHP_EOL;
$code .= $methodCodes[$method->name].PHP_EOL;
}
$code .= PHP_EOL;
@ -686,28 +705,28 @@ class Translator extends Preprocessor
$callParams = '';
foreach ($functionDef->argInfoList as $k => $argInfo) {
if ($argInfo->default) {
$argExpr = 'php::getCallArg(' . $k . ', ' . $argInfo->default . ')';
$argExpr = 'php::getCallArg('.$k.', '.$argInfo->default.')';
} else {
$argExpr = 'php::getCallArg(' . $k . ')';
$argExpr = 'php::getCallArg('.$k.')';
}
$expr = $this->convertExprFromType($argInfo->type, $argExpr);
$cppCode .= $this->getIndent() . $argInfo->type . ' arg_' . $argInfo->name . ' = ' . $expr . ';' . PHP_EOL;
$callParams .= 'arg_' . $argInfo->name . ',';
$cppCode .= $this->getIndent().$argInfo->type.' arg_'.$argInfo->name.' = '.$expr.';'.PHP_EOL;
$callParams .= 'arg_'.$argInfo->name.',';
}
if ($functionDef->method) {
$callParams = $functionDef->argInfoList ? 'this_, ' . rtrim($callParams, ',') : 'this_';
$callParams = $functionDef->argInfoList ? 'this_, '.rtrim($callParams, ',') : 'this_';
} else {
$callParams = $functionDef->argInfoList ? rtrim($callParams, ',') : '';
}
if ($functionDef->returnType !== self::TYPE_VOID) {
$cppCode .= $this->getIndent() . 'auto retval = ' . $fn . '(' . $callParams . ');' . PHP_EOL;
$cppCode .= $this->getIndent() . 'php::move(retval, return_value);' . PHP_EOL;
if (self::TYPE_VOID !== $functionDef->returnType) {
$cppCode .= $this->getIndent().'auto retval = '.$fn.'('.$callParams.');'.PHP_EOL;
$cppCode .= $this->getIndent().'php::move(retval, return_value);'.PHP_EOL;
} else {
$cppCode .= $this->getIndent() . $fn . '(' . $callParams . ');' . PHP_EOL;
$cppCode .= $this->getIndent().$fn.'('.$callParams.');'.PHP_EOL;
}
$cppCode .= '}' . PHP_EOL . PHP_EOL;
$cppCode .= '}'.PHP_EOL.PHP_EOL;
return $cppCode;
}
@ -715,27 +734,29 @@ class Translator extends Preprocessor
protected function genMethodWrapper(ClassDef $classDef, MethodDef $methodDef): string
{
$name = $classDef->getNamespacedName();
$cppCode = 'ZEND_METHOD(' . $name . ', ' . $methodDef->name . '){' . PHP_EOL;
$cppCode .= $this->getIndent() . self::TYPE_OBJECT . ' this_(&execute_data->This);' . PHP_EOL;
$cppCode = 'ZEND_METHOD('.$name.', '.$methodDef->name.'){'.PHP_EOL;
$cppCode .= $this->getIndent().self::TYPE_OBJECT.' this_(&execute_data->This);'.PHP_EOL;
foreach ($classDef->properties as $property) {
if ($property->type === self::TYPE_ARRAY and $property->default and $property->default !== self::TYPE_ARRAY . '{}') {
$propOffset = self::PREFIX . $this->getPropertyOffset($property->name, $classDef->name, $classDef->namespace);
$cppCode .= $this->getIndent() . 'this_.getPropertyIndirect(' . $propOffset . ') = ' . $property->default . ';' . PHP_EOL;
if (self::TYPE_ARRAY === $property->type and $property->default and $property->default !== self::TYPE_ARRAY.'{}') {
$propOffset = self::PREFIX.$this->getPropertyOffset($property->name, $classDef->name, $classDef->namespace);
$cppCode .= $this->getIndent().'this_.getPropertyIndirect('.$propOffset.') = '.$property->default.';'.PHP_EOL;
}
}
$fn = self::PREFIX . $this->getNativeMethodName($classDef, $methodDef);
$fn = self::PREFIX.$this->getNativeMethodName($classDef, $methodDef);
$cppCode .= $this->genWrapperFunctionArgs($fn, $methodDef->functionDef);
return $cppCode;
}
private function genFunctionWrapper(FunctionDef $functionDef): string
{
$name = $functionDef->name;
$cppCode = 'ZEND_FUNCTION(' . $name . '){' . PHP_EOL;
$fn = self::PREFIX . $this->getNativeName($functionDef->name);
$cppCode = 'ZEND_FUNCTION('.$name.'){'.PHP_EOL;
$fn = self::PREFIX.$this->getNativeName($functionDef->name);
$cppCode .= $this->genWrapperFunctionArgs($fn, $functionDef);
return $cppCode;
}
@ -745,12 +766,11 @@ class Translator extends Preprocessor
$name = $classDef->getNamespacedName();
$argsDef = $this->getRegisterClassFunctionArgDef($classDef);
$param = $this->getRegisterClassFunctionArgs($classDef);
$cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $argsDef . ') {' . PHP_EOL;
$cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL;
$cppCode .= '}' . PHP_EOL . PHP_EOL;
$cppCode .= 'zend_class_entry *'.$this->getRegisterClassFunction($name).'('.$argsDef.') {'.PHP_EOL;
$cppCode .= $this->getIndent().'return register_class_'.$name.'('.$param.');'.PHP_EOL;
$cppCode .= '}'.PHP_EOL.PHP_EOL;
}
protected function genClassWrapper(ClassDef|InterfaceDef $classDef): string
{
$cppCode = '';
@ -768,7 +788,7 @@ class Translator extends Preprocessor
private function genClassNative(): string
{
$code = 'class ' . $this->class . ' { ';
$code = 'class '.$this->class.' { ';
$publicMethods = [];
$protectedMethods = [];
@ -815,36 +835,37 @@ class Translator extends Preprocessor
}
if ($privateConstants) {
$code .= 'private:' . PHP_EOL;
$code .= 'private:'.PHP_EOL;
$code .= $this->genClassConstantList($privateConstants);
}
if ($protectedConstants) {
$code .= 'protected:' . PHP_EOL;
$code .= 'protected:'.PHP_EOL;
$code .= $this->genClassConstantList($protectedConstants);
}
if ($publicConstants) {
$code .= 'public:' . PHP_EOL;
$code .= 'public:'.PHP_EOL;
$code .= $this->genClassConstantList($publicConstants);
}
if ($privateProperties) {
$code .= 'private:' . PHP_EOL;
$code .= 'private:'.PHP_EOL;
$code .= $this->genClassPropertyList($privateProperties);
}
if ($protectedProperties) {
$code .= 'protected:' . PHP_EOL;
$code .= 'protected:'.PHP_EOL;
$code .= $this->genClassPropertyList($protectedProperties);
}
if ($publicProperties) {
$code .= 'public:' . PHP_EOL;
$code .= 'public:'.PHP_EOL;
$code .= $this->genClassPropertyList($publicProperties);
}
$code .= '};' . PHP_EOL . PHP_EOL;
$code .= '};'.PHP_EOL.PHP_EOL;
return $code;
}
@ -853,9 +874,10 @@ class Translator extends Preprocessor
$headers = array_merge($this->globalHeaders, $this->localHeaders);
$lines = [];
foreach ($headers as $header) {
$lines[] = '#include <' . $header . '>';
$lines[] = '#include <'.$header.'>';
}
return implode(PHP_EOL, $lines) . PHP_EOL . PHP_EOL;
return implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL;
}
/**
@ -865,14 +887,15 @@ class Translator extends Preprocessor
{
$code = '';
foreach ($list as $const) {
$code .= $this->getIndent() . $this->genClassConstant($const);
$code .= $this->getIndent().$this->genClassConstant($const);
}
return $code;
}
protected function genClassConstant(ConstantDef $const): string
{
return 'static const ' . $const->type . ' ' . $const->name . ';' . PHP_EOL;
return 'static const '.$const->type.' '.$const->name.';'.PHP_EOL;
}
/**
@ -882,29 +905,32 @@ class Translator extends Preprocessor
{
$code = '';
foreach ($list as $prop) {
$code .= $this->getIndent() . $this->genClassProperty($prop);
$code .= $this->getIndent().$this->genClassProperty($prop);
}
return $code;
}
protected function genClassProperty(PropertyDef $prop): string
{
$code = $prop->type . ' ' . $prop->name;
$code = $prop->type.' '.$prop->name;
if ($prop->default) {
$code .= ' = ' . $prop->default;
$code .= ' = '.$prop->default;
}
return $code . ';' . PHP_EOL;
return $code.';'.PHP_EOL;
}
protected function genFunction(string $name, string $returnType, array $args = [], array $lines = []): string
{
$_args = [];
foreach ($args as $arg => $type) {
$_args[] = $type . ' ' . $arg;
$_args[] = $type.' '.$arg;
}
$code = $returnType . ' ' . $name . '(' . implode(', ', $_args) . ') {' . PHP_EOL;
$code .= implode(PHP_EOL, $lines) . PHP_EOL;
$code .= '}' . PHP_EOL;
$code = $returnType.' '.$name.'('.implode(', ', $_args).') {'.PHP_EOL;
$code .= implode(PHP_EOL, $lines).PHP_EOL;
$code .= '}'.PHP_EOL;
return $code;
}
@ -915,7 +941,7 @@ class Translator extends Preprocessor
foreach ($v->consts as $const) {
$constName = $this->parseIdentifier($const->name);
if (isset($this->classDef->constants[$constName])) {
$this->fatalError($const, 'Cannot redefine class constant ' . $this->class . '::' . $constName);
$this->fatalError($const, 'Cannot redefine class constant '.$this->class.'::'.$constName);
}
$constInfo = new ConstantDef($constName, $flags, $type, $this->parseIdentifier($const->value));
$this->classDef->constants[$constInfo->name] = $constInfo;
@ -930,7 +956,7 @@ class Translator extends Preprocessor
foreach ($v->props as $prop) {
$propDef = new PropertyDef($this->parseIdentifier($prop->name), $flags, $type);
if ($prop->default) {
if ($prop->default->getType() == 'Expr_Array' and count($prop->default->items) > 0) {
if ('Expr_Array' == $prop->default->getType() and count($prop->default->items) > 0) {
$this->classDef->requireCtor = true;
$propDef->type = self::TYPE_ARRAY;
}
@ -961,6 +987,7 @@ class Translator extends Preprocessor
foreach ($implements as $implement) {
$list[] = $this->parseIdentifier($implement);
}
return $list;
}
@ -983,35 +1010,35 @@ class Translator extends Preprocessor
$tmpArrayVar = $this->genTmpVarName();
$this->addLocalVar($tmpArrayVar, self::TYPE_ARRAY);
$code = 'if (' . $obj . '.instanceOf("IteratorAggregate")) {' . PHP_EOL;
$code .= $this->getIndent() . $tmpVar . ' = ' . $obj . '.exec("getIterator");' . PHP_EOL . '}' . PHP_EOL;
$code .= 'else if (' . $obj . '.instanceOf("Iterator")) {' . PHP_EOL;
$code .= $this->getIndent() . $tmpVar . ' = ' . $obj . ';' . PHP_EOL . '}'. PHP_EOL;
$code = 'if ('.$obj.'.instanceOf("IteratorAggregate")) {'.PHP_EOL;
$code .= $this->getIndent().$tmpVar.' = '.$obj.'.exec("getIterator");'.PHP_EOL.'}'.PHP_EOL;
$code .= 'else if ('.$obj.'.instanceOf("Iterator")) {'.PHP_EOL;
$code .= $this->getIndent().$tmpVar.' = '.$obj.';'.PHP_EOL.'}'.PHP_EOL;
$code .= 'if (' . $tmpVar . ') {'. PHP_EOL;
$code .= 'if ('.$tmpVar.') {'.PHP_EOL;
$this->indentLevel++;
$code .= $this->getIndent() . $tmpVar . '.exec("rewind");' . PHP_EOL;
$code .= $this->getIndent() . 'for (;' . $tmpVar . '.exec("valid"); ' . $tmpVar . '.exec("next")) {' . PHP_EOL;
$this->indentLevel++;
++$this->indentLevel;
$code .= $this->getIndent().$tmpVar.'.exec("rewind");'.PHP_EOL;
$code .= $this->getIndent().'for (;'.$tmpVar.'.exec("valid"); '.$tmpVar.'.exec("next")) {'.PHP_EOL;
++$this->indentLevel;
$valueVar = $this->parseIdentifier($node->valueVar);
$this->checkVar($node, $valueVar);
$code .= $this->getIndent() . ' ' . $valueVar . ' = ' . $tmpVar . '.exec("current");' . PHP_EOL;
$code .= $this->getIndent().' '.$valueVar.' = '.$tmpVar.'.exec("current");'.PHP_EOL;
if ($node->keyVar) {
$keyVar = $this->parseIdentifier($node->keyVar);
$this->checkVar($node, $keyVar);
$code .= $this->getIndent() . ' ' . $keyVar . ' = ' . $tmpVar . '.exec("key");' . PHP_EOL;
$code .= $this->getIndent().' '.$keyVar.' = '.$tmpVar.'.exec("key");'.PHP_EOL;
}
$code .= $this->parseStmts($node->stmts);
$code .= '}' . PHP_EOL;
$this->indentLevel--;
$code .= $this->getIndent() . '} else {' . PHP_EOL;
$code .= $this->getIndent() . $tmpArrayVar . ' = php::call("get_object_vars", {' . $obj . '});' . PHP_EOL;
$code .= '}'.PHP_EOL;
--$this->indentLevel;
$code .= $this->getIndent().'} else {'.PHP_EOL;
$code .= $this->getIndent().$tmpArrayVar.' = php::call("get_object_vars", {'.$obj.'});'.PHP_EOL;
$code .= $this->parseForeachArray($node, $tmpArrayVar);
$this->indentLevel--;
$code .= '}' . PHP_EOL;
--$this->indentLevel;
$code .= '}'.PHP_EOL;
return $code;
}

@ -21,6 +21,16 @@ foreach ($this->classCeList as $ce):
zend_class_entry * <?= $ce ?>;
<?php endforeach; ?>
// class entry
zend_class_entry *<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP . '[' . count($this->classMap) . ']' ?>;
zend_class_entry *php_get_class_entry(int class_id, const char *class_name) {
if (<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP ?>[class_id] == nullptr) {
<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP ?>[class_id] = php::getClassEntrySafe(class_name);
}
return <?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP ?>[class_id];
}
// literal strings
php::Var <?=Translator::LITERAL_STRINGS?>[] = {
<?php
@ -97,6 +107,13 @@ foreach ($this->classes as $classDef):
endforeach;
endforeach;
?>
// class entry
<?php
foreach ($this->classMap as $class => $id):
?>
<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP . '[' . $id . ']' ?> = php::getClassEntry("<?= $this->escapeString($class) ?>");
<?php endforeach; ?>
}
void php_app_clean() {

Loading…
Cancel
Save