TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

66 lines
3.0 KiB

<blog>
# 解析器与 AST
TypePHP 复用 **nikic/php-parser** 作为前端词法/语法分析器(依赖固定版本 `5.6.1`)。解析得到的 PHP AST 是后续所有翻译与符号收集的输入。本章说明 AST 从何而来、以何种形态进入编译器。
Sources: [composer.json](composer.json#L10) · [project.yml](project.yml#L34-L35)
## AST 来源
解析发生在两个时机:
1. **预处理阶段**:`Preprocessor::prepareFile()` 解析每个 PHP 文件,收集类/函数/常量/属性等符号,构建全局符号表(详见 [预处理与符号表](preprocessor))。
2. **转换阶段**:`doConvert()` 通过 `parseCachedAst()` 解析同一文件,得到供代码生成的 AST。
> `parseCachedAst()` 做了两层缓存——同一文件的 AST 在进程内复用,避免重复解析;这也是编译性能优化(S1)的关键点之一。
Sources: [src/Preprocessor.php](src/Preprocessor.php#L116) · [src/Translator.php](src/Translator.php#L2459)
## 表达式翻译:Parser Trait 集合
编译器主体 `CompilerBase` 并未把「PHP 表达式 → C++」的逻辑塞进一个巨型方法,而是拆成 `src/Parser/` 下的 **21 个 trait**,每个 trait 负责一类语法结构:
| Trait | 负责的 PHP 结构 |
|---|---|
| `BinaryOpTrait` | `+ - * /` 等二元运算 |
| `AssignOpTrait` | `+=`、`??=` 等复合赋值 |
| `UnaryExpressionTrait` | `!`、`-`、`++` 等一元运算 |
| `FunctionCallTrait` | 普通函数调用 |
| `MethodCallTrait` / `UniversalMethodCall` | 对象/静态方法调用 |
| `PropertyAccessTrait` | 属性读写 |
| `ArrayExpressionTrait` | 数组字面量 |
| `ForeachTrait` / `LoopControlTrait` | `foreach` / `for` / `while` |
| `SelectionExpressionTrait` / `SwitchTrait` | `if` / `switch` |
| `ConditionalControlTrait` | `?:` / `match` |
| `NullsafeAccessTrait` | `?->` |
| `ClassConstantFetchTrait` | 类常量读取 |
| `TypeConversionTrait` / `TypeDetectionTrait` | 类型转换与 `instanceof` |
| `ConstantExpressionTrait` | 编译期常量折叠 |
| `ExceptionControlFlowTrait` | `try/catch/throw` |
| `StdContainerTrait` | `std` 容器操作 |
Sources: [src/CompilerBase.php](src/CompilerBase.php#L43-L63) · [src/Parser/](src/Parser/)
## 访客链
`doConvert()` 在遍历 AST 前先挂载四个 `NodeVisitor`
```php
$traverser->addVisitor(new NameResolver(...)); // 全限定名解析
$traverser->addVisitor(new Visitor(...)); // Transform lowering(见 transform)
$traverser->addVisitor(new ConstantExpressionValidationVisitor(...));
$traverser->addVisitor(new RuntimeAttributeFactoryLowering(...));
```
`NameResolver` 把短名解析为全限定名(但不替换节点),让后续生成能拿到准确的命名空间路径。
Sources: [src/Translator.php](src/Translator.php#L2460-L2467)
## 相关阅读
- 符号如何被收集 → [预处理与符号表](preprocessor)
- 遍历中做了哪些改写 → [AST 转换](transform)
- 解析结果的消费方 → [代码生成](generator)
</blog>