重构语法树/符号表
This commit is contained in:
@@ -0,0 +1,541 @@
|
||||
# 从反序列化到符号表 - 设计架构
|
||||
|
||||
## 📐 系统架构总览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 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<ASTNode> |
|
||||
| **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 遍历)
|
||||
|
||||
```cpp
|
||||
// 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 模式 (符号创建)
|
||||
|
||||
```cpp
|
||||
// 统一的符号创建入口
|
||||
class Factory {
|
||||
static VariablePtr CreateVariable(...);
|
||||
static FunctionPtr CreateFunction(...);
|
||||
static ClassPtr CreateClass(...);
|
||||
};
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 统一创建逻辑
|
||||
- 易于维护和扩展
|
||||
- 可以添加缓存、验证等逻辑
|
||||
|
||||
### 3. RAII 模式 (作用域管理)
|
||||
|
||||
```cpp
|
||||
// 自动管理作用域切换
|
||||
class ScopeGuard {
|
||||
~ScopeGuard() { /* 自动恢复 */ }
|
||||
};
|
||||
|
||||
// 使用
|
||||
auto guard = scope_manager.EnterScope(new_scope);
|
||||
// 作用域内操作
|
||||
// guard 析构时自动恢复
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 异常安全
|
||||
- 自动资源管理
|
||||
- 避免忘记恢复
|
||||
|
||||
### 4. Builder 模式 (符号表构建)
|
||||
|
||||
```cpp
|
||||
class SymbolTableBuilder {
|
||||
bool Build(nodes) {
|
||||
Collector collector(...);
|
||||
collector.Collect(nodes);
|
||||
|
||||
ReferenceResolver resolver(...);
|
||||
resolver.Resolve();
|
||||
|
||||
Validator validator(...);
|
||||
validator.Validate();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 分步构建复杂对象
|
||||
- 易于理解和维护
|
||||
- 可以中断和恢复
|
||||
|
||||
### 5. Strategy 模式 (错误报告)
|
||||
|
||||
```cpp
|
||||
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
|
||||
│
|
||||
└─→ 上层决定是否继续
|
||||
```
|
||||
|
||||
**原则**:
|
||||
- 尽可能收集多个错误
|
||||
- 不因一个错误而停止整个过程
|
||||
- 提供详细的错误位置和上下文
|
||||
|
||||
---
|
||||
|
||||
## 🔍 使用示例
|
||||
|
||||
### 完整流程
|
||||
|
||||
```cpp
|
||||
#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;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
### 核心理念
|
||||
|
||||
1. **分层清晰**:解析 → AST → 符号表,每层职责明确
|
||||
2. **错误容忍**:收集所有错误,不因一个错误而停止
|
||||
3. **三阶段构建**:收集 → 解析 → 验证,逐步完善符号表
|
||||
4. **类型安全**:使用 variant, dynamic_cast 等确保类型安全
|
||||
5. **资源管理**:使用智能指针和 RAII 自动管理资源
|
||||
|
||||
### 扩展点
|
||||
|
||||
- **新的 AST 节点**:在 types.hpp 添加类型,在 deserializer 添加解析
|
||||
- **新的符号类型**:在 symbol.hpp 添加类型,在 factory 添加创建方法
|
||||
- **新的验证规则**:在 validator 添加验证方法
|
||||
- **新的工具函数**:在 utils/ 添加工具类
|
||||
|
||||
### 最佳实践
|
||||
|
||||
- 保持模块职责单一
|
||||
- 使用前向声明减少编译依赖
|
||||
- 在 .cpp 文件中包含完整定义
|
||||
- 使用 RAII 管理资源
|
||||
- 收集错误而非立即中断
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "./cache.hpp"
|
||||
#include "./tree_sitter_utils.hpp"
|
||||
|
||||
namespace lsp::language::ast
|
||||
{
|
||||
NodeCache::NodeCache(size_t max_size) :
|
||||
max_size_(max_size)
|
||||
{
|
||||
}
|
||||
|
||||
const ASTNode* NodeCache::Find(const NodeKey& key)
|
||||
{
|
||||
auto it = cache_.find(key);
|
||||
if (it != cache_.end())
|
||||
{
|
||||
// 缓存命中,更新LRU
|
||||
Touch(key, it->second.lru_iter);
|
||||
++hit_count_;
|
||||
return &it->second.node;
|
||||
}
|
||||
|
||||
++miss_count_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NodeCache::Insert(const NodeKey& key, const ASTNode& node)
|
||||
{
|
||||
auto it = cache_.find(key);
|
||||
|
||||
if (it != cache_.end())
|
||||
{
|
||||
// 键已存在,更新值和LRU
|
||||
it->second.node = node;
|
||||
Touch(key, it->second.lru_iter);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否需要淘汰
|
||||
if (cache_.size() >= max_size_)
|
||||
{
|
||||
EvictLRU();
|
||||
}
|
||||
|
||||
// 插入新条目
|
||||
lru_list_.push_front(key);
|
||||
cache_[key] = CacheEntry{ node, lru_list_.begin() };
|
||||
}
|
||||
|
||||
void NodeCache::Clear()
|
||||
{
|
||||
cache_.clear();
|
||||
lru_list_.clear();
|
||||
ResetStats();
|
||||
}
|
||||
|
||||
void NodeCache::EvictLRU()
|
||||
{
|
||||
if (lru_list_.empty())
|
||||
return;
|
||||
|
||||
// 移除最久未使用的(列表尾部)
|
||||
const NodeKey& evict_key = lru_list_.back();
|
||||
cache_.erase(evict_key);
|
||||
lru_list_.pop_back();
|
||||
}
|
||||
|
||||
void NodeCache::Touch([[maybe_unused]] const NodeKey& key, KeyIter iter)
|
||||
{
|
||||
// 将元素移到列表前面(最近使用)
|
||||
lru_list_.splice(lru_list_.begin(), lru_list_, iter);
|
||||
}
|
||||
|
||||
NodeKey NodeCache::MakeKey(const ASTNode& node)
|
||||
{
|
||||
return std::visit([](auto&& arg) -> NodeKey {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, std::monostate>)
|
||||
{
|
||||
return NodeKey{ 0, 0, "" };
|
||||
}
|
||||
else
|
||||
{
|
||||
return NodeKey{
|
||||
arg.location.start_byte,
|
||||
arg.location.end_byte,
|
||||
arg.node_type
|
||||
};
|
||||
}
|
||||
},
|
||||
node);
|
||||
}
|
||||
|
||||
NodeKey NodeCache::MakeKey(TSNode ts_node)
|
||||
{
|
||||
return NodeKey{
|
||||
ts_node_start_byte(ts_node),
|
||||
ts_node_end_byte(ts_node),
|
||||
std::string(ts::Type(ts_node))
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <cstddef>
|
||||
#include "./types.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
|
||||
namespace lsp::language::ast
|
||||
{
|
||||
// ==================== 缓存键 ====================
|
||||
|
||||
struct NodeKey
|
||||
{
|
||||
uint32_t start_byte;
|
||||
uint32_t end_byte;
|
||||
std::string node_type;
|
||||
|
||||
inline bool operator==(const NodeKey& other) const
|
||||
{
|
||||
return start_byte == other.start_byte &&
|
||||
end_byte == other.end_byte &&
|
||||
node_type == other.node_type;
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeKeyHash
|
||||
{
|
||||
inline size_t operator()(const NodeKey& key) const
|
||||
{
|
||||
return std::hash<uint32_t>()(key.start_byte) ^
|
||||
(std::hash<uint32_t>()(key.end_byte) << 1) ^
|
||||
(std::hash<std::string>()(key.node_type) << 2);
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== LRU 缓存(重构 1)====================
|
||||
|
||||
class NodeCache
|
||||
{
|
||||
public:
|
||||
explicit NodeCache(size_t max_size = 1000);
|
||||
|
||||
const ASTNode* Find(const NodeKey& key);
|
||||
void Insert(const NodeKey& key, const ASTNode& node);
|
||||
void Clear();
|
||||
inline size_t Size() const { return cache_.size(); }
|
||||
inline void SetMaxSize(size_t max_size) { max_size_ = max_size; }
|
||||
inline size_t GetMaxSize() const { return max_size_; }
|
||||
|
||||
// 缓存统计
|
||||
inline size_t HitCount() const { return hit_count_; }
|
||||
inline size_t MissCount() const { return miss_count_; }
|
||||
inline double HitRate() const
|
||||
{
|
||||
size_t total = hit_count_ + miss_count_;
|
||||
return total > 0 ? static_cast<double>(hit_count_) / total : 0.0;
|
||||
}
|
||||
|
||||
// 重置统计
|
||||
inline void ResetStats()
|
||||
{
|
||||
hit_count_ = 0;
|
||||
miss_count_ = 0;
|
||||
}
|
||||
|
||||
static NodeKey MakeKey(const ASTNode& node);
|
||||
static NodeKey MakeKey(TSNode ts_node);
|
||||
|
||||
private:
|
||||
// LRU 列表:最近使用的在前面
|
||||
using KeyList = std::list<NodeKey>;
|
||||
using KeyIter = KeyList::iterator;
|
||||
|
||||
struct CacheEntry
|
||||
{
|
||||
ASTNode node;
|
||||
KeyIter lru_iter;
|
||||
};
|
||||
|
||||
void EvictLRU();
|
||||
void Touch(const NodeKey& key, KeyIter iter);
|
||||
|
||||
size_t max_size_;
|
||||
KeyList lru_list_;
|
||||
std::unordered_map<NodeKey, CacheEntry, NodeKeyHash> cache_;
|
||||
|
||||
// 统计信息
|
||||
size_t hit_count_ = 0;
|
||||
size_t miss_count_ = 0;
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include "./types.hpp"
|
||||
#include "./tree_sitter_utils.hpp"
|
||||
#include "./cache.hpp"
|
||||
|
||||
namespace lsp::language::ast
|
||||
{
|
||||
// ==================== 增量解析结果 ====================
|
||||
|
||||
struct IncrementalParseResult
|
||||
{
|
||||
ParseResult result;
|
||||
std::vector<size_t> changed_indices;
|
||||
std::vector<size_t> reused_indices;
|
||||
|
||||
inline size_t ChangedCount() const { return changed_indices.size(); }
|
||||
inline size_t ReusedCount() const { return reused_indices.size(); }
|
||||
inline size_t TotalCount() const { return result.nodes.size(); }
|
||||
inline double ReuseRate() const
|
||||
{
|
||||
return TotalCount() > 0 ? static_cast<double>(ReusedCount()) / TotalCount() : 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
class Deserializer
|
||||
{
|
||||
public:
|
||||
Deserializer();
|
||||
~Deserializer();
|
||||
|
||||
// 基础解析(不使用缓存)
|
||||
ParseResult Parse(TSNode root, const std::string& source);
|
||||
|
||||
// 增量解析(自动复用缓存)
|
||||
IncrementalParseResult ParseIncremental(TSNode root, const std::string& source);
|
||||
|
||||
// 缓存管理
|
||||
void ClearCache();
|
||||
size_t CacheSize() const;
|
||||
void SetCacheMaxSize(size_t max_size);
|
||||
|
||||
// 缓存统计
|
||||
double CacheHitRate() const;
|
||||
void ResetCacheStats();
|
||||
|
||||
private:
|
||||
std::unique_ptr<NodeCache> cache_;
|
||||
|
||||
void ParseChildWithCache(TSNode child, const std::string& source, IncrementalParseResult& result);
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
using ParseFunc = std::function<Result<ASTNode>(TSNode, const std::string&)>;
|
||||
|
||||
// 获取解析函数映射表
|
||||
const std::unordered_map<std::string, ParseFunc>& GetParseFuncMap();
|
||||
|
||||
// 辅助函数
|
||||
template<typename T>
|
||||
inline void InitNode(T& node, TSNode ts_node)
|
||||
{
|
||||
node.location = ts::NodeLocation(ts_node);
|
||||
node.node_type = std::string(ts::Type(ts_node));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool ExtractNameAndLocation(T& node, TSNode ts_node, const std::string& source)
|
||||
{
|
||||
TSNode name_node = ts::FieldChild(ts_node, "name");
|
||||
if (ts::IsNull(name_node))
|
||||
return false;
|
||||
|
||||
node.name = ts::Text(name_node, source);
|
||||
node.name_location = ts::NodeLocation(name_node);
|
||||
return !node.name.empty();
|
||||
}
|
||||
|
||||
Result<std::string> GetRequiredField(TSNode node, std::string_view field, const std::string& source, const std::string& error_msg);
|
||||
Result<std::string> ParseType(TSNode node, const std::string& source);
|
||||
Result<Signature> ParseSignature(TSNode node, const std::string& source);
|
||||
Result<std::vector<Parameter>> ParseParameters(TSNode node, const std::string& source);
|
||||
Result<Block> ParseBlock(TSNode node, const std::string& source);
|
||||
Access ParseAccess(std::string_view text);
|
||||
ParseError MakeError(TSNode node, const std::string& message, ErrorSeverity severity = ErrorSeverity::Error);
|
||||
|
||||
template<typename T>
|
||||
inline std::vector<Result<T>> SplitVariableDeclaration(
|
||||
TSNode node,
|
||||
const std::string& source,
|
||||
std::function<Result<T>(TSNode, const std::string&, const std::string&, TSNode)> parse_func)
|
||||
{
|
||||
std::vector<Result<T>> results;
|
||||
auto names = ts::FieldSummaries(node, "name", source);
|
||||
for (const auto& name_summary : names)
|
||||
{
|
||||
results.push_back(parse_func(node, source, name_summary.text, name_summary.node));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void ParseClassMembers(TSNode body_node, const std::string& source, ClassDefinition& def);
|
||||
void ParseClassVariableMember(TSNode node, const std::string& source, Access current_access, ClassDefinition& def);
|
||||
void ParseClassMethodMember(TSNode node, const std::string& source, Access current_access, ClassDefinition& def);
|
||||
void ParseClassPropertyMember(TSNode node, const std::string& source, Access current_access, ClassDefinition& def);
|
||||
|
||||
ParseResult ParseStatements(TSNode node, const std::string& source);
|
||||
ParseResult ParseChildren(const std::vector<TSNode>& children, const std::string& source);
|
||||
}
|
||||
|
||||
// ==================== 顶层解析 API ====================
|
||||
|
||||
Result<ASTNode> ParseNode(TSNode node, const std::string& source);
|
||||
ParseResult ParseRoot(TSNode root, const std::string& source);
|
||||
|
||||
// ==================== 具体类型解析函数 ====================
|
||||
|
||||
Result<VarDeclaration> ParseVarDeclaration(TSNode node, const std::string& source, const std::string& var_name, TSNode name_node);
|
||||
Result<StaticDeclaration> ParseStaticDeclaration(TSNode node, const std::string& source, const std::string& var_name, TSNode name_node);
|
||||
Result<GlobalDeclaration> ParseGlobalDeclaration(TSNode node, const std::string& source, const std::string& var_name, TSNode name_node);
|
||||
Result<ConstDeclaration> ParseConstDeclaration(TSNode node, const std::string& source);
|
||||
Result<AssignmentStatement> ParseAssignmentStatement(TSNode node, const std::string& source);
|
||||
Result<FunctionDefinition> ParseFunctionDefinition(TSNode node, const std::string& source);
|
||||
Result<ClassDefinition> ParseClassDefinition(TSNode node, const std::string& source);
|
||||
Result<Method> ParseMethod(TSNode node, const std::string& source);
|
||||
Result<ExternalMethod> ParseExternalMethod(TSNode node, const std::string& source);
|
||||
Result<Property> ParseProperty(TSNode node, const std::string& source);
|
||||
Result<UnitDefinition> ParseUnitDefinition(TSNode node, const std::string& source);
|
||||
Result<UsesClause> ParseUsesClause(TSNode node, const std::string& source);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "./tree_sitter_utils.hpp"
|
||||
|
||||
namespace lsp::language::ast::ts
|
||||
{
|
||||
// ==================== 字符串池实现 ====================
|
||||
|
||||
StringPool& StringPool::Instance()
|
||||
{
|
||||
static StringPool instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::string_view StringPool::Intern(std::string_view str)
|
||||
{
|
||||
auto it = pool_.find(std::string(str));
|
||||
if (it != pool_.end())
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
|
||||
auto [inserted_it, _] = pool_.insert(std::string(str));
|
||||
return *inserted_it;
|
||||
}
|
||||
|
||||
void StringPool::Clear()
|
||||
{
|
||||
pool_.clear();
|
||||
}
|
||||
|
||||
// ==================== 文本提取 ====================
|
||||
|
||||
std::string Text(TSNode node, std::string_view source)
|
||||
{
|
||||
uint32_t start = ts_node_start_byte(node);
|
||||
uint32_t end = ts_node_end_byte(node);
|
||||
if (start >= source.length() || end > source.length() || start >= end)
|
||||
return "";
|
||||
return std::string(source.substr(start, end - start));
|
||||
}
|
||||
|
||||
std::string Text(TSNode node, const std::string& source)
|
||||
{
|
||||
return Text(node, std::string_view(source));
|
||||
}
|
||||
|
||||
Location NodeLocation(TSNode node)
|
||||
{
|
||||
TSPoint start = ts_node_start_point(node);
|
||||
TSPoint end = ts_node_end_point(node);
|
||||
return Location{
|
||||
static_cast<uint32_t>(start.row),
|
||||
static_cast<uint32_t>(start.column),
|
||||
static_cast<uint32_t>(end.row),
|
||||
static_cast<uint32_t>(end.column),
|
||||
ts_node_start_byte(node),
|
||||
ts_node_end_byte(node)
|
||||
};
|
||||
}
|
||||
|
||||
std::string FieldText(TSNode node, std::string_view field_name, std::string_view source)
|
||||
{
|
||||
TSNode field = FieldChild(node, field_name);
|
||||
return IsNull(field) ? "" : Text(field, source);
|
||||
}
|
||||
|
||||
std::string FieldText(TSNode node, std::string_view field_name, const std::string& source)
|
||||
{
|
||||
return FieldText(node, field_name, std::string_view(source));
|
||||
}
|
||||
|
||||
std::vector<TSNode> Children(TSNode node)
|
||||
{
|
||||
std::vector<TSNode> children;
|
||||
uint32_t count = ts_node_child_count(node);
|
||||
children.reserve(count);
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
children.push_back(ts_node_child(node, i));
|
||||
return children;
|
||||
}
|
||||
|
||||
std::vector<TSNode> FieldChildren(TSNode node, std::string_view field_name)
|
||||
{
|
||||
std::vector<TSNode> result;
|
||||
uint32_t count = ts_node_child_count(node);
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
const char* field = ts_node_field_name_for_child(node, i);
|
||||
if (field && field_name == field)
|
||||
result.push_back(ts_node_child(node, i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<NodeSummary> ChildSummaries(TSNode node, std::string_view source)
|
||||
{
|
||||
std::vector<NodeSummary> result;
|
||||
uint32_t count = ts_node_child_count(node);
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
TSNode child = ts_node_child(node, i);
|
||||
const char* field_name = ts_node_field_name_for_child(node, i);
|
||||
result.push_back(NodeSummary{
|
||||
.node = child,
|
||||
.field = field_name ? field_name : "",
|
||||
.type = std::string(Type(child)),
|
||||
.text = Text(child, source) });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<NodeSummary> ChildSummaries(TSNode node, const std::string& source)
|
||||
{
|
||||
return ChildSummaries(node, std::string_view(source));
|
||||
}
|
||||
|
||||
std::vector<NodeSummary> FieldSummaries(TSNode node, std::string_view field_name, std::string_view source)
|
||||
{
|
||||
std::vector<NodeSummary> result;
|
||||
uint32_t count = ts_node_child_count(node);
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
TSNode child = ts_node_child(node, i);
|
||||
const char* field = ts_node_field_name_for_child(node, i);
|
||||
if (field && field_name == field)
|
||||
{
|
||||
result.push_back(NodeSummary{
|
||||
.node = child,
|
||||
.field = field,
|
||||
.type = std::string(Type(child)),
|
||||
.text = Text(child, source) });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<NodeSummary> FieldSummaries(TSNode node, std::string_view field_name, const std::string& source)
|
||||
{
|
||||
return FieldSummaries(node, field_name, std::string_view(source));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include "./types.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
|
||||
namespace lsp::language::ast::ts
|
||||
{
|
||||
class StringPool
|
||||
{
|
||||
public:
|
||||
static StringPool& Instance();
|
||||
|
||||
// 缓存字符串,返回池中的引用
|
||||
std::string_view Intern(std::string_view str);
|
||||
|
||||
void Clear();
|
||||
size_t Size() const { return pool_.size(); }
|
||||
|
||||
private:
|
||||
StringPool() = default;
|
||||
StringPool(const StringPool&) = delete;
|
||||
StringPool& operator=(const StringPool&) = delete;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> pool_;
|
||||
};
|
||||
|
||||
// ==================== 节点摘要 ====================
|
||||
|
||||
struct NodeSummary
|
||||
{
|
||||
TSNode node;
|
||||
std::string field;
|
||||
std::string type;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
// ==================== 基础查询 ====================
|
||||
|
||||
// 获取节点文本(使用 string_view 优化)
|
||||
std::string Text(TSNode node, std::string_view source);
|
||||
std::string Text(TSNode node, const std::string& source);
|
||||
|
||||
// 获取节点类型(使用字符串池)
|
||||
inline std::string_view Type(TSNode node);
|
||||
|
||||
// 获取节点位置
|
||||
Location NodeLocation(TSNode node);
|
||||
|
||||
// 节点状态检查
|
||||
inline bool IsNull(TSNode node);
|
||||
inline bool IsComment(TSNode node);
|
||||
|
||||
// ==================== 字段操作 ====================
|
||||
|
||||
inline TSNode FieldChild(TSNode node, std::string_view field_name);
|
||||
std::string FieldText(TSNode node, std::string_view field_name, std::string_view source);
|
||||
std::string FieldText(TSNode node, std::string_view field_name, const std::string& source);
|
||||
inline bool HasField(TSNode node, std::string_view field_name);
|
||||
|
||||
// ==================== 子节点操作 ====================
|
||||
|
||||
std::vector<TSNode> Children(TSNode node);
|
||||
std::vector<TSNode> FieldChildren(TSNode node, std::string_view field_name);
|
||||
std::vector<NodeSummary> ChildSummaries(TSNode node, std::string_view source);
|
||||
std::vector<NodeSummary> ChildSummaries(TSNode node, const std::string& source);
|
||||
std::vector<NodeSummary> FieldSummaries(TSNode node, std::string_view field_name, std::string_view source);
|
||||
std::vector<NodeSummary> FieldSummaries(TSNode node, std::string_view field_name, const std::string& source);
|
||||
|
||||
// ==================== Inline 实现 ====================
|
||||
|
||||
inline std::string_view Type(TSNode node)
|
||||
{
|
||||
const char* type_str = ts_node_type(node);
|
||||
return StringPool::Instance().Intern(type_str);
|
||||
}
|
||||
|
||||
inline bool IsNull(TSNode node)
|
||||
{
|
||||
return ts_node_is_null(node);
|
||||
}
|
||||
|
||||
inline bool IsComment(TSNode node)
|
||||
{
|
||||
std::string_view type = Type(node);
|
||||
return type == "line_comment" || type == "block_comment" || type == "nested_comment";
|
||||
}
|
||||
|
||||
inline TSNode FieldChild(TSNode node, std::string_view field_name)
|
||||
{
|
||||
return ts_node_child_by_field_name(node, field_name.data(), field_name.length());
|
||||
}
|
||||
|
||||
inline bool HasField(TSNode node, std::string_view field_name)
|
||||
{
|
||||
return !IsNull(FieldChild(node, field_name));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace lsp::language::ast
|
||||
{
|
||||
// ==================== 基础类型 ====================
|
||||
|
||||
struct Location
|
||||
{
|
||||
uint32_t start_line = 0;
|
||||
uint32_t start_column = 0;
|
||||
uint32_t end_line = 0;
|
||||
uint32_t end_column = 0;
|
||||
uint32_t start_byte = 0;
|
||||
uint32_t end_byte = 0;
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
Location location;
|
||||
std::string node_type;
|
||||
};
|
||||
|
||||
struct Expression
|
||||
{
|
||||
Location location;
|
||||
std::string node_type;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
struct Parameter
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string name;
|
||||
std::optional<std::string> type_name;
|
||||
std::optional<std::string> default_value;
|
||||
bool is_var = false;
|
||||
bool is_out = false;
|
||||
};
|
||||
|
||||
struct Signature
|
||||
{
|
||||
std::vector<Parameter> parameters;
|
||||
std::optional<std::string> return_type;
|
||||
};
|
||||
|
||||
// ==================== 前向声明 ====================
|
||||
|
||||
struct VarDeclaration;
|
||||
struct StaticDeclaration;
|
||||
struct GlobalDeclaration;
|
||||
struct ConstDeclaration;
|
||||
struct AssignmentStatement;
|
||||
struct FunctionDefinition;
|
||||
struct ClassDefinition;
|
||||
struct Method;
|
||||
struct ExternalMethod;
|
||||
struct ConstructorDeclaration;
|
||||
struct DestructorDeclaration;
|
||||
struct Property;
|
||||
struct UsesClause;
|
||||
struct Block;
|
||||
struct UnitDefinition;
|
||||
|
||||
using ASTNode = std::variant<
|
||||
std::monostate,
|
||||
FunctionDefinition,
|
||||
ClassDefinition,
|
||||
VarDeclaration,
|
||||
StaticDeclaration,
|
||||
GlobalDeclaration,
|
||||
ConstDeclaration,
|
||||
AssignmentStatement,
|
||||
Method,
|
||||
ExternalMethod,
|
||||
Property,
|
||||
UsesClause,
|
||||
UnitDefinition,
|
||||
Expression,
|
||||
Block>;
|
||||
|
||||
// ==================== AST 节点定义 ====================
|
||||
|
||||
struct Block
|
||||
{
|
||||
Location location;
|
||||
std::string node_type;
|
||||
std::vector<ASTNode> statements;
|
||||
};
|
||||
|
||||
struct VarDeclaration
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::optional<std::string> type_name;
|
||||
std::optional<Expression> value;
|
||||
};
|
||||
|
||||
struct StaticDeclaration
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::optional<std::string> type_name;
|
||||
std::optional<Expression> value;
|
||||
};
|
||||
|
||||
struct GlobalDeclaration
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::optional<std::string> type_name;
|
||||
std::optional<Expression> value;
|
||||
};
|
||||
|
||||
struct ConstDeclaration
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::optional<std::string> type_name;
|
||||
Expression value;
|
||||
};
|
||||
|
||||
struct AssignmentStatement
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
Expression value;
|
||||
};
|
||||
|
||||
struct FunctionDefinition
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
bool is_overload = false;
|
||||
Signature signature;
|
||||
Block body;
|
||||
};
|
||||
|
||||
enum class Access
|
||||
{
|
||||
kPublic,
|
||||
kProtected,
|
||||
kPrivate
|
||||
};
|
||||
|
||||
struct Property
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::optional<std::string> type_name;
|
||||
std::optional<std::string> getter;
|
||||
std::optional<std::string> setter;
|
||||
};
|
||||
|
||||
enum class Modifier
|
||||
{
|
||||
kNone,
|
||||
kVirtual,
|
||||
kOverride,
|
||||
kOverload
|
||||
};
|
||||
|
||||
struct Method
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
Signature signature;
|
||||
bool is_class_method = false;
|
||||
Modifier modifier = Modifier::kNone;
|
||||
std::optional<Block> body;
|
||||
};
|
||||
|
||||
struct ExternalMethod
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string class_name;
|
||||
std::string method_name;
|
||||
Signature signature;
|
||||
bool is_class_method = false;
|
||||
bool is_operator = false;
|
||||
std::string operator_symbol;
|
||||
Modifier modifier = Modifier::kNone;
|
||||
Block body;
|
||||
};
|
||||
|
||||
struct ConstructorDeclaration
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
Signature signature;
|
||||
std::optional<Block> body;
|
||||
};
|
||||
|
||||
struct DestructorDeclaration
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::optional<Block> body;
|
||||
};
|
||||
|
||||
struct ClassMember
|
||||
{
|
||||
Access access = Access::kPublic;
|
||||
std::variant<
|
||||
std::monostate,
|
||||
VarDeclaration,
|
||||
StaticDeclaration,
|
||||
Method,
|
||||
ConstructorDeclaration,
|
||||
DestructorDeclaration,
|
||||
Property>
|
||||
content;
|
||||
};
|
||||
|
||||
struct ClassDefinition
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::vector<std::string> parents;
|
||||
std::vector<ClassMember> members;
|
||||
};
|
||||
|
||||
struct UsesClause
|
||||
{
|
||||
Location location;
|
||||
std::string node_type;
|
||||
std::vector<std::string> units;
|
||||
};
|
||||
|
||||
struct UnitDefinition
|
||||
{
|
||||
Location location;
|
||||
Location name_location;
|
||||
std::string node_type;
|
||||
std::string name;
|
||||
std::optional<UsesClause> uses;
|
||||
std::vector<ASTNode> interface_statements;
|
||||
std::vector<ASTNode> implementation_statements;
|
||||
std::vector<ASTNode> initialization_statements;
|
||||
std::vector<ASTNode> finalization_statements;
|
||||
};
|
||||
|
||||
// ==================== 错误处理 ====================
|
||||
|
||||
enum class ErrorSeverity
|
||||
{
|
||||
Warning,
|
||||
Error,
|
||||
Fatal
|
||||
};
|
||||
|
||||
struct ParseError
|
||||
{
|
||||
Location location;
|
||||
std::string node_type;
|
||||
std::string message;
|
||||
ErrorSeverity severity = ErrorSeverity::Error;
|
||||
};
|
||||
|
||||
struct ParseResult
|
||||
{
|
||||
std::vector<ASTNode> nodes;
|
||||
std::vector<ParseError> errors;
|
||||
|
||||
inline bool HasErrors() const { return !errors.empty(); }
|
||||
inline bool IsSuccess() const { return errors.empty(); }
|
||||
};
|
||||
|
||||
// ==================== Result<T> 模板 ====================
|
||||
|
||||
template<typename T>
|
||||
class Result
|
||||
{
|
||||
public:
|
||||
static Result<T> Ok(T&& val)
|
||||
{
|
||||
return { true, std::move(val), "", ErrorSeverity::Error };
|
||||
}
|
||||
|
||||
static Result<T> Err(const std::string& msg, ErrorSeverity sev = ErrorSeverity::Error)
|
||||
{
|
||||
return { false, std::nullopt, msg, sev };
|
||||
}
|
||||
|
||||
inline bool IsOk() const { return success; }
|
||||
inline bool IsErr() const { return !success; }
|
||||
|
||||
T Unwrap() &&
|
||||
{
|
||||
if (!success)
|
||||
throw std::runtime_error("Unwrap on error: " + error);
|
||||
return std::move(value).value();
|
||||
}
|
||||
|
||||
T UnwrapOr(T&& default_val) &&
|
||||
{
|
||||
return success ? std::move(*value) : std::move(default_val);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
std::optional<T> value;
|
||||
std::string error;
|
||||
ErrorSeverity severity = ErrorSeverity::Error;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "./repo.hpp"
|
||||
|
||||
namespace lsp::language::keyword
|
||||
{
|
||||
Repo& Repo::Instance()
|
||||
{
|
||||
static Repo instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Repo::Repo()
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
std::vector<Info> Repo::GetAll()
|
||||
{
|
||||
std::vector<Info> keyword;
|
||||
keyword.reserve(keywords_.size());
|
||||
for (const auto& [key, value] : keywords_)
|
||||
keyword.push_back(value);
|
||||
return keyword;
|
||||
}
|
||||
|
||||
std::vector<Info> Repo::FindByPrefix(std::string_view prefix)
|
||||
{
|
||||
std::vector<Info> keyword;
|
||||
for (const auto& [key, value] : keywords_)
|
||||
{
|
||||
if (key.starts_with(prefix))
|
||||
keyword.push_back(value);
|
||||
}
|
||||
return keyword;
|
||||
}
|
||||
|
||||
std::optional<Info> Repo::FindByName(std::string_view name)
|
||||
{
|
||||
auto target = keywords_.find(std::string(name));
|
||||
if (target == keywords_.end())
|
||||
return std::nullopt;
|
||||
return target->second;
|
||||
}
|
||||
|
||||
void Repo::Load()
|
||||
{
|
||||
keywords_.reserve(200);
|
||||
|
||||
LoadProgramStructure();
|
||||
LoadDataTypes();
|
||||
LoadClasses();
|
||||
LoadControlFlow();
|
||||
LoadOperators();
|
||||
LoadSql();
|
||||
LoadBuiltins();
|
||||
LoadConstants();
|
||||
}
|
||||
|
||||
void Repo::LoadProgramStructure()
|
||||
{
|
||||
keywords_["program"] = {"program", Kind::kProgramStructure, ""};
|
||||
keywords_["function"] = {"function", Kind::kProgramStructure, ""};
|
||||
keywords_["procedure"] = {"procedure", Kind::kProgramStructure, ""};
|
||||
keywords_["unit"] = {"unit", Kind::kProgramStructure, ""};
|
||||
keywords_["uses"] = {"uses", Kind::kProgramStructure, ""};
|
||||
keywords_["implementation"] = {"implementation", Kind::kProgramStructure, ""};
|
||||
keywords_["interface"] = {"interface", Kind::kProgramStructure, ""};
|
||||
keywords_["initialization"] = {"initialization", Kind::kProgramStructure, ""};
|
||||
keywords_["finalization"] = {"finalization", Kind::kProgramStructure, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadDataTypes()
|
||||
{
|
||||
keywords_["string"] = {"string", Kind::kDataTypes, ""};
|
||||
keywords_["integer"] = {"integer", Kind::kDataTypes, ""};
|
||||
keywords_["boolean"] = {"boolean", Kind::kDataTypes, ""};
|
||||
keywords_["int64"] = {"int64", Kind::kDataTypes, ""};
|
||||
keywords_["real"] = {"real", Kind::kDataTypes, ""};
|
||||
keywords_["array"] = {"array", Kind::kDataTypes, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadClasses()
|
||||
{
|
||||
keywords_["type"] = {"type", Kind::kClassTypes, ""};
|
||||
keywords_["class"] = {"class", Kind::kClassTypes, ""};
|
||||
keywords_["new"] = {"new", Kind::kClassTypes, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadControlFlow()
|
||||
{
|
||||
keywords_["if"] = {"if", Kind::kConditionals, ""};
|
||||
keywords_["for"] = {"for", Kind::kLoops, ""};
|
||||
keywords_["while"] = {"while", Kind::kLoops, ""};
|
||||
keywords_["case"] = {"case", Kind::kConditionals, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadOperators()
|
||||
{
|
||||
keywords_["and"] = {"and", Kind::kLogicalOperators, ""};
|
||||
keywords_["or"] = {"or", Kind::kLogicalOperators, ""};
|
||||
keywords_["div"] = {"div", Kind::kArithmeticOperators, ""};
|
||||
keywords_["mod"] = {"mod", Kind::kArithmeticOperators, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadSql()
|
||||
{
|
||||
keywords_["select"] = {"select", Kind::kSqlControl, ""};
|
||||
keywords_["update"] = {"update", Kind::kSqlControl, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadBuiltins()
|
||||
{
|
||||
keywords_["echo"] = {"echo", Kind::kBuiltinFunctions, ""};
|
||||
keywords_["mtic"] = {"mtic", Kind::kBuiltinFunctions, ""};
|
||||
keywords_["mtoc"] = {"mtoc", Kind::kBuiltinFunctions, ""};
|
||||
}
|
||||
|
||||
void Repo::LoadConstants()
|
||||
{
|
||||
keywords_["true"] = {"true", Kind::kBooleanConstants, ""};
|
||||
keywords_["false"] = {"false", Kind::kBooleanConstants, ""};
|
||||
keywords_["nil"] = {"nil", Kind::kNullConstants, ""};
|
||||
keywords_["inf"] = {"inf", Kind::kMathConstants, ""};
|
||||
keywords_["nan"] = {"nan", Kind::kMathConstants, ""};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "./types.hpp"
|
||||
|
||||
namespace lsp::language::keyword
|
||||
{
|
||||
class Repo
|
||||
{
|
||||
public:
|
||||
Repo(const Repo&) = delete;
|
||||
Repo& operator=(const Repo&) = delete;
|
||||
|
||||
static Repo& Instance();
|
||||
std::vector<Info> GetAll();
|
||||
std::vector<Info> FindByPrefix(std::string_view prefix);
|
||||
std::optional<Info> FindByName(std::string_view name);
|
||||
|
||||
private:
|
||||
Repo();
|
||||
void Load();
|
||||
|
||||
void LoadProgramStructure();
|
||||
void LoadDataTypes();
|
||||
void LoadClasses();
|
||||
void LoadControlFlow();
|
||||
void LoadOperators();
|
||||
void LoadSql();
|
||||
void LoadBuiltins();
|
||||
void LoadConstants();
|
||||
|
||||
// std::unordered_map<std::string, Info, std::hash<std::string_view>, std::equal_to<>> keywords_;
|
||||
std::unordered_map<std::string, Info> keywords_;
|
||||
};
|
||||
}
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "../protocol/protocol.hpp"
|
||||
#include "../../protocol/protocol.hpp"
|
||||
|
||||
namespace tsl
|
||||
namespace lsp::language::keyword
|
||||
{
|
||||
enum class KeywordCategory
|
||||
enum class Kind
|
||||
{
|
||||
kProgramStructure, // program, function, procedure, unit, uses, implementation, interface, initialization, finalization
|
||||
kDataTypes, // string, integer, boolean, int64, real, array
|
||||
@@ -39,10 +39,10 @@ namespace tsl
|
||||
kNullConstants // nil
|
||||
};
|
||||
|
||||
struct KeywordInfo
|
||||
struct Info
|
||||
{
|
||||
std::string keyword;
|
||||
KeywordCategory category;
|
||||
Kind category;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
#include "./keyword_manager.hpp"
|
||||
|
||||
namespace tsl
|
||||
{
|
||||
KeywordManager& KeywordManager::GetInstance()
|
||||
{
|
||||
static KeywordManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
KeywordManager::KeywordManager()
|
||||
{
|
||||
InitKeywords();
|
||||
}
|
||||
|
||||
std::vector<KeywordInfo> KeywordManager::GetAllKeywords()
|
||||
{
|
||||
std::vector<KeywordInfo> keyword;
|
||||
keyword.reserve(keywords_.size());
|
||||
for (const auto& [key, value] : keywords_)
|
||||
keyword.push_back(value);
|
||||
return keyword;
|
||||
}
|
||||
|
||||
std::vector<KeywordInfo> KeywordManager::GetKeyWordByPrefix(std::string prefix)
|
||||
{
|
||||
std::vector<KeywordInfo> keyword;
|
||||
for (const auto& [key, value] : keywords_)
|
||||
{
|
||||
if (key.starts_with(prefix))
|
||||
keyword.push_back(value);
|
||||
}
|
||||
return keyword;
|
||||
}
|
||||
|
||||
std::optional<KeywordInfo> KeywordManager::GetKeywordInfo(std::string key)
|
||||
{
|
||||
auto target = keywords_.find(key);
|
||||
if (target == keywords_.end())
|
||||
return std::nullopt;
|
||||
return target->second;
|
||||
}
|
||||
|
||||
void KeywordManager::InitKeywords()
|
||||
{
|
||||
keywords_.reserve(200);
|
||||
|
||||
InitProgramStructureKeywords();
|
||||
InitDataTypeKeywords();
|
||||
InitClassKeywords();
|
||||
InitControlFlowKeywords();
|
||||
InitOperatorKeywords();
|
||||
InitSqlKeywords();
|
||||
InitBuiltinKeywords();
|
||||
InitConstantKeywords();
|
||||
}
|
||||
|
||||
void KeywordManager::InitProgramStructureKeywords()
|
||||
{
|
||||
keywords_["program"] = {
|
||||
"program",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Program\n\n程序开始的入口,一般用户不需要使用,在作为独立的TSL脚本时可以使用。 \n通常来说,倘若编写TSL代码作为CGI执行运行,系统默认以PROGRAM模式运行。虽然TSL可以省略PROGRAM关键字,但是使用PROGRAM关键字可以使得TSL代码里包含子函数.\n\n**例如:**\n```pascal\nprogram Test;\n\tfunction sub1();\n\tbegin\n\t\twriteln('Execute sub1');\n\tend;\nbegin\n\tsub1();\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["function"] = {
|
||||
"function",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Function\n\n函数声明开始,组成类似于FUNCTION XXXX(); BEGIN END;的函数块"
|
||||
};
|
||||
|
||||
keywords_["procedure"] = {
|
||||
"procedure",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Procedure\n\n与FUNCTION类似,但是在函数头后不允许加返回类型值"
|
||||
};
|
||||
|
||||
keywords_["unit"] = {
|
||||
"unit",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Unit Declaration\n\nDeclares a code unit/module.\n\n**Syntax:**\n```pascal\nunit UnitName;\ninterface\n // public declarations\nimplementation\n // private implementation\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["uses"] = {
|
||||
"uses",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Uses Clause\n\nImports external units/modules.\n\n**Syntax:**\n```pascal\nuses Unit1, Unit2, Unit3;\n```\n\n**Example:**\n```pascal\nuses System, SysUtils, Classes;\n```"
|
||||
};
|
||||
|
||||
keywords_["implementation"] = {
|
||||
"implementation",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Implementation Section\n\nMarks the beginning of the private implementation section in a unit.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\n // public interface\nimplementation\n // private implementation\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["interface"] = {
|
||||
"interface",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Interface Section\n\nMarks the public interface section in a unit.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\n // public declarations\n function PublicFunction: integer;\nimplementation\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["initialization"] = {
|
||||
"initialization",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Initialization Section\n\nCode executed when the unit is first loaded.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\nimplementation\ninitialization\n // initialization code\nend.\n```"
|
||||
};
|
||||
|
||||
keywords_["finalization"] = {
|
||||
"finalization",
|
||||
KeywordCategory::kProgramStructure,
|
||||
"## Finalization Section\n\nCode executed when the program terminates.\n\n**Usage:**\n```pascal\nunit MyUnit;\ninterface\nimplementation\ninitialization\n // setup code\nfinalization\n // cleanup code\nend.\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitDataTypeKeywords()
|
||||
{
|
||||
keywords_["string"] = {
|
||||
"string",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## String Type\n\nVariable-length string data type.\n\n**Example:**\n```pascal\nvar\n myString: string;\nbegin\n myString := 'Hello World';\nend;\n```\n\n**Note:** Supports Unicode and automatic memory management."
|
||||
};
|
||||
|
||||
keywords_["integer"] = {
|
||||
"integer",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Integer Type\n\n32-bit signed integer data type.\n\n**Range:** -2,147,483,648 to 2,147,483,647\n\n**Example:**\n```pascal\nvar\n count: integer;\nbegin\n count := 42;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["boolean"] = {
|
||||
"boolean",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Boolean Type\n\nLogical data type with values `true` or `false`.\n\n**Example:**\n```pascal\nvar\n isValid: boolean;\nbegin\n isValid := true;\n if isValid then\n echo('Valid!');\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["int64"] = {
|
||||
"int64",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Int64 Type\n\n64-bit signed integer data type.\n\n**Range:** -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807\n\n**Example:**\n```pascal\nvar\n bigNumber: int64;\nbegin\n bigNumber := 1234567890123456789;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["real"] = {
|
||||
"real",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Real Type\n\nFloating-point number data type.\n\n**Example:**\n```pascal\nvar\n price: real;\nbegin\n price := 19.99;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["array"] = {
|
||||
"array",
|
||||
KeywordCategory::kDataTypes,
|
||||
"## Array Type\n\nCollection of elements of the same type.\n\n**Syntax:**\n```pascal\narray[IndexType] of ElementType\n```\n\n**Examples:**\n```pascal\nvar\n numbers: array[1..10] of integer;\n names: array of string; // dynamic array\nbegin\n numbers[1] := 42;\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitClassKeywords()
|
||||
{
|
||||
keywords_["type"] = {
|
||||
"type",
|
||||
KeywordCategory::kClassTypes,
|
||||
"## Type Declaration\n\nDeclares custom data types.\n\n**Syntax:**\n```pascal\ntype\n TypeName = TypeDefinition;\n```\n\n**Example:**\n```pascal\ntype\n TPoint = record\n X, Y: integer;\n end;\n \n TMyClass = class\n // class members\n end;\n```"
|
||||
};
|
||||
|
||||
keywords_["class"] = {
|
||||
"class",
|
||||
KeywordCategory::kClassTypes,
|
||||
"## Class Declaration\n\nDeclares an object-oriented class.\n\n**Syntax:**\n```pascal\ntype\n TClassName = class(TBaseClass)\n private\n // private members\n public\n // public members\n end;\n```\n\n**Example:**\n```pascal\ntype\n TPerson = class\n private\n FName: string;\n public\n constructor Create(AName: string);\n property Name: string read FName write FName;\n end;\n```"
|
||||
};
|
||||
|
||||
keywords_["new"] = {
|
||||
"new",
|
||||
KeywordCategory::kClassTypes,
|
||||
"## New Instance\n\nCreates a new instance of a class.\n\n**Syntax:**\n```pascal\nInstanceVar := ClassName.Create();\n```\n\n**Example:**\n```pascal\nvar\n person: TPerson;\nbegin\n person := TPerson.Create('John');\n try\n // use person\n finally\n person.Free;\n end;\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitControlFlowKeywords()
|
||||
{
|
||||
keywords_["if"] = {
|
||||
"if",
|
||||
KeywordCategory::kConditionals,
|
||||
"## If Statement\n\nConditional execution based on a boolean expression.\n\n**Syntax:**\n```pascal\nif condition then\n statement\nelse\n statement;\n```\n\n**Example:**\n```pascal\nif age >= 18 then\n echo('Adult')\nelse\n echo('Minor');\n```\n\n**Multi-line:**\n```pascal\nif score >= 90 then\nbegin\n grade := 'A';\n echo('Excellent!');\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["for"] = {
|
||||
"for",
|
||||
KeywordCategory::kLoops,
|
||||
"## For Loop\n\nIterates over a range of values.\n\n**Syntax:**\n```pascal\nfor variable := startValue to endValue do\n statement;\n \nfor variable := startValue downto endValue do\n statement;\n```\n\n**Examples:**\n```pascal\n// Forward loop\nfor i := 1 to 10 do\n echo(i);\n \n// Reverse loop\nfor i := 10 downto 1 do\n echo(i);\n \n// Array iteration\nfor i := Low(myArray) to High(myArray) do\n echo(myArray[i]);\n```"
|
||||
};
|
||||
|
||||
keywords_["while"] = {
|
||||
"while",
|
||||
KeywordCategory::kLoops,
|
||||
"## While Loop\n\nRepeats while a condition is true.\n\n**Syntax:**\n```pascal\nwhile condition do\n statement;\n```\n\n**Example:**\n```pascal\ni := 0;\nwhile i < 10 do\nbegin\n echo(i);\n i := i + 1;\nend;\n```\n\n**Note:** The condition is checked before each iteration."
|
||||
};
|
||||
|
||||
keywords_["case"] = {
|
||||
"case",
|
||||
KeywordCategory::kConditionals,
|
||||
"## Case Statement\n\nMulti-way conditional based on value matching.\n\n**Syntax:**\n```pascal\ncase expression of\n value1: statement1;\n value2: statement2;\n else\n defaultStatement;\nend;\n```\n\n**Example:**\n```pascal\ncase dayOfWeek of\n 1: echo('Monday');\n 2: echo('Tuesday');\n 3: echo('Wednesday');\n 4: echo('Thursday');\n 5: echo('Friday');\n 6, 7: echo('Weekend');\n else\n echo('Invalid day');\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitOperatorKeywords()
|
||||
{
|
||||
keywords_["and"] = {
|
||||
"and",
|
||||
KeywordCategory::kLogicalOperators,
|
||||
"## Logical AND\n\nLogical conjunction operator.\n\n**Truth Table:**\n| A | B | A and B |\n|---|---|--------|\n| T | T | T |\n| T | F | F |\n| F | T | F |\n| F | F | F |\n\n**Example:**\n```pascal\nif (age >= 18) and (hasLicense) then\n echo('Can drive');\n```"
|
||||
};
|
||||
|
||||
keywords_["or"] = {
|
||||
"or",
|
||||
KeywordCategory::kLogicalOperators,
|
||||
"## Logical OR\n\nLogical disjunction operator.\n\n**Truth Table:**\n| A | B | A or B |\n|---|---|-------|\n| T | T | T |\n| T | F | T |\n| F | T | T |\n| F | F | F |\n\n**Example:**\n```pascal\nif (isAdmin) or (isOwner) then\n echo('Has permission');\n```"
|
||||
};
|
||||
|
||||
keywords_["div"] = {
|
||||
"div",
|
||||
KeywordCategory::kArithmeticOperators,
|
||||
"## Integer Division\n\nPerforms integer division (truncates decimal part).\n\n**Example:**\n```pascal\nvar result: integer;\nbegin\n result := 17 div 5; // result = 3\n result := 20 div 4; // result = 5\nend;\n```\n\n**Note:** Use `/` for real division, `div` for integer division."
|
||||
};
|
||||
|
||||
keywords_["mod"] = {
|
||||
"mod",
|
||||
KeywordCategory::kArithmeticOperators,
|
||||
"## Modulo Operator\n\nReturns the remainder of integer division.\n\n**Example:**\n```pascal\nvar remainder: integer;\nbegin\n remainder := 17 mod 5; // remainder = 2\n remainder := 20 mod 4; // remainder = 0\n \n // Check if number is even\n if (number mod 2) = 0 then\n echo('Even number');\nend;\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitSqlKeywords()
|
||||
{
|
||||
keywords_["select"] = {
|
||||
"select",
|
||||
KeywordCategory::kSqlControl,
|
||||
"## SQL SELECT Statement\n\nRetrieves data from database tables.\n\n**Syntax:**\n```sql\nSELECT column1, column2, ...\nFROM table_name\nWHERE condition\nORDER BY column;\n```\n\n**Examples:**\n```sql\n-- Basic select\nSELECT name, age FROM users;\n\n-- With condition\nSELECT * FROM products WHERE price > 100;\n\n-- With ordering\nSELECT name, salary FROM employees ORDER BY salary DESC;\n```"
|
||||
};
|
||||
|
||||
keywords_["update"] = {
|
||||
"update",
|
||||
KeywordCategory::kSqlControl,
|
||||
"## SQL UPDATE Statement\n\nModifies existing records in a table.\n\n**Syntax:**\n```sql\nUPDATE table_name\nSET column1 = value1, column2 = value2, ...\nWHERE condition;\n```\n\n**Examples:**\n```sql\n-- Update single record\nUPDATE users SET age = 30 WHERE id = 1;\n\n-- Update multiple columns\nUPDATE products \nSET price = 99.99, category = 'Electronics'\nWHERE id = 100;\n```\n\n**⚠️ Warning:** Always use WHERE clause to avoid updating all records!"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitBuiltinKeywords()
|
||||
{
|
||||
keywords_["echo"] = {
|
||||
"echo",
|
||||
KeywordCategory::kBuiltinFunctions,
|
||||
"## Echo Function\n\nOutputs text to the console or output stream.\n\n**Syntax:**\n```pascal\necho(expression);\necho(format, args...);\n```\n\n**Examples:**\n```pascal\necho('Hello World!');\necho('Number: ', 42);\necho('Name: %s, Age: %d', name, age);\n```\n\n**Features:**\n- Supports multiple arguments\n- Automatic type conversion\n- Format string support"
|
||||
};
|
||||
|
||||
keywords_["mtic"] = {
|
||||
"mtic",
|
||||
KeywordCategory::kBuiltinFunctions,
|
||||
"## Timer Start (mtic)\n\nStarts a high-precision timer for performance measurement.\n\n**Usage:**\n```pascal\nmtic(); // Start timer\n// ... code to measure ...\nvar elapsed := mtoc(); // Get elapsed time\necho('Elapsed: ', elapsed, ' seconds');\n```\n\n**Note:** Use with `mtoc()` to measure execution time."
|
||||
};
|
||||
|
||||
keywords_["mtoc"] = {
|
||||
"mtoc",
|
||||
KeywordCategory::kBuiltinFunctions,
|
||||
"## Timer End (mtoc)\n\nReturns elapsed time since last `mtic()` call.\n\n**Returns:** Time in seconds (real number)\n\n**Example:**\n```pascal\nmtic();\nfor i := 1 to 1000000 do\n // some computation\nvar timeElapsed := mtoc();\necho('Loop took: ', timeElapsed, ' seconds');\n```"
|
||||
};
|
||||
}
|
||||
|
||||
void KeywordManager::InitConstantKeywords()
|
||||
{
|
||||
keywords_["true"] = {
|
||||
"true",
|
||||
KeywordCategory::kBooleanConstants,
|
||||
"## Boolean True\n\nRepresents the boolean value **true**.\n\n**Usage:**\n```pascal\nvar\n flag: boolean;\nbegin\n flag := true;\n \n if flag then\n echo('Flag is set!');\nend;\n```\n\n**Note:** Case-insensitive in most Pascal dialects."
|
||||
};
|
||||
|
||||
keywords_["false"] = {
|
||||
"false",
|
||||
KeywordCategory::kBooleanConstants,
|
||||
"## Boolean False\n\nRepresents the boolean value **false**.\n\n**Usage:**\n```pascal\nvar\n isComplete: boolean;\nbegin\n isComplete := false;\n \n while not isComplete do\n begin\n // do work\n isComplete := checkCompletion();\n end;\nend;\n```"
|
||||
};
|
||||
|
||||
keywords_["nil"] = {
|
||||
"nil",
|
||||
KeywordCategory::kNullConstants,
|
||||
"## Nil Constant\n\nRepresents a null/empty pointer or object reference.\n\n**Usage:**\n```pascal\nvar\n obj: TMyClass;\nbegin\n obj := nil; // Initialize to null\n \n if obj <> nil then\n obj.DoSomething();\n \n obj := TMyClass.Create();\n try\n // use obj\n finally\n obj.Free;\n obj := nil; // Clear reference\n end;\nend;\n```\n\n**Best Practice:** Always check for nil before using object references."
|
||||
};
|
||||
|
||||
keywords_["inf"] = {
|
||||
"inf",
|
||||
KeywordCategory::kMathConstants,
|
||||
"## Infinity Constant\n\nRepresents positive mathematical infinity.\n\n**Usage:**\n```pascal\nvar\n result: real;\nbegin\n result := 1.0 / 0.0; // Results in inf\n \n if result = inf then\n echo('Result is infinite');\nend;\n```\n\n**Note:** Use for floating-point calculations and comparisons."
|
||||
};
|
||||
|
||||
keywords_["nan"] = {
|
||||
"nan",
|
||||
KeywordCategory::kMathConstants,
|
||||
"## Not a Number (NaN)\n\nRepresents an undefined or invalid floating-point result.\n\n**Common Causes:**\n- `0.0 / 0.0`\n- `sqrt(-1.0)`\n- `inf - inf`\n\n**Usage:**\n```pascal\nvar\n result: real;\nbegin\n result := sqrt(-1.0); // Results in NaN\n \n if IsNaN(result) then\n echo('Invalid calculation');\nend;\n```\n\n**Note:** NaN ≠ NaN, use `IsNaN()` function for checking."
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "./keyword_types.hpp"
|
||||
|
||||
namespace tsl
|
||||
{
|
||||
class KeywordManager
|
||||
{
|
||||
public:
|
||||
KeywordManager(const KeywordManager&) = delete;
|
||||
KeywordManager& operator=(const KeywordManager&) = delete;
|
||||
|
||||
static KeywordManager& GetInstance();
|
||||
std::vector<KeywordInfo> GetAllKeywords();
|
||||
std::vector<KeywordInfo> GetKeyWordByPrefix(std::string prefix);
|
||||
std::optional<KeywordInfo> GetKeywordInfo(std::string key);
|
||||
|
||||
private:
|
||||
KeywordManager();
|
||||
void InitKeywords();
|
||||
|
||||
void InitProgramStructureKeywords();
|
||||
void InitDataTypeKeywords();
|
||||
void InitClassKeywords();
|
||||
void InitControlFlowKeywords();
|
||||
void InitOperatorKeywords();
|
||||
void InitSqlKeywords();
|
||||
void InitBuiltinKeywords();
|
||||
void InitConstantKeywords();
|
||||
|
||||
std::unordered_map<std::string, KeywordInfo> keywords_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
#include "./builder.hpp"
|
||||
#include "../collector/symbol_collector.hpp"
|
||||
#include "../collector/incremental_collector.hpp"
|
||||
#include "../incremental/incremental_engine.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 构造和析构 ====================
|
||||
|
||||
SymbolTableBuilder::SymbolTableBuilder() :
|
||||
incremental_enabled_(false)
|
||||
{
|
||||
}
|
||||
|
||||
SymbolTableBuilder::~SymbolTableBuilder() = default;
|
||||
|
||||
// ==================== 构建接口 ====================
|
||||
|
||||
bool SymbolTableBuilder::Build(const std::vector<ast::ASTNode>& nodes)
|
||||
{
|
||||
// 清空错误
|
||||
error_reporter_.Clear();
|
||||
|
||||
// 初始化统计信息
|
||||
stats_ = BuildStatistics{};
|
||||
stats_.is_incremental = false;
|
||||
stats_.total_symbols = nodes.size();
|
||||
|
||||
// 创建收集上下文
|
||||
CollectorContext context(registry_, error_reporter_);
|
||||
|
||||
// 创建基础收集器并执行
|
||||
SymbolCollector collector(context);
|
||||
bool success = collector.Collect(nodes);
|
||||
|
||||
// 更新统计信息
|
||||
stats_.success = success && !error_reporter_.HasErrors();
|
||||
stats_.new_symbols = stats_.total_symbols;
|
||||
stats_.reused_symbols = 0;
|
||||
stats_.reuse_rate = 0.0;
|
||||
|
||||
// 完整构建后,如果启用增量,则构建缓存
|
||||
if (stats_.success && incremental_enabled_ && incremental_engine_)
|
||||
{
|
||||
incremental_engine_->BuildCache(registry_);
|
||||
}
|
||||
|
||||
return stats_.success;
|
||||
}
|
||||
|
||||
bool SymbolTableBuilder::BuildIncremental(
|
||||
const ast::IncrementalParseResult& parse_result)
|
||||
{
|
||||
// 检查增量是否启用
|
||||
if (!incremental_enabled_ || !incremental_engine_)
|
||||
{
|
||||
// 增量未启用,退回完整构建
|
||||
return Build(parse_result.result.nodes);
|
||||
}
|
||||
|
||||
// 清空错误
|
||||
error_reporter_.Clear();
|
||||
|
||||
// 初始化统计信息
|
||||
stats_ = BuildStatistics{};
|
||||
stats_.is_incremental = true;
|
||||
stats_.total_symbols = parse_result.result.nodes.size();
|
||||
|
||||
// 创建收集上下文
|
||||
CollectorContext context(registry_, error_reporter_);
|
||||
|
||||
// 创建增量收集器并执行
|
||||
IncrementalCollector collector(context, *incremental_engine_);
|
||||
bool success = collector.CollectIncremental(parse_result);
|
||||
|
||||
// 更新统计信息
|
||||
stats_.reused_symbols = collector.GetReusedCount();
|
||||
stats_.new_symbols = collector.GetNewCount();
|
||||
|
||||
// 修复:防止除零
|
||||
if (stats_.total_symbols > 0)
|
||||
{
|
||||
stats_.reuse_rate = static_cast<double>(stats_.reused_symbols) / stats_.total_symbols;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats_.reuse_rate = 0.0;
|
||||
}
|
||||
|
||||
stats_.success = success && !error_reporter_.HasErrors();
|
||||
|
||||
// 检查缓存大小,必要时进行清理
|
||||
if (incremental_engine_->GetCacheSize() > 10000) // 可配置
|
||||
{
|
||||
// LRU 会自动处理,这里只是检查
|
||||
// 如果需要强制限制,可以调用 SetMaxCacheSize
|
||||
}
|
||||
|
||||
return stats_.success;
|
||||
}
|
||||
|
||||
// ==================== 访问器 ====================
|
||||
|
||||
const std::vector<Error>& SymbolTableBuilder::GetErrors() const
|
||||
{
|
||||
return error_reporter_.GetErrors();
|
||||
}
|
||||
|
||||
bool SymbolTableBuilder::HasErrors() const
|
||||
{
|
||||
return error_reporter_.HasErrors();
|
||||
}
|
||||
|
||||
size_t SymbolTableBuilder::ErrorCount() const
|
||||
{
|
||||
return error_reporter_.ErrorCount();
|
||||
}
|
||||
|
||||
void SymbolTableBuilder::ClearErrors()
|
||||
{
|
||||
error_reporter_.Clear();
|
||||
}
|
||||
|
||||
// ==================== 增量配置 ====================
|
||||
|
||||
void SymbolTableBuilder::EnableIncremental(bool enable)
|
||||
{
|
||||
incremental_enabled_ = enable;
|
||||
|
||||
if (enable && !incremental_engine_)
|
||||
{
|
||||
incremental_engine_ = std::make_unique<IncrementalEngine>();
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTableBuilder::SetMaxCacheSize(size_t max_size)
|
||||
{
|
||||
if (incremental_engine_)
|
||||
{
|
||||
incremental_engine_->SetMaxCacheSize(max_size);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTableBuilder::ClearCache()
|
||||
{
|
||||
if (incremental_engine_)
|
||||
{
|
||||
incremental_engine_->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
size_t SymbolTableBuilder::GetCacheSize() const
|
||||
{
|
||||
if (incremental_engine_)
|
||||
{
|
||||
return incremental_engine_->GetCacheSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "../../ast/types.hpp"
|
||||
#include "../../ast/deserializer.hpp"
|
||||
#include "../core/registry.hpp"
|
||||
#include "../core/error.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// 前向声明
|
||||
class IncrementalEngine;
|
||||
|
||||
// ==================== 构建统计信息 ====================
|
||||
|
||||
struct BuildStatistics
|
||||
{
|
||||
size_t total_symbols = 0; // 总符号数
|
||||
size_t reused_symbols = 0; // 复用的符号数
|
||||
size_t new_symbols = 0; // 新创建的符号数
|
||||
double reuse_rate = 0.0; // 复用率
|
||||
bool is_incremental = false; // 是否为增量构建
|
||||
bool success = false; // 构建是否成功
|
||||
};
|
||||
|
||||
// ==================== 符号表构建器 ====================
|
||||
|
||||
/**
|
||||
* 符号表构建器 - 简化为调度器
|
||||
*
|
||||
* 职责:
|
||||
* - 提供构建入口(完整/增量)
|
||||
* - 管理核心组件(Registry、ErrorReporter)
|
||||
* - 管理增量引擎(可选)
|
||||
* - 收集和提供统计信息
|
||||
*
|
||||
* 不负责:
|
||||
* - 具体的符号收集逻辑(委托给 Collector)
|
||||
* - 增量细节(委托给 IncrementalEngine)
|
||||
* - 语义分析(属于后续阶段)
|
||||
*/
|
||||
class SymbolTableBuilder
|
||||
{
|
||||
public:
|
||||
SymbolTableBuilder();
|
||||
~SymbolTableBuilder();
|
||||
|
||||
// 禁止拷贝
|
||||
SymbolTableBuilder(const SymbolTableBuilder&) = delete;
|
||||
SymbolTableBuilder& operator=(const SymbolTableBuilder&) = delete;
|
||||
|
||||
bool Build(const std::vector<ast::ASTNode>& nodes);
|
||||
bool BuildIncremental(const ast::IncrementalParseResult& parse_result);
|
||||
|
||||
SymbolRegistry& GetRegistry() { return registry_; }
|
||||
const SymbolRegistry& GetRegistry() const { return registry_; }
|
||||
|
||||
const std::vector<Error>& GetErrors() const;
|
||||
bool HasErrors() const;
|
||||
size_t ErrorCount() const;
|
||||
void ClearErrors();
|
||||
|
||||
BuildStatistics GetStatistics() const { return stats_; }
|
||||
|
||||
void EnableIncremental(bool enable);
|
||||
void SetMaxCacheSize(size_t max_size);
|
||||
void ClearCache();
|
||||
size_t GetCacheSize() const;
|
||||
bool IsIncrementalEnabled() const { return incremental_enabled_; }
|
||||
|
||||
private:
|
||||
// 核心组件
|
||||
SymbolRegistry registry_;
|
||||
ErrorReporter error_reporter_;
|
||||
|
||||
// 增量支持(可选)
|
||||
std::unique_ptr<IncrementalEngine> incremental_engine_;
|
||||
bool incremental_enabled_;
|
||||
|
||||
// 统计信息
|
||||
BuildStatistics stats_;
|
||||
};
|
||||
|
||||
// ==================== 便捷函数 ====================
|
||||
|
||||
/**
|
||||
* 便捷函数:一次性构建符号表
|
||||
*
|
||||
* @param nodes AST节点列表
|
||||
* @param errors 可选的错误输出参数
|
||||
* @return 构建好的符号注册表(移动语义)
|
||||
*/
|
||||
inline SymbolRegistry BuildSymbolTable(const std::vector<ast::ASTNode>& nodes, std::vector<Error>* errors = nullptr)
|
||||
{
|
||||
SymbolTableBuilder builder;
|
||||
builder.Build(nodes);
|
||||
|
||||
if (errors)
|
||||
*errors = builder.GetErrors();
|
||||
|
||||
// 移动 Registry(避免拷贝)
|
||||
return std::move(builder.GetRegistry());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include "../core/registry.hpp"
|
||||
#include "../core/error.hpp"
|
||||
#include "../factory/scope_manager.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
/**
|
||||
* 收集上下文 - 封装收集过程中的共享状态
|
||||
*
|
||||
* 职责:
|
||||
* - 提供对 Registry、ErrorReporter、ScopeManager 的统一访问
|
||||
* - 维护当前上下文(当前 Unit、当前 Class)
|
||||
* - 提供便捷的错误报告接口
|
||||
*/
|
||||
struct CollectorContext
|
||||
{
|
||||
SymbolRegistry& registry;
|
||||
ErrorReporter& error_reporter;
|
||||
ScopeManager scope_manager;
|
||||
|
||||
// 当前上下文
|
||||
Unit* current_unit = nullptr;
|
||||
Class* current_class = nullptr;
|
||||
|
||||
CollectorContext(SymbolRegistry& reg, ErrorReporter& reporter) :
|
||||
registry(reg), error_reporter(reporter), scope_manager(reg.GlobalScope())
|
||||
{
|
||||
}
|
||||
|
||||
// 便捷访问
|
||||
Table* CurrentScope() { return scope_manager.Current(); }
|
||||
Table* GlobalScope() { return registry.GlobalScope(); }
|
||||
|
||||
// ==================== 改进的错误报告 ====================
|
||||
|
||||
void ReportError(ErrorKind kind, const std::string& msg, const ast::Location& loc)
|
||||
{
|
||||
error_reporter.Report(kind, msg, loc);
|
||||
}
|
||||
|
||||
void ReportDuplicateDefinition(const std::string& name, const ast::Location& loc)
|
||||
{
|
||||
// 查找已存在的符号位置
|
||||
auto existing = CurrentScope()->LookupLocal(name);
|
||||
if (existing && existing.symbol)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << "Symbol '" << name << "' already defined at "
|
||||
<< existing.symbol->location.start_line << ":"
|
||||
<< existing.symbol->location.start_column;
|
||||
error_reporter.Report(ErrorKind::kDuplicateDefinition, msg.str(), loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_reporter.ReportDuplicateDefinition(name, loc);
|
||||
}
|
||||
}
|
||||
|
||||
void ReportSignatureConflict(const std::string& name, const ast::Location& loc)
|
||||
{
|
||||
// 查找冲突的函数重载
|
||||
auto overloads = CurrentScope()->LookupOverloads(name);
|
||||
if (!overloads.empty())
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << "Function signature conflict: '" << name
|
||||
<< "' (conflicts with overload at "
|
||||
<< overloads[0]->location.start_line << ":"
|
||||
<< overloads[0]->location.start_column << ")";
|
||||
error_reporter.Report(ErrorKind::kSignatureConflict, msg.str(), loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_reporter.Report(ErrorKind::kSignatureConflict,
|
||||
"Function signature conflict: " + name,
|
||||
loc);
|
||||
}
|
||||
}
|
||||
|
||||
void ReportUnitConflict(const std::string& name, const ast::Location& loc)
|
||||
{
|
||||
auto existing_unit = registry.FindUnit(name);
|
||||
if (existing_unit)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << "Unit '" << name << "' already defined at "
|
||||
<< existing_unit->location.start_line << ":"
|
||||
<< existing_unit->location.start_column;
|
||||
error_reporter.Report(ErrorKind::kDuplicateDefinition, msg.str(), loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_reporter.ReportDuplicateDefinition(name, loc);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "./incremental_collector.hpp"
|
||||
#include "../incremental/incremental_engine.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
IncrementalCollector::IncrementalCollector(CollectorContext& context, IncrementalEngine& engine) :
|
||||
SymbolCollector(context), engine_(engine)
|
||||
{
|
||||
}
|
||||
|
||||
bool IncrementalCollector::CollectIncremental(const ast::IncrementalParseResult& parse_result)
|
||||
{
|
||||
// 重置统计
|
||||
reused_count_ = 0;
|
||||
new_count_ = 0;
|
||||
|
||||
// 构建变化节点索引
|
||||
std::unordered_set<size_t> changed_set(
|
||||
parse_result.changed_indices.begin(),
|
||||
parse_result.changed_indices.end());
|
||||
|
||||
// 处理所有节点
|
||||
for (size_t i = 0; i < parse_result.result.nodes.size(); ++i)
|
||||
{
|
||||
const auto& node = parse_result.result.nodes[i];
|
||||
bool is_changed = changed_set.count(i) > 0;
|
||||
|
||||
if (!ProcessNode(node, is_changed))
|
||||
return false;
|
||||
}
|
||||
|
||||
return !ctx_.error_reporter.HasErrors();
|
||||
}
|
||||
|
||||
bool IncrementalCollector::ProcessNode(const ast::ASTNode& node, bool is_changed)
|
||||
{
|
||||
if (is_changed)
|
||||
{
|
||||
// 节点已变化,必须重新收集
|
||||
new_count_++;
|
||||
|
||||
bool success = Visit(node);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// 收集成功后,缓存新符号
|
||||
CacheCurrentSymbol(node);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 节点未变化,尝试复用缓存
|
||||
if (TryReuseFromCache(node))
|
||||
{
|
||||
reused_count_++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 缓存未命中,重新收集
|
||||
new_count_++;
|
||||
bool success = Visit(node);
|
||||
|
||||
if (success)
|
||||
{
|
||||
CacheCurrentSymbol(node);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IncrementalCollector::TryReuseFromCache(const ast::ASTNode& node)
|
||||
{
|
||||
// 委托给增量引擎,传入 Registry 用于 Unit 复用
|
||||
return engine_.TryReuseSymbol(node, ctx_.CurrentScope(), &ctx_.registry);
|
||||
}
|
||||
|
||||
void IncrementalCollector::CacheCurrentSymbol(const ast::ASTNode& node)
|
||||
{
|
||||
// 委托给增量引擎
|
||||
engine_.CacheSymbol(node, ctx_.CurrentScope());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "./symbol_collector.hpp"
|
||||
#include "../../ast/deserializer.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// 前向声明
|
||||
class IncrementalEngine;
|
||||
|
||||
/**
|
||||
* 增量符号收集器
|
||||
*
|
||||
* 职责:
|
||||
* - 继承基础收集器的所有能力
|
||||
* - 根据节点是否变化决定复用或重新收集
|
||||
* - 委托 IncrementalEngine 进行缓存操作
|
||||
* - 收集统计信息
|
||||
*/
|
||||
class IncrementalCollector : public SymbolCollector
|
||||
{
|
||||
public:
|
||||
IncrementalCollector(CollectorContext& context, IncrementalEngine& engine);
|
||||
|
||||
// 增量收集入口
|
||||
bool CollectIncremental(const ast::IncrementalParseResult& parse_result);
|
||||
|
||||
// 统计信息
|
||||
size_t GetReusedCount() const { return reused_count_; }
|
||||
size_t GetNewCount() const { return new_count_; }
|
||||
|
||||
private:
|
||||
// 处理单个节点(判断是复用还是重新收集)
|
||||
bool ProcessNode(const ast::ASTNode& node, bool is_changed);
|
||||
|
||||
// 尝试从缓存复用符号
|
||||
bool TryReuseFromCache(const ast::ASTNode& node);
|
||||
|
||||
// 缓存当前收集的符号
|
||||
void CacheCurrentSymbol(const ast::ASTNode& node);
|
||||
|
||||
private:
|
||||
IncrementalEngine& engine_;
|
||||
size_t reused_count_ = 0;
|
||||
size_t new_count_ = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
#include "./symbol_collector.hpp"
|
||||
#include "../utils/type.hpp"
|
||||
#include "../factory/factory.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
SymbolCollector::SymbolCollector(CollectorContext& context) :
|
||||
ctx_(context)
|
||||
{
|
||||
}
|
||||
|
||||
bool SymbolCollector::Collect(const std::vector<ast::ASTNode>& nodes)
|
||||
{
|
||||
for (const auto& node : nodes)
|
||||
{
|
||||
if (!Visit(node))
|
||||
return false;
|
||||
}
|
||||
return !ctx_.error_reporter.HasErrors();
|
||||
}
|
||||
|
||||
// ==================== AST 访问 ====================
|
||||
|
||||
bool SymbolCollector::Visit(const ast::ASTNode& node)
|
||||
{
|
||||
if (std::holds_alternative<std::monostate>(node))
|
||||
return true;
|
||||
|
||||
if (auto* unit = std::get_if<ast::UnitDefinition>(&node))
|
||||
return CollectUnit(*unit);
|
||||
|
||||
if (auto* global = std::get_if<ast::GlobalDeclaration>(&node))
|
||||
return CollectGlobal(*global);
|
||||
|
||||
if (auto* static_decl = std::get_if<ast::StaticDeclaration>(&node))
|
||||
return CollectStatic(*static_decl);
|
||||
|
||||
if (auto* var = std::get_if<ast::VarDeclaration>(&node))
|
||||
return CollectVariable(*var);
|
||||
|
||||
if (auto* constant = std::get_if<ast::ConstDeclaration>(&node))
|
||||
return CollectConstant(*constant);
|
||||
|
||||
if (auto* stmt = std::get_if<ast::AssignmentStatement>(&node))
|
||||
return CollectAssignment(*stmt);
|
||||
|
||||
if (auto* func_def = std::get_if<ast::FunctionDefinition>(&node))
|
||||
return CollectFunctionDef(*func_def);
|
||||
|
||||
if (auto* cls = std::get_if<ast::ClassDefinition>(&node))
|
||||
return CollectClass(*cls);
|
||||
|
||||
if (auto* uses = std::get_if<ast::UsesClause>(&node))
|
||||
return CollectUsesClause(*uses);
|
||||
|
||||
// 跳过表达式和块
|
||||
if (std::holds_alternative<ast::Expression>(node) ||
|
||||
std::holds_alternative<ast::Block>(node))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== 收集方法 ====================
|
||||
|
||||
bool SymbolCollector::CollectUnit(const ast::UnitDefinition& unit)
|
||||
{
|
||||
auto unit_symbol = factory::CreateUnit(unit.name, unit.location);
|
||||
|
||||
if (!TryInsertUnit(unit_symbol))
|
||||
return false;
|
||||
|
||||
ctx_.current_unit = unit_symbol.get();
|
||||
|
||||
// 创建 interface 和 implementation 作用域
|
||||
unit_symbol->interface_symbols =
|
||||
std::make_unique<Table>(ScopeKind::kInterface, ctx_.GlobalScope());
|
||||
unit_symbol->implementation_symbols =
|
||||
std::make_unique<Table>(ScopeKind::kImplementation, ctx_.GlobalScope());
|
||||
|
||||
// 收集 uses 子句
|
||||
if (unit.uses)
|
||||
CollectUsesClause(*unit.uses);
|
||||
|
||||
// 收集各部分的声明
|
||||
CollectInScope(unit_symbol->interface_symbols.get(), unit.interface_statements);
|
||||
CollectInScope(unit_symbol->implementation_symbols.get(), unit.implementation_statements);
|
||||
CollectInScope(unit_symbol->implementation_symbols.get(), unit.initialization_statements);
|
||||
CollectInScope(unit_symbol->implementation_symbols.get(), unit.finalization_statements);
|
||||
|
||||
ctx_.current_unit = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectGlobal(const ast::GlobalDeclaration& global)
|
||||
{
|
||||
TypeInfo type = global.type_name ?
|
||||
TypeFactory::FromAnnotation(*global.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto var_symbol = factory::CreateVariable(
|
||||
global.name, Kind::kGlobalVariable, global.location, type);
|
||||
|
||||
if (global.value)
|
||||
var_symbol->initialization_expr = global.value->text;
|
||||
|
||||
return TryInsert(var_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectStatic(const ast::StaticDeclaration& decl)
|
||||
{
|
||||
TypeInfo type = decl.type_name ?
|
||||
TypeFactory::FromAnnotation(*decl.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto var_symbol = factory::CreateVariable(
|
||||
decl.name, Kind::kStaticVariable, decl.location, type);
|
||||
|
||||
var_symbol->attributes.is_static = true;
|
||||
|
||||
if (decl.value)
|
||||
var_symbol->initialization_expr = decl.value->text;
|
||||
|
||||
return TryInsert(var_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectVariable(const ast::VarDeclaration& var)
|
||||
{
|
||||
TypeInfo type = var.type_name ?
|
||||
TypeFactory::FromAnnotation(*var.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto var_symbol = factory::CreateVariable(
|
||||
var.name, Kind::kVariable, var.location, type);
|
||||
|
||||
if (var.value)
|
||||
var_symbol->initialization_expr = var.value->text;
|
||||
|
||||
return TryInsert(var_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectConstant(const ast::ConstDeclaration& constant)
|
||||
{
|
||||
TypeInfo type = constant.type_name ?
|
||||
TypeFactory::FromAnnotation(*constant.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto const_symbol = factory::CreateConstant(
|
||||
constant.name, constant.location, type, constant.value.text);
|
||||
|
||||
return TryInsert(const_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectAssignment(const ast::AssignmentStatement& stmt)
|
||||
{
|
||||
TypeInfo type;
|
||||
|
||||
auto var_symbol = factory::CreateVariable(
|
||||
stmt.name, Kind::kVariable, stmt.location, type);
|
||||
|
||||
var_symbol->initialization_expr = stmt.value.text;
|
||||
|
||||
return TryInsert(var_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectFunctionDef(const ast::FunctionDefinition& func)
|
||||
{
|
||||
Signature sig = CreateSignature(func.signature);
|
||||
|
||||
auto func_symbol = factory::CreateFunction(
|
||||
func.name, func.location, sig);
|
||||
|
||||
if (!TryInsertFunction(func_symbol, func.location))
|
||||
return false;
|
||||
|
||||
// 收集函数体
|
||||
if (!func.body.statements.empty())
|
||||
CollectFunctionBody(func_symbol.get(), func.body);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectClass(const ast::ClassDefinition& class_def)
|
||||
{
|
||||
auto class_symbol = factory::CreateClass(
|
||||
class_def.name, class_def.location);
|
||||
|
||||
// 存储父类名称(字符串形式,不解析引用)
|
||||
class_symbol->parent_names = class_def.parents;
|
||||
|
||||
if (!TryInsert(class_symbol))
|
||||
return false;
|
||||
|
||||
// 创建成员作用域
|
||||
class_symbol->members = std::make_unique<Table>(
|
||||
ScopeKind::kClass, ctx_.CurrentScope());
|
||||
|
||||
ctx_.current_class = class_symbol.get();
|
||||
|
||||
// 进入类作用域,收集成员
|
||||
auto guard = ctx_.scope_manager.EnterScope(class_symbol->members.get());
|
||||
for (const auto& member : class_def.members)
|
||||
{
|
||||
CollectClassMember(member, class_symbol.get());
|
||||
}
|
||||
|
||||
ctx_.current_class = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectUsesClause(const ast::UsesClause& uses)
|
||||
{
|
||||
if (ctx_.current_unit)
|
||||
ctx_.current_unit->uses = uses.units;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== 类成员收集 ====================
|
||||
|
||||
bool SymbolCollector::CollectClassMember(const ast::ClassMember& member, Class* owner)
|
||||
{
|
||||
if (std::holds_alternative<std::monostate>(member.content))
|
||||
return true;
|
||||
|
||||
Access access = member.access;
|
||||
|
||||
if (auto* var = std::get_if<ast::VarDeclaration>(&member.content))
|
||||
return CollectMemberVariable(*var, access);
|
||||
|
||||
if (auto* static_decl = std::get_if<ast::StaticDeclaration>(&member.content))
|
||||
return CollectMemberStatic(*static_decl, access);
|
||||
|
||||
if (auto* method = std::get_if<ast::Method>(&member.content))
|
||||
return CollectMemberMethod(*method, access, owner);
|
||||
|
||||
if (auto* property = std::get_if<ast::Property>(&member.content))
|
||||
return CollectMemberProperty(*property, access);
|
||||
|
||||
if (auto* ctor = std::get_if<ast::ConstructorDeclaration>(&member.content))
|
||||
return CollectMemberConstructor(*ctor, access, owner);
|
||||
|
||||
if (auto* dtor = std::get_if<ast::DestructorDeclaration>(&member.content))
|
||||
return CollectMemberDestructor(*dtor, access, owner);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectMemberVariable(const ast::VarDeclaration& var, Access access)
|
||||
{
|
||||
TypeInfo type = var.type_name ?
|
||||
TypeFactory::FromAnnotation(*var.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto var_symbol = factory::CreateVariable(
|
||||
var.name, Kind::kVariable, var.location, type);
|
||||
|
||||
var_symbol->attributes.access = access;
|
||||
|
||||
if (var.value)
|
||||
var_symbol->initialization_expr = var.value->text;
|
||||
|
||||
return TryInsert(var_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectMemberStatic(const ast::StaticDeclaration& decl, Access access)
|
||||
{
|
||||
TypeInfo type = decl.type_name ?
|
||||
TypeFactory::FromAnnotation(*decl.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto var_symbol = factory::CreateVariable(
|
||||
decl.name, Kind::kStaticVariable, decl.location, type);
|
||||
|
||||
var_symbol->attributes.access = access;
|
||||
var_symbol->attributes.is_static = true;
|
||||
|
||||
if (decl.value)
|
||||
var_symbol->initialization_expr = decl.value->text;
|
||||
|
||||
return TryInsert(var_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectMemberMethod(const ast::Method& method,
|
||||
Access access,
|
||||
Class* owner)
|
||||
{
|
||||
Signature sig = CreateSignature(method.signature);
|
||||
|
||||
auto method_symbol = factory::CreateMethod(
|
||||
method.name, method.location, sig, owner);
|
||||
|
||||
method_symbol->attributes.access = access;
|
||||
method_symbol->attributes.is_class_method = method.is_class_method;
|
||||
|
||||
// 设置 virtual/override 属性
|
||||
switch (method.modifier)
|
||||
{
|
||||
case ast::Modifier::kVirtual:
|
||||
method_symbol->attributes.is_virtual = true;
|
||||
break;
|
||||
case ast::Modifier::kOverride:
|
||||
method_symbol->attributes.is_override = true;
|
||||
break;
|
||||
case ast::Modifier::kOverload:
|
||||
method_symbol->attributes.is_overload = true;
|
||||
break;
|
||||
case ast::Modifier::kNone:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!TryInsertFunction(method_symbol, method.location))
|
||||
return false;
|
||||
|
||||
// 收集方法体
|
||||
if (method.body)
|
||||
CollectFunctionBody(method_symbol.get(), *method.body);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectMemberProperty(const ast::Property& property, Access access)
|
||||
{
|
||||
TypeInfo type = property.type_name ?
|
||||
TypeFactory::FromAnnotation(*property.type_name) :
|
||||
TypeInfo();
|
||||
|
||||
auto property_symbol = factory::CreateProperty(
|
||||
property.name, property.location, type);
|
||||
|
||||
property_symbol->attributes.access = access;
|
||||
property_symbol->getter = property.getter;
|
||||
property_symbol->setter = property.setter;
|
||||
|
||||
return TryInsert(property_symbol);
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectMemberConstructor(const ast::ConstructorDeclaration& ctor,
|
||||
Access access,
|
||||
Class* owner)
|
||||
{
|
||||
Signature sig = CreateSignature(ctor.signature);
|
||||
|
||||
auto ctor_symbol = factory::CreateConstructor(
|
||||
"Create", ctor.location, sig, owner);
|
||||
|
||||
ctor_symbol->attributes.access = access;
|
||||
|
||||
if (!TryInsert(ctor_symbol))
|
||||
return false;
|
||||
|
||||
// 收集构造函数体
|
||||
if (ctor.body)
|
||||
CollectConstructorBody(ctor_symbol.get(), *ctor.body);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::CollectMemberDestructor(const ast::DestructorDeclaration& dtor,
|
||||
Access access,
|
||||
Class* owner)
|
||||
{
|
||||
auto dtor_symbol = factory::CreateDestructor(
|
||||
"Destroy", dtor.location, owner);
|
||||
|
||||
dtor_symbol->attributes.access = access;
|
||||
|
||||
if (!TryInsert(dtor_symbol))
|
||||
return false;
|
||||
|
||||
// 收集析构函数体
|
||||
if (dtor.body)
|
||||
CollectDestructorBody(dtor_symbol.get(), *dtor.body);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== 函数体收集 ====================
|
||||
|
||||
void SymbolCollector::CollectFunctionBody(Function* func, const ast::Block& body)
|
||||
{
|
||||
// 创建函数作用域
|
||||
func->body_scope = std::make_unique<Table>(
|
||||
ScopeKind::kFunction, ctx_.CurrentScope());
|
||||
|
||||
// 进入函数作用域
|
||||
auto guard = ctx_.scope_manager.EnterScope(func->body_scope.get());
|
||||
|
||||
// 收集参数符号
|
||||
CollectFunctionParams(func);
|
||||
|
||||
// 收集函数体中的局部声明
|
||||
CollectStatements(body.statements);
|
||||
}
|
||||
|
||||
void SymbolCollector::CollectFunctionParams(Function* func)
|
||||
{
|
||||
for (const auto& param : func->signature.parameters)
|
||||
{
|
||||
auto param_symbol = factory::CreateVariable(
|
||||
param.name, Kind::kParameter, func->location, param.type);
|
||||
|
||||
param_symbol->attributes.is_var_param = param.is_var;
|
||||
param_symbol->attributes.is_out_param = param.is_out;
|
||||
|
||||
func->body_scope->Insert(param_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolCollector::CollectConstructorBody(Constructor* ctor, const ast::Block& body)
|
||||
{
|
||||
ctor->body_scope = std::make_unique<Table>(
|
||||
ScopeKind::kFunction, ctx_.CurrentScope());
|
||||
|
||||
auto guard = ctx_.scope_manager.EnterScope(ctor->body_scope.get());
|
||||
|
||||
// 收集参数
|
||||
for (const auto& param : ctor->signature.parameters)
|
||||
{
|
||||
auto param_symbol = factory::CreateVariable(
|
||||
param.name, Kind::kParameter, ctor->location, param.type);
|
||||
|
||||
param_symbol->attributes.is_var_param = param.is_var;
|
||||
param_symbol->attributes.is_out_param = param.is_out;
|
||||
|
||||
ctor->body_scope->Insert(param_symbol);
|
||||
}
|
||||
|
||||
CollectStatements(body.statements);
|
||||
}
|
||||
|
||||
void SymbolCollector::CollectDestructorBody(Destructor* dtor, const ast::Block& body)
|
||||
{
|
||||
dtor->body_scope = std::make_unique<Table>(
|
||||
ScopeKind::kFunction, ctx_.CurrentScope());
|
||||
|
||||
auto guard = ctx_.scope_manager.EnterScope(dtor->body_scope.get());
|
||||
|
||||
CollectStatements(body.statements);
|
||||
}
|
||||
|
||||
// ==================== 辅助方法 ====================
|
||||
|
||||
void SymbolCollector::CollectInScope(Table* scope,
|
||||
const std::vector<ast::ASTNode>& statements)
|
||||
{
|
||||
auto guard = ctx_.scope_manager.EnterScope(scope);
|
||||
CollectStatements(statements);
|
||||
}
|
||||
|
||||
void SymbolCollector::CollectStatements(const std::vector<ast::ASTNode>& statements)
|
||||
{
|
||||
for (const auto& stmt : statements)
|
||||
Visit(stmt);
|
||||
}
|
||||
|
||||
// ==================== 插入方法 ====================
|
||||
|
||||
bool SymbolCollector::TryInsert(SymbolPtr symbol)
|
||||
{
|
||||
if (!ctx_.CurrentScope()->Insert(symbol))
|
||||
{
|
||||
ctx_.ReportDuplicateDefinition(symbol->name, symbol->location);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::TryInsertFunction(FunctionPtr func, const ast::Location& loc)
|
||||
{
|
||||
if (!ctx_.CurrentScope()->InsertFunction(func))
|
||||
{
|
||||
ctx_.ReportSignatureConflict(func->name, loc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolCollector::TryInsertUnit(UnitPtr unit)
|
||||
{
|
||||
if (!ctx_.registry.AddUnit(unit))
|
||||
{
|
||||
ctx_.ReportUnitConflict(unit->name, unit->location);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==================== 创建签名 ====================
|
||||
|
||||
Signature SymbolCollector::CreateSignature(const ast::Signature& ast_sig)
|
||||
{
|
||||
Signature sig;
|
||||
|
||||
for (const auto& ast_param : ast_sig.parameters)
|
||||
{
|
||||
sig.parameters.push_back(CreateParameter(ast_param));
|
||||
}
|
||||
|
||||
if (ast_sig.return_type)
|
||||
sig.return_type = TypeFactory::FromAnnotation(*ast_sig.return_type);
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
Signature::Param SymbolCollector::CreateParameter(const ast::Parameter& ast_param)
|
||||
{
|
||||
Signature::Param param;
|
||||
param.name = ast_param.name;
|
||||
param.type = ast_param.type_name ?
|
||||
TypeFactory::FromAnnotation(*ast_param.type_name) :
|
||||
TypeInfo();
|
||||
param.is_var = ast_param.is_var;
|
||||
param.is_out = ast_param.is_out;
|
||||
param.default_value = ast_param.default_value;
|
||||
return param;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "../../ast/types.hpp"
|
||||
#include "./context.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
/**
|
||||
* 符号收集器 - 负责从 AST 收集符号
|
||||
*
|
||||
* 职责:
|
||||
* - 遍历 AST 节点
|
||||
* - 创建符号对象
|
||||
* - 插入作用域
|
||||
* - 管理作用域切换
|
||||
*
|
||||
* 不负责:
|
||||
* - 增量构建逻辑
|
||||
* - 缓存管理
|
||||
* - 依赖追踪
|
||||
* - 类型引用解析(保持字符串形式)
|
||||
*/
|
||||
class SymbolCollector
|
||||
{
|
||||
public:
|
||||
explicit SymbolCollector(CollectorContext& context);
|
||||
virtual ~SymbolCollector() = default;
|
||||
|
||||
// 主入口 - 收集所有节点
|
||||
bool Collect(const std::vector<ast::ASTNode>& nodes);
|
||||
|
||||
protected:
|
||||
// ==================== AST 访问 ====================
|
||||
|
||||
virtual bool Visit(const ast::ASTNode& node);
|
||||
|
||||
// ==================== 顶层声明 ====================
|
||||
|
||||
bool CollectUnit(const ast::UnitDefinition& unit);
|
||||
bool CollectGlobal(const ast::GlobalDeclaration& global);
|
||||
bool CollectStatic(const ast::StaticDeclaration& decl);
|
||||
bool CollectVariable(const ast::VarDeclaration& var);
|
||||
bool CollectConstant(const ast::ConstDeclaration& constant);
|
||||
bool CollectAssignment(const ast::AssignmentStatement& stmt);
|
||||
bool CollectFunctionDef(const ast::FunctionDefinition& func);
|
||||
bool CollectClass(const ast::ClassDefinition& class_def);
|
||||
bool CollectUsesClause(const ast::UsesClause& uses);
|
||||
|
||||
// ==================== 类成员收集 ====================
|
||||
|
||||
bool CollectClassMember(const ast::ClassMember& member, Class* owner);
|
||||
bool CollectMemberVariable(const ast::VarDeclaration& var, Access access);
|
||||
bool CollectMemberStatic(const ast::StaticDeclaration& decl, Access access);
|
||||
bool CollectMemberMethod(const ast::Method& method, Access access, Class* owner);
|
||||
bool CollectMemberProperty(const ast::Property& property, Access access);
|
||||
bool CollectMemberConstructor(const ast::ConstructorDeclaration& ctor, Access access, Class* owner);
|
||||
bool CollectMemberDestructor(const ast::DestructorDeclaration& dtor, Access access, Class* owner);
|
||||
|
||||
// ==================== 函数体收集 ====================
|
||||
|
||||
void CollectFunctionBody(Function* func, const ast::Block& body);
|
||||
void CollectFunctionParams(Function* func);
|
||||
void CollectConstructorBody(Constructor* ctor, const ast::Block& body);
|
||||
void CollectDestructorBody(Destructor* dtor, const ast::Block& body);
|
||||
|
||||
// ==================== 辅助方法 ====================
|
||||
|
||||
void CollectInScope(Table* scope, const std::vector<ast::ASTNode>& statements);
|
||||
void CollectStatements(const std::vector<ast::ASTNode>& statements);
|
||||
|
||||
// ==================== 插入方法 ====================
|
||||
|
||||
bool TryInsert(SymbolPtr symbol);
|
||||
bool TryInsertFunction(FunctionPtr func, const ast::Location& loc);
|
||||
bool TryInsertUnit(UnitPtr unit);
|
||||
|
||||
// ==================== 创建签名 ====================
|
||||
|
||||
Signature CreateSignature(const ast::Signature& ast_sig);
|
||||
Signature::Param CreateParameter(const ast::Parameter& ast_param);
|
||||
|
||||
protected:
|
||||
CollectorContext& ctx_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include "./error.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 错误类型名称映射 ====================
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* GetErrorKindName(ErrorKind kind)
|
||||
{
|
||||
static const std::unordered_map<ErrorKind, const char*> names = {
|
||||
{ ErrorKind::kDuplicateDefinition, "Duplicate definition" },
|
||||
{ ErrorKind::kSignatureConflict, "Signature conflict" },
|
||||
{ ErrorKind::kUndefinedType, "Undefined type" },
|
||||
{ ErrorKind::kInvalidAccess, "Invalid access" },
|
||||
{ ErrorKind::kCircularDependency, "Circular dependency" },
|
||||
{ ErrorKind::kInvalidOverride, "Invalid override" },
|
||||
{ ErrorKind::kInvalidTypeReference, "Invalid type reference" },
|
||||
{ ErrorKind::kMemberNotFound, "Member not found" },
|
||||
{ ErrorKind::kInvalidModifier, "Invalid modifier" },
|
||||
{ ErrorKind::kInvalidParent, "Invalid parent" },
|
||||
};
|
||||
|
||||
auto it = names.find(kind);
|
||||
return it != names.end() ? it->second : "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Error 实现 ====================
|
||||
|
||||
Error::Error(ErrorKind k, const std::string& msg, const ast::Location& loc) :
|
||||
kind(k), message(msg), location(loc)
|
||||
{
|
||||
}
|
||||
|
||||
std::string Error::ToString() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[" << location.start_line << ":" << location.start_column << "] ";
|
||||
oss << GetErrorKindName(kind);
|
||||
oss << ": " << message;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Error Error::DuplicateDefinition(const std::string& name, const ast::Location& loc)
|
||||
{
|
||||
return Error(ErrorKind::kDuplicateDefinition, "Duplicate definition: " + name, loc);
|
||||
}
|
||||
|
||||
Error Error::UndefinedType(const std::string& type, const ast::Location& loc)
|
||||
{
|
||||
return Error(ErrorKind::kUndefinedType, "Undefined type: " + type, loc);
|
||||
}
|
||||
|
||||
Error Error::CircularDependency(const std::string& msg, const ast::Location& loc)
|
||||
{
|
||||
return Error(ErrorKind::kCircularDependency, msg, loc);
|
||||
}
|
||||
|
||||
// ==================== ErrorReporter 实现 ====================
|
||||
|
||||
void ErrorReporter::Report(ErrorKind kind, const std::string& msg, const ast::Location& loc)
|
||||
{
|
||||
errors_.emplace_back(kind, msg, loc);
|
||||
}
|
||||
|
||||
void ErrorReporter::Report(const Error& error)
|
||||
{
|
||||
errors_.push_back(error);
|
||||
}
|
||||
|
||||
const std::vector<Error>& ErrorReporter::GetErrors() const
|
||||
{
|
||||
return errors_;
|
||||
}
|
||||
|
||||
bool ErrorReporter::HasErrors() const
|
||||
{
|
||||
return !errors_.empty();
|
||||
}
|
||||
|
||||
size_t ErrorReporter::ErrorCount() const
|
||||
{
|
||||
return errors_.size();
|
||||
}
|
||||
|
||||
void ErrorReporter::Clear()
|
||||
{
|
||||
errors_.clear();
|
||||
}
|
||||
|
||||
void ErrorReporter::ReportDuplicateDefinition(const std::string& name, const ast::Location& loc)
|
||||
{
|
||||
Report(Error::DuplicateDefinition(name, loc));
|
||||
}
|
||||
|
||||
void ErrorReporter::ReportUndefinedType(const std::string& type, const ast::Location& loc)
|
||||
{
|
||||
Report(Error::UndefinedType(type, loc));
|
||||
}
|
||||
|
||||
void ErrorReporter::ReportCircularDependency(const std::string& msg, const ast::Location& loc)
|
||||
{
|
||||
Report(Error::CircularDependency(msg, loc));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "../../ast/types.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
enum class ErrorKind
|
||||
{
|
||||
kDuplicateDefinition,
|
||||
kSignatureConflict,
|
||||
kUndefinedType,
|
||||
kInvalidAccess,
|
||||
kCircularDependency,
|
||||
kInvalidOverride,
|
||||
kInvalidTypeReference,
|
||||
kMemberNotFound,
|
||||
kInvalidModifier,
|
||||
kInvalidParent,
|
||||
};
|
||||
|
||||
struct Error
|
||||
{
|
||||
ErrorKind kind;
|
||||
std::string message;
|
||||
ast::Location location;
|
||||
|
||||
Error(ErrorKind k, const std::string& msg, const ast::Location& loc);
|
||||
std::string ToString() const;
|
||||
|
||||
static Error DuplicateDefinition(const std::string& name, const ast::Location& loc);
|
||||
static Error UndefinedType(const std::string& type, const ast::Location& loc);
|
||||
static Error CircularDependency(const std::string& msg, const ast::Location& loc);
|
||||
};
|
||||
|
||||
class ErrorReporter
|
||||
{
|
||||
public:
|
||||
ErrorReporter() = default;
|
||||
|
||||
void Report(ErrorKind kind, const std::string& msg, const ast::Location& loc);
|
||||
void Report(const Error& error);
|
||||
|
||||
const std::vector<Error>& GetErrors() const;
|
||||
bool HasErrors() const;
|
||||
size_t ErrorCount() const;
|
||||
void Clear();
|
||||
|
||||
void ReportDuplicateDefinition(const std::string& name, const ast::Location& loc);
|
||||
void ReportUndefinedType(const std::string& type, const ast::Location& loc);
|
||||
void ReportCircularDependency(const std::string& msg, const ast::Location& loc);
|
||||
|
||||
private:
|
||||
std::vector<Error> errors_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "./registry.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
SymbolRegistry::SymbolRegistry() :
|
||||
global_scope_(ScopeKind::kGlobal, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// 移动构造函数
|
||||
SymbolRegistry::SymbolRegistry(SymbolRegistry&& other) noexcept :
|
||||
global_scope_(std::move(other.global_scope_)),
|
||||
units_(std::move(other.units_))
|
||||
{
|
||||
// 修复 global_scope_ 中所有符号的 scope 指针
|
||||
for (auto& [name, symbol] : global_scope_.Symbols())
|
||||
{
|
||||
if (symbol && symbol->scope == &other.global_scope_)
|
||||
{
|
||||
symbol->scope = &global_scope_;
|
||||
}
|
||||
}
|
||||
|
||||
// 修复 units_ 中所有符号的 scope 指针
|
||||
for (auto& [name, unit] : units_)
|
||||
{
|
||||
if (unit && unit->scope == &other.global_scope_)
|
||||
{
|
||||
unit->scope = &global_scope_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移动赋值运算符
|
||||
SymbolRegistry& SymbolRegistry::operator=(SymbolRegistry&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
global_scope_ = std::move(other.global_scope_);
|
||||
units_ = std::move(other.units_);
|
||||
|
||||
// 修复 global_scope_ 中所有符号的 scope 指针
|
||||
for (auto& [name, symbol] : global_scope_.Symbols())
|
||||
{
|
||||
if (symbol && symbol->scope == &other.global_scope_)
|
||||
{
|
||||
symbol->scope = &global_scope_;
|
||||
}
|
||||
}
|
||||
|
||||
// 修复 units_ 中所有符号的 scope 指针
|
||||
for (auto& [name, unit] : units_)
|
||||
{
|
||||
if (unit && unit->scope == &other.global_scope_)
|
||||
{
|
||||
unit->scope = &global_scope_;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Table* SymbolRegistry::GlobalScope()
|
||||
{
|
||||
return &global_scope_;
|
||||
}
|
||||
|
||||
const Table* SymbolRegistry::GlobalScope() const
|
||||
{
|
||||
return &global_scope_;
|
||||
}
|
||||
|
||||
bool SymbolRegistry::AddUnit(UnitPtr unit)
|
||||
{
|
||||
if (!unit)
|
||||
return false;
|
||||
|
||||
if (units_.count(unit->name) > 0)
|
||||
return false;
|
||||
|
||||
if (!global_scope_.Insert(unit))
|
||||
return false;
|
||||
|
||||
units_[unit->name] = unit;
|
||||
return true;
|
||||
}
|
||||
|
||||
UnitPtr SymbolRegistry::FindUnit(const std::string& name) const
|
||||
{
|
||||
auto it = units_.find(name);
|
||||
if (it != units_.end())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, UnitPtr>& SymbolRegistry::Units() const
|
||||
{
|
||||
return units_;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include "./symbol.hpp"
|
||||
#include "./table.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
class SymbolRegistry
|
||||
{
|
||||
public:
|
||||
SymbolRegistry();
|
||||
~SymbolRegistry() = default;
|
||||
|
||||
SymbolRegistry(const SymbolRegistry&) = delete;
|
||||
SymbolRegistry& operator=(const SymbolRegistry&) = delete;
|
||||
|
||||
// 自定义移动构造和移动赋值
|
||||
SymbolRegistry(SymbolRegistry&& other) noexcept;
|
||||
SymbolRegistry& operator=(SymbolRegistry&& other) noexcept;
|
||||
|
||||
// ==================== 访问全局作用域 ====================
|
||||
|
||||
Table* GlobalScope();
|
||||
const Table* GlobalScope() const;
|
||||
|
||||
// ==================== Unit 管理 ====================
|
||||
|
||||
bool AddUnit(UnitPtr unit);
|
||||
UnitPtr FindUnit(const std::string& name) const;
|
||||
const std::unordered_map<std::string, UnitPtr>& Units() const;
|
||||
|
||||
private:
|
||||
Table global_scope_;
|
||||
std::unordered_map<std::string, UnitPtr> units_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "./symbol.hpp"
|
||||
#include "./table.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== Function 实现 ====================
|
||||
|
||||
Function::Function(const std::string& name, const ast::Location& loc, const Signature& sig) :
|
||||
Symbol(name, Kind::kFunction, loc), signature(sig), is_overload(false), body_scope(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Function::~Function() = default;
|
||||
|
||||
Function::Function(Function&&) noexcept = default;
|
||||
|
||||
Function& Function::operator=(Function&&) noexcept = default;
|
||||
|
||||
// ==================== Method 实现 ====================
|
||||
|
||||
Method::Method(const std::string& name, const ast::Location& loc, const Signature& sig) :
|
||||
Function(name, loc, sig), owner_class(nullptr)
|
||||
{
|
||||
kind = Kind::kMethod;
|
||||
}
|
||||
|
||||
// ==================== Constructor 实现 ====================
|
||||
|
||||
Constructor::Constructor(const std::string& name, const ast::Location& loc, const Signature& sig) :
|
||||
Symbol(name, Kind::kConstructor, loc), signature(sig), owner_class(nullptr), body_scope(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Constructor::~Constructor() = default;
|
||||
|
||||
Constructor::Constructor(Constructor&&) noexcept = default;
|
||||
|
||||
Constructor& Constructor::operator=(Constructor&&) noexcept = default;
|
||||
|
||||
// ==================== Destructor 实现 ====================
|
||||
|
||||
Destructor::Destructor(const std::string& name, const ast::Location& loc) :
|
||||
Symbol(name, Kind::kDestructor, loc), owner_class(nullptr), body_scope(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Destructor::~Destructor() = default;
|
||||
|
||||
Destructor::Destructor(Destructor&&) noexcept = default;
|
||||
|
||||
Destructor& Destructor::operator=(Destructor&&) noexcept = default;
|
||||
|
||||
// ==================== Class 实现 ====================
|
||||
|
||||
Class::Class(const std::string& name, const ast::Location& loc) :
|
||||
Symbol(name, Kind::kClass, loc), members(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Class::~Class() = default;
|
||||
|
||||
Class::Class(Class&&) noexcept = default;
|
||||
|
||||
Class& Class::operator=(Class&&) noexcept = default;
|
||||
|
||||
// ==================== Unit 实现 ====================
|
||||
|
||||
Unit::Unit(const std::string& name, const ast::Location& loc) :
|
||||
Symbol(name, Kind::kUnit, loc), interface_symbols(nullptr), implementation_symbols(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Unit::~Unit() = default;
|
||||
|
||||
Unit::Unit(Unit&&) noexcept = default;
|
||||
|
||||
Unit& Unit::operator=(Unit&&) noexcept = default;
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
#include "../../ast/types.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// 前向声明
|
||||
class Table;
|
||||
|
||||
// ==================== 基本枚举 ====================
|
||||
|
||||
enum class Kind
|
||||
{
|
||||
kVariable,
|
||||
kStaticVariable,
|
||||
kGlobalVariable,
|
||||
kConstant,
|
||||
kParameter,
|
||||
kFunction,
|
||||
kClass,
|
||||
kMethod,
|
||||
kConstructor,
|
||||
kDestructor,
|
||||
kProperty,
|
||||
kUnit,
|
||||
};
|
||||
|
||||
enum class ScopeKind
|
||||
{
|
||||
kGlobal,
|
||||
kUnit,
|
||||
kInterface,
|
||||
kImplementation,
|
||||
kFunction,
|
||||
kClass,
|
||||
kBlock,
|
||||
};
|
||||
|
||||
using Access = ast::Access;
|
||||
|
||||
// ==================== 符号属性 ====================
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
bool is_const = false;
|
||||
bool is_static = false;
|
||||
bool is_var_param = false;
|
||||
bool is_out_param = false;
|
||||
Access access = Access::kPublic;
|
||||
bool is_virtual = false;
|
||||
bool is_override = false;
|
||||
bool is_overload = false;
|
||||
bool is_class_method = false;
|
||||
};
|
||||
|
||||
// ==================== 类型信息(纯数据) ====================
|
||||
class TypeInfo
|
||||
{
|
||||
public:
|
||||
TypeInfo() = default;
|
||||
|
||||
explicit TypeInfo(const std::string& annotation) :
|
||||
annotation_(annotation) {}
|
||||
|
||||
bool HasAnnotation() const { return !annotation_.empty(); }
|
||||
const std::string& Annotation() const { return annotation_; }
|
||||
// bool IsArray() const;
|
||||
// bool IsPrimitive() const;
|
||||
|
||||
private:
|
||||
std::string annotation_; // 类型注解(原始字符串)
|
||||
};
|
||||
|
||||
// ==================== 函数签名(纯数据) ====================
|
||||
|
||||
class Signature
|
||||
{
|
||||
public:
|
||||
size_t ParamCount() const { return parameters.size(); }
|
||||
bool HasReturnType() const { return return_type.has_value(); }
|
||||
|
||||
public:
|
||||
struct Param
|
||||
{
|
||||
std::string name;
|
||||
TypeInfo type;
|
||||
bool is_var = false;
|
||||
bool is_out = false;
|
||||
std::optional<std::string> default_value;
|
||||
};
|
||||
|
||||
std::vector<Param> parameters;
|
||||
std::optional<TypeInfo> return_type;
|
||||
};
|
||||
|
||||
// ==================== 符号基类 ====================
|
||||
|
||||
class Symbol
|
||||
{
|
||||
public:
|
||||
Symbol(const std::string& name, Kind kind, const ast::Location& loc) :
|
||||
name(name), kind(kind), location(loc), scope(nullptr)
|
||||
{
|
||||
}
|
||||
virtual ~Symbol() = default;
|
||||
Symbol(const Symbol&) = delete;
|
||||
Symbol& operator=(const Symbol&) = delete;
|
||||
Symbol(Symbol&&) noexcept = default;
|
||||
Symbol& operator=(Symbol&&) noexcept = default;
|
||||
|
||||
public:
|
||||
std::string name;
|
||||
Kind kind;
|
||||
ast::Location location;
|
||||
Table* scope;
|
||||
Attributes attributes;
|
||||
};
|
||||
|
||||
// ==================== 具体符号类 ====================
|
||||
|
||||
class Variable : public Symbol
|
||||
{
|
||||
public:
|
||||
Variable(const std::string& name, Kind kind, const ast::Location& loc, const TypeInfo& type) :
|
||||
Symbol(name, kind, loc), type(type)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
TypeInfo type;
|
||||
std::optional<std::string> initialization_expr;
|
||||
};
|
||||
|
||||
class Constant : public Symbol
|
||||
{
|
||||
public:
|
||||
Constant(const std::string& name, const ast::Location& loc, const TypeInfo& type, const std::string& value) :
|
||||
Symbol(name, Kind::kConstant, loc), type(type), value(value)
|
||||
{
|
||||
attributes.is_const = true;
|
||||
}
|
||||
|
||||
public:
|
||||
TypeInfo type;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
class Function : public Symbol
|
||||
{
|
||||
public:
|
||||
Function(const std::string& name, const ast::Location& loc, const Signature& sig);
|
||||
~Function() override;
|
||||
Function(const Function&) = delete;
|
||||
Function& operator=(const Function&) = delete;
|
||||
Function(Function&&) noexcept;
|
||||
Function& operator=(Function&&) noexcept;
|
||||
|
||||
public:
|
||||
Signature signature;
|
||||
bool is_overload;
|
||||
std::unique_ptr<Table> body_scope;
|
||||
};
|
||||
|
||||
class Method : public Function
|
||||
{
|
||||
public:
|
||||
Method(const std::string& name, const ast::Location& loc, const Signature& sig);
|
||||
|
||||
public:
|
||||
class Class* owner_class;
|
||||
std::optional<ast::Location> implementation_location;
|
||||
};
|
||||
|
||||
class Constructor : public Symbol
|
||||
{
|
||||
public:
|
||||
Signature signature;
|
||||
class Class* owner_class;
|
||||
std::unique_ptr<Table> body_scope;
|
||||
|
||||
Constructor(const std::string& name, const ast::Location& loc, const Signature& sig);
|
||||
|
||||
~Constructor() override;
|
||||
|
||||
Constructor(const Constructor&) = delete;
|
||||
Constructor& operator=(const Constructor&) = delete;
|
||||
Constructor(Constructor&&) noexcept;
|
||||
Constructor& operator=(Constructor&&) noexcept;
|
||||
};
|
||||
|
||||
class Destructor : public Symbol
|
||||
{
|
||||
public:
|
||||
class Class* owner_class;
|
||||
std::unique_ptr<Table> body_scope;
|
||||
|
||||
Destructor(const std::string& name, const ast::Location& loc);
|
||||
|
||||
~Destructor() override;
|
||||
|
||||
Destructor(const Destructor&) = delete;
|
||||
Destructor& operator=(const Destructor&) = delete;
|
||||
Destructor(Destructor&&) noexcept;
|
||||
Destructor& operator=(Destructor&&) noexcept;
|
||||
};
|
||||
|
||||
class Property : public Symbol
|
||||
{
|
||||
public:
|
||||
TypeInfo type;
|
||||
std::optional<std::string> getter;
|
||||
std::optional<std::string> setter;
|
||||
|
||||
Property(const std::string& name, const ast::Location& loc, const TypeInfo& type) :
|
||||
Symbol(name, Kind::kProperty, loc), type(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Class : public Symbol
|
||||
{
|
||||
public:
|
||||
std::vector<std::string> parent_names;
|
||||
std::vector<Class*> parents;
|
||||
std::unique_ptr<Table> members;
|
||||
|
||||
Class(const std::string& name, const ast::Location& loc);
|
||||
|
||||
~Class() override;
|
||||
|
||||
Class(const Class&) = delete;
|
||||
Class& operator=(const Class&) = delete;
|
||||
Class(Class&&) noexcept;
|
||||
Class& operator=(Class&&) noexcept;
|
||||
};
|
||||
|
||||
class Unit : public Symbol
|
||||
{
|
||||
public:
|
||||
std::vector<std::string> uses;
|
||||
std::unique_ptr<Table> interface_symbols;
|
||||
std::unique_ptr<Table> implementation_symbols;
|
||||
|
||||
Unit(const std::string& name, const ast::Location& loc);
|
||||
|
||||
~Unit() override;
|
||||
|
||||
Unit(const Unit&) = delete;
|
||||
Unit& operator=(const Unit&) = delete;
|
||||
Unit(Unit&&) noexcept;
|
||||
Unit& operator=(Unit&&) noexcept;
|
||||
};
|
||||
|
||||
// ==================== 智能指针类型别名 ====================
|
||||
|
||||
using SymbolPtr = std::shared_ptr<Symbol>;
|
||||
using VariablePtr = std::shared_ptr<Variable>;
|
||||
using ConstantPtr = std::shared_ptr<Constant>;
|
||||
using FunctionPtr = std::shared_ptr<Function>;
|
||||
using MethodPtr = std::shared_ptr<Method>;
|
||||
using ConstructorPtr = std::shared_ptr<Constructor>;
|
||||
using DestructorPtr = std::shared_ptr<Destructor>;
|
||||
using PropertyPtr = std::shared_ptr<Property>;
|
||||
using ClassPtr = std::shared_ptr<Class>;
|
||||
using UnitPtr = std::shared_ptr<Unit>;
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
#include "./table.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== LookupResult 实现 ====================
|
||||
|
||||
LookupResult LookupResult::Found(Symbol* sym, Table* scp)
|
||||
{
|
||||
LookupResult result;
|
||||
result.symbol = sym;
|
||||
result.scope = scp;
|
||||
result.success = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
LookupResult LookupResult::NotFound()
|
||||
{
|
||||
return LookupResult{};
|
||||
}
|
||||
|
||||
LookupResult::operator bool() const
|
||||
{
|
||||
return success;
|
||||
}
|
||||
|
||||
// ==================== Table 实现 ====================
|
||||
|
||||
Table::Table(ScopeKind kind, Table* parent) :
|
||||
kind_(kind), parent_(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ScopeKind Table::Kind() const
|
||||
{
|
||||
return kind_;
|
||||
}
|
||||
|
||||
Table* Table::Parent() const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, SymbolPtr>& Table::Symbols() const
|
||||
{
|
||||
return symbols_;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::vector<FunctionPtr>>& Table::OverloadedFunctions() const
|
||||
{
|
||||
return overloaded_functions_;
|
||||
}
|
||||
|
||||
Table* Table::CreateChild(ScopeKind kind)
|
||||
{
|
||||
auto child = std::make_unique<Table>(kind, this);
|
||||
Table* ptr = child.get();
|
||||
children_.push_back(std::move(child));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool Table::Insert(SymbolPtr symbol)
|
||||
{
|
||||
if (!symbol)
|
||||
return false;
|
||||
|
||||
if (symbols_.count(symbol->name) > 0)
|
||||
return false;
|
||||
|
||||
symbol->scope = this;
|
||||
symbols_[symbol->name] = symbol;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Table::InsertFunction(FunctionPtr func)
|
||||
{
|
||||
if (!func)
|
||||
return false;
|
||||
|
||||
func->scope = this;
|
||||
|
||||
auto& overloads = overloaded_functions_[func->name];
|
||||
|
||||
if (func->is_overload)
|
||||
overloads.push_back(func);
|
||||
|
||||
if (overloads.size() == 1)
|
||||
symbols_[func->name] = func;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LookupResult Table::LookupLocal(const std::string& name) const
|
||||
{
|
||||
auto it = symbols_.find(name);
|
||||
if (it != symbols_.end())
|
||||
return LookupResult::Found(it->second.get(), const_cast<Table*>(this));
|
||||
return LookupResult::NotFound();
|
||||
}
|
||||
|
||||
LookupResult Table::Lookup(const std::string& name) const
|
||||
{
|
||||
auto result = LookupLocal(name);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (parent_)
|
||||
return parent_->Lookup(name);
|
||||
|
||||
return LookupResult::NotFound();
|
||||
}
|
||||
|
||||
std::vector<FunctionPtr> Table::LookupOverloads(const std::string& name) const
|
||||
{
|
||||
auto it = overloaded_functions_.find(name);
|
||||
if (it != overloaded_functions_.end())
|
||||
return it->second;
|
||||
|
||||
if (parent_)
|
||||
return parent_->LookupOverloads(name);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
MethodPtr Table::FindMethodInClass(const std::string& class_name, const std::string& method_name) const
|
||||
{
|
||||
// 1. 查找类符号
|
||||
auto class_result = Lookup(class_name);
|
||||
if (!class_result || class_result.symbol->kind != Kind::kClass)
|
||||
return nullptr;
|
||||
|
||||
auto class_sym = static_cast<Class*>(class_result.symbol);
|
||||
if (!class_sym->members)
|
||||
return nullptr;
|
||||
|
||||
auto method_result = class_sym->members->LookupLocal(method_name);
|
||||
if (!method_result || method_result.symbol->kind != Kind::kMethod)
|
||||
return nullptr;
|
||||
|
||||
auto it = class_sym->members->Symbols().find(method_name);
|
||||
if (it != class_sym->members->Symbols().end())
|
||||
return std::static_pointer_cast<Method>(it->second);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "./symbol.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 查找结果 ====================
|
||||
|
||||
struct LookupResult
|
||||
{
|
||||
Symbol* symbol = nullptr;
|
||||
Table* scope = nullptr;
|
||||
bool success = false;
|
||||
|
||||
static LookupResult Found(Symbol* sym, Table* scp);
|
||||
static LookupResult NotFound();
|
||||
|
||||
explicit operator bool() const;
|
||||
};
|
||||
|
||||
// ==================== 符号表 / 作用域 ====================
|
||||
|
||||
class Table
|
||||
{
|
||||
public:
|
||||
explicit Table(ScopeKind kind, Table* parent = nullptr);
|
||||
~Table() = default;
|
||||
|
||||
Table(const Table&) = delete;
|
||||
Table& operator=(const Table&) = delete;
|
||||
Table(Table&&) noexcept = default;
|
||||
Table& operator=(Table&&) noexcept = default;
|
||||
|
||||
// ==================== 访问器 ====================
|
||||
|
||||
ScopeKind Kind() const;
|
||||
Table* Parent() const;
|
||||
const std::unordered_map<std::string, SymbolPtr>& Symbols() const;
|
||||
const std::unordered_map<std::string, std::vector<FunctionPtr>>& OverloadedFunctions() const;
|
||||
|
||||
// ==================== 作用域管理 ====================
|
||||
|
||||
Table* CreateChild(ScopeKind kind);
|
||||
|
||||
// ==================== 符号插入(核心方法) ====================
|
||||
|
||||
bool Insert(SymbolPtr symbol);
|
||||
bool InsertFunction(FunctionPtr func);
|
||||
|
||||
// ==================== 符号查找 ====================
|
||||
|
||||
LookupResult LookupLocal(const std::string& name) const;
|
||||
LookupResult Lookup(const std::string& name) const;
|
||||
|
||||
// 优化:返回 vector 引用或空 vector
|
||||
std::vector<FunctionPtr> LookupOverloads(const std::string& name) const;
|
||||
MethodPtr FindMethodInClass(const std::string& class_name, const std::string& method_name) const;
|
||||
|
||||
private:
|
||||
ScopeKind kind_;
|
||||
Table* parent_;
|
||||
std::vector<std::unique_ptr<Table>> children_;
|
||||
std::unordered_map<std::string, SymbolPtr> symbols_;
|
||||
std::unordered_map<std::string, std::vector<FunctionPtr>> overloaded_functions_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "../utils/type.hpp"
|
||||
#include "./factory.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 创建符号对象 ====================
|
||||
|
||||
VariablePtr factory::CreateVariable(
|
||||
const std::string& name,
|
||||
Kind kind,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type)
|
||||
{
|
||||
return std::make_shared<Variable>(name, kind, loc, type);
|
||||
}
|
||||
|
||||
ConstantPtr factory::CreateConstant(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type,
|
||||
const std::string& value)
|
||||
{
|
||||
return std::make_shared<Constant>(name, loc, type, value);
|
||||
}
|
||||
|
||||
FunctionPtr factory::CreateFunction(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const Signature& sig)
|
||||
{
|
||||
return std::make_shared<Function>(name, loc, sig);
|
||||
}
|
||||
|
||||
MethodPtr factory::CreateMethod(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const Signature& sig,
|
||||
Class* owner)
|
||||
{
|
||||
auto method = std::make_shared<Method>(name, loc, sig);
|
||||
method->owner_class = owner;
|
||||
return method;
|
||||
}
|
||||
|
||||
ConstructorPtr factory::CreateConstructor(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const Signature& sig,
|
||||
Class* owner)
|
||||
{
|
||||
auto ctor = std::make_shared<Constructor>(name, loc, sig);
|
||||
ctor->owner_class = owner;
|
||||
return ctor;
|
||||
}
|
||||
|
||||
DestructorPtr factory::CreateDestructor(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
Class* owner)
|
||||
{
|
||||
auto dtor = std::make_shared<Destructor>(name, loc);
|
||||
dtor->owner_class = owner;
|
||||
return dtor;
|
||||
}
|
||||
|
||||
PropertyPtr factory::CreateProperty(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type)
|
||||
{
|
||||
return std::make_shared<Property>(name, loc, type);
|
||||
}
|
||||
|
||||
ClassPtr factory::CreateClass(
|
||||
const std::string& name,
|
||||
const ast::Location& loc)
|
||||
{
|
||||
return std::make_shared<Class>(name, loc);
|
||||
}
|
||||
|
||||
UnitPtr factory::CreateUnit(
|
||||
const std::string& name,
|
||||
const ast::Location& loc)
|
||||
{
|
||||
return std::make_shared<Unit>(name, loc);
|
||||
}
|
||||
|
||||
// ==================== 便捷方法 ====================
|
||||
|
||||
VariablePtr factory::CreateAndInsert(
|
||||
Table* table,
|
||||
const std::string& name,
|
||||
Kind kind,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type)
|
||||
{
|
||||
auto var = CreateVariable(name, kind, loc, type);
|
||||
if (table && table->Insert(var))
|
||||
return var;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VariablePtr factory::CreateVariableFromAST(
|
||||
const std::string& name,
|
||||
Kind kind,
|
||||
const ast::Location& loc,
|
||||
const std::optional<std::string>& type_str)
|
||||
{
|
||||
TypeInfo type = type_str ?
|
||||
TypeFactory::FromAnnotation(*type_str) :
|
||||
TypeInfo();
|
||||
return CreateVariable(name, kind, loc, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include "../../ast/types.hpp"
|
||||
#include "../core/symbol.hpp"
|
||||
#include "../core/table.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
/**
|
||||
* 符号工厂 - 创建符号对象
|
||||
*
|
||||
* 职责:
|
||||
* - 提供符号对象的创建接口
|
||||
* - 封装 std::make_shared 调用
|
||||
*
|
||||
* 不负责:
|
||||
* - AST 到 Symbol 的转换逻辑(属于 Collector)
|
||||
*/
|
||||
namespace factory
|
||||
{
|
||||
// ==================== 创建符号对象 ====================
|
||||
|
||||
/**
|
||||
* 创建变量符号
|
||||
*/
|
||||
VariablePtr CreateVariable(
|
||||
const std::string& name,
|
||||
Kind kind,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type);
|
||||
|
||||
/**
|
||||
* 创建常量符号
|
||||
*/
|
||||
ConstantPtr CreateConstant(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type,
|
||||
const std::string& value);
|
||||
|
||||
/**
|
||||
* 创建函数符号
|
||||
*/
|
||||
FunctionPtr CreateFunction(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const Signature& sig);
|
||||
|
||||
/**
|
||||
* 创建方法符号
|
||||
*/
|
||||
MethodPtr CreateMethod(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const Signature& sig,
|
||||
Class* owner);
|
||||
|
||||
/**
|
||||
* 创建构造函数符号
|
||||
*/
|
||||
ConstructorPtr CreateConstructor(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const Signature& sig,
|
||||
Class* owner);
|
||||
|
||||
/**
|
||||
* 创建析构函数符号
|
||||
*/
|
||||
DestructorPtr CreateDestructor(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
Class* owner);
|
||||
|
||||
/**
|
||||
* 创建属性符号
|
||||
*/
|
||||
PropertyPtr CreateProperty(
|
||||
const std::string& name,
|
||||
const ast::Location& loc,
|
||||
const TypeInfo& type);
|
||||
|
||||
/**
|
||||
* 创建类符号
|
||||
*/
|
||||
ClassPtr CreateClass(
|
||||
const std::string& name,
|
||||
const ast::Location& loc);
|
||||
|
||||
/**
|
||||
* 创建 Unit 符号
|
||||
*/
|
||||
UnitPtr CreateUnit(const std::string& name, const ast::Location& loc);
|
||||
|
||||
// ==================== 便捷方法 ====================
|
||||
|
||||
/**
|
||||
* 创建并插入变量
|
||||
* @return 如果插入成功返回符号,否则返回 nullptr
|
||||
*/
|
||||
VariablePtr CreateAndInsert(Table* table, const std::string& name, Kind kind, const ast::Location& loc, const TypeInfo& type);
|
||||
|
||||
/**
|
||||
* 从 AST 类型字符串创建变量
|
||||
*/
|
||||
VariablePtr CreateVariableFromAST(const std::string& name, Kind kind, const ast::Location& loc,
|
||||
const std::optional<std::string>& type_str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "./scope_manager.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== ScopeGuard 实现 ====================
|
||||
|
||||
ScopeGuard::ScopeGuard(Table*& current, Table* new_scope) :
|
||||
current_(current), previous_(current), active_(true)
|
||||
{
|
||||
current_ = new_scope;
|
||||
}
|
||||
|
||||
ScopeGuard::~ScopeGuard()
|
||||
{
|
||||
if (active_)
|
||||
{
|
||||
current_ = previous_;
|
||||
}
|
||||
}
|
||||
|
||||
ScopeGuard::ScopeGuard(ScopeGuard&& other) noexcept :
|
||||
current_(other.current_),
|
||||
previous_(other.previous_),
|
||||
active_(other.active_)
|
||||
{
|
||||
other.active_ = false;
|
||||
}
|
||||
|
||||
ScopeGuard& ScopeGuard::operator=(ScopeGuard&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if (active_)
|
||||
{
|
||||
current_ = previous_;
|
||||
}
|
||||
|
||||
current_ = other.current_;
|
||||
previous_ = other.previous_;
|
||||
active_ = other.active_;
|
||||
|
||||
other.active_ = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ==================== ScopeManager 实现 ====================
|
||||
|
||||
ScopeManager::ScopeManager(Table* root) :
|
||||
root_(root), current_(root)
|
||||
{
|
||||
}
|
||||
|
||||
Table* ScopeManager::Current() const
|
||||
{
|
||||
return current_;
|
||||
}
|
||||
|
||||
ScopeGuard ScopeManager::EnterScope(Table* scope)
|
||||
{
|
||||
return ScopeGuard(current_, scope);
|
||||
}
|
||||
|
||||
ScopeGuard ScopeManager::CreateAndEnterChild(ScopeKind kind)
|
||||
{
|
||||
Table* child = current_->CreateChild(kind);
|
||||
return ScopeGuard(current_, child);
|
||||
}
|
||||
|
||||
void ScopeManager::SetCurrent(Table* scope)
|
||||
{
|
||||
current_ = scope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "../core/table.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 作用域守卫 ====================
|
||||
// RAII风格的作用域管理
|
||||
|
||||
class ScopeGuard
|
||||
{
|
||||
public:
|
||||
ScopeGuard(Table*& current, Table* new_scope);
|
||||
~ScopeGuard();
|
||||
|
||||
ScopeGuard(const ScopeGuard&) = delete;
|
||||
ScopeGuard& operator=(const ScopeGuard&) = delete;
|
||||
ScopeGuard(ScopeGuard&& other) noexcept;
|
||||
ScopeGuard& operator=(ScopeGuard&& other) noexcept;
|
||||
|
||||
private:
|
||||
Table*& current_;
|
||||
Table* previous_;
|
||||
bool active_;
|
||||
};
|
||||
|
||||
// ==================== 作用域管理器 ====================
|
||||
// 负责管理当前作用域的切换和导航
|
||||
|
||||
class ScopeManager
|
||||
{
|
||||
public:
|
||||
explicit ScopeManager(Table* root);
|
||||
|
||||
// 获取当前作用域
|
||||
Table* Current() const;
|
||||
|
||||
// 进入指定作用域(返回守卫,自动恢复)
|
||||
[[nodiscard]] ScopeGuard EnterScope(Table* scope);
|
||||
|
||||
// 创建子作用域并进入
|
||||
[[nodiscard]] ScopeGuard CreateAndEnterChild(ScopeKind kind);
|
||||
|
||||
// 直接设置当前作用域(不推荐,破坏RAII)
|
||||
void SetCurrent(Table* scope);
|
||||
|
||||
// 获取根作用域
|
||||
Table* Root() const { return root_; }
|
||||
|
||||
private:
|
||||
Table* root_;
|
||||
Table* current_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#include <sstream>
|
||||
#include "./incremental.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== SymbolCacheKey 实现 ====================
|
||||
|
||||
std::string SymbolCacheKey::ComputeSignatureHash(const Signature& sig)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << sig.parameters.size() << "|";
|
||||
for (const auto& param : sig.parameters)
|
||||
{
|
||||
oss << param.name << ":"
|
||||
<< param.type.Annotation() << ":"
|
||||
<< (param.is_var ? "v" : "")
|
||||
<< (param.is_out ? "o" : "") << "|";
|
||||
}
|
||||
|
||||
if (sig.return_type)
|
||||
{
|
||||
oss << "ret:" << sig.return_type->Annotation();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ==================== SymbolCache 实现 ====================
|
||||
|
||||
SymbolCache::SymbolCache(size_t max_size) :
|
||||
max_size_(max_size)
|
||||
{
|
||||
}
|
||||
|
||||
const SymbolPtr* SymbolCache::Find(const SymbolCacheKey& key)
|
||||
{
|
||||
auto it = cache_.find(key);
|
||||
if (it != cache_.end())
|
||||
{
|
||||
// 更新 LRU:移到最前面
|
||||
TouchKey(key);
|
||||
return &it->second.symbol;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SymbolCache::Insert(const SymbolCacheKey& key, const SymbolPtr& symbol)
|
||||
{
|
||||
// 检查是否已存在
|
||||
auto it = cache_.find(key);
|
||||
if (it != cache_.end())
|
||||
{
|
||||
// 更新现有条目
|
||||
it->second.symbol = symbol;
|
||||
TouchKey(key);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否需要淘汰
|
||||
if (cache_.size() >= max_size_)
|
||||
{
|
||||
EvictLRU();
|
||||
}
|
||||
|
||||
// 插入新条目
|
||||
lru_list_.push_front(key);
|
||||
cache_[key] = CacheEntry{ symbol, lru_list_.begin() };
|
||||
}
|
||||
|
||||
void SymbolCache::Clear()
|
||||
{
|
||||
cache_.clear();
|
||||
lru_list_.clear();
|
||||
}
|
||||
|
||||
void SymbolCache::EvictLRU()
|
||||
{
|
||||
if (lru_list_.empty())
|
||||
return;
|
||||
|
||||
// 删除最久未使用的项(列表末尾)
|
||||
auto lru_key = lru_list_.back();
|
||||
lru_list_.pop_back();
|
||||
cache_.erase(lru_key);
|
||||
}
|
||||
|
||||
void SymbolCache::TouchKey(const SymbolCacheKey& key)
|
||||
{
|
||||
auto it = cache_.find(key);
|
||||
if (it == cache_.end())
|
||||
return;
|
||||
|
||||
// 从当前位置删除
|
||||
lru_list_.erase(it->second.lru_iter);
|
||||
|
||||
// 移到最前面
|
||||
lru_list_.push_front(key);
|
||||
it->second.lru_iter = lru_list_.begin();
|
||||
}
|
||||
|
||||
SymbolCacheKey SymbolCache::MakeKey(const Symbol* symbol)
|
||||
{
|
||||
if (!symbol)
|
||||
return SymbolCacheKey{};
|
||||
|
||||
SymbolCacheKey key;
|
||||
key.symbol_name = symbol->name;
|
||||
key.symbol_kind = symbol->kind;
|
||||
key.declaration_line = symbol->location.start_line;
|
||||
key.declaration_column = symbol->location.start_column;
|
||||
|
||||
// 对于函数,添加签名哈希
|
||||
if (auto* func = dynamic_cast<const Function*>(symbol))
|
||||
{
|
||||
key.signature_hash = SymbolCacheKey::ComputeSignatureHash(func->signature);
|
||||
}
|
||||
else if (auto* ctor = dynamic_cast<const Constructor*>(symbol))
|
||||
{
|
||||
key.signature_hash = SymbolCacheKey::ComputeSignatureHash(ctor->signature);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
SymbolCacheKey SymbolCache::MakeKeyFromAST(
|
||||
const std::string& name,
|
||||
Kind kind,
|
||||
const ast::Location& name_location,
|
||||
const std::optional<Signature>& signature)
|
||||
{
|
||||
SymbolCacheKey key;
|
||||
key.symbol_name = name;
|
||||
key.symbol_kind = kind;
|
||||
key.declaration_line = name_location.start_line;
|
||||
key.declaration_column = name_location.start_column;
|
||||
|
||||
if (signature)
|
||||
{
|
||||
key.signature_hash = SymbolCacheKey::ComputeSignatureHash(*signature);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <list>
|
||||
#include "../core/symbol.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 改进的缓存键设计 ====================
|
||||
// 基于 AST 位置和内容,避免指针地址依赖
|
||||
|
||||
struct SymbolCacheKey
|
||||
{
|
||||
std::string symbol_name;
|
||||
Kind symbol_kind;
|
||||
uint32_t declaration_line; // 使用声明位置行号
|
||||
uint32_t declaration_column; // 使用声明位置列号
|
||||
std::optional<std::string> signature_hash; // 函数签名哈希
|
||||
|
||||
bool operator==(const SymbolCacheKey& other) const
|
||||
{
|
||||
return symbol_name == other.symbol_name &&
|
||||
symbol_kind == other.symbol_kind &&
|
||||
declaration_line == other.declaration_line &&
|
||||
declaration_column == other.declaration_column &&
|
||||
signature_hash == other.signature_hash;
|
||||
}
|
||||
|
||||
// 生成签名哈希(用于函数/方法)
|
||||
static std::string ComputeSignatureHash(const Signature& sig);
|
||||
};
|
||||
|
||||
struct SymbolCacheKeyHash
|
||||
{
|
||||
size_t operator()(const SymbolCacheKey& key) const
|
||||
{
|
||||
size_t h1 = std::hash<std::string>()(key.symbol_name);
|
||||
size_t h2 = std::hash<int>()(static_cast<int>(key.symbol_kind));
|
||||
size_t h3 = std::hash<uint32_t>()(key.declaration_line);
|
||||
size_t h4 = std::hash<uint32_t>()(key.declaration_column);
|
||||
size_t h5 = key.signature_hash ?
|
||||
std::hash<std::string>()(*key.signature_hash) :
|
||||
0;
|
||||
|
||||
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3) ^ (h5 << 4);
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 符号缓存管理器(带LRU) ====================
|
||||
|
||||
class SymbolCache
|
||||
{
|
||||
public:
|
||||
explicit SymbolCache(size_t max_size = 10000);
|
||||
|
||||
// 查找缓存
|
||||
const SymbolPtr* Find(const SymbolCacheKey& key);
|
||||
|
||||
// 插入缓存
|
||||
void Insert(const SymbolCacheKey& key, const SymbolPtr& symbol);
|
||||
|
||||
// 清空缓存
|
||||
void Clear();
|
||||
|
||||
// 获取缓存大小
|
||||
size_t Size() const { return cache_.size(); }
|
||||
|
||||
// 设置最大缓存大小
|
||||
void SetMaxSize(size_t max_size) { max_size_ = max_size; }
|
||||
|
||||
// 从 Symbol 生成 Key
|
||||
static SymbolCacheKey MakeKey(const Symbol* symbol);
|
||||
|
||||
// 从 AST 信息生成 Key
|
||||
static SymbolCacheKey MakeKeyFromAST(
|
||||
const std::string& name,
|
||||
Kind kind,
|
||||
const ast::Location& name_location,
|
||||
const std::optional<Signature>& signature = std::nullopt);
|
||||
|
||||
private:
|
||||
// LRU 淘汰策略
|
||||
void EvictLRU();
|
||||
void TouchKey(const SymbolCacheKey& key);
|
||||
|
||||
private:
|
||||
struct CacheEntry
|
||||
{
|
||||
SymbolPtr symbol;
|
||||
std::list<SymbolCacheKey>::iterator lru_iter;
|
||||
};
|
||||
|
||||
std::unordered_map<SymbolCacheKey, CacheEntry, SymbolCacheKeyHash> cache_;
|
||||
std::list<SymbolCacheKey> lru_list_; // 最近使用列表
|
||||
size_t max_size_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
#include "../core/symbol.hpp"
|
||||
#include "./incremental_engine.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
IncrementalEngine::IncrementalEngine() :
|
||||
cache_(10000),
|
||||
max_cache_size_(10000)
|
||||
{
|
||||
}
|
||||
|
||||
// ==================== 符号复用与缓存 ====================
|
||||
|
||||
bool IncrementalEngine::TryReuseSymbol(const ast::ASTNode& node, Table* scope, SymbolRegistry* registry)
|
||||
{
|
||||
return std::visit([this, scope, registry](auto&& arg) -> bool {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, std::monostate>)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::VarDeclaration>)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kVariable, arg.name_location);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
return scope->Insert(*cached);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::GlobalDeclaration>)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kGlobalVariable, arg.name_location);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
return scope->Insert(*cached);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::StaticDeclaration>)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kStaticVariable, arg.name_location);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
return scope->Insert(*cached);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::ConstDeclaration>)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kConstant, arg.name_location);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
return scope->Insert(*cached);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::FunctionDefinition>)
|
||||
{
|
||||
// 创建签名用于缓存键
|
||||
Signature sig;
|
||||
for (const auto& param : arg.signature.parameters)
|
||||
{
|
||||
Signature::Param p;
|
||||
p.name = param.name;
|
||||
if (param.type_name)
|
||||
{
|
||||
p.type = TypeInfo(*param.type_name);
|
||||
}
|
||||
p.is_var = param.is_var;
|
||||
p.is_out = param.is_out;
|
||||
sig.parameters.push_back(p);
|
||||
}
|
||||
if (arg.signature.return_type)
|
||||
{
|
||||
sig.return_type = TypeInfo(*arg.signature.return_type);
|
||||
}
|
||||
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kFunction, arg.name_location, sig);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
auto func = std::dynamic_pointer_cast<Function>(*cached);
|
||||
if (func)
|
||||
{
|
||||
return scope->InsertFunction(func);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::ClassDefinition>)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kClass, arg.name_location);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
return scope->Insert(*cached);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::UnitDefinition>)
|
||||
{
|
||||
// Unit 支持复用
|
||||
if (registry)
|
||||
{
|
||||
return TryReuseUnit(arg, registry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他类型(Expression, Block 等)直接跳过
|
||||
return true;
|
||||
}
|
||||
},
|
||||
node);
|
||||
}
|
||||
|
||||
bool IncrementalEngine::TryReuseUnit(
|
||||
const ast::UnitDefinition& unit_ast,
|
||||
SymbolRegistry* registry)
|
||||
{
|
||||
if (!registry)
|
||||
return false;
|
||||
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
unit_ast.name, Kind::kUnit, unit_ast.name_location);
|
||||
const SymbolPtr* cached = cache_.Find(key);
|
||||
|
||||
if (cached && *cached)
|
||||
{
|
||||
auto unit = std::dynamic_pointer_cast<Unit>(*cached);
|
||||
if (unit)
|
||||
{
|
||||
// 尝试将缓存的 Unit 添加到 Registry
|
||||
return registry->AddUnit(unit);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void IncrementalEngine::CacheSymbol(const ast::ASTNode& node, Table* scope)
|
||||
{
|
||||
std::visit([this, scope](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, ast::VarDeclaration> ||
|
||||
std::is_same_v<T, ast::GlobalDeclaration> ||
|
||||
std::is_same_v<T, ast::StaticDeclaration>)
|
||||
{
|
||||
auto result = scope->LookupLocal(arg.name);
|
||||
if (result && result.symbol)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, result.symbol->kind, arg.name_location);
|
||||
|
||||
const auto& symbols = scope->Symbols();
|
||||
auto it = symbols.find(arg.name);
|
||||
if (it != symbols.end())
|
||||
{
|
||||
cache_.Insert(key, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::ConstDeclaration>)
|
||||
{
|
||||
auto result = scope->LookupLocal(arg.name);
|
||||
if (result && result.symbol)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kConstant, arg.name_location);
|
||||
|
||||
const auto& symbols = scope->Symbols();
|
||||
auto it = symbols.find(arg.name);
|
||||
if (it != symbols.end())
|
||||
{
|
||||
cache_.Insert(key, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::FunctionDefinition>)
|
||||
{
|
||||
auto result = scope->LookupLocal(arg.name);
|
||||
if (result && result.symbol)
|
||||
{
|
||||
// 创建签名用于缓存键
|
||||
Signature sig;
|
||||
for (const auto& param : arg.signature.parameters)
|
||||
{
|
||||
Signature::Param p;
|
||||
p.name = param.name;
|
||||
if (param.type_name)
|
||||
{
|
||||
p.type = TypeInfo(*param.type_name);
|
||||
}
|
||||
p.is_var = param.is_var;
|
||||
p.is_out = param.is_out;
|
||||
sig.parameters.push_back(p);
|
||||
}
|
||||
if (arg.signature.return_type)
|
||||
{
|
||||
sig.return_type = TypeInfo(*arg.signature.return_type);
|
||||
}
|
||||
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kFunction, arg.name_location, sig);
|
||||
|
||||
const auto& symbols = scope->Symbols();
|
||||
auto it = symbols.find(arg.name);
|
||||
if (it != symbols.end())
|
||||
{
|
||||
cache_.Insert(key, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::ClassDefinition>)
|
||||
{
|
||||
auto result = scope->LookupLocal(arg.name);
|
||||
if (result && result.symbol)
|
||||
{
|
||||
auto key = SymbolCache::MakeKeyFromAST(
|
||||
arg.name, Kind::kClass, arg.name_location);
|
||||
|
||||
const auto& symbols = scope->Symbols();
|
||||
auto it = symbols.find(arg.name);
|
||||
if (it != symbols.end())
|
||||
{
|
||||
cache_.Insert(key, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, ast::UnitDefinition>)
|
||||
{
|
||||
// Unit 缓存需要从 Registry 获取
|
||||
// 这里暂时不处理,在 BuildCache 中统一处理
|
||||
}
|
||||
// 其他类型不需要缓存
|
||||
},
|
||||
node);
|
||||
}
|
||||
|
||||
void IncrementalEngine::BuildCache(const SymbolRegistry& registry)
|
||||
{
|
||||
// 缓存所有 Unit
|
||||
for (const auto& [name, unit] : registry.Units())
|
||||
{
|
||||
auto key = SymbolCache::MakeKey(unit.get());
|
||||
cache_.Insert(key, unit);
|
||||
|
||||
// 递归缓存 Unit 内部的符号
|
||||
if (unit->interface_symbols)
|
||||
CacheScopeRecursive(unit->interface_symbols.get());
|
||||
if (unit->implementation_symbols)
|
||||
CacheScopeRecursive(unit->implementation_symbols.get());
|
||||
}
|
||||
|
||||
// 缓存全局作用域
|
||||
CacheScopeRecursive(const_cast<Table*>(registry.GlobalScope()));
|
||||
}
|
||||
|
||||
void IncrementalEngine::CacheScopeRecursive(Table* scope)
|
||||
{
|
||||
if (!scope)
|
||||
return;
|
||||
|
||||
// 缓存当前作用域的所有符号
|
||||
for (const auto& [name, symbol] : scope->Symbols())
|
||||
{
|
||||
auto key = SymbolCache::MakeKey(symbol.get());
|
||||
cache_.Insert(key, symbol);
|
||||
|
||||
// 递归缓存类成员
|
||||
if (auto* cls = dynamic_cast<Class*>(symbol.get()))
|
||||
{
|
||||
if (cls->members)
|
||||
{
|
||||
CacheScopeRecursive(cls->members.get());
|
||||
}
|
||||
}
|
||||
|
||||
// 递归缓存函数体作用域
|
||||
if (auto* func = dynamic_cast<Function*>(symbol.get()))
|
||||
{
|
||||
if (func->body_scope)
|
||||
{
|
||||
CacheScopeRecursive(func->body_scope.get());
|
||||
}
|
||||
}
|
||||
|
||||
// 递归缓存构造函数体作用域
|
||||
if (auto* ctor = dynamic_cast<Constructor*>(symbol.get()))
|
||||
{
|
||||
if (ctor->body_scope)
|
||||
{
|
||||
CacheScopeRecursive(ctor->body_scope.get());
|
||||
}
|
||||
}
|
||||
|
||||
// 递归缓存析构函数体作用域
|
||||
if (auto* dtor = dynamic_cast<Destructor*>(symbol.get()))
|
||||
{
|
||||
if (dtor->body_scope)
|
||||
{
|
||||
CacheScopeRecursive(dtor->body_scope.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 管理接口 ====================
|
||||
|
||||
void IncrementalEngine::Clear()
|
||||
{
|
||||
cache_.Clear();
|
||||
}
|
||||
|
||||
void IncrementalEngine::SetMaxCacheSize(size_t max_size)
|
||||
{
|
||||
max_cache_size_ = max_size;
|
||||
cache_.SetMaxSize(max_size);
|
||||
}
|
||||
|
||||
size_t IncrementalEngine::GetCacheSize() const
|
||||
{
|
||||
return cache_.Size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../ast/types.hpp"
|
||||
#include "../core/registry.hpp"
|
||||
#include "../core/table.hpp"
|
||||
#include "./incremental.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
/**
|
||||
* 增量构建引擎 - 管理符号缓存和复用
|
||||
*
|
||||
* 职责:
|
||||
* - 管理符号缓存 (SymbolCache)
|
||||
* - 提供符号复用接口
|
||||
* - 提供符号缓存接口
|
||||
* - 构建全局缓存
|
||||
*
|
||||
* 不负责:
|
||||
* - 依赖追踪(移到语义分析阶段)
|
||||
* - 类型解析(移到语义分析阶段)
|
||||
*/
|
||||
class IncrementalEngine
|
||||
{
|
||||
public:
|
||||
IncrementalEngine();
|
||||
|
||||
// ==================== 符号复用与缓存 ====================
|
||||
|
||||
/**
|
||||
* 尝试从缓存复用符号
|
||||
* @param node AST 节点
|
||||
* @param scope 当前作用域
|
||||
* @param registry 符号注册表(用于 Unit 复用)
|
||||
* @return 是否成功复用
|
||||
*/
|
||||
bool TryReuseSymbol(const ast::ASTNode& node, Table* scope, SymbolRegistry* registry = nullptr);
|
||||
|
||||
/**
|
||||
* 缓存当前符号
|
||||
* @param node AST 节点
|
||||
* @param scope 当前作用域
|
||||
*/
|
||||
void CacheSymbol(const ast::ASTNode& node, Table* scope);
|
||||
|
||||
/**
|
||||
* 从整个注册表构建缓存
|
||||
* @param registry 符号注册表
|
||||
*/
|
||||
void BuildCache(const SymbolRegistry& registry);
|
||||
|
||||
// ==================== 管理接口 ====================
|
||||
|
||||
void Clear();
|
||||
void SetMaxCacheSize(size_t max_size);
|
||||
size_t GetCacheSize() const;
|
||||
|
||||
// 访问器
|
||||
SymbolCache& GetCache() { return cache_; }
|
||||
const SymbolCache& GetCache() const { return cache_; }
|
||||
|
||||
private:
|
||||
// ==================== 内部辅助方法 ====================
|
||||
|
||||
// 递归缓存作用域中的所有符号
|
||||
void CacheScopeRecursive(Table* scope);
|
||||
|
||||
// 尝试复用 Unit
|
||||
bool TryReuseUnit(const ast::UnitDefinition& unit_ast, SymbolRegistry* registry);
|
||||
|
||||
private:
|
||||
SymbolCache cache_;
|
||||
size_t max_cache_size_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "./type.hpp"
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== TypeFactory 实现 ====================
|
||||
|
||||
TypeInfo TypeFactory::FromAnnotation(const std::string& annotation)
|
||||
{
|
||||
// 直接存储原始注解字符串,不做任何解析
|
||||
// 类型引用的解析将在语义分析阶段完成
|
||||
return TypeInfo(Trim(annotation));
|
||||
}
|
||||
|
||||
std::string TypeFactory::Trim(const std::string& str)
|
||||
{
|
||||
size_t start = 0;
|
||||
while (start < str.length() && std::isspace(static_cast<unsigned char>(str[start])))
|
||||
++start;
|
||||
|
||||
if (start == str.length())
|
||||
return "";
|
||||
|
||||
size_t end = str.length();
|
||||
while (end > start && std::isspace(static_cast<unsigned char>(str[end - 1])))
|
||||
--end;
|
||||
|
||||
return str.substr(start, end - start);
|
||||
}
|
||||
|
||||
// ==================== TypeFormatter 实现 ====================
|
||||
|
||||
std::string TypeFormatter::ToString(const TypeInfo& type)
|
||||
{
|
||||
if (!type.HasAnnotation())
|
||||
return "<no annotation>";
|
||||
|
||||
return type.Annotation();
|
||||
}
|
||||
|
||||
std::string TypeFormatter::ToDebugString(const TypeInfo& type)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "TypeInfo { ";
|
||||
|
||||
if (type.HasAnnotation())
|
||||
{
|
||||
oss << "annotation: \"" << type.Annotation() << "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "no annotation";
|
||||
}
|
||||
|
||||
oss << " }";
|
||||
return oss.str();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "../core/symbol.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ==================== 类型工厂 ====================
|
||||
|
||||
/**
|
||||
* 类型工厂 - 仅用于符号表构建
|
||||
*
|
||||
* 职责:
|
||||
* - 从类型注解字符串创建 TypeInfo
|
||||
* - 存储原始字符串,不解析任何引用
|
||||
*
|
||||
* 不负责:
|
||||
* - 类型引用解析(属于语义分析)
|
||||
* - 表达式解析(属于语义分析)
|
||||
* - 类型检查(属于语义分析)
|
||||
*/
|
||||
class TypeFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* 从类型注解创建 TypeInfo
|
||||
* @param annotation 类型注解字符串(如 "Integer", "TMyClass")
|
||||
* @return TypeInfo 对象
|
||||
*
|
||||
* 注意:直接存储原始字符串,不做任何解析
|
||||
*/
|
||||
static TypeInfo FromAnnotation(const std::string& annotation);
|
||||
|
||||
private:
|
||||
// 辅助函数:去除首尾空格
|
||||
static std::string Trim(const std::string& str);
|
||||
};
|
||||
|
||||
// ==================== 类型格式化器 ====================
|
||||
|
||||
/**
|
||||
* 类型格式化器 - 用于调试和日志输出
|
||||
*/
|
||||
class TypeFormatter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* 转换为可读字符串
|
||||
*/
|
||||
static std::string ToString(const TypeInfo& type);
|
||||
|
||||
/**
|
||||
* 转换为调试字符串(包含详细信息)
|
||||
*/
|
||||
static std::string ToDebugString(const TypeInfo& type);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user