🚀 优化`ast`相关代码
|
||
|---|---|---|
| .. | ||
| ast | ||
| keyword | ||
| symbol | ||
| README.md | ||
README.md
从反序列化到符号表 - 设计架构
📐 系统架构总览
┌─────────────────────────────────────────────────────────────────┐
│ Source Code │
│ (tsl) │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Tree-sitter Parser │
│ (外部依赖,生成 TSTree) │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌────────┐
│ TSTree │ Parse Tree (CST)
│ TSNode │
└────┬───┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AST 反序列化层 (ast/) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ deserializer.hpp/cpp │ │
│ │ - ParseRoot() │ │
│ │ - ParseNode() │ │
│ │ - ParseVarDeclaration(), ParseFunctionDefinition()... │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ types.hpp │ │
│ │ - ASTNode (variant) │ │
│ │ - VarDeclaration, FunctionDefinition, ClassDefinition │ │
│ │ - Expression, Block, Signature, Parameter... │ │
│ └─────────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌────────────────────┐
│ vector<ASTNode> │ 抽象语法树
│ ParseResult │
└──────┬─────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 符号表构建层 (symbol/) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Phase 1: Collection (builder/collector.hpp/cpp) │ │
│ │ - 遍历 AST │ │
│ │ - 创建符号 (Variable, Function, Class...) │ │
│ │ - 插入符号表 │ │
│ │ - 建立作用域层次 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Phase 2: Resolution (builder/resolver.hpp/cpp) │ │
│ │ - 解析 Unit 依赖关系 │ │
│ │ - 解析类继承关系 │ │
│ │ - 检测循环依赖 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Phase 3: Validation (builder/validator.hpp/cpp) │ │
│ │ - 验证类型引用 │ │
│ │ - 验证方法覆盖 │ │
│ │ - 验证访问权限 │ │
│ │ - 验证虚方法 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Coordinator (builder/builder.hpp/cpp) │ │
│ │ - 协调三阶段流程 │ │
│ │ - 错误收集和报告 │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌────────────────────┐
│ SymbolRegistry │ 完整的符号表
│ - GlobalScope │
│ - Units │
└──────┬─────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 应用层 │
│ - LSP 服务 (代码补全、跳转定义、查找引用...) │
│ - 语义分析 │
│ - 代码生成 │
└─────────────────────────────────────────────────────────────────┘
🔄 数据流详解
1. 解析阶段 (Tree-sitter → AST)
Source Code
│
├─→ Tree-sitter Parser
│ │
│ └─→ TSTree (Concrete Syntax Tree)
│ │
│ └─→ TSNode (每个语法节点)
│
└─→ AST Deserializer
│
├─→ ParseRoot(TSNode, source)
│ │
│ └─→ ParseNode() 递归解析
│ │
│ ├─→ ParseVarDeclaration()
│ ├─→ ParseFunctionDefinition()
│ ├─→ ParseClassDefinition()
│ └─→ ...
│
└─→ vector<ASTNode>
│
└─→ AST (抽象语法树)
关键点:
- Tree-sitter 生成 CST(具体语法树),包含所有语法细节
- Deserializer 将 CST 转换为 AST(抽象语法树),去除语法细节
- AST 使用
std::variant<...>表示不同类型的节点
2. 符号表构建阶段 (AST → Symbol Table)
vector<ASTNode>
│
├─→ Phase 1: Collection
│ │
│ ├─→ 遍历每个 ASTNode
│ │ │
│ │ ├─→ Visit(UnitDefinition)
│ │ │ └─→ CreateUnit → AddUnit
│ │ │
│ │ ├─→ Visit(ClassDefinition)
│ │ │ └─→ CreateClass → Insert
│ │ │ │
│ │ │ └─→ Visit(ClassMembers)
│ │ │
│ │ ├─→ Visit(FunctionDefinition)
│ │ │ └─→ CreateFunction → InsertFunction
│ │ │ │
│ │ │ └─→ CollectFunctionBody
│ │ │
│ │ └─→ Visit(VarDeclaration)
│ │ └─→ CreateVariable → Insert
│ │
│ └─→ 结果:带有符号但引用未解析的符号表
│
├─→ Phase 2: Resolution
│ │
│ ├─→ ResolveUnitDependencies()
│ │ │
│ │ └─→ 对每个 Unit.uses 查找目标 Unit
│ │ └─→ 检测循环依赖
│ │
│ └─→ ResolveClassHierarchy()
│ │
│ └─→ 对每个 Class.parent_names 查找父类
│ └─→ 检测循环继承
│
└─→ Phase 3: Validation
│
├─→ ValidateTypeReferences()
│ └─→ 检查所有类型名是否存在
│
├─→ ValidateMethodOverrides()
│ └─→ 检查 override 是否合法
│
└─→ ValidateVirtualMethods()
└─→ 检查虚方法表一致性
🏗️ 模块职责划分
📦 AST 模块 (ast/)
| 组件 | 职责 | 输入 | 输出 |
|---|---|---|---|
| deserializer | 将 Tree-sitter 的 CST 转换为 AST | TSNode, source code | vector |
| types | 定义 AST 节点类型 | - | 类型定义 |
设计原则:
- 无状态转换(纯函数)
- 错误容忍(收集错误而非中断)
- 完整信息保留(位置、类型、文本)
📦 符号表模块 (symbol/)
🔹 core/ - 核心类型
| 文件 | 职责 | 关键类型 |
|---|---|---|
| error | 定义错误类型 | ErrorKind, Error |
| symbol | 定义所有符号类型 | Symbol, Variable, Function, Class... |
| table | 管理作用域和符号 | Table, LookupResult |
| registry | 管理全局资源 | SymbolRegistry |
🔹 builder/ - 构建流程
| 文件 | 职责 | 主要方法 |
|---|---|---|
| reporter | 收集和报告错误 | Report(), GetErrors() |
| collector | 阶段1: 收集符号 | Collect(), Visit() |
| resolver | 阶段2: 解析引用 | Resolve(), ResolveUnitDependencies() |
| validator | 阶段3: 验证完整性 | Validate(), ValidateTypeReferences() |
| builder | 协调三阶段流程 | Build() |
🔹 factory/ - 工厂和管理
| 文件 | 职责 | 主要功能 |
|---|---|---|
| factory | 创建符号实例 | CreateVariable(), CreateClass()... |
| scope_manager | 管理当前作用域 | EnterScope(), ScopeGuard (RAII) |
🔹 utils/ - 工具类
| 文件 | 职责 | 主要功能 |
|---|---|---|
| type | 类型操作工具 | TypeFactory, TypeQuery, TypeFormatter |
| signature | 签名操作工具 | SignatureComparator, SignatureFormatter |
| class_member | 成员查找 | FindMember(), GetAllMethods() |
| class_hierarchy | 层次分析 | BuildVTable(), ValidateHierarchy() |
🔗 模块间依赖关系
┌─────────────────────────────────────────────────────────┐
│ Application │
└──────────────────────┬──────────────────────────────────┘
│ uses
▼
┌─────────────────────────────────────────────────────────┐
│ symbol/builder/builder │
│ (SymbolTableBuilder) │
└───────┬──────────────────────────────────┬──────────────┘
│ uses │ uses
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ symbol/builder/ │ │ symbol/core/ │
│ - collector │◄─────────────│ - registry │
│ - resolver │ uses │ - table │
│ - validator │ │ - symbol │
│ - reporter │ │ - error │
└────────┬─────────┘ └────────┬─────────┘
│ uses │
▼ │
┌──────────────────┐ │
│ symbol/factory/ │◄──────────────────────┘
│ - factory │ uses
│ - scope_manager │
└────────┬─────────┘
│ uses
▼
┌──────────────────┐
│ symbol/utils/ │
│ - type │
│ - signature │
│ - class_member │
│ - class_hierarchy│
└──────────────────┘
依赖规则:
- 上层模块依赖下层模块
- builder 依赖 core, factory, utils
- factory 依赖 core, utils
- utils 依赖 core
- core 无外部依赖(除了 ast)
🎯 关键设计模式
1. Visitor 模式 (AST 遍历)
// Collector 访问 AST
class Collector {
bool Visit(const ast::ASTNode& node) {
if (auto* unit = std::get_if<ast::UnitDefinition>(&node))
return CollectUnit(*unit);
if (auto* cls = std::get_if<ast::ClassDefinition>(&node))
return CollectClass(*cls);
// ...
}
};
优点:
- 分离数据结构和操作
- 易于添加新的访问操作
- 类型安全(使用 variant)
2. Factory 模式 (符号创建)
// 统一的符号创建入口
class Factory {
static VariablePtr CreateVariable(...);
static FunctionPtr CreateFunction(...);
static ClassPtr CreateClass(...);
};
优点:
- 统一创建逻辑
- 易于维护和扩展
- 可以添加缓存、验证等逻辑
3. RAII 模式 (作用域管理)
// 自动管理作用域切换
class ScopeGuard {
~ScopeGuard() { /* 自动恢复 */ }
};
// 使用
auto guard = scope_manager.EnterScope(new_scope);
// 作用域内操作
// guard 析构时自动恢复
优点:
- 异常安全
- 自动资源管理
- 避免忘记恢复
4. Builder 模式 (符号表构建)
class SymbolTableBuilder {
bool Build(nodes) {
Collector collector(...);
collector.Collect(nodes);
ReferenceResolver resolver(...);
resolver.Resolve();
Validator validator(...);
validator.Validate();
}
};
优点:
- 分步构建复杂对象
- 易于理解和维护
- 可以中断和恢复
5. Strategy 模式 (错误报告)
class ErrorReporter {
void Report(ErrorKind kind, ...);
};
// 不同组件使用同一报告器
Collector collector(registry, reporter);
Resolver resolver(registry, reporter);
Validator validator(registry, reporter);
优点:
- 统一错误处理
- 易于替换报告策略
- 集中管理错误
📊 性能考虑
1. 时间复杂度
| 阶段 | 复杂度 | 说明 |
|---|---|---|
| 解析 | O(n) | n = 源代码大小 |
| 收集 | O(m) | m = AST 节点数 |
| 解析引用 | O(u + c) | u = Unit数, c = Class数 |
| 验证 | O(s) | s = 符号总数 |
总体:O(n + m + s) ≈ O(n),线性时间
2. 空间复杂度
| 数据结构 | 空间 | 优化 |
|---|---|---|
| AST | O(m) | 构建符号表后可释放 |
| 符号表 | O(s) | 使用智能指针共享 |
| 作用域树 | O(d) | d = 作用域深度,通常很小 |
总体:O(n),线性空间
3. 优化技术
- 增量更新:只重新解析修改的文件
- 缓存:缓存符号查找结果
- 延迟加载:按需加载 Unit 内容
- 并行处理:独立 Unit 可并行构建
🛡️ 错误处理策略
错误分类
| 错误类型 | 严重性 | 处理 |
|---|---|---|
| 语法错误 | Fatal | Tree-sitter 处理 |
| 结构错误 | Error | 收集但继续 |
| 类型错误 | Error | 收集但继续 |
| 警告 | Warning | 记录不中断 |
错误恢复
错误发生
│
├─→ 记录错误信息(位置、消息)
│
├─→ 尝试继续处理
│ └─→ 跳过当前节点
│ 或使用默认值
│
└─→ 返回 false 或 Error
│
└─→ 上层决定是否继续
原则:
- 尽可能收集多个错误
- 不因一个错误而停止整个过程
- 提供详细的错误位置和上下文
🔍 使用示例
完整流程
#include "ast/deserializer.hpp"
#include "symbol/builder/builder.hpp"
int main() {
// 1. 解析源代码
std::string source = ReadFile("program.pas");
TSTree* tree = ts_parser_parse_string(parser, nullptr,
source.c_str(),
source.length());
TSNode root = ts_tree_root_node(tree);
// 2. 反序列化为 AST
auto parse_result = ast::deserializer::ParseRoot(root, source);
if (parse_result.HasErrors()) {
// 处理解析错误
for (const auto& error : parse_result.errors) {
std::cerr << error.message << std::endl;
}
}
// 3. 构建符号表
symbol::SymbolTableBuilder builder;
bool success = builder.Build(parse_result.nodes);
if (!success) {
// 处理符号表错误
for (const auto& error : builder.GetErrors()) {
std::cerr << error.ToString() << std::endl;
}
return 1;
}
// 4. 使用符号表
auto& registry = builder.GetRegistry();
// 查找符号
auto result = registry.GlobalScope()->Lookup("MyClass");
if (result) {
auto* cls = dynamic_cast<symbol::Class*>(result.symbol);
// 使用类信息...
}
// 查找 Unit
auto unit = registry.FindUnit("System");
if (unit) {
// 使用 Unit 信息...
}
return 0;
}
📝 总结
核心理念
- 分层清晰:解析 → AST → 符号表,每层职责明确
- 错误容忍:收集所有错误,不因一个错误而停止
- 三阶段构建:收集 → 解析 → 验证,逐步完善符号表
- 类型安全:使用 variant, dynamic_cast 等确保类型安全
- 资源管理:使用智能指针和 RAII 自动管理资源
扩展点
- 新的 AST 节点:在 types.hpp 添加类型,在 deserializer 添加解析
- 新的符号类型:在 symbol.hpp 添加类型,在 factory 添加创建方法
- 新的验证规则:在 validator 添加验证方法
- 新的工具函数:在 utils/ 添加工具类
最佳实践
- 保持模块职责单一
- 使用前向声明减少编译依赖
- 在 .cpp 文件中包含完整定义
- 使用 RAII 管理资源
- 收集错误而非立即中断