refactor(translator): 重构PHP到C++编译器的文件处理逻辑

- 将prepare方法重命名为prepareFile,convert方法重命名为convertFile
- 添加ignore路径配置支持,可在项目配置中忽略特定文件或目录
- 重构编译器主流程,将文件扫描、预处理和转换分离为独立步骤
- 移除不必要的异常类引用,优化代码结构
- 添加文件过滤功能,支持在预处理阶段跳过无效文件
- 修复预处理器中的默认情况处理逻辑,统一错误处理方式
pull/1/head
韩天峰 4 months ago
parent 8865796b43
commit e5b7955fa1
  1. 50
      bin/compiler.php
  2. 4
      phpunit/bootstrap.php
  3. 4
      phpunit/src/DuplicateTest.php
  4. 8
      src/Php/Preprocessor.php
  5. 101
      src/Php/Translator.php

@ -3,9 +3,6 @@
require __DIR__ . '/bootstrap.php';
require __DIR__ . '/../src/gen_stub.php';
use PhpAot\Php\Exception\SyntaxError;
use PhpAot\Php\Exception\Unsupported;
use PhpAot\Php\FileScanner;
use PhpAot\Php\Translator;
if (empty($argv[1])) {
@ -15,52 +12,11 @@ if (empty($argv[1])) {
$path = $argv[1];
$translator = new Translator(ROOT_PATH);
$translator->setIndent(' ');
$list = $translator->getFiles($path);
$sourceFiles = [];
$objectFiles = [];
// 分析 PHP 文件,预处理
foreach ($list as $k => $file) {
if (FileScanner::isPhpFile($file)) {
try {
$translator->prepare($file);
} catch (Unsupported $e) {
$translator->output(" unsupported syntax: " . $e->getMessage() . "\n" . " skip: " . $file . "\n", 'error');
unset($list[$k]);
} catch (SyntaxError $e) {
$translator->output(" syntax error: " . $e->getMessage() . "\n" . " skip: " . $file . "\n", 'error');
unset($list[$k]);
}
}
}
$translator->sortFiles($list);
// 扫描所有 PHP 文件,预处理
$files = $translator->prepare($path);
// 生成 C++ 文件
foreach ($list as $k => $file) {
try {
if (FileScanner::isPhpFile($file)) {
$cppFile = $translator->convert($file);
} elseif (FileScanner::isCppFile($file)) {
$cppFile = $file;
} else {
continue;
}
$sourceFiles[] = $cppFile;
} catch (Unsupported $e) {
echo " unsupported syntax: " . $e->getMessage() . "\n";
echo " skip: " . $file . "\n";
unset($list[$k]);
}
}
if (empty($sourceFiles)) {
$translator->stop("No valid source file found");
}
$sourceFiles = $translator->convert($files);
// 编译所有 C++ 文件
$objectFiles = $translator->compile($sourceFiles);
// 连接所有目标文件,生成可执行文件
$translator->build($objectFiles);

@ -14,8 +14,8 @@ class BaseTest extends TestCase
$compiler = CompilerTest::create(ROOT_PATH);
$testFile = __DIR__ . '/code/' . $file;
$compiler->addFiles([$testFile]);
$compiler->prepare($testFile);
$compiler->convert($testFile);
$compiler->prepareFile($testFile);
$compiler->convertFile($testFile);
} catch (TestError $exception) {
$this->assertStringContainsString($expected, $exception->getMessage());
return;

@ -13,8 +13,8 @@ class DuplicateTest extends TestCase
$compiler = CompilerTest::create(ROOT_PATH);
$testFile = __DIR__ . '/../code/' . $file;
$compiler->addFiles([$testFile]);
$compiler->prepare($testFile);
$compiler->convert($testFile);
$compiler->prepareFile($testFile);
$compiler->convertFile($testFile);
} catch (TestError $exception) {
$this->assertStringContainsString($expected, $exception->getMessage());
return;

@ -90,7 +90,7 @@ class Preprocessor extends CompilerBase
return false;
}
public function prepare(string $file): void
public function prepareFile(string $file): void
{
if ($this->hasCppFileCache($file)) {
$this->climate->darkGray('skip: ' . $file . ', cache exists');
@ -210,11 +210,9 @@ class Preprocessor extends CompilerBase
case 'Stmt_Const':
case 'Stmt_Interface':
break;
case 'Stmt_Expression':
$this->foundStrayCode($v2);
// no break
default:
throw new Unsupported('Unsupported statement: ' . $type2);
$this->foundStrayCode($v2);
break;
}
}
}

@ -17,6 +17,7 @@ use PhpAot\Php\Entity\InterfaceDef;
use PhpAot\Php\Entity\MethodDef;
use PhpAot\Php\Entity\PropertyDef;
use PhpAot\Php\Exception\Redo;
use PhpAot\Php\Exception\SyntaxError;
use PhpAot\Php\Exception\Unsupported;
use PhpParser\Modifiers;
use PhpParser\Node;
@ -31,6 +32,7 @@ class Translator extends Preprocessor
protected array $sourceDirs = [];
protected bool $verbose = false;
protected array $phpSrcFiles = [];
protected array $ignorePaths = [];
protected array $argInfoHeaderFiles = [];
protected array $registerSymbols = [];
@ -98,7 +100,7 @@ class Translator extends Preprocessor
$climate->br();
}
public function convert(string $file): string
public function convertFile(string $file): string
{
$file = realpath($file);
if ($this->hasCppFileCache($file)) {
@ -190,6 +192,68 @@ class Translator extends Preprocessor
return $list;
}
public function prepare(string $path): array
{
$files = $this->getFiles($path);
// 应用 ignorePaths 过滤
if (!empty($this->ignorePaths)) {
$files = array_filter($files, function ($file) {
foreach ($this->ignorePaths as $ignorePath) {
if ($file === $ignorePath) {
return false;
}
if (is_dir($ignorePath) && str_starts_with($file, $ignorePath . DIRECTORY_SEPARATOR)) {
return false;
}
}
return true;
});
}
// 分析 PHP 文件,预处理
foreach ($files as $k => $file) {
if (FileScanner::isPhpFile($file)) {
try {
$this->prepareFile($file);
} catch (Unsupported $e) {
$this->output(" unsupported syntax: " . $e->getMessage() . "\n" . " skip: " . $file . "\n", 'error');
unset($files[$k]);
} catch (SyntaxError $e) {
$this->output(" syntax error: " . $e->getMessage() . "\n" . " skip: " . $file . "\n", 'error');
unset($files[$k]);
}
}
}
$this->sortFiles($files);
return $files;
}
public function convert(array $files): array
{
$sourceFiles = [];
// 生成 C++ 文件
foreach ($files as $k => $file) {
try {
if (FileScanner::isPhpFile($file)) {
$cppFile = $this->convertFile($file);
} elseif (FileScanner::isCppFile($file)) {
$cppFile = $file;
} else {
continue;
}
$sourceFiles[] = $cppFile;
} catch (Unsupported $e) {
echo " unsupported syntax: " . $e->getMessage() . "\n";
echo " skip: " . $file . "\n";
unset($files[$k]);
}
}
if (empty($sourceFiles)) {
$this->stop("No valid source file found");
}
return $sourceFiles;
}
public function preprocessArgvAdvanced(): void
{
global $argv;
@ -653,6 +717,17 @@ class Translator extends Preprocessor
return $code;
}
protected function getAbsolutePath(string $path, string $projectDir): string
{
$path = trim($path);
if ($path[0] != '/') {
$absPath = $projectDir . '/' . $path;
} else {
$absPath = $path;
}
return realpath($absPath);
}
protected function parseProjectYaml(string $path): array
{
$cfg = Yaml::parseFile($path);
@ -660,15 +735,12 @@ class Translator extends Preprocessor
if (!empty($cfg['sources'])) {
$sources = $cfg['sources'];
if (!is_array($sources)) {
$this->error('`sources` must be array');
}
$list = [];
foreach ($sources as $src) {
$src = trim($src);
if ($src[0] != '/') {
$absPath = $projectDir . '/' . $src;
} else {
$absPath = $src;
}
$realPath = realpath($absPath);
$realPath = $this->getAbsolutePath($src, $projectDir);
if (!$realPath) {
$this->error('Source file not exists: `' . $src . '`');
}
@ -705,6 +777,19 @@ class Translator extends Preprocessor
$this->setBuildMode($cfg['type']);
}
if (!empty($cfg['ignore'])) {
if (!is_array($cfg['ignore'])) {
$this->error('`ignore` must be array');
}
foreach ($cfg['ignore'] as $src) {
$realPath = $this->getAbsolutePath($src, $projectDir);
if (!$realPath) {
$this->error('Source file not exists: `' . $src . '`');
}
$this->ignorePaths[] = $realPath;
}
}
return $list;
}

Loading…
Cancel
Save