add symbol table and test file
This commit is contained in:
parent
7d9b966bc7
commit
100e210ed1
|
|
@ -0,0 +1,662 @@
|
|||
#include "./builder.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
Builder::Builder(SymbolTable& table) : table_(table), current_scope_id_(kInvalidScopeId)
|
||||
{
|
||||
}
|
||||
|
||||
void Builder::Build(ast::ASTNode& root)
|
||||
{
|
||||
current_scope_id_ = table_.CreateScope(
|
||||
ScopeKind::Global,
|
||||
root.span,
|
||||
std::nullopt,
|
||||
std::nullopt);
|
||||
|
||||
SymbolId global_symbol = table_.CreateSymbol(
|
||||
"::",
|
||||
SymbolKind::Namespace,
|
||||
root.span,
|
||||
current_scope_id_,
|
||||
std::nullopt,
|
||||
std::nullopt);
|
||||
|
||||
table_.GetScopeManager().AddSymbol(current_scope_id_, "::", global_symbol);
|
||||
|
||||
root.Accept(*this);
|
||||
}
|
||||
|
||||
SymbolId Builder::CreateSymbol(const std::string& name, SymbolKind kind, const ast::ASTNode& node, const std::optional<std::string>& type_hint)
|
||||
{
|
||||
return table_.CreateSymbol(
|
||||
name,
|
||||
kind,
|
||||
node.span,
|
||||
current_scope_id_,
|
||||
current_parent_symbol_id_,
|
||||
type_hint);
|
||||
}
|
||||
|
||||
ScopeId Builder::EnterScopeWithSymbol(ScopeKind kind, SymbolId symbol_id, const ast::Location& range)
|
||||
{
|
||||
ScopeId parent_scope = current_scope_id_;
|
||||
current_scope_id_ = table_.CreateScope(kind, range, parent_scope, symbol_id);
|
||||
return current_scope_id_;
|
||||
}
|
||||
|
||||
ScopeId Builder::EnterScope(ScopeKind kind, const ast::Location& range)
|
||||
{
|
||||
ScopeId parent_scope = current_scope_id_;
|
||||
current_scope_id_ = table_.CreateScope(kind, range, parent_scope, std::nullopt);
|
||||
return current_scope_id_;
|
||||
}
|
||||
|
||||
void Builder::ExitScope()
|
||||
{
|
||||
auto info = table_.GetScopeManager().GetScopeInfo(current_scope_id_);
|
||||
if (info && info->parent_scope_id)
|
||||
current_scope_id_ = *info->parent_scope_id;
|
||||
}
|
||||
|
||||
void Builder::VisitStatements(const std::vector<ast::StatementPtr>& statements)
|
||||
{
|
||||
for (const auto& stmt : statements)
|
||||
{
|
||||
if (stmt)
|
||||
stmt->Accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitExpression(ast::Expression& expr)
|
||||
{
|
||||
expr.Accept(*this);
|
||||
}
|
||||
|
||||
std::string Builder::FormatSignature(const ast::Signature& signature)
|
||||
{
|
||||
std::string result = "(";
|
||||
for (size_t i = 0; i < signature.parameters.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
result += ", ";
|
||||
const auto& param = signature.parameters[i];
|
||||
|
||||
if (param.is_var)
|
||||
result += "var ";
|
||||
if (param.is_out)
|
||||
result += "out ";
|
||||
|
||||
result += param.name;
|
||||
if (param.type)
|
||||
result += ": " + param.type->name;
|
||||
}
|
||||
result += ")";
|
||||
|
||||
if (signature.return_type)
|
||||
result += ": " + signature.return_type->name;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Builder::ProcessLeftHandSide(const ast::LeftHandSide& lhs, bool is_write)
|
||||
{
|
||||
std::visit([this, is_write](auto& variant) {
|
||||
using T = std::decay_t<decltype(variant)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, std::unique_ptr<ast::Identifier>>)
|
||||
{
|
||||
if (variant)
|
||||
{
|
||||
auto symbol_id = table_.GetScopeManager().FindInScopeChain(current_scope_id_, variant->name);
|
||||
if (symbol_id)
|
||||
table_.AddReference(*symbol_id, variant->span, is_write);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::unique_ptr<ast::AttributeExpression>>)
|
||||
{
|
||||
if (variant)
|
||||
VisitExpression(*variant->object);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::unique_ptr<ast::SubscriptExpression>>)
|
||||
{
|
||||
if (variant)
|
||||
VisitExpression(*variant->value);
|
||||
}
|
||||
},
|
||||
lhs);
|
||||
}
|
||||
|
||||
void Builder::VisitProgram(ast::Program& node)
|
||||
{
|
||||
VisitStatements(node.statements);
|
||||
}
|
||||
|
||||
void Builder::VisitUnitDefinition(ast::UnitDefinition& node)
|
||||
{
|
||||
auto symbol_id = CreateSymbol(node.name, SymbolKind::Module, node);
|
||||
|
||||
EnterScopeWithSymbol(ScopeKind::Unit, symbol_id, node.span);
|
||||
auto prev_parent = current_parent_symbol_id_;
|
||||
current_parent_symbol_id_ = symbol_id;
|
||||
|
||||
VisitStatements(node.interface_statements);
|
||||
VisitStatements(node.implementation_statements);
|
||||
VisitStatements(node.initialization_statements);
|
||||
VisitStatements(node.finalization_statements);
|
||||
|
||||
current_parent_symbol_id_ = prev_parent;
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitClassDefinition(ast::ClassDefinition& node)
|
||||
{
|
||||
auto symbol_id = CreateSymbol(node.name, SymbolKind::Class, node);
|
||||
|
||||
// 处理继承关系
|
||||
for (const auto& parent_class : node.parent_classes)
|
||||
{
|
||||
auto parent_symbols = table_.GetDefinitionStore().FindByName(parent_class.name);
|
||||
for (const auto* parent_def : parent_symbols)
|
||||
{
|
||||
if (parent_def->kind == SymbolKind::Class)
|
||||
table_.GetInheritanceGraph().AddInheritance(symbol_id, parent_def->id);
|
||||
}
|
||||
}
|
||||
|
||||
EnterScopeWithSymbol(ScopeKind::Class, symbol_id, node.span);
|
||||
auto prev_parent = current_parent_symbol_id_;
|
||||
current_parent_symbol_id_ = symbol_id;
|
||||
|
||||
for (const auto& member : node.members)
|
||||
{
|
||||
if (member)
|
||||
member->Accept(*this);
|
||||
}
|
||||
|
||||
current_parent_symbol_id_ = prev_parent;
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitFunctionDefinition(ast::FunctionDefinition& node)
|
||||
{
|
||||
auto symbol_id = CreateSymbol(node.name, SymbolKind::Function, node);
|
||||
|
||||
// 使用新的 Update 接口更新符号信息
|
||||
table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) {
|
||||
def.detail = FormatSignature(node.signature);
|
||||
});
|
||||
|
||||
EnterScopeWithSymbol(ScopeKind::Function, symbol_id, node.span);
|
||||
auto prev_function = current_function_id_;
|
||||
current_function_id_ = symbol_id;
|
||||
|
||||
// 添加参数
|
||||
for (const auto& param : node.signature.parameters)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (param.type)
|
||||
type_hint = param.type->name;
|
||||
CreateSymbol(param.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
current_function_id_ = prev_function;
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitFunctionDeclaration(ast::FunctionDeclaration& node)
|
||||
{
|
||||
auto symbol_id = CreateSymbol(node.name, SymbolKind::Function, node);
|
||||
|
||||
table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) {
|
||||
def.detail = FormatSignature(node.signature);
|
||||
});
|
||||
}
|
||||
|
||||
void Builder::VisitMethodDeclaration(ast::MethodDeclaration& node)
|
||||
{
|
||||
SymbolKind kind = node.method_type == ast::MethodType::kConstructor ? SymbolKind::Constructor : SymbolKind::Method;
|
||||
|
||||
auto symbol_id = CreateSymbol(node.name, kind, node);
|
||||
|
||||
table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) {
|
||||
def.detail = FormatSignature(node.signature);
|
||||
def.method_modifier = node.modifier;
|
||||
});
|
||||
|
||||
EnterScopeWithSymbol(ScopeKind::Function, symbol_id, node.span);
|
||||
auto prev_function = current_function_id_;
|
||||
current_function_id_ = symbol_id;
|
||||
|
||||
for (const auto& param : node.signature.parameters)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (param.type)
|
||||
type_hint = param.type->name;
|
||||
CreateSymbol(param.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
current_function_id_ = prev_function;
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitPropertyDeclaration(ast::PropertyDeclaration& node)
|
||||
{
|
||||
CreateSymbol(node.name, SymbolKind::Property, node, node.type_name);
|
||||
}
|
||||
|
||||
void Builder::VisitExternalMethodDefinition(ast::ExternalMethodDefinition& node)
|
||||
{
|
||||
SymbolKind kind = node.method_type == ast::MethodType::kConstructor ? SymbolKind::Constructor : SymbolKind::Method;
|
||||
|
||||
auto symbol_id = CreateSymbol(node.name, kind, node);
|
||||
|
||||
table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) {
|
||||
def.detail = FormatSignature(node.signature);
|
||||
def.method_modifier = node.modifier;
|
||||
});
|
||||
|
||||
EnterScopeWithSymbol(ScopeKind::Function, symbol_id, node.span);
|
||||
auto prev_function = current_function_id_;
|
||||
current_function_id_ = symbol_id;
|
||||
|
||||
for (const auto& param : node.signature.parameters)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (param.type)
|
||||
type_hint = param.type->name;
|
||||
CreateSymbol(param.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
current_function_id_ = prev_function;
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitClassMember(ast::ClassMember& node)
|
||||
{
|
||||
std::visit([this](auto& member_ptr) {
|
||||
if (member_ptr)
|
||||
member_ptr->Accept(*this);
|
||||
}, node.member);
|
||||
}
|
||||
|
||||
void Builder::VisitVarStatement(ast::VarStatement& node)
|
||||
{
|
||||
for (const auto& decl : node.declarations)
|
||||
{
|
||||
if (decl)
|
||||
decl->Accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitStaticStatement(ast::StaticStatement& node)
|
||||
{
|
||||
for (const auto& decl : node.declarations)
|
||||
{
|
||||
if (decl)
|
||||
decl->Accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitGlobalStatement(ast::GlobalStatement& node)
|
||||
{
|
||||
for (const auto& decl : node.declarations)
|
||||
{
|
||||
if (decl)
|
||||
decl->Accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitConstStatement(ast::ConstStatement& node)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (node.type_name)
|
||||
type_hint = *node.type_name;
|
||||
CreateSymbol(node.name, SymbolKind::Constant, node, type_hint);
|
||||
}
|
||||
|
||||
void Builder::VisitVarDeclaration(ast::VarDeclaration& node)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (node.type)
|
||||
type_hint = node.type->name;
|
||||
CreateSymbol(node.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
void Builder::VisitStaticDeclaration(ast::StaticDeclaration& node)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (node.type)
|
||||
type_hint = node.type->name;
|
||||
CreateSymbol(node.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
void Builder::VisitGlobalDeclaration(ast::GlobalDeclaration& node)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (node.type)
|
||||
type_hint = node.type->name;
|
||||
CreateSymbol(node.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
void Builder::VisitFieldDeclaration(ast::FieldDeclaration& node)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (node.type)
|
||||
type_hint = node.type->name;
|
||||
CreateSymbol(node.name, SymbolKind::Field, node, type_hint);
|
||||
}
|
||||
|
||||
void Builder::VisitBlockStatement(ast::BlockStatement& node)
|
||||
{
|
||||
// 为块创建新作用域
|
||||
EnterScope(ScopeKind::Block, node.span);
|
||||
VisitStatements(node.statements);
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitIfStatement(ast::IfStatement& node)
|
||||
{
|
||||
for (auto& branch : node.branches)
|
||||
{
|
||||
if (branch.condition)
|
||||
VisitExpression(*branch.condition);
|
||||
if (branch.body)
|
||||
branch.body->Accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitForInStatement(ast::ForInStatement& node)
|
||||
{
|
||||
// 为循环创建作用域
|
||||
EnterScope(ScopeKind::Block, node.span);
|
||||
|
||||
CreateSymbol(node.key, SymbolKind::Variable, node);
|
||||
CreateSymbol(node.value, SymbolKind::Variable, node);
|
||||
|
||||
if (node.collection)
|
||||
VisitExpression(*node.collection);
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitForToStatement(ast::ForToStatement& node)
|
||||
{
|
||||
// 为循环创建作用域
|
||||
EnterScope(ScopeKind::Block, node.span);
|
||||
|
||||
CreateSymbol(node.counter, SymbolKind::Variable, node);
|
||||
|
||||
if (node.start)
|
||||
VisitExpression(*node.start);
|
||||
if (node.end)
|
||||
VisitExpression(*node.end);
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitWhileStatement(ast::WhileStatement& node)
|
||||
{
|
||||
if (node.condition)
|
||||
VisitExpression(*node.condition);
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
}
|
||||
|
||||
void Builder::VisitRepeatStatement(ast::RepeatStatement& node)
|
||||
{
|
||||
EnterScope(ScopeKind::Block, node.span);
|
||||
VisitStatements(node.body);
|
||||
|
||||
if (node.condition)
|
||||
VisitExpression(*node.condition);
|
||||
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitCaseStatement(ast::CaseStatement& node)
|
||||
{
|
||||
if (node.discriminant)
|
||||
VisitExpression(*node.discriminant);
|
||||
|
||||
for (auto& branch : node.branches)
|
||||
{
|
||||
for (auto& value : branch.values)
|
||||
{
|
||||
if (value)
|
||||
VisitExpression(*value);
|
||||
}
|
||||
|
||||
if (branch.body)
|
||||
branch.body->Accept(*this);
|
||||
}
|
||||
|
||||
if (node.default_case)
|
||||
node.default_case->Accept(*this);
|
||||
}
|
||||
|
||||
void Builder::VisitTryStatement(ast::TryStatement& node)
|
||||
{
|
||||
if (node.try_body)
|
||||
node.try_body->Accept(*this);
|
||||
|
||||
if (node.except_body)
|
||||
node.except_body->Accept(*this);
|
||||
}
|
||||
|
||||
void Builder::VisitIdentifier(ast::Identifier& node)
|
||||
{
|
||||
auto symbol_id = table_.GetScopeManager().FindInScopeChain(current_scope_id_, node.name);
|
||||
if (symbol_id)
|
||||
table_.AddReference(*symbol_id, node.span, false);
|
||||
}
|
||||
|
||||
void Builder::VisitCallExpression(ast::CallExpression& node)
|
||||
{
|
||||
if (node.callee)
|
||||
{
|
||||
VisitExpression(*node.callee);
|
||||
|
||||
if (auto* ident = dynamic_cast<ast::Identifier*>(node.callee.get()))
|
||||
{
|
||||
auto callee_id = table_.GetScopeManager().FindInScopeChain(current_scope_id_, ident->name);
|
||||
if (callee_id && current_function_id_)
|
||||
table_.GetCallGraph().AddCall(*current_function_id_, *callee_id, node.span);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& arg : node.arguments)
|
||||
{
|
||||
if (arg.value)
|
||||
VisitExpression(*arg.value);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitAttributeExpression(ast::AttributeExpression& node)
|
||||
{
|
||||
if (node.object)
|
||||
VisitExpression(*node.object);
|
||||
}
|
||||
|
||||
void Builder::VisitAssignmentExpression(ast::AssignmentExpression& node)
|
||||
{
|
||||
ProcessLeftHandSide(node.left, true);
|
||||
|
||||
if (node.right)
|
||||
VisitExpression(*node.right);
|
||||
}
|
||||
|
||||
void Builder::VisitAssignmentStatement(ast::AssignmentStatement& node)
|
||||
{
|
||||
ProcessLeftHandSide(node.left, true);
|
||||
|
||||
if (node.right)
|
||||
VisitExpression(*node.right);
|
||||
}
|
||||
|
||||
void Builder::VisitBinaryExpression(ast::BinaryExpression& node)
|
||||
{
|
||||
if (node.left)
|
||||
VisitExpression(*node.left);
|
||||
if (node.right)
|
||||
VisitExpression(*node.right);
|
||||
}
|
||||
|
||||
void Builder::VisitUnaryExpression(ast::UnaryExpression& node)
|
||||
{
|
||||
if (node.argument)
|
||||
VisitExpression(*node.argument);
|
||||
}
|
||||
|
||||
void Builder::VisitTernaryExpression(ast::TernaryExpression& node)
|
||||
{
|
||||
if (node.condition)
|
||||
VisitExpression(*node.condition);
|
||||
if (node.consequence)
|
||||
VisitExpression(*node.consequence);
|
||||
if (node.alternative)
|
||||
VisitExpression(*node.alternative);
|
||||
}
|
||||
|
||||
void Builder::VisitSubscriptExpression(ast::SubscriptExpression& node)
|
||||
{
|
||||
if (node.value)
|
||||
VisitExpression(*node.value);
|
||||
|
||||
for (auto& index : node.indices)
|
||||
{
|
||||
if (index.start)
|
||||
VisitExpression(*index.start);
|
||||
if (index.end)
|
||||
VisitExpression(*index.end);
|
||||
if (index.step)
|
||||
VisitExpression(*index.step);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitArrayExpression(ast::ArrayExpression& node)
|
||||
{
|
||||
for (auto& elem : node.elements)
|
||||
{
|
||||
if (elem.key)
|
||||
VisitExpression(*elem.key);
|
||||
if (elem.value)
|
||||
VisitExpression(*elem.value);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitAnonymousFunctionExpression(ast::AnonymousFunctionExpression& node)
|
||||
{
|
||||
// 为匿名函数创建作用域
|
||||
EnterScope(ScopeKind::Function, node.span);
|
||||
|
||||
for (const auto& param : node.signature.parameters)
|
||||
{
|
||||
std::optional<std::string> type_hint;
|
||||
if (param.type)
|
||||
type_hint = param.type->name;
|
||||
CreateSymbol(param.name, SymbolKind::Variable, node, type_hint);
|
||||
}
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
void Builder::VisitPrefixIncrementExpression(ast::PrefixIncrementExpression& node)
|
||||
{
|
||||
if (node.argument)
|
||||
VisitExpression(*node.argument);
|
||||
}
|
||||
|
||||
void Builder::VisitPrefixDecrementExpression(ast::PrefixDecrementExpression& node)
|
||||
{
|
||||
if (node.argument)
|
||||
VisitExpression(*node.argument);
|
||||
}
|
||||
|
||||
void Builder::VisitPostfixIncrementExpression(ast::PostfixIncrementExpression& node)
|
||||
{
|
||||
if (node.argument)
|
||||
VisitExpression(*node.argument);
|
||||
}
|
||||
|
||||
void Builder::VisitPostfixDecrementExpression(ast::PostfixDecrementExpression& node)
|
||||
{
|
||||
if (node.argument)
|
||||
VisitExpression(*node.argument);
|
||||
}
|
||||
|
||||
void Builder::VisitComparisonExpression(ast::ComparisonExpression& node)
|
||||
{
|
||||
if (node.left)
|
||||
VisitExpression(*node.left);
|
||||
|
||||
for (auto& comp : node.comparisons)
|
||||
{
|
||||
if (comp.right)
|
||||
VisitExpression(*comp.right);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitExpressionStatement(ast::ExpressionStatement& node)
|
||||
{
|
||||
if (node.expression)
|
||||
VisitExpression(*node.expression);
|
||||
}
|
||||
|
||||
void Builder::VisitReturnStatement(ast::ReturnStatement& node)
|
||||
{
|
||||
if (node.value)
|
||||
VisitExpression(*node.value);
|
||||
}
|
||||
|
||||
void Builder::VisitUsesStatement(ast::UsesStatement& node)
|
||||
{
|
||||
// 为每个导入创建一个符号
|
||||
for (const auto& unit_name : node.units)
|
||||
{
|
||||
// 记录导入关系
|
||||
table_.AddUnitImport(unit_name, node.span);
|
||||
|
||||
// 创建一个符号来表示这个导入
|
||||
[[maybe_unused]] SymbolId import_symbol_id = CreateSymbol(
|
||||
unit_name,
|
||||
SymbolKind::Module,
|
||||
node,
|
||||
std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::VisitMatrixIterationStatement(ast::MatrixIterationStatement& node)
|
||||
{
|
||||
// 为矩阵迭代创建作用域
|
||||
EnterScope(ScopeKind::Block, node.span);
|
||||
|
||||
if (node.target)
|
||||
VisitExpression(*node.target);
|
||||
|
||||
if (node.body)
|
||||
node.body->Accept(*this);
|
||||
|
||||
ExitScope();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include "./table.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// 符号表构建器
|
||||
class Builder : public ast::ASTVisitor
|
||||
{
|
||||
public:
|
||||
explicit Builder(SymbolTable& table);
|
||||
|
||||
void Build(ast::ASTNode& root);
|
||||
|
||||
// 访问语句和声明
|
||||
void VisitProgram(ast::Program& node) override;
|
||||
void VisitUnitDefinition(ast::UnitDefinition& node) override;
|
||||
void VisitClassDefinition(ast::ClassDefinition& node) override;
|
||||
void VisitFunctionDefinition(ast::FunctionDefinition& node) override;
|
||||
void VisitFunctionDeclaration(ast::FunctionDeclaration& node) override;
|
||||
void VisitMethodDeclaration(ast::MethodDeclaration& node) override;
|
||||
void VisitPropertyDeclaration(ast::PropertyDeclaration& node) override;
|
||||
void VisitExternalMethodDefinition(ast::ExternalMethodDefinition& node) override;
|
||||
void VisitClassMember(ast::ClassMember& node) override;
|
||||
void VisitVarStatement(ast::VarStatement& node) override;
|
||||
void VisitStaticStatement(ast::StaticStatement& node) override;
|
||||
void VisitGlobalStatement(ast::GlobalStatement& node) override;
|
||||
void VisitConstStatement(ast::ConstStatement& node) override;
|
||||
void VisitVarDeclaration(ast::VarDeclaration& node) override;
|
||||
void VisitStaticDeclaration(ast::StaticDeclaration& node) override;
|
||||
void VisitGlobalDeclaration(ast::GlobalDeclaration& node) override;
|
||||
void VisitFieldDeclaration(ast::FieldDeclaration& node) override;
|
||||
void VisitBlockStatement(ast::BlockStatement& node) override;
|
||||
void VisitIfStatement(ast::IfStatement& node) override;
|
||||
void VisitForInStatement(ast::ForInStatement& node) override;
|
||||
void VisitForToStatement(ast::ForToStatement& node) override;
|
||||
void VisitWhileStatement(ast::WhileStatement& node) override;
|
||||
void VisitRepeatStatement(ast::RepeatStatement& node) override;
|
||||
void VisitCaseStatement(ast::CaseStatement& node) override;
|
||||
void VisitTryStatement(ast::TryStatement& node) override;
|
||||
|
||||
// Uses 语句处理
|
||||
void VisitUsesStatement(ast::UsesStatement& node) override;
|
||||
|
||||
// 访问表达式(收集引用)
|
||||
void VisitIdentifier(ast::Identifier& node) override;
|
||||
void VisitCallExpression(ast::CallExpression& node) override;
|
||||
void VisitAttributeExpression(ast::AttributeExpression& node) override;
|
||||
void VisitAssignmentExpression(ast::AssignmentExpression& node) override;
|
||||
void VisitAssignmentStatement(ast::AssignmentStatement& node) override;
|
||||
|
||||
// 其他节点访问
|
||||
void VisitLiteral(ast::Literal&) override {}
|
||||
void VisitBinaryExpression(ast::BinaryExpression& node) override;
|
||||
void VisitUnaryExpression(ast::UnaryExpression& node) override;
|
||||
void VisitTernaryExpression(ast::TernaryExpression& node) override;
|
||||
void VisitSubscriptExpression(ast::SubscriptExpression& node) override;
|
||||
void VisitArrayExpression(ast::ArrayExpression& node) override;
|
||||
void VisitAnonymousFunctionExpression(ast::AnonymousFunctionExpression& node) override;
|
||||
void VisitPrefixIncrementExpression(ast::PrefixIncrementExpression& node) override;
|
||||
void VisitPrefixDecrementExpression(ast::PrefixDecrementExpression& node) override;
|
||||
void VisitPostfixIncrementExpression(ast::PostfixIncrementExpression& node) override;
|
||||
void VisitPostfixDecrementExpression(ast::PostfixDecrementExpression& node) override;
|
||||
void VisitFunctionPointerExpression(ast::FunctionPointerExpression&) override {}
|
||||
void VisitComparisonExpression(ast::ComparisonExpression& node) override;
|
||||
void VisitExpressionStatement(ast::ExpressionStatement& node) override;
|
||||
void VisitBreakStatement(ast::BreakStatement&) override {}
|
||||
void VisitContinueStatement(ast::ContinueStatement&) override {}
|
||||
void VisitReturnStatement(ast::ReturnStatement& node) override;
|
||||
void VisitTSSQLExpression(ast::TSSQLExpression&) override {}
|
||||
void VisitUnpackPattern(ast::UnpackPattern&) override {}
|
||||
void VisitMatrixIterationStatement(ast::MatrixIterationStatement& node) override;
|
||||
|
||||
private:
|
||||
SymbolId CreateSymbol(const std::string& name, SymbolKind kind, const ast::ASTNode& node, const std::optional<std::string>& type_hint = std::nullopt);
|
||||
ScopeId EnterScopeWithSymbol(ScopeKind kind, SymbolId symbol_id, const ast::Location& range);
|
||||
ScopeId EnterScope(ScopeKind kind, const ast::Location& range);
|
||||
|
||||
void ExitScope();
|
||||
void VisitStatements(const std::vector<ast::StatementPtr>& statements);
|
||||
void VisitExpression(ast::Expression& expr);
|
||||
void ProcessLeftHandSide(const ast::LeftHandSide& lhs, bool is_write);
|
||||
std::string FormatSignature(const ast::Signature& signature);
|
||||
|
||||
private:
|
||||
SymbolTable& table_;
|
||||
ScopeId current_scope_id_;
|
||||
std::optional<SymbolId> current_parent_symbol_id_;
|
||||
std::optional<SymbolId> current_function_id_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
#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());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
#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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
#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());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#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;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,518 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
#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_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
#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));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#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_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
#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_;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#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_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -1,270 +0,0 @@
|
|||
#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>;
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
#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_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
#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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
#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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#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_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
#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_;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,344 +0,0 @@
|
|||
#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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
#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,105 @@
|
|||
#include <algorithm>
|
||||
#include "./location_index.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
void LocationIndex::AddSymbol(SymbolId id, const ast::Location& location)
|
||||
{
|
||||
symbol_entries_.push_back({ location.start_byte,
|
||||
location.end_byte,
|
||||
id });
|
||||
symbols_sorted_ = false;
|
||||
}
|
||||
|
||||
void LocationIndex::AddScope(ScopeId id, const ast::Location& range)
|
||||
{
|
||||
scope_entries_.push_back({ range.start_byte,
|
||||
range.end_byte,
|
||||
id });
|
||||
scopes_sorted_ = false;
|
||||
}
|
||||
|
||||
void LocationIndex::AddReference(SymbolId symbol_id, const ast::Location& location)
|
||||
{
|
||||
reference_entries_.push_back({ location.start_byte,
|
||||
location.end_byte,
|
||||
symbol_id });
|
||||
references_sorted_ = false;
|
||||
}
|
||||
|
||||
std::optional<SymbolId> LocationIndex::FindSymbolAt(const ast::Location& location) const
|
||||
{
|
||||
// 确保索引已排序
|
||||
if (!symbols_sorted_)
|
||||
return std::nullopt;
|
||||
|
||||
return FindInSortedEntries<LocationEntry, SymbolId>(symbol_entries_, location, true);
|
||||
}
|
||||
|
||||
std::optional<ScopeId> LocationIndex::FindScopeAt(const ast::Location& location) const
|
||||
{
|
||||
// 确保索引已排序
|
||||
if (!scopes_sorted_)
|
||||
return std::nullopt;
|
||||
|
||||
return FindInSortedEntries<ScopeEntry, ScopeId>(scope_entries_, location, true);
|
||||
}
|
||||
|
||||
std::optional<SymbolId> LocationIndex::FindReferenceAt(const ast::Location& location) const
|
||||
{
|
||||
// 确保索引已排序
|
||||
if (!references_sorted_)
|
||||
return std::nullopt;
|
||||
|
||||
auto it = std::lower_bound(
|
||||
reference_entries_.begin(),
|
||||
reference_entries_.end(),
|
||||
location.start_byte,
|
||||
[](const ReferenceEntry& entry, uint32_t pos) {
|
||||
return entry.start_byte < pos;
|
||||
});
|
||||
|
||||
if (it != reference_entries_.begin())
|
||||
--it;
|
||||
|
||||
for (; it != reference_entries_.end() && it->start_byte <= location.start_byte; ++it)
|
||||
{
|
||||
if (IsLocationInRange(location, it->start_byte, it->end_byte))
|
||||
return it->symbol_id;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void LocationIndex::RebuildIndex()
|
||||
{
|
||||
if (!symbols_sorted_)
|
||||
{
|
||||
std::sort(symbol_entries_.begin(), symbol_entries_.end());
|
||||
symbols_sorted_ = true;
|
||||
}
|
||||
|
||||
if (!scopes_sorted_)
|
||||
{
|
||||
std::sort(scope_entries_.begin(), scope_entries_.end());
|
||||
scopes_sorted_ = true;
|
||||
}
|
||||
|
||||
if (!references_sorted_)
|
||||
{
|
||||
std::sort(reference_entries_.begin(), reference_entries_.end());
|
||||
references_sorted_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void LocationIndex::Clear()
|
||||
{
|
||||
symbol_entries_.clear();
|
||||
scope_entries_.clear();
|
||||
reference_entries_.clear();
|
||||
symbols_sorted_ = true;
|
||||
scopes_sorted_ = true;
|
||||
references_sorted_ = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include "./types.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
class LocationIndex
|
||||
{
|
||||
public:
|
||||
struct LocationEntry
|
||||
{
|
||||
uint32_t start_byte;
|
||||
uint32_t end_byte;
|
||||
SymbolId symbol_id;
|
||||
|
||||
bool operator<(const LocationEntry& other) const
|
||||
{
|
||||
if (start_byte != other.start_byte)
|
||||
return start_byte < other.start_byte;
|
||||
return end_byte > other.end_byte;
|
||||
}
|
||||
};
|
||||
|
||||
struct ScopeEntry
|
||||
{
|
||||
uint32_t start_byte;
|
||||
uint32_t end_byte;
|
||||
ScopeId scope_id;
|
||||
|
||||
bool operator<(const ScopeEntry& other) const
|
||||
{
|
||||
if (start_byte != other.start_byte)
|
||||
return start_byte < other.start_byte;
|
||||
return end_byte > other.end_byte;
|
||||
}
|
||||
};
|
||||
|
||||
struct ReferenceEntry
|
||||
{
|
||||
uint32_t start_byte;
|
||||
uint32_t end_byte;
|
||||
SymbolId symbol_id;
|
||||
|
||||
bool operator<(const ReferenceEntry& other) const
|
||||
{
|
||||
return start_byte < other.start_byte;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSymbol(SymbolId id, const ast::Location& location);
|
||||
void AddScope(ScopeId id, const ast::Location& range);
|
||||
void AddReference(SymbolId symbol_id, const ast::Location& location);
|
||||
void RebuildIndex();
|
||||
void Clear();
|
||||
|
||||
std::optional<SymbolId> FindSymbolAt(const ast::Location& location) const;
|
||||
std::optional<ScopeId> FindScopeAt(const ast::Location& location) const;
|
||||
std::optional<SymbolId> FindReferenceAt(const ast::Location& location) const;
|
||||
|
||||
private:
|
||||
// 符号定义位置索引(按起始位置排序)
|
||||
std::vector<LocationEntry> symbol_entries_;
|
||||
bool symbols_sorted_ = true;
|
||||
|
||||
// 作用域位置索引(按起始位置排序)
|
||||
std::vector<ScopeEntry> scope_entries_;
|
||||
bool scopes_sorted_ = true;
|
||||
|
||||
// 引用位置索引(位置 -> 符号ID)
|
||||
std::vector<ReferenceEntry> reference_entries_;
|
||||
bool references_sorted_ = true;
|
||||
|
||||
// 辅助方法:在排序数组中查找位置(模板实现放在头文件)
|
||||
template<typename T, typename IdType>
|
||||
std::optional<IdType> FindInSortedEntries(const std::vector<T>& entries, const ast::Location& location, bool find_innermost = true) const
|
||||
{
|
||||
if (entries.empty())
|
||||
return std::nullopt;
|
||||
|
||||
auto it = std::lower_bound(
|
||||
entries.begin(),
|
||||
entries.end(),
|
||||
location.start_byte,
|
||||
[](const T& entry, uint32_t pos) {
|
||||
return entry.start_byte < pos;
|
||||
});
|
||||
|
||||
if (it != entries.begin())
|
||||
--it;
|
||||
|
||||
std::vector<IdType> candidates;
|
||||
for (; it != entries.end() && it->start_byte <= location.start_byte; ++it)
|
||||
{
|
||||
if (IsLocationInRange(location, it->start_byte, it->end_byte))
|
||||
{
|
||||
if constexpr (std::is_same_v<T, LocationEntry> || std::is_same_v<T, ReferenceEntry>)
|
||||
candidates.push_back(it->symbol_id);
|
||||
else if constexpr (std::is_same_v<T, ScopeEntry>)
|
||||
candidates.push_back(it->scope_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.empty())
|
||||
return std::nullopt;
|
||||
|
||||
if (find_innermost)
|
||||
return candidates.back();
|
||||
else
|
||||
return candidates.front();
|
||||
}
|
||||
|
||||
static bool IsLocationInRange(const ast::Location& location, uint32_t start, uint32_t end)
|
||||
{
|
||||
return location.start_byte >= start && location.start_byte < end;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
#include <unordered_set>
|
||||
#include "./relations.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// ===== ReferenceGraph 实现 =====
|
||||
|
||||
void ReferenceGraph::AddReference(SymbolId symbol_id, const ast::Location& location, bool is_definition, bool is_write)
|
||||
{
|
||||
references_[symbol_id].push_back({ location, symbol_id, is_definition, is_write });
|
||||
}
|
||||
|
||||
const std::vector<Reference>* ReferenceGraph::GetReferences(SymbolId symbol_id) const
|
||||
{
|
||||
auto it = references_.find(symbol_id);
|
||||
return it != references_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
std::optional<ast::Location> ReferenceGraph::GetDefinition(SymbolId symbol_id) const
|
||||
{
|
||||
auto it = references_.find(symbol_id);
|
||||
if (it != references_.end())
|
||||
{
|
||||
for (const auto& ref : it->second)
|
||||
{
|
||||
if (ref.is_definition)
|
||||
return ref.location;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void ReferenceGraph::Clear()
|
||||
{
|
||||
references_.clear();
|
||||
}
|
||||
|
||||
// ===== InheritanceGraph 实现 =====
|
||||
|
||||
void InheritanceGraph::AddInheritance(SymbolId derived_class, SymbolId base_class)
|
||||
{
|
||||
base_classes_[derived_class].push_back(base_class);
|
||||
derived_classes_[base_class].push_back(derived_class);
|
||||
}
|
||||
|
||||
const std::vector<SymbolId>* InheritanceGraph::GetBaseClasses(SymbolId class_id) const
|
||||
{
|
||||
auto it = base_classes_.find(class_id);
|
||||
return it != base_classes_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<SymbolId>* InheritanceGraph::GetDerivedClasses(SymbolId class_id) const
|
||||
{
|
||||
auto it = derived_classes_.find(class_id);
|
||||
return it != derived_classes_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
bool InheritanceGraph::IsSubclassOf(SymbolId derived, SymbolId base) const
|
||||
{
|
||||
std::unordered_set<SymbolId> visited;
|
||||
std::vector<SymbolId> queue = { derived };
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
SymbolId current = queue.back();
|
||||
queue.pop_back();
|
||||
|
||||
if (current == base)
|
||||
return true;
|
||||
|
||||
if (visited.count(current))
|
||||
continue;
|
||||
visited.insert(current);
|
||||
|
||||
auto bases = GetBaseClasses(current);
|
||||
if (bases)
|
||||
queue.insert(queue.end(), bases->begin(), bases->end());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InheritanceGraph::Clear()
|
||||
{
|
||||
base_classes_.clear();
|
||||
derived_classes_.clear();
|
||||
}
|
||||
|
||||
// ===== CallGraph 实现 =====
|
||||
|
||||
void CallGraph::AddCall(SymbolId caller, SymbolId callee, const ast::Location& location)
|
||||
{
|
||||
CallRelation rel{ caller, callee, location };
|
||||
callers_[callee].push_back(rel);
|
||||
callees_[caller].push_back(rel);
|
||||
}
|
||||
|
||||
const std::vector<CallRelation>* CallGraph::GetCallers(SymbolId function_id) const
|
||||
{
|
||||
auto it = callers_.find(function_id);
|
||||
return it != callers_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<CallRelation>* CallGraph::GetCallees(SymbolId function_id) const
|
||||
{
|
||||
auto it = callees_.find(function_id);
|
||||
return it != callees_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
void CallGraph::Clear()
|
||||
{
|
||||
callers_.clear();
|
||||
callees_.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "./types.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
// 引用图
|
||||
class ReferenceGraph
|
||||
{
|
||||
public:
|
||||
void AddReference(SymbolId symbol_id, const ast::Location& location, bool is_definition = false, bool is_write = false);
|
||||
void Clear();
|
||||
|
||||
// 返回引用避免拷贝,如果不存在返回 nullptr
|
||||
const std::vector<Reference>* GetReferences(SymbolId symbol_id) const;
|
||||
std::optional<ast::Location> GetDefinition(SymbolId symbol_id) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<SymbolId, std::vector<Reference>> references_;
|
||||
};
|
||||
|
||||
// 继承图
|
||||
class InheritanceGraph
|
||||
{
|
||||
public:
|
||||
void AddInheritance(SymbolId derived_class, SymbolId base_class);
|
||||
void Clear();
|
||||
|
||||
// 返回引用避免拷贝
|
||||
const std::vector<SymbolId>* GetBaseClasses(SymbolId class_id) const;
|
||||
const std::vector<SymbolId>* GetDerivedClasses(SymbolId class_id) const;
|
||||
bool IsSubclassOf(SymbolId derived, SymbolId base) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<SymbolId, std::vector<SymbolId>> base_classes_;
|
||||
std::unordered_map<SymbolId, std::vector<SymbolId>> derived_classes_;
|
||||
};
|
||||
|
||||
// 调用图
|
||||
class CallGraph
|
||||
{
|
||||
public:
|
||||
void AddCall(SymbolId caller, SymbolId callee, const ast::Location& location);
|
||||
void Clear();
|
||||
|
||||
// 返回引用避免拷贝
|
||||
const std::vector<CallRelation>* GetCallers(SymbolId function_id) const;
|
||||
const std::vector<CallRelation>* GetCallees(SymbolId function_id) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<SymbolId, std::vector<CallRelation>> callers_;
|
||||
std::unordered_map<SymbolId, std::vector<CallRelation>> callees_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
#include "./scope.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
ScopeId ScopeManager::CreateScope(ScopeKind kind, const ast::Location& range, std::optional<ScopeId> parent_scope_id, std::optional<SymbolId> associated_symbol_id)
|
||||
{
|
||||
ScopeId new_scope_id = next_scope_id_++;
|
||||
|
||||
ScopeInfo info;
|
||||
info.scope_id = new_scope_id;
|
||||
info.kind = kind;
|
||||
info.range = range;
|
||||
info.parent_scope_id = parent_scope_id;
|
||||
info.associated_symbol_id = associated_symbol_id;
|
||||
|
||||
scopes_[new_scope_id] = std::move(info);
|
||||
|
||||
if (kind == ScopeKind::Global)
|
||||
global_scope_id_ = new_scope_id;
|
||||
|
||||
return new_scope_id;
|
||||
}
|
||||
|
||||
void ScopeManager::AddSymbol(ScopeId scope_id, const std::string& name, SymbolId symbol_id)
|
||||
{
|
||||
auto it = scopes_.find(scope_id);
|
||||
if (it != scopes_.end())
|
||||
it->second.symbols[name] = symbol_id;
|
||||
}
|
||||
|
||||
std::optional<SymbolId> ScopeManager::FindInScope(ScopeId scope_id, const std::string& name) const
|
||||
{
|
||||
auto it = scopes_.find(scope_id);
|
||||
if (it == scopes_.end())
|
||||
return std::nullopt;
|
||||
|
||||
auto sym_it = it->second.symbols.find(name);
|
||||
if (sym_it != it->second.symbols.end())
|
||||
return sym_it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<SymbolId> ScopeManager::FindInScopeChain(ScopeId scope_id, const std::string& name) const
|
||||
{
|
||||
auto current_id = scope_id;
|
||||
|
||||
while (current_id != kInvalidScopeId)
|
||||
{
|
||||
if (auto result = FindInScope(current_id, name))
|
||||
return result;
|
||||
|
||||
auto it = scopes_.find(current_id);
|
||||
if (it == scopes_.end() || !it->second.parent_scope_id)
|
||||
break;
|
||||
|
||||
current_id = *it->second.parent_scope_id;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const ScopeInfo* ScopeManager::GetScopeInfo(ScopeId scope_id) const
|
||||
{
|
||||
auto it = scopes_.find(scope_id);
|
||||
return it != scopes_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
std::vector<SymbolId> ScopeManager::GetSymbolsInScope(ScopeId scope_id) const
|
||||
{
|
||||
std::vector<SymbolId> result;
|
||||
auto it = scopes_.find(scope_id);
|
||||
if (it != scopes_.end())
|
||||
{
|
||||
for (const auto& [name, id] : it->second.symbols)
|
||||
result.push_back(id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ScopeManager::Clear()
|
||||
{
|
||||
scopes_.clear();
|
||||
global_scope_id_ = kInvalidScopeId;
|
||||
next_scope_id_ = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "./types.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
class ScopeManager
|
||||
{
|
||||
public:
|
||||
ScopeId CreateScope(ScopeKind kind, const ast::Location& range, std::optional<ScopeId> parent_scope_id = std::nullopt, std::optional<SymbolId> associated_symbol_id = std::nullopt);
|
||||
|
||||
void AddSymbol(ScopeId scope_id, const std::string& name, SymbolId symbol_id);
|
||||
std::optional<SymbolId> FindInScope(ScopeId scope_id, const std::string& name) const;
|
||||
std::optional<SymbolId> FindInScopeChain(ScopeId scope_id, const std::string& name) const;
|
||||
const ScopeInfo* GetScopeInfo(ScopeId scope_id) const;
|
||||
std::vector<SymbolId> GetSymbolsInScope(ScopeId scope_id) const;
|
||||
ScopeId GetGlobalScope() const { return global_scope_id_; }
|
||||
const std::unordered_map<ScopeId, ScopeInfo>& GetAllScopes() const { return scopes_; }
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
ScopeId next_scope_id_ = 1;
|
||||
ScopeId global_scope_id_ = kInvalidScopeId;
|
||||
std::unordered_map<ScopeId, ScopeInfo> scopes_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
#include <algorithm>
|
||||
#include "./store.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
SymbolId SymbolDefinitionStore::Add(SymbolDefinition def)
|
||||
{
|
||||
def.id = next_id_++;
|
||||
UpdateIndices(def);
|
||||
definitions_[def.id] = std::move(def);
|
||||
return def.id;
|
||||
}
|
||||
|
||||
const SymbolDefinition* SymbolDefinitionStore::Get(SymbolId id) const
|
||||
{
|
||||
auto it = definitions_.find(id);
|
||||
return it != definitions_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
bool SymbolDefinitionStore::Update(SymbolId id, std::function<void(SymbolDefinition&)> updater)
|
||||
{
|
||||
auto it = definitions_.find(id);
|
||||
if (it == definitions_.end())
|
||||
return false;
|
||||
|
||||
RemoveFromIndices(it->second);
|
||||
updater(it->second);
|
||||
UpdateIndices(it->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SymbolDefinitionStore::Remove(SymbolId id)
|
||||
{
|
||||
auto it = definitions_.find(id);
|
||||
if (it == definitions_.end())
|
||||
return false;
|
||||
|
||||
RemoveFromIndices(it->second);
|
||||
definitions_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<const SymbolDefinition*> SymbolDefinitionStore::GetAll() const
|
||||
{
|
||||
std::vector<const SymbolDefinition*> result;
|
||||
result.reserve(definitions_.size());
|
||||
for (const auto& [id, def] : definitions_)
|
||||
result.push_back(&def);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const SymbolDefinition*> SymbolDefinitionStore::FindByName(const std::string& name) const
|
||||
{
|
||||
std::vector<const SymbolDefinition*> result;
|
||||
auto it = name_index_.find(name);
|
||||
if (it != name_index_.end())
|
||||
{
|
||||
for (SymbolId id : it->second)
|
||||
{
|
||||
if (auto def = Get(id))
|
||||
result.push_back(def);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<SymbolId> SymbolDefinitionStore::GetChildren(SymbolId parent_id) const
|
||||
{
|
||||
auto it = children_index_.find(parent_id);
|
||||
return it != children_index_.end() ? it->second : std::vector<SymbolId>{};
|
||||
}
|
||||
|
||||
void SymbolDefinitionStore::Clear()
|
||||
{
|
||||
definitions_.clear();
|
||||
name_index_.clear();
|
||||
children_index_.clear();
|
||||
next_id_ = 1;
|
||||
}
|
||||
|
||||
void SymbolDefinitionStore::UpdateIndices(const SymbolDefinition& def)
|
||||
{
|
||||
name_index_[def.name].push_back(def.id);
|
||||
|
||||
if (def.parent_id)
|
||||
children_index_[*def.parent_id].push_back(def.id);
|
||||
}
|
||||
|
||||
void SymbolDefinitionStore::RemoveFromIndices(const SymbolDefinition& def)
|
||||
{
|
||||
auto& name_vec = name_index_[def.name];
|
||||
name_vec.erase(std::remove(name_vec.begin(), name_vec.end(), def.id), name_vec.end());
|
||||
|
||||
if (def.parent_id)
|
||||
{
|
||||
auto& children_vec = children_index_[*def.parent_id];
|
||||
children_vec.erase(std::remove(children_vec.begin(), children_vec.end(), def.id), children_vec.end());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "./types.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
class SymbolDefinitionStore
|
||||
{
|
||||
public:
|
||||
SymbolId Add(SymbolDefinition def);
|
||||
|
||||
const SymbolDefinition* Get(SymbolId id) const;
|
||||
|
||||
bool Update(SymbolId id, std::function<void(SymbolDefinition&)> updater);
|
||||
bool Remove(SymbolId id);
|
||||
void Clear();
|
||||
|
||||
std::vector<const SymbolDefinition*> GetAll() const;
|
||||
std::vector<const SymbolDefinition*> FindByName(const std::string& name) const;
|
||||
std::vector<SymbolId> GetChildren(SymbolId parent_id) const;
|
||||
|
||||
private:
|
||||
SymbolId next_id_ = 1;
|
||||
std::unordered_map<SymbolId, SymbolDefinition> definitions_;
|
||||
std::unordered_map<std::string, std::vector<SymbolId>, utils::IHasher, utils::IEqualTo> name_index_;
|
||||
std::unordered_map<SymbolId, std::vector<SymbolId>> children_index_;
|
||||
|
||||
void UpdateIndices(const SymbolDefinition& def);
|
||||
void RemoveFromIndices(const SymbolDefinition& def);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
#include <algorithm>
|
||||
#include "./table.hpp"
|
||||
#include "./builder.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
SymbolTable::SymbolTable()
|
||||
{
|
||||
}
|
||||
|
||||
void SymbolTable::Build(ast::ASTNode& root)
|
||||
{
|
||||
Clear();
|
||||
|
||||
Builder builder(*this);
|
||||
builder.Build(root);
|
||||
|
||||
// 构建完成后优化位置索引
|
||||
location_index_.RebuildIndex();
|
||||
}
|
||||
|
||||
void SymbolTable::Clear()
|
||||
{
|
||||
definition_store_.Clear();
|
||||
scope_manager_.Clear();
|
||||
location_index_.Clear();
|
||||
reference_graph_.Clear();
|
||||
inheritance_graph_.Clear();
|
||||
call_graph_.Clear();
|
||||
unit_imports_.clear();
|
||||
import_index_.clear();
|
||||
}
|
||||
|
||||
const SymbolDefinition* SymbolTable::GetDefinition(SymbolId id) const
|
||||
{
|
||||
return definition_store_.Get(id);
|
||||
}
|
||||
|
||||
std::vector<const SymbolDefinition*> SymbolTable::GetAllDefinitions() const
|
||||
{
|
||||
return definition_store_.GetAll();
|
||||
}
|
||||
|
||||
std::vector<const SymbolDefinition*> SymbolTable::FindDefinitionsByName(const std::string& name) const
|
||||
{
|
||||
return definition_store_.FindByName(name);
|
||||
}
|
||||
|
||||
std::optional<SymbolId> SymbolTable::FindSymbolAt(const ast::Location& location) const
|
||||
{
|
||||
return location_index_.FindSymbolAt(location);
|
||||
}
|
||||
|
||||
std::optional<SymbolId> SymbolTable::FindSymbol(const std::string& name, ScopeId scope_id) const
|
||||
{
|
||||
return scope_manager_.FindInScopeChain(scope_id, name);
|
||||
}
|
||||
|
||||
std::vector<SymbolId> SymbolTable::FindSymbolsByName(const std::string& name) const
|
||||
{
|
||||
std::vector<SymbolId> result;
|
||||
auto defs = definition_store_.FindByName(name);
|
||||
for (const auto* def : defs)
|
||||
result.push_back(def->id);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<ScopeId> SymbolTable::FindScopeAt(const ast::Location& location) const
|
||||
{
|
||||
return location_index_.FindScopeAt(location);
|
||||
}
|
||||
|
||||
std::optional<SymbolId> SymbolTable::FindReferenceAt(const ast::Location& location) const
|
||||
{
|
||||
return location_index_.FindReferenceAt(location);
|
||||
}
|
||||
|
||||
std::vector<SymbolId> SymbolTable::GetChildren(SymbolId symbol_id) const
|
||||
{
|
||||
return definition_store_.GetChildren(symbol_id);
|
||||
}
|
||||
|
||||
ScopeId SymbolTable::GetGlobalScope() const
|
||||
{
|
||||
return scope_manager_.GetGlobalScope();
|
||||
}
|
||||
|
||||
const std::vector<Reference>* SymbolTable::GetReferences(SymbolId symbol_id) const
|
||||
{
|
||||
return reference_graph_.GetReferences(symbol_id);
|
||||
}
|
||||
|
||||
std::optional<ast::Location> SymbolTable::GetDefinitionLocation(SymbolId symbol_id) const
|
||||
{
|
||||
return reference_graph_.GetDefinition(symbol_id);
|
||||
}
|
||||
|
||||
const std::vector<SymbolId>* SymbolTable::GetBaseClasses(SymbolId class_id) const
|
||||
{
|
||||
return inheritance_graph_.GetBaseClasses(class_id);
|
||||
}
|
||||
|
||||
const std::vector<SymbolId>* SymbolTable::GetDerivedClasses(SymbolId class_id) const
|
||||
{
|
||||
return inheritance_graph_.GetDerivedClasses(class_id);
|
||||
}
|
||||
|
||||
const std::vector<CallRelation>* SymbolTable::GetCallers(SymbolId function_id) const
|
||||
{
|
||||
return call_graph_.GetCallers(function_id);
|
||||
}
|
||||
|
||||
const std::vector<CallRelation>* SymbolTable::GetCallees(SymbolId function_id) const
|
||||
{
|
||||
return call_graph_.GetCallees(function_id);
|
||||
}
|
||||
|
||||
// ===== Unit 导入管理实现 =====
|
||||
|
||||
void SymbolTable::AddUnitImport(const std::string& unit_name, const ast::Location& location)
|
||||
{
|
||||
// 检查是否已经导入过(避免重复)
|
||||
if (import_index_.find(unit_name) != import_index_.end())
|
||||
{
|
||||
// 已经存在,可以选择:
|
||||
// 1. 忽略重复导入
|
||||
// 2. 记录多次导入(用于诊断)
|
||||
// 这里选择忽略
|
||||
return;
|
||||
}
|
||||
|
||||
size_t index = unit_imports_.size();
|
||||
unit_imports_.push_back(UnitImport{ unit_name, location });
|
||||
import_index_[unit_name] = index;
|
||||
}
|
||||
|
||||
const std::vector<UnitImport>& SymbolTable::GetUnitImports() const
|
||||
{
|
||||
return unit_imports_;
|
||||
}
|
||||
|
||||
std::optional<ast::Location> SymbolTable::FindImportLocation(const std::string& unit_name) const
|
||||
{
|
||||
auto it = import_index_.find(unit_name);
|
||||
if (it != import_index_.end() && it->second < unit_imports_.size())
|
||||
{
|
||||
return unit_imports_[it->second].location;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool SymbolTable::HasImport(const std::string& unit_name) const
|
||||
{
|
||||
return import_index_.find(unit_name) != import_index_.end();
|
||||
}
|
||||
|
||||
// ===== LSP 接口实现 =====
|
||||
|
||||
std::vector<const SymbolDefinition*> SymbolTable::GetDocumentSymbols() const
|
||||
{
|
||||
std::vector<const SymbolDefinition*> result;
|
||||
|
||||
for (const auto* def : definition_store_.GetAll())
|
||||
{
|
||||
// 只返回顶层符号(没有父符号的符号)
|
||||
if (!def->parent_id)
|
||||
result.push_back(def);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const SymbolDefinition*> SymbolTable::GetWorkspaceSymbols(const std::string& query) const
|
||||
{
|
||||
if (query.empty())
|
||||
return definition_store_.GetAll();
|
||||
|
||||
// 使用小写查询字符串进行大小写无关的匹配
|
||||
std::string lower_query = utils::ToLower(query);
|
||||
|
||||
std::vector<const SymbolDefinition*> result;
|
||||
for (const auto* def : definition_store_.GetAll())
|
||||
{
|
||||
std::string lower_name = utils::ToLower(def->name);
|
||||
if (lower_name.find(lower_query) != std::string::npos)
|
||||
result.push_back(def);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===== Builder 专用内部接口实现 =====
|
||||
|
||||
SymbolId SymbolTable::CreateSymbol(
|
||||
const std::string& name,
|
||||
SymbolKind kind,
|
||||
const ast::Location& location,
|
||||
ScopeId scope_id,
|
||||
std::optional<SymbolId> parent_id,
|
||||
const std::optional<std::string>& type_hint)
|
||||
{
|
||||
// 创建符号定义
|
||||
SymbolDefinition def;
|
||||
def.name = name;
|
||||
def.kind = kind;
|
||||
def.location = location;
|
||||
def.selection_range = location;
|
||||
def.type_hint = type_hint;
|
||||
def.parent_id = parent_id;
|
||||
|
||||
SymbolId symbol_id = definition_store_.Add(std::move(def));
|
||||
|
||||
// 统一处理所有索引更新
|
||||
scope_manager_.AddSymbol(scope_id, name, symbol_id);
|
||||
location_index_.AddSymbol(symbol_id, location);
|
||||
|
||||
// 添加定义引用
|
||||
reference_graph_.AddReference(symbol_id, location, true, false);
|
||||
location_index_.AddReference(symbol_id, location);
|
||||
|
||||
return symbol_id;
|
||||
}
|
||||
|
||||
ScopeId SymbolTable::CreateScope(ScopeKind kind, const ast::Location& range, std::optional<ScopeId> parent_scope_id, std::optional<SymbolId> associated_symbol_id)
|
||||
{
|
||||
ScopeId scope_id = scope_manager_.CreateScope(kind, range, parent_scope_id, associated_symbol_id);
|
||||
|
||||
// 添加到位置索引
|
||||
location_index_.AddScope(scope_id, range);
|
||||
|
||||
return scope_id;
|
||||
}
|
||||
|
||||
void SymbolTable::AddReference(SymbolId symbol_id, const ast::Location& location, bool is_write)
|
||||
{
|
||||
reference_graph_.AddReference(symbol_id, location, false, is_write);
|
||||
location_index_.AddReference(symbol_id, location);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
|
||||
#include "./store.hpp"
|
||||
#include "./scope.hpp"
|
||||
#include "./location_index.hpp"
|
||||
#include "./relations.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
class Builder;
|
||||
|
||||
// 统一的符号表接口
|
||||
class SymbolTable
|
||||
{
|
||||
public:
|
||||
SymbolTable();
|
||||
|
||||
// 构建符号表(完整构建)
|
||||
void Build(ast::ASTNode& root);
|
||||
|
||||
// 清空所有数据
|
||||
void Clear();
|
||||
|
||||
// ===== 第一层: 定义访问 =====
|
||||
const SymbolDefinition* GetDefinition(SymbolId id) const;
|
||||
std::vector<const SymbolDefinition*> GetAllDefinitions() const;
|
||||
std::vector<const SymbolDefinition*> FindDefinitionsByName(const std::string& name) const;
|
||||
|
||||
// ===== 第二层: 作用域和位置查询 =====
|
||||
// 名称查找
|
||||
std::optional<SymbolId> FindSymbol(const std::string& name, ScopeId scope_id) const;
|
||||
std::vector<SymbolId> FindSymbolsByName(const std::string& name) const;
|
||||
|
||||
// 位置查找
|
||||
std::optional<SymbolId> FindSymbolAt(const ast::Location& location) const;
|
||||
std::optional<ScopeId> FindScopeAt(const ast::Location& location) const;
|
||||
std::optional<SymbolId> FindReferenceAt(const ast::Location& location) const;
|
||||
|
||||
// 作用域查询
|
||||
std::vector<SymbolId> GetChildren(SymbolId symbol_id) const;
|
||||
ScopeId GetGlobalScope() const;
|
||||
|
||||
// ===== 第三层: 关系访问 =====
|
||||
// 返回引用避免拷贝,使用指针表示可能为空
|
||||
const std::vector<Reference>* GetReferences(SymbolId symbol_id) const;
|
||||
std::optional<ast::Location> GetDefinitionLocation(SymbolId symbol_id) const;
|
||||
const std::vector<SymbolId>* GetBaseClasses(SymbolId class_id) const;
|
||||
const std::vector<SymbolId>* GetDerivedClasses(SymbolId class_id) const;
|
||||
const std::vector<CallRelation>* GetCallers(SymbolId function_id) const;
|
||||
const std::vector<CallRelation>* GetCallees(SymbolId function_id) const;
|
||||
|
||||
// ===== Unit 导入管理 =====
|
||||
// 添加单元导入
|
||||
void AddUnitImport(const std::string& unit_name, const ast::Location& location);
|
||||
|
||||
// 获取所有导入的单元
|
||||
const std::vector<UnitImport>& GetUnitImports() const;
|
||||
|
||||
// 查找特定单元的导入位置(用于跳转到定义)
|
||||
std::optional<ast::Location> FindImportLocation(const std::string& unit_name) const;
|
||||
|
||||
// 检查是否导入了某个单元
|
||||
bool HasImport(const std::string& unit_name) const;
|
||||
|
||||
// ===== LSP 便捷接口 =====
|
||||
// 获取文档符号(用于 textDocument/documentSymbol)
|
||||
std::vector<const SymbolDefinition*> GetDocumentSymbols() const;
|
||||
|
||||
// 获取工作区符号(用于 workspace/symbol)
|
||||
std::vector<const SymbolDefinition*> GetWorkspaceSymbols(const std::string& query = "") const;
|
||||
|
||||
// ===== Builder 专用内部接口 =====
|
||||
// 统一的符号创建接口,自动处理所有索引更新
|
||||
SymbolId CreateSymbol(
|
||||
const std::string& name,
|
||||
SymbolKind kind,
|
||||
const ast::Location& location,
|
||||
ScopeId scope_id,
|
||||
std::optional<SymbolId> parent_id = std::nullopt,
|
||||
const std::optional<std::string>& type_hint = std::nullopt);
|
||||
|
||||
// 创建作用域(可以选择关联符号)
|
||||
ScopeId CreateScope(
|
||||
ScopeKind kind,
|
||||
const ast::Location& range,
|
||||
std::optional<ScopeId> parent_scope_id = std::nullopt,
|
||||
std::optional<SymbolId> associated_symbol_id = std::nullopt);
|
||||
|
||||
// 添加引用
|
||||
void AddReference(SymbolId symbol_id, const ast::Location& location, bool is_write = false);
|
||||
|
||||
// 获取内部组件的访问权限(供 Builder 使用)
|
||||
SymbolDefinitionStore& GetDefinitionStore() { return definition_store_; }
|
||||
ScopeManager& GetScopeManager() { return scope_manager_; }
|
||||
LocationIndex& GetLocationIndex() { return location_index_; }
|
||||
ReferenceGraph& GetReferenceGraph() { return reference_graph_; }
|
||||
InheritanceGraph& GetInheritanceGraph() { return inheritance_graph_; }
|
||||
CallGraph& GetCallGraph() { return call_graph_; }
|
||||
|
||||
const SymbolDefinitionStore& GetDefinitionStore() const { return definition_store_; }
|
||||
const ScopeManager& GetScopeManager() const { return scope_manager_; }
|
||||
const LocationIndex& GetLocationIndex() const { return location_index_; }
|
||||
const ReferenceGraph& GetReferenceGraph() const { return reference_graph_; }
|
||||
const InheritanceGraph& GetInheritanceGraph() const { return inheritance_graph_; }
|
||||
const CallGraph& GetCallGraph() const { return call_graph_; }
|
||||
|
||||
private:
|
||||
// 第一层
|
||||
SymbolDefinitionStore definition_store_;
|
||||
|
||||
// 第二层
|
||||
ScopeManager scope_manager_;
|
||||
LocationIndex location_index_;
|
||||
|
||||
// 第三层
|
||||
ReferenceGraph reference_graph_;
|
||||
InheritanceGraph inheritance_graph_;
|
||||
CallGraph call_graph_;
|
||||
|
||||
// Unit 导入
|
||||
std::vector<UnitImport> unit_imports_;
|
||||
// 快速查找: unit_name -> index in unit_imports_
|
||||
std::unordered_map<std::string, size_t, utils::IHasher, utils::IEqualTo> import_index_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include "../ast/types.hpp"
|
||||
#include "../../utils/string.hpp"
|
||||
|
||||
namespace lsp::language::symbol
|
||||
{
|
||||
enum class SymbolKind
|
||||
{
|
||||
File = 1,
|
||||
Module = 2,
|
||||
Namespace = 3,
|
||||
Package = 4,
|
||||
Class = 5,
|
||||
Method = 6,
|
||||
Property = 7,
|
||||
Field = 8,
|
||||
Constructor = 9,
|
||||
Enum = 10,
|
||||
Interface = 11,
|
||||
Function = 12,
|
||||
Variable = 13,
|
||||
Constant = 14,
|
||||
String = 15,
|
||||
Number = 16,
|
||||
Boolean = 17,
|
||||
Array = 18,
|
||||
Object = 19,
|
||||
Key = 20,
|
||||
Null = 21,
|
||||
EnumMember = 22,
|
||||
Struct = 23,
|
||||
Event = 24,
|
||||
Operator = 25,
|
||||
TypeParameter = 26
|
||||
};
|
||||
|
||||
enum class ScopeKind
|
||||
{
|
||||
Global,
|
||||
Unit,
|
||||
Class,
|
||||
Function,
|
||||
Block
|
||||
};
|
||||
|
||||
// 符号ID类型
|
||||
using SymbolId = uint64_t;
|
||||
constexpr SymbolId kInvalidSymbolId = 0;
|
||||
|
||||
using ScopeId = uint64_t;
|
||||
constexpr ScopeId kInvalidScopeId = 0;
|
||||
|
||||
struct UnitImport
|
||||
{
|
||||
std::string unit_name;
|
||||
ast::Location location;
|
||||
};
|
||||
|
||||
struct SymbolDefinition
|
||||
{
|
||||
SymbolId id = kInvalidSymbolId;
|
||||
std::string name;
|
||||
SymbolKind kind;
|
||||
ast::Location location;
|
||||
ast::Location selection_range;
|
||||
|
||||
std::optional<std::string> type_hint;
|
||||
|
||||
std::string detail;
|
||||
|
||||
std::optional<ast::AccessModifier> access_modifier;
|
||||
std::optional<ast::MethodModifier> method_modifier;
|
||||
std::optional<ast::ReferenceModifier> reference_modifier;
|
||||
|
||||
std::optional<SymbolId> parent_id;
|
||||
};
|
||||
|
||||
struct ScopeInfo
|
||||
{
|
||||
ScopeId scope_id;
|
||||
ScopeKind kind;
|
||||
ast::Location range;
|
||||
std::optional<ScopeId> parent_scope_id;
|
||||
std::optional<SymbolId> associated_symbol_id;
|
||||
std::unordered_map<std::string, SymbolId, utils::IHasher, utils::IEqualTo> symbols;
|
||||
};
|
||||
|
||||
struct Reference
|
||||
{
|
||||
ast::Location location;
|
||||
SymbolId symbol_id;
|
||||
bool is_definition;
|
||||
bool is_write;
|
||||
};
|
||||
|
||||
struct CallRelation
|
||||
{
|
||||
SymbolId caller;
|
||||
SymbolId callee;
|
||||
ast::Location call_location;
|
||||
};
|
||||
|
||||
} // namespace lsp::language::symbol
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#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);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
cmake_minimum_required(VERSION 4.0)
|
||||
|
||||
project(test_symbol)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
|
||||
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if (DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
message(STATUS ">>> CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
|
||||
endif()
|
||||
if (DEFINED VCPKG_TARGET_TRIPLET)
|
||||
message(STATUS ">>> VCPKG_TARGET_TRIPLET: ${VCPKG_TARGET_TRIPLET}")
|
||||
endif()
|
||||
|
||||
# 设置默认构建类型
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE
|
||||
"Release"
|
||||
CACHE STRING "Build type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
|
||||
"MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# MinGW/MSYS2 静态链接
|
||||
if(MINGW)
|
||||
add_link_options(-static -static-libgcc -static-libstdc++)
|
||||
elseif(UNIX AND NOT APPLE) # Linux 静态链接
|
||||
add_link_options(-static-libgcc -static-libstdc++)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib" ".dll.a")
|
||||
else()
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
|
||||
endif()
|
||||
|
||||
find_package(glaze CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(Taskflow REQUIRED)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
find_package(unofficial-tree-sitter CONFIG REQUIRED)
|
||||
set(TREESITTER_TARGET unofficial::tree-sitter::tree-sitter)
|
||||
else()
|
||||
# find_package(PkgConfig REQUIRED)
|
||||
# pkg_check_modules(TREESITTER tree-sitter)
|
||||
find_library(TREESITTER_LIBRARY tree-sitter) # use ${TREESITTER_LIBRARY}
|
||||
set(TREESITTER_TARGET ${TREESITTER_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(NOT TARGET spdlog::spdlog_header_only)
|
||||
message(WARNING "spdlog header-only target not found, using shared library")
|
||||
endif()
|
||||
if(NOT TARGET fmt::fmt-header-only)
|
||||
message(WARNING "fmt header-only target not found, using shared library")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(SOURCES
|
||||
./test.cpp
|
||||
./debug_printer.cpp
|
||||
../../src/language/ast/deserializer.cpp
|
||||
../../src/language/ast/detail.cpp
|
||||
../../src/language/ast/tree_sitter_utils.cpp
|
||||
../../src/language/symbol/builder.cpp
|
||||
../../src/language/symbol/location_index.cpp
|
||||
../../src/language/symbol/relations.cpp
|
||||
../../src/language/symbol/store.cpp
|
||||
../../src/language/symbol/scope.cpp
|
||||
../../src/language/symbol/table.cpp
|
||||
../../src/language/symbol/builder.cpp
|
||||
../../src/utils/string.cpp
|
||||
../../src/tree-sitter/parser.c)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE src)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SPDLOG_HEADER_ONLY
|
||||
FMT_HEADER_ONLY)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
glaze::glaze
|
||||
Taskflow::Taskflow
|
||||
spdlog::spdlog_header_only
|
||||
fmt::fmt-header-only
|
||||
${TREESITTER_TARGET} # 使用变量,避免条件判断
|
||||
$<$<PLATFORM_ID:Linux>:Threads::Threads> # 使用生成器表达式
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
-Wall -Wextra -Wpedantic
|
||||
$<$<CONFIG:Debug>:-g -O0>
|
||||
$<$<CONFIG:Release>:-O3>
|
||||
)
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,165 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "../../src/language/symbol/table.hpp"
|
||||
|
||||
namespace lsp::language::symbol::debug
|
||||
{
|
||||
// ==================== 颜色和样式 ====================
|
||||
|
||||
namespace Color
|
||||
{
|
||||
// ANSI 颜色码
|
||||
constexpr const char* Reset = "\033[0m";
|
||||
constexpr const char* Bold = "\033[1m";
|
||||
constexpr const char* Dim = "\033[2m";
|
||||
|
||||
// 前景色
|
||||
constexpr const char* Black = "\033[30m";
|
||||
constexpr const char* Red = "\033[31m";
|
||||
constexpr const char* Green = "\033[32m";
|
||||
constexpr const char* Yellow = "\033[33m";
|
||||
constexpr const char* Blue = "\033[34m";
|
||||
constexpr const char* Magenta = "\033[35m";
|
||||
constexpr const char* Cyan = "\033[36m";
|
||||
constexpr const char* White = "\033[37m";
|
||||
|
||||
// 亮色
|
||||
constexpr const char* BrightBlack = "\033[90m";
|
||||
constexpr const char* BrightRed = "\033[91m";
|
||||
constexpr const char* BrightGreen = "\033[92m";
|
||||
constexpr const char* BrightYellow = "\033[93m";
|
||||
constexpr const char* BrightBlue = "\033[94m";
|
||||
constexpr const char* BrightMagenta = "\033[95m";
|
||||
constexpr const char* BrightCyan = "\033[96m";
|
||||
constexpr const char* BrightWhite = "\033[97m";
|
||||
}
|
||||
|
||||
// ==================== 打印选项 ====================
|
||||
|
||||
struct PrintOptions
|
||||
{
|
||||
bool use_color = true; // 使用颜色
|
||||
bool show_location = true; // 显示位置信息
|
||||
bool show_details = true; // 显示详细信息
|
||||
bool show_children = true; // 显示子符号
|
||||
bool show_references = false; // 显示引用列表
|
||||
bool compact_mode = false; // 紧凑模式
|
||||
int indent_size = 2; // 缩进大小
|
||||
int max_depth = -1; // 最大深度 (-1 = 无限制)
|
||||
|
||||
static PrintOptions Default();
|
||||
static PrintOptions Compact();
|
||||
static PrintOptions Verbose();
|
||||
static PrintOptions NoColor();
|
||||
};
|
||||
|
||||
// ==================== 统计信息 ====================
|
||||
|
||||
struct Statistics
|
||||
{
|
||||
size_t total_symbols = 0;
|
||||
size_t total_scopes = 0;
|
||||
size_t total_references = 0;
|
||||
|
||||
std::unordered_map<SymbolKind, size_t> symbol_counts;
|
||||
std::unordered_map<ScopeKind, size_t> scope_counts;
|
||||
|
||||
size_t symbols_with_refs = 0;
|
||||
size_t max_references = 0;
|
||||
SymbolId most_referenced = kInvalidSymbolId;
|
||||
|
||||
void Compute(const SymbolTable& table);
|
||||
void Print(std::ostream& os, bool use_color = true) const;
|
||||
};
|
||||
|
||||
// ==================== 核心打印器 ====================
|
||||
|
||||
class DebugPrinter
|
||||
{
|
||||
public:
|
||||
explicit DebugPrinter(const SymbolTable& table, const PrintOptions& options = PrintOptions::Default());
|
||||
|
||||
// ===== 顶层打印接口 =====
|
||||
void PrintAll(std::ostream& os = std::cout);
|
||||
void PrintOverview(std::ostream& os = std::cout);
|
||||
void PrintStatistics(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 符号打印 =====
|
||||
void PrintSymbol(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolTree(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolList(std::ostream& os = std::cout);
|
||||
void PrintSymbolsByKind(SymbolKind kind, std::ostream& os = std::cout);
|
||||
|
||||
// ===== 作用域打印 =====
|
||||
void PrintScope(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeTree(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeHierarchy(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 关系打印 =====
|
||||
void PrintReferences(SymbolId id, std::ostream& os = std::cout);
|
||||
void PrintInheritance(SymbolId class_id, std::ostream& os = std::cout);
|
||||
void PrintCallGraph(SymbolId function_id, std::ostream& os = std::cout);
|
||||
void PrintAllReferences(std::ostream& os = std::cout);
|
||||
void PrintAllInheritance(std::ostream& os = std::cout);
|
||||
void PrintAllCalls(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 搜索和查询 =====
|
||||
void FindAndPrint(const std::string& name, std::ostream& os = std::cout);
|
||||
void FindAtLocation(const ast::Location& loc, std::ostream& os = std::cout);
|
||||
|
||||
// ===== 选项管理 =====
|
||||
void SetOptions(const PrintOptions& options) { options_ = options; }
|
||||
const PrintOptions& GetOptions() const { return options_; }
|
||||
|
||||
private:
|
||||
const SymbolTable& table_;
|
||||
PrintOptions options_;
|
||||
Statistics stats_;
|
||||
|
||||
// ===== 辅助方法 =====
|
||||
std::string Indent(int depth) const;
|
||||
std::string ColorizeSymbolKind(SymbolKind kind) const;
|
||||
std::string ColorizeSymbolName(const std::string& name, SymbolKind kind) const;
|
||||
std::string FormatLocation(const ast::Location& loc) const;
|
||||
std::string FormatSymbolKind(SymbolKind kind) const;
|
||||
std::string FormatScopeKind(ScopeKind kind) const;
|
||||
std::string SymbolIcon(SymbolKind kind) const;
|
||||
|
||||
void PrintSeparator(std::ostream& os, char ch = '=', int width = 80) const;
|
||||
void PrintHeader(const std::string& title, std::ostream& os) const;
|
||||
void PrintSubHeader(const std::string& title, std::ostream& os) const;
|
||||
|
||||
std::string Color(const char* color_code) const;
|
||||
std::string Bold(const std::string& text) const;
|
||||
std::string Dim(const std::string& text) const;
|
||||
};
|
||||
|
||||
// ==================== 快速打印函数 ====================
|
||||
|
||||
// 打印所有内容(带统计)
|
||||
void Print(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印概览
|
||||
void PrintOverview(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印统计信息
|
||||
void PrintStats(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印符号树
|
||||
void PrintSymbolTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印作用域树
|
||||
void PrintScopeTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 搜索并打印
|
||||
void Find(const SymbolTable& table, const std::string& name, std::ostream& os = std::cout);
|
||||
|
||||
// 紧凑打印
|
||||
void PrintCompact(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 详细打印
|
||||
void PrintVerbose(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
} // namespace lsp::language::symbol::debug
|
||||
|
|
@ -0,0 +1,557 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
|
||||
extern "C" const TSLanguage* tree_sitter_tsf(void);
|
||||
|
||||
#include "../../src/language/ast/deserializer.hpp"
|
||||
#include "../../src/language/symbol/table.hpp"
|
||||
#include "./debug_printer.hpp"
|
||||
|
||||
using namespace lsp::language;
|
||||
|
||||
// ==================== 文件读取 ====================
|
||||
|
||||
std::string ReadFile(const std::string& filepath)
|
||||
{
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open())
|
||||
{
|
||||
throw std::runtime_error("Cannot open file: " + filepath);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << file.rdbuf();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ==================== Tree-Sitter 解析器 ====================
|
||||
|
||||
class TreeSitterParser
|
||||
{
|
||||
public:
|
||||
TreeSitterParser()
|
||||
{
|
||||
parser_ = ts_parser_new();
|
||||
if (!parser_)
|
||||
{
|
||||
throw std::runtime_error("Failed to create parser");
|
||||
}
|
||||
|
||||
if (!ts_parser_set_language(parser_, tree_sitter_tsf()))
|
||||
{
|
||||
ts_parser_delete(parser_);
|
||||
throw std::runtime_error("Failed to set language");
|
||||
}
|
||||
}
|
||||
|
||||
~TreeSitterParser()
|
||||
{
|
||||
if (tree_)
|
||||
{
|
||||
ts_tree_delete(tree_);
|
||||
}
|
||||
if (parser_)
|
||||
{
|
||||
ts_parser_delete(parser_);
|
||||
}
|
||||
}
|
||||
|
||||
TSTree* Parse(const std::string& source)
|
||||
{
|
||||
if (tree_)
|
||||
{
|
||||
ts_tree_delete(tree_);
|
||||
tree_ = nullptr;
|
||||
}
|
||||
|
||||
tree_ = ts_parser_parse_string(
|
||||
parser_,
|
||||
nullptr,
|
||||
source.c_str(),
|
||||
source.length());
|
||||
|
||||
if (!tree_)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse source");
|
||||
}
|
||||
|
||||
return tree_;
|
||||
}
|
||||
|
||||
TSNode GetRootNode()
|
||||
{
|
||||
if (!tree_)
|
||||
{
|
||||
throw std::runtime_error("No tree available");
|
||||
}
|
||||
return ts_tree_root_node(tree_);
|
||||
}
|
||||
|
||||
private:
|
||||
TSParser* parser_ = nullptr;
|
||||
TSTree* tree_ = nullptr;
|
||||
};
|
||||
|
||||
// ==================== 命令行选项 ====================
|
||||
|
||||
struct Options
|
||||
{
|
||||
std::string input_file;
|
||||
std::string output_file;
|
||||
bool print_all = true;
|
||||
bool print_definitions = false;
|
||||
bool print_scopes = false;
|
||||
bool print_references = false;
|
||||
bool print_inheritance = false;
|
||||
bool print_calls = false;
|
||||
bool compact_mode = false;
|
||||
bool statistics_only = false;
|
||||
std::string search_symbol;
|
||||
bool verbose = false;
|
||||
bool show_ast = false;
|
||||
bool no_color = false;
|
||||
bool print_overview = false;
|
||||
};
|
||||
|
||||
void PrintUsage(const char* program_name)
|
||||
{
|
||||
std::cout << "Symbol Table Analyzer - Analyze source code symbols\n\n";
|
||||
std::cout << "Usage: " << program_name << " <input_file> [options]\n\n";
|
||||
std::cout << "Options:\n";
|
||||
std::cout << " -o, --output <file> Write output to file instead of stdout\n";
|
||||
std::cout << " -d, --definitions Print only symbol definitions\n";
|
||||
std::cout << " -s, --scopes Print only scope hierarchy\n";
|
||||
std::cout << " -r, --references Print only references\n";
|
||||
std::cout << " -i, --inheritance Print only inheritance graph\n";
|
||||
std::cout << " -c, --calls Print only call graph\n";
|
||||
std::cout << " -C, --compact Use compact output format\n";
|
||||
std::cout << " -S, --stats Print statistics only\n";
|
||||
std::cout << " -O, --overview Print overview only\n";
|
||||
std::cout << " -f, --find <name> Search for a specific symbol\n";
|
||||
std::cout << " -v, --verbose Enable verbose output\n";
|
||||
std::cout << " -a, --ast Show AST structure\n";
|
||||
std::cout << " --no-color Disable colored output\n";
|
||||
std::cout << " -h, --help Show this help message\n\n";
|
||||
std::cout << "Examples:\n";
|
||||
std::cout << " " << program_name << " program.tsf\n";
|
||||
std::cout << " " << program_name << " program.tsf -o symbols.txt\n";
|
||||
std::cout << " " << program_name << " program.tsf --definitions --scopes\n";
|
||||
std::cout << " " << program_name << " program.tsf --find MyClass\n";
|
||||
std::cout << " " << program_name << " program.tsf --compact --stats\n";
|
||||
std::cout << " " << program_name << " program.tsf --overview\n";
|
||||
}
|
||||
|
||||
bool ParseArguments(int argc, char* argv[], Options& options)
|
||||
{
|
||||
if (argc < 2)
|
||||
return false;
|
||||
|
||||
options.input_file = argv[1];
|
||||
bool any_specific_print = false;
|
||||
|
||||
for (int i = 2; i < argc; ++i)
|
||||
{
|
||||
std::string arg = argv[i];
|
||||
|
||||
if (arg == "-h" || arg == "--help")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (arg == "-o" || arg == "--output")
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
options.output_file = argv[++i];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: " << arg << " requires an argument\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (arg == "-d" || arg == "--definitions")
|
||||
{
|
||||
options.print_definitions = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-s" || arg == "--scopes")
|
||||
{
|
||||
options.print_scopes = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-r" || arg == "--references")
|
||||
{
|
||||
options.print_references = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-i" || arg == "--inheritance")
|
||||
{
|
||||
options.print_inheritance = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-c" || arg == "--calls")
|
||||
{
|
||||
options.print_calls = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-C" || arg == "--compact")
|
||||
{
|
||||
options.compact_mode = true;
|
||||
}
|
||||
else if (arg == "-S" || arg == "--stats")
|
||||
{
|
||||
options.statistics_only = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-O" || arg == "--overview")
|
||||
{
|
||||
options.print_overview = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-f" || arg == "--find")
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
options.search_symbol = argv[++i];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: " << arg << " requires an argument\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (arg == "-v" || arg == "--verbose")
|
||||
{
|
||||
options.verbose = true;
|
||||
}
|
||||
else if (arg == "-a" || arg == "--ast")
|
||||
{
|
||||
options.show_ast = true;
|
||||
}
|
||||
else if (arg == "--no-color")
|
||||
{
|
||||
options.no_color = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: Unknown option: " << arg << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_specific_print)
|
||||
options.print_all = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string NodeKindToString(ast::NodeKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ast::NodeKind::kProgram: return "Program";
|
||||
case ast::NodeKind::kFunctionDefinition: return "FunctionDefinition";
|
||||
case ast::NodeKind::kClassDefinition: return "ClassDefinition";
|
||||
case ast::NodeKind::kUnitDefinition: return "UnitDefinition";
|
||||
case ast::NodeKind::kVarStatement: return "VarStatement";
|
||||
case ast::NodeKind::kConstStatement: return "ConstStatement";
|
||||
case ast::NodeKind::kIfStatement: return "IfStatement";
|
||||
case ast::NodeKind::kForInStatement: return "ForInStatement";
|
||||
case ast::NodeKind::kWhileStatement: return "WhileStatement";
|
||||
// ... 添加其他类型
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintASTStructure(const ast::ParseResult& parse_result, std::ostream& os)
|
||||
{
|
||||
os << "\n╔════════════════════════════════════════════════════════════╗\n";
|
||||
os << "║ AST STRUCTURE ║\n";
|
||||
os << "╚════════════════════════════════════════════════════════════╝\n\n";
|
||||
|
||||
os << "Statements: " << parse_result.root->statements.size() << "\n\n";
|
||||
|
||||
for (size_t i = 0; i < parse_result.root->statements.size(); ++i)
|
||||
{
|
||||
const auto& stmt = parse_result.root->statements[i];
|
||||
if (!stmt)
|
||||
continue;
|
||||
|
||||
// 修复:使用 kind 和 span
|
||||
os << "[" << i << "] " << NodeKindToString(stmt->kind)
|
||||
<< " at [" << stmt->span.start_line << ":" << stmt->span.start_column << "]";
|
||||
|
||||
// 打印特定类型的详细信息
|
||||
if (auto* func_def = dynamic_cast<ast::FunctionDefinition*>(stmt.get()))
|
||||
{
|
||||
os << " - Function: " << func_def->name;
|
||||
}
|
||||
else if (auto* class_def = dynamic_cast<ast::ClassDefinition*>(stmt.get()))
|
||||
{
|
||||
os << " - Class: " << class_def->name;
|
||||
}
|
||||
else if (auto* unit_def = dynamic_cast<ast::UnitDefinition*>(stmt.get()))
|
||||
{
|
||||
os << " - Unit: " << unit_def->name;
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
// ==================== 主分析函数 ====================
|
||||
|
||||
void AnalyzeFile(const Options& options)
|
||||
{
|
||||
// 打印头部
|
||||
if (!options.compact_mode)
|
||||
{
|
||||
std::cout << "\n╔════════════════════════════════════════════════════════════╗\n";
|
||||
std::cout << "║ SYMBOL TABLE ANALYZER ║\n";
|
||||
std::cout << "╚════════════════════════════════════════════════════════════╝\n\n";
|
||||
std::cout << "Input file: " << options.input_file << "\n";
|
||||
}
|
||||
|
||||
// 1. 读取源文件
|
||||
if (options.verbose)
|
||||
std::cout << "Reading file...\n";
|
||||
|
||||
std::string source = ReadFile(options.input_file);
|
||||
|
||||
if (options.verbose)
|
||||
{
|
||||
std::cout << "File size: " << source.length() << " bytes\n";
|
||||
std::cout << "----------------------------------------\n";
|
||||
std::cout << source << "\n";
|
||||
std::cout << "----------------------------------------\n\n";
|
||||
}
|
||||
|
||||
// 2. 使用 Tree-Sitter 解析
|
||||
if (options.verbose)
|
||||
std::cout << "Parsing with Tree-Sitter...\n";
|
||||
|
||||
TreeSitterParser ts_parser;
|
||||
[[maybe_unused]] TSTree* tree = ts_parser.Parse(source);
|
||||
TSNode root = ts_parser.GetRootNode();
|
||||
|
||||
if (options.verbose)
|
||||
{
|
||||
std::cout << "Root node type: " << ts_node_type(root) << "\n";
|
||||
std::cout << "Root node child count: " << ts_node_child_count(root) << "\n\n";
|
||||
}
|
||||
|
||||
// 3. 反序列化为 AST
|
||||
if (options.verbose)
|
||||
std::cout << "Deserializing to AST...\n";
|
||||
|
||||
ast::Deserializer deserializer;
|
||||
ast::ParseResult parse_result = deserializer.Parse(root, source);
|
||||
|
||||
if (parse_result.HasErrors())
|
||||
{
|
||||
std::cerr << "\n⚠️ Parse Errors:\n";
|
||||
for (const auto& error : parse_result.errors)
|
||||
{
|
||||
std::cerr << " [" << error.location.start_line << ":"
|
||||
<< error.location.start_column << "] "
|
||||
<< error.message << "\n";
|
||||
}
|
||||
std::cerr << "\n";
|
||||
}
|
||||
|
||||
if (options.show_ast)
|
||||
{
|
||||
PrintASTStructure(parse_result, std::cout);
|
||||
}
|
||||
|
||||
// 4. 构建符号表
|
||||
if (options.verbose)
|
||||
std::cout << "Building symbol table...\n";
|
||||
|
||||
symbol::SymbolTable table;
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
table.Build(*parse_result.root);
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
|
||||
if (options.verbose)
|
||||
std::cout << "Symbol table built in " << duration.count() << " ms\n\n";
|
||||
|
||||
// 5. 准备输出流
|
||||
std::ostream* out = &std::cout;
|
||||
std::ofstream file_out;
|
||||
|
||||
if (!options.output_file.empty())
|
||||
{
|
||||
file_out.open(options.output_file);
|
||||
if (!file_out.is_open())
|
||||
{
|
||||
std::cerr << "Error: Cannot write to file: " << options.output_file << "\n";
|
||||
return;
|
||||
}
|
||||
out = &file_out;
|
||||
|
||||
// 写入文件头
|
||||
*out << "Symbol Table Analysis\n";
|
||||
*out << "Source: " << options.input_file << "\n";
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time = std::chrono::system_clock::to_time_t(now);
|
||||
*out << "Generated: " << std::ctime(&time);
|
||||
*out << std::string(80, '=') << "\n\n";
|
||||
}
|
||||
|
||||
// 6. ✅ 使用新的 debug_print API
|
||||
|
||||
// 配置打印选项
|
||||
symbol::debug::PrintOptions print_opts;
|
||||
if (options.compact_mode)
|
||||
print_opts = symbol::debug::PrintOptions::Compact();
|
||||
else if (options.verbose)
|
||||
print_opts = symbol::debug::PrintOptions::Verbose();
|
||||
else
|
||||
print_opts = symbol::debug::PrintOptions::Default();
|
||||
|
||||
if (options.no_color || !options.output_file.empty())
|
||||
print_opts.use_color = false;
|
||||
|
||||
print_opts.show_references = options.print_references || options.verbose;
|
||||
|
||||
// 创建打印器
|
||||
symbol::debug::DebugPrinter printer(table, print_opts);
|
||||
|
||||
// 7. 执行查询或打印
|
||||
if (!options.search_symbol.empty())
|
||||
{
|
||||
// 搜索符号
|
||||
printer.FindAndPrint(options.search_symbol, *out);
|
||||
}
|
||||
else if (options.statistics_only)
|
||||
{
|
||||
// 只打印统计
|
||||
printer.PrintStatistics(*out);
|
||||
}
|
||||
else if (options.print_overview)
|
||||
{
|
||||
// 只打印概览
|
||||
printer.PrintOverview(*out);
|
||||
}
|
||||
else if (options.compact_mode)
|
||||
{
|
||||
// 紧凑模式
|
||||
symbol::debug::PrintCompact(table, *out);
|
||||
}
|
||||
else if (options.print_all)
|
||||
{
|
||||
// 打印所有内容
|
||||
printer.PrintAll(*out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 自定义打印
|
||||
bool printed_anything = false;
|
||||
|
||||
if (options.print_definitions)
|
||||
{
|
||||
printer.PrintSymbolList(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_scopes)
|
||||
{
|
||||
printer.PrintScopeHierarchy(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_references)
|
||||
{
|
||||
printer.PrintAllReferences(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_inheritance)
|
||||
{
|
||||
printer.PrintAllInheritance(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_calls)
|
||||
{
|
||||
printer.PrintAllCalls(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
// 总是打印统计信息
|
||||
if (printed_anything)
|
||||
{
|
||||
*out << "\n";
|
||||
}
|
||||
printer.PrintStatistics(*out);
|
||||
}
|
||||
|
||||
// 8. 完成
|
||||
if (file_out.is_open())
|
||||
{
|
||||
file_out.close();
|
||||
std::cout << "✓ Symbol table exported to: " << options.output_file << "\n";
|
||||
}
|
||||
|
||||
// 9. 打印摘要
|
||||
if (!options.compact_mode)
|
||||
{
|
||||
std::cout << "\n========================================\n";
|
||||
std::cout << "Summary:\n";
|
||||
std::cout << " File: " << options.input_file << "\n";
|
||||
std::cout << " Size: " << source.length() << " bytes\n";
|
||||
std::cout << " Lines: " << std::count(source.begin(), source.end(), '\n') + 1 << "\n";
|
||||
std::cout << " Statements: " << parse_result.root->statements.size() << "\n";
|
||||
std::cout << " Symbols: " << table.GetAllDefinitions().size() << "\n";
|
||||
std::cout << " Scopes: " << table.GetScopeManager().GetAllScopes().size() << "\n";
|
||||
std::cout << " Parse Errors: " << parse_result.errors.size() << "\n";
|
||||
std::cout << " Build Time: " << duration.count() << " ms\n";
|
||||
|
||||
if (parse_result.HasErrors())
|
||||
{
|
||||
std::cout << " Status: ⚠️ COMPLETED WITH ERRORS\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " Status: ✓ SUCCESS\n";
|
||||
}
|
||||
std::cout << "========================================\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 主程序 ====================
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Options options;
|
||||
|
||||
if (!ParseArguments(argc, argv, options))
|
||||
{
|
||||
PrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AnalyzeFile(options);
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "❌ Fatal error: " << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
function f1(a: string; b: boolean = true): integer;
|
||||
begin
|
||||
end;
|
||||
|
||||
function f2(a, b, c);overload;
|
||||
begin
|
||||
end;
|
||||
|
||||
// var d := 1;
|
||||
// c := false;
|
||||
// f := fa();
|
||||
Loading…
Reference in New Issue