From cee6e614bf45892ed31f5091516118ae3cd39ded Mon Sep 17 00:00:00 2001 From: csh Date: Sun, 16 Nov 2025 21:20:47 +0800 Subject: [PATCH] =?UTF-8?q?:recycle:=20=E9=87=8D=E6=9E=84=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7=E8=A1=A8=E7=9B=B8=E5=85=B3=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :rocket: 优化`ast`相关代码 --- lsp-server/src/language/ast/detail.cpp | 251 ++- lsp-server/src/language/ast/detail.hpp | 12 - lsp-server/src/language/symbol/builder.cpp | 1097 ++++++------ lsp-server/src/language/symbol/builder.hpp | 98 +- lsp-server/src/language/symbol/graph/call.hpp | 77 + .../src/language/symbol/graph/inheritance.hpp | 90 + .../src/language/symbol/graph/reference.hpp | 67 + .../src/language/symbol/index/location.hpp | 100 ++ .../src/language/symbol/index/scope.hpp | 144 ++ lsp-server/src/language/symbol/interface.hpp | 27 + .../src/language/symbol/location_index.cpp | 105 -- .../src/language/symbol/location_index.hpp | 148 +- lsp-server/src/language/symbol/relations.cpp | 116 -- lsp-server/src/language/symbol/relations.hpp | 57 - lsp-server/src/language/symbol/scope.cpp | 88 - lsp-server/src/language/symbol/scope.hpp | 139 +- lsp-server/src/language/symbol/store.cpp | 101 -- lsp-server/src/language/symbol/store.hpp | 86 +- lsp-server/src/language/symbol/table.cpp | 242 --- lsp-server/src/language/symbol/table.hpp | 207 ++- lsp-server/src/language/symbol/types.hpp | 275 ++- lsp-server/test/test_ast/debug_printer.cpp | 782 ++++++--- lsp-server/test/test_ast/debug_printer.hpp | 12 +- lsp-server/test/test_symbol/CMakeLists.txt | 9 +- lsp-server/test/test_symbol/debug_printer.cpp | 1515 ++++++++--------- lsp-server/test/test_symbol/debug_printer.hpp | 49 +- lsp-server/test/test_symbol/test.cpp | 657 ++++++- 27 files changed, 3740 insertions(+), 2811 deletions(-) create mode 100644 lsp-server/src/language/symbol/graph/call.hpp create mode 100644 lsp-server/src/language/symbol/graph/inheritance.hpp create mode 100644 lsp-server/src/language/symbol/graph/reference.hpp create mode 100644 lsp-server/src/language/symbol/index/location.hpp create mode 100644 lsp-server/src/language/symbol/index/scope.hpp create mode 100644 lsp-server/src/language/symbol/interface.hpp delete mode 100644 lsp-server/src/language/symbol/location_index.cpp delete mode 100644 lsp-server/src/language/symbol/relations.cpp delete mode 100644 lsp-server/src/language/symbol/relations.hpp delete mode 100644 lsp-server/src/language/symbol/scope.cpp delete mode 100644 lsp-server/src/language/symbol/store.cpp delete mode 100644 lsp-server/src/language/symbol/table.cpp diff --git a/lsp-server/src/language/ast/detail.cpp b/lsp-server/src/language/ast/detail.cpp index fd4c5ec..8087ba1 100644 --- a/lsp-server/src/language/ast/detail.cpp +++ b/lsp-server/src/language/ast/detail.cpp @@ -1,10 +1,91 @@ #include +#include #include "../../utils/string.hpp" #include "./tree_sitter_utils.hpp" #include "./detail.hpp" namespace lsp::language::ast::detail { + namespace + { + template + struct Overloaded : Ts... + { + using Ts::operator()...; + }; + + template + Overloaded(Ts...) -> Overloaded; + + struct AccessModifierToken + { + AccessModifier modifier; + }; + + struct ReferenceModifierToken + { + ReferenceModifier modifier; + }; + + struct ClassMemberNodeToken + { + std::unique_ptr member; + }; + + using ClassMemberToken = std::variant; + + class ClassMemberStateMachine + { + public: + ClassMemberStateMachine(AccessModifier access, ReferenceModifier reference) : + current_access_(access), + current_reference_(reference) + { + } + + AccessModifier CurrentAccess() const { return current_access_; } + ReferenceModifier CurrentReference() const { return current_reference_; } + + std::unique_ptr Consume(ClassMemberToken&& token) + { + return std::visit(Overloaded{ + [this](AccessModifierToken& t) -> std::unique_ptr { + current_access_ = t.modifier; + return nullptr; + }, + [this](ReferenceModifierToken& t) -> std::unique_ptr { + current_reference_ = t.modifier; + return nullptr; + }, + [this](ClassMemberNodeToken& t) -> std::unique_ptr { + if (t.member) + t.member->access_modifier = current_access_; + return std::move(t.member); + } }, + token); + } + + private: + AccessModifier current_access_; + ReferenceModifier current_reference_; + }; + + template + std::unique_ptr WrapClassMember(Location span, std::unique_ptr decl) + { + if (!decl) + return nullptr; + + auto member = MakeNode(); + member->span = span; + member->member = std::move(decl); + return member; + } + + std::vector BuildVariableDeclarationTokens(TSNode node, ParseContext& ctx, const ClassMemberStateMachine& state); + std::vector TokenizeClassMemberChild(TSNode node, ParseContext& ctx, const ClassMemberStateMachine& state); + } + void RegisterStatementParsers() { static std::once_flag once; @@ -1224,8 +1305,7 @@ namespace lsp::language::ast::detail TSNode body_node = ts_node_child_by_field_name(node, "body", 4); if (!ts_node_is_null(body_node)) { - AccessModifier current_access = AccessModifier::kPublic; - ReferenceModifier current_reference = ReferenceModifier::kNone; + ClassMemberStateMachine member_state(AccessModifier::kPublic, ReferenceModifier::kNone); uint32_t body_count = ts_node_child_count(body_node); for (uint32_t i = 0; i < body_count; i++) @@ -1253,13 +1333,11 @@ namespace lsp::language::ast::detail if (!ts_node_is_named(cm_child)) continue; - auto results = ParseClassMember(cm_child, ctx, current_access, current_reference); - for (auto& result : results) + auto tokens = TokenizeClassMemberChild(cm_child, ctx, member_state); + for (auto& token : tokens) { - current_access = result.access_modifier; - current_reference = result.reference_modifier; - if (result.member) - class_def->members.push_back(std::move(result.member)); + if (auto member = member_state.Consume(std::move(token))) + class_def->members.push_back(std::move(member)); } } } @@ -2112,60 +2190,41 @@ namespace lsp::language::ast::detail return prop; } - std::vector ParseClassMember(TSNode node, ParseContext& ctx, AccessModifier current_access, ReferenceModifier current_reference) + namespace { - std::vector results; - std::string_view node_type = ts_node_type(node); - - // 如果是访问修饰符,返回新的访问级别 - if (node_type == "access_modifier") + std::vector BuildVariableDeclarationTokens(TSNode node, ParseContext& ctx, const ClassMemberStateMachine& state) { - ClassMemberParseResult result; - result.access_modifier = ParseAccessModifier(node, ctx); - results.push_back(std::move(result)); - return results; - } - - // 如果是引用修饰符,返回新的引用修饰符 - if (node_type == "reference_modifier") - { - ClassMemberParseResult result; - result.reference_modifier = ParseReferenceModifier(node, ctx); - results.push_back(std::move(result)); - return results; - } - - // 变量声明 - if (node_type == "variable_declaration") - { - bool is_static = false; - ReferenceModifier ref_mod = current_reference; + std::vector tokens; + ReferenceModifier ref_mod = state.CurrentReference(); TSNode ref_node = ts_node_child_by_field_name(node, "ref_modifier", 12); if (!ts_node_is_null(ref_node)) - { ref_mod = ParseReferenceModifier(ref_node, ctx); - } TSNode variable_node = ts_node_child_by_field_name(node, "variable", 8); if (ts_node_is_null(variable_node)) - return results; + return tokens; TSNode member_var_node = ts_node_child(variable_node, 0); if (ts_node_is_null(member_var_node)) - return results; + return tokens; std::string_view child_type = ts_node_type(member_var_node); + bool is_static = false; if (child_type == "static_member_variable") is_static = true; else if (child_type == "field_member_variable") is_static = false; else - return results; + return tokens; - // 收集所有名称 - std::vector names; - std::vector locations; + struct NamedVariable + { + std::string name; + Location location; + }; + + std::vector names; uint32_t count = ts_node_child_count(member_var_node); for (uint32_t i = 0; i < count; i++) { @@ -2174,11 +2233,15 @@ namespace lsp::language::ast::detail continue; TSNode name_node = ts_node_child(member_var_node, i); - names.push_back(ts::Text(name_node, ctx.Source())); - locations.push_back(ts::NodeLocation(name_node)); + names.push_back(NamedVariable{ + ts::Text(name_node, ctx.Source()), + ts::NodeLocation(name_node) + }); } - // 类型和初始值 + if (names.empty()) + return tokens; + std::optional type_ann; TSNode type_node = ts_node_child_by_field_name(member_var_node, "type", 4); if (!ts_node_is_null(type_node)) @@ -2192,87 +2255,93 @@ namespace lsp::language::ast::detail ExpressionPtr initial_value; TSNode value_node = ts_node_child_by_field_name(member_var_node, "value", 5); if (!ts_node_is_null(value_node)) - { initial_value = ParseExpression(value_node, ctx); - } - // 为每个名称创建成员 for (size_t i = 0; i < names.size(); i++) { - auto member = MakeNode(); - member->span = locations[i]; - member->access_modifier = current_access; + Location span = names[i].location; if (is_static) { auto decl = MakeNode(); - decl->span = locations[i]; - decl->name = names[i]; - decl->location = locations[i]; + decl->span = span; + decl->name = names[i].name; + decl->location = span; decl->reference_modifier = ref_mod; - // 只有最后一个变量有类型和初始值 if (i == names.size() - 1) { decl->type = type_ann; decl->initializer = std::move(initial_value); } - member->member = std::move(decl); + if (auto member = WrapClassMember(span, std::move(decl))) + tokens.emplace_back(ClassMemberNodeToken{ std::move(member) }); } else { auto decl = MakeNode(); - decl->span = locations[i]; - decl->name = names[i]; - decl->location = locations[i]; + decl->span = span; + decl->name = names[i].name; + decl->location = span; decl->reference_modifier = ref_mod; - // 只有最后一个变量有类型和初始值 if (i == names.size() - 1) { decl->type = type_ann; decl->initializer = std::move(initial_value); } - member->member = std::move(decl); + if (auto member = WrapClassMember(span, std::move(decl))) + tokens.emplace_back(ClassMemberNodeToken{ std::move(member) }); } - - ClassMemberParseResult result; - result.member = std::move(member); - results.push_back(std::move(result)); } + + return tokens; } - // 方法声明 - else if (node_type == "method_declaration") + + std::vector TokenizeClassMemberChild(TSNode node, ParseContext& ctx, const ClassMemberStateMachine& state) { - auto member = MakeNode(); - member->span = ts::NodeLocation(node); - member->access_modifier = current_access; + std::vector tokens; + std::string_view node_type = ts_node_type(node); - auto method = ParseMethodDeclaration(node, ctx); - member->member = std::move(method); + if (node_type == "access_modifier") + { + tokens.emplace_back(AccessModifierToken{ ParseAccessModifier(node, ctx) }); + return tokens; + } - ClassMemberParseResult result; - result.member = std::move(member); - results.push_back(std::move(result)); + if (node_type == "reference_modifier") + { + tokens.emplace_back(ReferenceModifierToken{ ParseReferenceModifier(node, ctx) }); + return tokens; + } + + if (node_type == "variable_declaration") + return BuildVariableDeclarationTokens(node, ctx, state); + + if (node_type == "method_declaration") + { + if (auto method = ParseMethodDeclaration(node, ctx)) + { + if (auto member = WrapClassMember(ts::NodeLocation(node), std::move(method))) + tokens.emplace_back(ClassMemberNodeToken{ std::move(member) }); + } + return tokens; + } + + if (node_type == "property_declaration") + { + if (auto property = ParsePropertyDeclaration(node, ctx)) + { + if (auto member = WrapClassMember(ts::NodeLocation(node), std::move(property))) + tokens.emplace_back(ClassMemberNodeToken{ std::move(member) }); + } + return tokens; + } + + return tokens; } - // 属性声明 - else if (node_type == "property_declaration") - { - auto member = MakeNode(); - member->span = ts::NodeLocation(node); - member->access_modifier = current_access; - - auto prop = ParsePropertyDeclaration(node, ctx); - member->member = std::move(prop); - - ClassMemberParseResult result; - result.member = std::move(member); - results.push_back(std::move(result)); - } - - return results; } template diff --git a/lsp-server/src/language/ast/detail.hpp b/lsp-server/src/language/ast/detail.hpp index 2221eca..6f72033 100644 --- a/lsp-server/src/language/ast/detail.hpp +++ b/lsp-server/src/language/ast/detail.hpp @@ -29,15 +29,6 @@ namespace lsp::language::ast::detail std::vector& errors_; }; - // ===== 类成员解析结果 ===== - - struct ClassMemberParseResult - { - std::unique_ptr member; - AccessModifier access_modifier = AccessModifier::kPublic; - ReferenceModifier reference_modifier = ReferenceModifier::kNone; - }; - // ===== 语句解析器注册表 ===== class StatementParserRegistry @@ -91,9 +82,6 @@ namespace lsp::language::ast::detail std::unique_ptr ParseMethodDeclaration(TSNode node, ParseContext& ctx); std::unique_ptr ParsePropertyDeclaration(TSNode node, ParseContext& ctx); - // 类成员解析 - std::vector ParseClassMember(TSNode node, ParseContext& ctx, AccessModifier current_access, ReferenceModifier current_reference); - // ===== 通用解析函数 ===== std::vector> ParseParameters(TSNode params_node, ParseContext& ctx); diff --git a/lsp-server/src/language/symbol/builder.cpp b/lsp-server/src/language/symbol/builder.cpp index 3bf6713..d0096b1 100644 --- a/lsp-server/src/language/symbol/builder.cpp +++ b/lsp-server/src/language/symbol/builder.cpp @@ -1,77 +1,197 @@ +#include #include "./builder.hpp" namespace lsp::language::symbol { - Builder::Builder(SymbolTable& table) : - table_(table), current_scope_id_(kInvalidScopeId) + Builder::Builder(SymbolTable& table) : table_(table), current_scope_id_(kInvalidScopeId), in_interface_section_(false) { } void Builder::Build(ast::ASTNode& root) { - // 使用span作为作用域范围 - 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::Location& location, const std::optional& type_hint, bool is_class_method) + // ===== Helper Methods ===== + + SymbolId Builder::CreateSymbol(const std::string& name, SymbolKind kind, const ast::Location& location, const std::optional& type_hint) { - return table_.CreateSymbol( - name, - kind, - location, - current_scope_id_, - current_parent_symbol_id_, - type_hint, - is_class_method); + std::optional visibility; + if (in_interface_section_) + visibility = UnitVisibility::kInterface; + + Symbol symbol = [&]() -> Symbol { + switch (kind) + { + case SymbolKind::Class: + { + Class cls; + cls.name = name; + cls.selection_range = location; + cls.range = location; + cls.unit_visibility = visibility; + return Symbol(std::move(cls)); + } + case SymbolKind::Function: + { + Function fn; + fn.name = name; + fn.selection_range = location; + fn.range = location; + fn.declaration_range = location; + fn.return_type = type_hint; + fn.unit_visibility = visibility; + return Symbol(std::move(fn)); + } + case SymbolKind::Method: + { + Method method; + method.name = name; + method.selection_range = location; + method.range = location; + method.declaration_range = location; + method.return_type = type_hint; + return Symbol(std::move(method)); + } + case SymbolKind::Property: + { + Property property; + property.name = name; + property.selection_range = location; + property.range = location; + property.type = type_hint; + return Symbol(std::move(property)); + } + case SymbolKind::Field: + { + Field field; + field.name = name; + field.selection_range = location; + field.range = location; + field.type = type_hint; + return Symbol(std::move(field)); + } + case SymbolKind::Variable: + { + Variable var; + var.name = name; + var.selection_range = location; + var.range = location; + var.type = type_hint; + var.unit_visibility = visibility; + return Symbol(std::move(var)); + } + case SymbolKind::Constant: + { + Constant constant; + constant.name = name; + constant.selection_range = location; + constant.range = location; + constant.type = type_hint; + return Symbol(std::move(constant)); + } + default: + { + Variable fallback; + fallback.name = name; + fallback.selection_range = location; + fallback.range = location; + fallback.type = type_hint; + fallback.unit_visibility = visibility; + return Symbol(std::move(fallback)); + } + } + }(); + + SymbolId id = table_.CreateSymbol(std::move(symbol)); + + if (current_scope_id_ != kInvalidScopeId) + { + table_.AddSymbolToScope(current_scope_id_, name, id); + } + + return id; } - SymbolId Builder::CreateSymbol(const std::string& name, SymbolKind kind, const ast::ASTNode& node, const std::optional& type_hint, bool is_class_method) + SymbolId Builder::CreateSymbol(const std::string& name, SymbolKind kind, const ast::ASTNode& node, const std::optional& type_hint) { - return table_.CreateSymbol( - name, - kind, - node.span, - current_scope_id_, - current_parent_symbol_id_, - type_hint, - is_class_method); + return CreateSymbol(name, kind, node.span, type_hint); + } + + SymbolId Builder::CreateFunctionSymbol( + const std::string& name, + const ast::Location& location, + const std::vector>& parameters, + const std::optional& return_type) + { + std::optional visibility; + if (in_interface_section_) + visibility = UnitVisibility::kInterface; + + Function fn; + fn.name = name; + fn.selection_range = location; + fn.range = location; + fn.declaration_range = location; + fn.return_type = ExtractTypeName(return_type); + fn.unit_visibility = visibility; + fn.parameters = BuildParameters(parameters); + + Symbol symbol(std::move(fn)); + SymbolId id = table_.CreateSymbol(std::move(symbol)); + + if (current_scope_id_ != kInvalidScopeId) + { + table_.AddSymbolToScope(current_scope_id_, name, id); + } + + return id; + } + + SymbolId Builder::CreateMethodSymbol( + const std::string& name, + const ast::Location& location, + const std::vector>& parameters, + const std::optional& return_type) + { + Method method; + method.name = name; + method.selection_range = location; + method.range = location; + method.declaration_range = location; + method.return_type = ExtractTypeName(return_type); + method.parameters = BuildParameters(parameters); + + Symbol symbol(std::move(method)); + SymbolId id = table_.CreateSymbol(std::move(symbol)); + + if (current_scope_id_ != kInvalidScopeId) + { + table_.AddSymbolToScope(current_scope_id_, name, id); + } + + return id; } 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); + current_scope_id_ = table_.CreateScope(kind, range, current_scope_id_, 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); + current_scope_id_ = table_.CreateScope(kind, range, current_scope_id_, 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; + const auto* scope_info = table_.scopes().scope(current_scope_id_); + if (scope_info && scope_info->parent) + { + current_scope_id_ = *scope_info->parent; + } } void Builder::VisitStatements(const std::vector& statements) @@ -88,124 +208,68 @@ namespace lsp::language::symbol expr.Accept(*this); } - // 修改后的FormatSignature - 直接接收parameters和return_type - std::string Builder::FormatSignature( - const std::vector>& parameters, - const std::optional& return_type) + std::optional Builder::ExtractTypeName(const std::optional& type) const { - std::string result = "("; - for (size_t i = 0; i < parameters.size(); ++i) + if (type) + return type->name; + return std::nullopt; + } + + std::vector Builder::BuildParameters(const std::vector>& parameters) const + { + std::vector result; + result.reserve(parameters.size()); + + for (const auto& param : parameters) { - if (i > 0) - result += ", "; - const auto& param = *parameters[i]; // 解引用unique_ptr + if (!param) + continue; - if (param.is_var) - result += "var "; - if (param.is_out) - result += "out "; - - result += param.name; - if (param.type) - result += ": " + param.type->name; + language::symbol::Parameter p; + p.name = param->name; + if (param->type) + p.type = param->type->name; + if (param->default_value) + p.default_value = ""; + result.push_back(std::move(p)); } - result += ")"; - - if (return_type) - result += ": " + return_type->name; return result; } - // 使用LValue - void Builder::ProcessLValue(const ast::LValue& lhs, bool is_write) - { - std::visit([this, is_write](auto& variant) { - using T = std::decay_t; - - if constexpr (std::is_same_v>) - { - 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>) - { - if (variant && variant->object) - VisitExpression(*variant->object); - } - else if constexpr (std::is_same_v>) - { - if (variant && variant->base) - VisitExpression(*variant->base); - } - else if constexpr (std::is_same_v>) - { - // UnpackPattern 处理 - if (variant) - variant->Accept(*this); - } - else if constexpr (std::is_same_v>) - { - // ColumnReference 处理 - if (variant && variant->value) - VisitExpression(*variant->value); - } - }, - lhs); - } + // ===== Node Visitation ===== void Builder::VisitProgram(ast::Program& node) { + current_scope_id_ = table_.CreateScope(ScopeKind::kGlobal, node.span, std::nullopt, std::nullopt); VisitStatements(node.statements); } void Builder::VisitUnitDefinition(ast::UnitDefinition& node) { - // 使用node.location作为符号的精确位置 - auto symbol_id = CreateSymbol(node.name, SymbolKind::Module, node.location); - - // 使用node.span作为作用域范围 - EnterScopeWithSymbol(ScopeKind::Unit, symbol_id, node.span); - auto prev_parent = current_parent_symbol_id_; - current_parent_symbol_id_ = symbol_id; + auto unit_scope = EnterScope(ScopeKind::kUnit, node.span); + // Process interface section + in_interface_section_ = true; VisitStatements(node.interface_statements); - VisitStatements(node.implementation_statements); - VisitStatements(node.initialization_statements); - VisitStatements(node.finalization_statements); - current_parent_symbol_id_ = prev_parent; + // Process implementation section + in_interface_section_ = false; + VisitStatements(node.implementation_statements); + ExitScope(); } void Builder::VisitClassDefinition(ast::ClassDefinition& node) { - auto symbol_id = CreateSymbol(node.name, SymbolKind::Class, node.location); + auto class_id = CreateSymbol(node.name, SymbolKind::Class, node.location); - // 处理继承关系 - 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); - } - } + auto class_scope = EnterScopeWithSymbol(ScopeKind::kClass, class_id, node.span); - EnterScopeWithSymbol(ScopeKind::Class, symbol_id, node.span); auto prev_parent = current_parent_symbol_id_; - current_parent_symbol_id_ = symbol_id; + current_parent_symbol_id_ = class_id; - // 处理uses语句 - if (node.uses) - node.uses->Accept(*this); - - for (const auto& member : node.members) + for (auto& member : node.members) { if (member) member->Accept(*this); @@ -215,368 +279,218 @@ namespace lsp::language::symbol ExitScope(); } - void Builder::VisitFunctionDefinition(ast::FunctionDefinition& node) - { - auto symbol_id = CreateSymbol(node.name, SymbolKind::Function, node.location); - - table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) { - def.detail = FormatSignature(node.parameters, node.return_type); - }); - - EnterScopeWithSymbol(ScopeKind::Function, symbol_id, node.span); - auto prev_function = current_function_id_; - auto prev_parent = current_parent_symbol_id_; - - current_function_id_ = symbol_id; - current_parent_symbol_id_ = symbol_id; - - // 添加参数 - 使用->访问 - for (const auto& param : node.parameters) - { - std::optional type_hint; - if (param->type) - type_hint = param->type->name; - if (param->default_value) - VisitExpression(*param->default_value); - CreateSymbol(param->name, SymbolKind::Variable, param->location, type_hint); - } - - current_parent_symbol_id_ = prev_parent; - - if (node.body) - node.body->Accept(*this); - - current_function_id_ = prev_function; - ExitScope(); - } - void Builder::VisitFunctionDeclaration(ast::FunctionDeclaration& node) { - // FunctionDeclaration没有location字段,使用span - auto symbol_id = CreateSymbol(node.name, SymbolKind::Function, node); + auto location = ast::Location{}; + if (!node.name.empty() && !node.parameters.empty()) + { + location = node.span; + } + CreateFunctionSymbol(node.name, location, node.parameters, node.return_type); + } - table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) { - def.detail = FormatSignature(node.parameters, node.return_type); - }); + void Builder::VisitFunctionDefinition(ast::FunctionDefinition& node) + { + auto func_id = CreateFunctionSymbol(node.name, node.location, node.parameters, node.return_type); + + if (node.body) + { + auto func_scope = EnterScopeWithSymbol(ScopeKind::kFunction, func_id, node.body->span); + + auto prev_function = current_function_id_; + current_function_id_ = func_id; + + for (auto& param : node.parameters) + { + if (param) + { + CreateSymbol(param->name, SymbolKind::Variable, param->location); + } + } + + VisitStatements(node.body->statements); + + current_function_id_ = prev_function; + ExitScope(); + } } 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.location, "", node.is_class_method); - - table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) { - def.detail = FormatSignature(node.parameters, node.return_type); - def.method_modifier = node.modifier; - }); - - EnterScopeWithSymbol(ScopeKind::Function, symbol_id, node.span); - auto prev_function = current_function_id_; - auto prev_parent = current_parent_symbol_id_; - - current_function_id_ = symbol_id; - - for (const auto& param : node.parameters) - { - std::optional type_hint; - if (param->type) - type_hint = param->type->name; - if (param->default_value) - VisitExpression(*param->default_value); - auto param_prev = current_parent_symbol_id_; - current_parent_symbol_id_ = symbol_id; - CreateSymbol(param->name, SymbolKind::Variable, param->location, type_hint); - current_parent_symbol_id_ = param_prev; - } + auto method_id = CreateMethodSymbol(node.name, node.location, node.parameters, node.return_type); if (node.body) - node.body->Accept(*this); + { + auto method_scope = EnterScopeWithSymbol(ScopeKind::kFunction, method_id, node.body->span); - current_parent_symbol_id_ = prev_parent; - current_function_id_ = prev_function; - ExitScope(); + auto prev_function = current_function_id_; + current_function_id_ = method_id; + + for (auto& param : node.parameters) + { + if (param) + { + CreateSymbol(param->name, SymbolKind::Variable, param->location); + } + } + + VisitStatements(node.body->statements); + + current_function_id_ = prev_function; + ExitScope(); + } } void Builder::VisitPropertyDeclaration(ast::PropertyDeclaration& node) { - std::optional type_hint; - if (node.type) - type_hint = node.type->name; - - CreateSymbol(node.name, SymbolKind::Property, node.location, type_hint); - - // 处理索引表达式 - if (node.index) - VisitExpression(**node.index); + auto type = ExtractTypeName(node.type); + CreateSymbol(node.name, SymbolKind::Property, node.location, type); } 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.location, std::nullopt, node.is_class_method); - - table_.GetDefinitionStore().Update(symbol_id, [&](SymbolDefinition& def) { - def.detail = FormatSignature(node.parameters, node.return_type); - def.method_modifier = node.modifier; - }); - - EnterScopeWithSymbol(ScopeKind::Function, symbol_id, node.span); - auto prev_function = current_function_id_; - auto prev_parent = current_parent_symbol_id_; - - current_function_id_ = symbol_id; - - for (const auto& param : node.parameters) + std::string method_name = node.name; + size_t dot_pos = method_name.find_last_of('.'); + if (dot_pos != std::string::npos) { - std::optional type_hint; - if (param->type) - type_hint = param->type->name; - if (param->default_value) - VisitExpression(*param->default_value); - auto param_prev = current_parent_symbol_id_; - current_parent_symbol_id_ = symbol_id; - CreateSymbol(param->name, SymbolKind::Variable, param->location, type_hint); - current_parent_symbol_id_ = param_prev; + method_name = method_name.substr(dot_pos + 1); + } + + std::optional method_id; + + if (current_parent_symbol_id_) + { + const auto* scope_info = table_.scopes().scope(current_scope_id_); + if (scope_info) + { + method_id = table_.scopes().FindSymbolInScope(current_scope_id_, method_name); + } + } + + if (!method_id) + { + method_id = CreateMethodSymbol(method_name, node.location, node.parameters, node.return_type); } if (node.body) - node.body->Accept(*this); + { + auto method_scope = EnterScopeWithSymbol(ScopeKind::kFunction, *method_id, node.body->span); - current_parent_symbol_id_ = prev_parent; - current_function_id_ = prev_function; - ExitScope(); + auto prev_function = current_function_id_; + current_function_id_ = *method_id; + + for (auto& param : node.parameters) + { + if (param) + { + CreateSymbol(param->name, SymbolKind::Variable, param->location); + } + } + + VisitStatements(node.body->statements); + + 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); + std::visit([this](auto& member) { + if (member) + member->Accept(*this); }, node.member); } void Builder::VisitVarDeclaration(ast::VarDeclaration& node) { - std::optional type_hint; - if (node.type) - type_hint = node.type->name; - CreateSymbol(node.name, SymbolKind::Variable, node.location, type_hint); + CreateSymbol(node.name, SymbolKind::Variable, node.location, ExtractTypeName(node.type)); - // 注意:字段名是 initial_value,不是 initializer - if (node.initial_value) - VisitExpression(*node.initial_value); + if (node.initializer) + { + VisitExpression(*node.initializer.value()); + } } void Builder::VisitStaticDeclaration(ast::StaticDeclaration& node) { - std::optional type_hint; - if (node.type) - type_hint = node.type->name; - CreateSymbol(node.name, SymbolKind::Variable, node.location, type_hint); + CreateSymbol(node.name, SymbolKind::Variable, node.location, ExtractTypeName(node.type)); - if (node.initial_value) - VisitExpression(*node.initial_value); + if (node.initializer) + { + VisitExpression(*node.initializer.value()); + } } void Builder::VisitGlobalDeclaration(ast::GlobalDeclaration& node) { - std::optional type_hint; - if (node.type) - type_hint = node.type->name; - CreateSymbol(node.name, SymbolKind::Variable, node.location, type_hint); + CreateSymbol(node.name, SymbolKind::Variable, node.location, ExtractTypeName(node.type)); - if (node.initial_value) - VisitExpression(*node.initial_value); + if (node.initializer) + { + VisitExpression(*node.initializer.value()); + } } void Builder::VisitConstDeclaration(ast::ConstDeclaration& node) { - std::optional type_hint; - if (node.type) - type_hint = node.type->name; - CreateSymbol(node.name, SymbolKind::Constant, node.location, type_hint); + CreateSymbol(node.name, SymbolKind::Constant, node.location, ExtractTypeName(node.type)); if (node.value) + { VisitExpression(*node.value); + } } void Builder::VisitFieldDeclaration(ast::FieldDeclaration& node) { - std::optional type_hint; - if (node.type) - type_hint = node.type->name; - CreateSymbol(node.name, SymbolKind::Field, node.location, type_hint); + CreateSymbol(node.name, SymbolKind::Field, node.location, ExtractTypeName(node.type)); - if (node.initial_value) - VisitExpression(*node.initial_value); - } - - 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 (node.initializer) { - if (branch.condition) - VisitExpression(*branch.condition); - if (branch.body) - branch.body->Accept(*this); + VisitExpression(*node.initializer.value()); } - - if (node.else_body) - node.else_body->Accept(*this); - } - - void Builder::VisitForInStatement(ast::ForInStatement& node) - { - // 为循环创建作用域 - EnterScope(ScopeKind::Block, node.span); - - // 创建key和value符号 - if (!node.key.empty()) - CreateSymbol(node.key, SymbolKind::Variable, node.key_location); - - if (!node.value.empty()) - CreateSymbol(node.value, SymbolKind::Variable, node.value_location); - - // 访问集合表达式 - 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); - - // 创建计数器符号 - if (!node.counter.empty()) - CreateSymbol(node.counter, SymbolKind::Variable, node.counter_location); - - // 访问起始值 - if (node.start) - VisitExpression(*node.start); - - // 访问结束值 - if (node.end) - VisitExpression(*node.end); - - // 访问步长 - if (node.step) - VisitExpression(*node.step); - - // 访问循环体 - 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) - { - // 注意:body是vector,不是单个语句 - VisitStatements(node.body); - - if (node.condition) - VisitExpression(*node.condition); - } - - void Builder::VisitCaseStatement(ast::CaseStatement& node) - { - // 注意:字段名是discriminant,不是expression - if (node.discriminant) - VisitExpression(*node.discriminant); - - // 注意:字段名是branches,不是cases;values,不是labels - for (auto& branch : node.branches) - { - for (auto& value : branch.values) - { - if (value) - VisitExpression(*value); - } - if (branch.body) - branch.body->Accept(*this); - } - - if (node.else_body) - node.else_body->Accept(*this); - } - - void Builder::VisitTryStatement(ast::TryStatement& node) - { - // 注意:新AST的TryStatement非常简单,只有try_body和except_body - if (node.try_body) - node.try_body->Accept(*this); - - if (node.except_body) - node.except_body->Accept(*this); } void Builder::VisitUsesStatement(ast::UsesStatement& node) { - // 注意:units是vector,不是vector - for (const auto& unit : node.units) - { - // 记录导入关系 - table_.AddUnitImport(unit.name, unit.location); - - // 创建一个符号来表示这个导入 - [[maybe_unused]] SymbolId import_symbol_id = CreateSymbol( - unit.name, - SymbolKind::Module, - unit.location, - std::nullopt); - } + // Unit imports would be stored in the Unit symbol + // For now just skip since we don't have a way to store them } + // ===== Expression Processing (references) ===== + void Builder::VisitIdentifier(ast::Identifier& node) { - // 查找符号并添加引用 - auto symbol_id = table_.GetScopeManager().FindInScopeChain(current_scope_id_, node.name); + auto symbol_id = table_.scopes().FindSymbolInScopeChain(current_scope_id_, node.name); if (symbol_id) - table_.AddReference(*symbol_id, node.span, false); + { + table_.AddReference(*symbol_id, node.location, false, false); + } } void Builder::VisitCallExpression(ast::CallExpression& node) { - if (node.function) + if (node.callee) { - VisitExpression(*node.function); - - // 如果被调用者是标识符,尝试建立调用关系 - if (auto* id = dynamic_cast(node.function.get())) + if (auto* id = dynamic_cast(node.callee.get())) { - auto callee_id = table_.GetScopeManager().FindInScopeChain(current_scope_id_, id->name); - if (callee_id && current_function_id_) + auto symbol_id = table_.scopes().FindSymbolInScopeChain(current_scope_id_, id->name); + if (symbol_id) { - table_.GetCallGraph().AddCall(*current_function_id_, *callee_id, node.span); + table_.AddReference(*symbol_id, id->location, false, false); + + if (current_function_id_) + { + table_.AddCall(*current_function_id_, *symbol_id, node.span); + } } } + else + { + node.callee->Accept(*this); + } } for (auto& arg : node.arguments) @@ -589,7 +503,14 @@ namespace lsp::language::symbol void Builder::VisitAttributeExpression(ast::AttributeExpression& node) { if (node.object) - VisitExpression(*node.object); + { + node.object->Accept(*this); + } + + if (node.attribute) + { + node.attribute->Accept(*this); + } } void Builder::VisitAssignmentExpression(ast::AssignmentExpression& node) @@ -597,9 +518,214 @@ namespace lsp::language::symbol ProcessLValue(node.left, true); if (node.right) + { VisitExpression(*node.right); + } } + void Builder::ProcessLValue(const ast::LValue& lvalue, bool is_write) + { + std::visit([this, is_write](auto& val) { + using T = std::decay_t; + if constexpr (std::is_same_v>) + { + if (val) + { + auto symbol_id = table_.scopes().FindSymbolInScopeChain(current_scope_id_, val->name); + if (symbol_id) + { + table_.AddReference(*symbol_id, val->location, false, is_write); + } + } + } + else if constexpr (std::is_same_v>) + { + if (val) + { + if (val->object) + { + val->object->Accept(*this); + } + if (val->attribute) + { + val->attribute->Accept(*this); + } + } + } + else if constexpr (std::is_same_v>) + { + if (val) + { + if (val->base) + { + val->base->Accept(*this); + } + for (auto& idx : val->indices) + { + if (idx.start) + idx.start->Accept(*this); + if (idx.end) + idx.end->Accept(*this); + if (idx.step) + idx.step->Accept(*this); + } + } + } + else if constexpr (std::is_same_v>) + { + if (val && val->value) + { + val->value->Accept(*this); + } + } + }, + lvalue); + } + + // ===== Statement Processing ===== + + void Builder::VisitBlockStatement(ast::BlockStatement& node) + { + auto block_scope = EnterScope(ScopeKind::kBlock, 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); + } + + if (node.else_body && *node.else_body) + { + (*node.else_body)->Accept(*this); + } + } + + void Builder::VisitForInStatement(ast::ForInStatement& node) + { + auto for_scope = EnterScope(ScopeKind::kBlock, node.span); + + if (!node.key.empty()) + { + CreateSymbol(node.key, SymbolKind::Variable, node.key_location); + } + + if (!node.value.empty()) + { + CreateSymbol(node.value, SymbolKind::Variable, node.value_location); + } + + if (node.collection) + VisitExpression(*node.collection); + + if (node.body) + node.body->Accept(*this); + + ExitScope(); + } + + void Builder::VisitForToStatement(ast::ForToStatement& node) + { + auto for_scope = EnterScope(ScopeKind::kBlock, node.span); + + CreateSymbol(node.counter, SymbolKind::Variable, node.counter_location); + + if (node.start) + VisitExpression(*node.start); + if (node.end) + VisitExpression(*node.end); + if (node.step) + VisitExpression(*node.step); + 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) + { + VisitStatements(node.body); + if (node.condition) + VisitExpression(*node.condition); + } + + 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.else_body && *node.else_body) + { + (*node.else_body)->Accept(*this); + } + } + + void Builder::VisitTryStatement(ast::TryStatement& node) + { + if (node.try_body) + { + VisitStatements(node.try_body->statements); + } + + if (node.except_body) + { + VisitStatements(node.except_body->statements); + } + } + + void Builder::VisitMatrixIterationStatement(ast::MatrixIterationStatement& node) + { + auto iter_scope = EnterScope(ScopeKind::kBlock, node.span); + + if (node.target) + VisitExpression(*node.target); + + if (node.body) + VisitStatements(node.body->statements); + + ExitScope(); + } + + void Builder::VisitExpressionStatement(ast::ExpressionStatement& node) + { + if (node.expression) + VisitExpression(*node.expression); + } + + void Builder::VisitReturnStatement(ast::ReturnStatement& node) + { + if (node.value && *node.value) + VisitExpression(**node.value); + } + + // ===== Other Expressions ===== + void Builder::VisitBinaryExpression(ast::BinaryExpression& node) { if (node.left) @@ -623,14 +749,14 @@ namespace lsp::language::symbol if (node.base) VisitExpression(*node.base); - for (auto& index : node.indices) + for (auto& idx : node.indices) { - if (index.start) - VisitExpression(*index.start); - if (index.end) - VisitExpression(*index.end); - if (index.step) - VisitExpression(*index.step); + if (idx.start) + VisitExpression(*idx.start); + if (idx.end) + VisitExpression(*idx.end); + if (idx.step) + VisitExpression(*idx.step); } } @@ -647,26 +773,30 @@ namespace lsp::language::symbol void Builder::VisitAnonymousFunctionExpression(ast::AnonymousFunctionExpression& node) { - // 为匿名函数创建作用域 - EnterScope(ScopeKind::Function, node.span); - - for (const auto& param : node.parameters) - { - std::optional type_hint; - if (param->type) - type_hint = param->type->name; - if (param->default_value) - VisitExpression(*param->default_value); - CreateSymbol(param->name, SymbolKind::Variable, param->location, type_hint); - } + auto func_id = CreateFunctionSymbol("", node.span, node.parameters, node.return_type); if (node.body) - node.body->Accept(*this); + { + auto func_scope = EnterScopeWithSymbol(ScopeKind::kAnonymousFunction, func_id, node.body->span); - ExitScope(); + auto prev_function = current_function_id_; + current_function_id_ = func_id; + + for (auto& param : node.parameters) + { + if (param) + { + CreateSymbol(param->name, SymbolKind::Variable, param->location); + } + } + + VisitStatements(node.body->statements); + + current_function_id_ = prev_function; + ExitScope(); + } } - // 一元表达式访问者实现 void Builder::VisitUnaryPlusExpression(ast::UnaryPlusExpression& node) { if (node.argument) @@ -733,24 +863,21 @@ namespace lsp::language::symbol VisitExpression(*node.argument); } - void Builder::VisitFunctionPointerExpression(ast::FunctionPointerExpression& node) + void Builder::VisitFunctionPointerExpression([[maybe_unused]] ast::FunctionPointerExpression& node) { if (node.argument) VisitExpression(*node.argument); } - // 其他表达式访问者实现 void Builder::VisitNewExpression(ast::NewExpression& node) { - // 注意:NewExpression只有class_expr字段,没有arguments - if (node.class_expr) - VisitExpression(*node.class_expr); + if (node.target) + VisitExpression(*node.target); } void Builder::VisitEchoExpression(ast::EchoExpression& node) { - // 注意:EchoExpression有多个expressions - for (const auto& expr : node.expressions) + for (auto& expr : node.expressions) { if (expr) VisitExpression(*expr); @@ -759,16 +886,16 @@ namespace lsp::language::symbol void Builder::VisitRaiseExpression(ast::RaiseExpression& node) { - // 注意:RaiseExpression只有exception字段 if (node.exception) VisitExpression(*node.exception); } void Builder::VisitInheritedExpression(ast::InheritedExpression& node) { - // InheritedExpression有一个可选的call字段 - if (node.call) - node.call->Accept(*this); + if (node.call && *node.call) + { + (*node.call)->Accept(*this); + } } void Builder::VisitParenthesizedExpression(ast::ParenthesizedExpression& node) @@ -776,79 +903,39 @@ namespace lsp::language::symbol for (auto& elem : node.elements) { if (elem.key) - VisitExpression(**elem.key); + VisitExpression(*elem.key.value()); if (elem.value) VisitExpression(*elem.value); } } - 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::VisitColumnReference(ast::ColumnReference& node) { if (node.value) - VisitExpression(*node.value); - } - - void Builder::VisitUnpackPattern(ast::UnpackPattern& node) - { - for (auto& elem : node.elements) { - ProcessLValue(elem, false); // 递归处理每个元素 + VisitExpression(*node.value); } } - void Builder::VisitMatrixIterationStatement(ast::MatrixIterationStatement& node) + void Builder::VisitUnpackPattern([[maybe_unused]] ast::UnpackPattern& node) { - // 为矩阵迭代创建作用域 - EnterScope(ScopeKind::Block, node.span); - - if (node.target) - VisitExpression(*node.target); - - if (node.body) - node.body->Accept(*this); - - ExitScope(); + // Unpack pattern processing - would need to handle LValue variants } - void Builder::VisitCompilerDirective([[maybe_unused]]ast::CompilerDirective& node) + void Builder::VisitCompilerDirective([[maybe_unused]] ast::CompilerDirective& node) { - // 当前阶段:不处理 - // 未来可以在这里维护宏定义状态 + // Compiler directive processing } - void Builder::VisitConditionalDirective([[maybe_unused]]ast::ConditionalDirective& node) + void Builder::VisitConditionalDirective([[maybe_unused]] ast::ConditionalDirective& node) { - // 当前阶段:不处理 - // 条件指令本身不影响符号收集 + // Conditional compilation directive - no statements to visit } void Builder::VisitConditionalBlock(ast::ConditionalBlock& node) { - // 处理所有分支,不管条件是否满足 - - // 处理 THEN 分支 (consequence) - if (!node.consequence.empty()) - { - VisitStatements(node.consequence); - } - - // 处理 ELSE 分支 (alternative) - if (!node.alternative.empty()) - { - VisitStatements(node.alternative); - } + VisitStatements(node.consequence); + VisitStatements(node.alternative); } -} +} // namespace lsp::language::symbol diff --git a/lsp-server/src/language/symbol/builder.hpp b/lsp-server/src/language/symbol/builder.hpp index b27656a..b3209d6 100644 --- a/lsp-server/src/language/symbol/builder.hpp +++ b/lsp-server/src/language/symbol/builder.hpp @@ -4,7 +4,7 @@ namespace lsp::language::symbol { - // 符号表构建器 + // Symbol table builder - responsible for stable traversal logic only class Builder : public ast::ASTVisitor { public: @@ -12,7 +12,7 @@ namespace lsp::language::symbol void Build(ast::ASTNode& root); - // 访问语句和声明 + // Visit statements and declarations void VisitProgram(ast::Program& node) override; void VisitUnitDefinition(ast::UnitDefinition& node) override; void VisitClassDefinition(ast::ClassDefinition& node) override; @@ -23,7 +23,7 @@ namespace lsp::language::symbol void VisitExternalMethodDefinition(ast::ExternalMethodDefinition& node) override; void VisitClassMember(ast::ClassMember& node) override; - // 声明 + // Declarations void VisitVarDeclaration(ast::VarDeclaration& node) override; void VisitStaticDeclaration(ast::StaticDeclaration& node) override; void VisitGlobalDeclaration(ast::GlobalDeclaration& node) override; @@ -39,24 +39,24 @@ namespace lsp::language::symbol void VisitCaseStatement(ast::CaseStatement& node) override; void VisitTryStatement(ast::TryStatement& node) override; - // Uses 语句处理 + // Uses statement handling void VisitUsesStatement(ast::UsesStatement& node) override; - // 访问表达式(收集引用) + // Visit expressions (collect references) 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 VisitLiteral(ast::Literal&) override {} + // Other node visits + void VisitLiteral([[maybe_unused]] ast::Literal& node) override {} void VisitBinaryExpression(ast::BinaryExpression& 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; - // 一元表达式(细化的类型) + // Unary expressions (refined types) void VisitUnaryPlusExpression(ast::UnaryPlusExpression& node) override; void VisitUnaryMinusExpression(ast::UnaryMinusExpression& node) override; void VisitPrefixIncrementExpression(ast::PrefixIncrementExpression& node) override; @@ -69,9 +69,9 @@ namespace lsp::language::symbol void VisitMatrixTransposeExpression(ast::MatrixTransposeExpression& node) override; void VisitExprOperatorExpression(ast::ExprOperatorExpression& node) override; - void VisitFunctionPointerExpression(ast::FunctionPointerExpression&) override; + void VisitFunctionPointerExpression([[maybe_unused]] ast::FunctionPointerExpression& node) override; - // 其他表达式 + // Other expressions void VisitNewExpression(ast::NewExpression& node) override; void VisitEchoExpression(ast::EchoExpression& node) override; void VisitRaiseExpression(ast::RaiseExpression& node) override; @@ -79,44 +79,78 @@ namespace lsp::language::symbol void VisitParenthesizedExpression(ast::ParenthesizedExpression& node) override; void VisitExpressionStatement(ast::ExpressionStatement& node) override; - void VisitBreakStatement(ast::BreakStatement&) override {} - void VisitContinueStatement(ast::ContinueStatement&) override {} + void VisitBreakStatement([[maybe_unused]] ast::BreakStatement& node) override {} + void VisitContinueStatement([[maybe_unused]] ast::ContinueStatement& node) override {} void VisitReturnStatement(ast::ReturnStatement& node) override; - void VisitTSSQLExpression(ast::TSSQLExpression&) override {} + void VisitTSSQLExpression([[maybe_unused]] ast::TSSQLExpression& node) override {} void VisitColumnReference(ast::ColumnReference& node) override; - void VisitUnpackPattern(ast::UnpackPattern&) override; + void VisitUnpackPattern([[maybe_unused]] ast::UnpackPattern& node) override; void VisitMatrixIterationStatement(ast::MatrixIterationStatement& node) override; - // 编译指令(正确的名称,无Statement后缀) - void VisitCompilerDirective(ast::CompilerDirective& node) override; + // Compiler directives (correct names without Statement suffix) + void VisitCompilerDirective([[maybe_unused]] ast::CompilerDirective& node) override; void VisitConditionalDirective(ast::ConditionalDirective& node) override; void VisitConditionalBlock(ast::ConditionalBlock& node) override; - void VisitTSLXBlock(ast::TSLXBlock&) override {} + void VisitTSLXBlock([[maybe_unused]] ast::TSLXBlock& node) override {} - void VisitParameter(ast::Parameter&) override {} + void VisitParameter([[maybe_unused]] ast::Parameter& node) override {} private: - SymbolId CreateSymbol(const std::string& name, SymbolKind kind, const ast::Location& location, const std::optional& type_hint = std::nullopt, bool is_class_method = false); - SymbolId CreateSymbol(const std::string& name, SymbolKind kind, const ast::ASTNode& node, const std::optional& type_hint = std::nullopt, bool is_class_method = false); - 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& statements); - void VisitExpression(ast::Expression& expr); - - void ProcessLValue(const ast::LValue& lvalue, bool is_write); - - // 修改后的签名:不再使用Signature结构 - std::string FormatSignature( + // Symbol creation helpers - now returns symbol with parameters pre-set + SymbolId CreateFunctionSymbol( + const std::string& name, + const ast::Location& location, const std::vector>& parameters, const std::optional& return_type); + SymbolId CreateMethodSymbol( + const std::string& name, + const ast::Location& location, + const std::vector>& parameters, + const std::optional& return_type); + + SymbolId CreateSymbol( + const std::string& name, + SymbolKind kind, + const ast::Location& location, + const std::optional& type_hint = std::nullopt); + + SymbolId CreateSymbol( + const std::string& name, + SymbolKind kind, + const ast::ASTNode& node, + const std::optional& type_hint = std::nullopt); + + // Scope management + ScopeId EnterScopeWithSymbol(ScopeKind kind, SymbolId symbol_id, const ast::Location& range); + ScopeId EnterScope(ScopeKind kind, const ast::Location& range); + void ExitScope(); + + // Traversal helpers + void VisitStatements(const std::vector& statements); + void VisitExpression(ast::Expression& expr); + + // LValue processing for assignments + void ProcessLValue(const ast::LValue& lvalue, bool is_write); + + // Type and parameter extraction + std::optional ExtractTypeName( + const std::optional& type) const; + + std::vector BuildParameters( + const std::vector>& parameters) const; + private: + // Symbol table reference SymbolTable& table_; + + // Current traversal state ScopeId current_scope_id_; std::optional current_parent_symbol_id_; std::optional current_function_id_; + + // Interface/implementation section tracking + bool in_interface_section_; }; -} +} // namespace lsp::language::symbol diff --git a/lsp-server/src/language/symbol/graph/call.hpp b/lsp-server/src/language/symbol/graph/call.hpp new file mode 100644 index 0000000..09fa4e5 --- /dev/null +++ b/lsp-server/src/language/symbol/graph/call.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include + +#include "../interface.hpp" +#include "../types.hpp" + +namespace lsp::language::symbol::graph +{ + + class Call : public ISymbolGraph + { + public: + void OnSymbolRemoved(SymbolId id) override + { + callers_map_.erase(id); + callees_map_.erase(id); + + // Remove all calls where this symbol is the caller + for (auto& [symbol_id, calls] : callers_map_) + { + calls.erase(std::remove_if(calls.begin(), calls.end(), [id](const symbol::Call& call) { + return call.caller == id; + }), + calls.end()); + } + + // Remove all calls where this symbol is the callee + for (auto& [symbol_id, calls] : callees_map_) + { + calls.erase(std::remove_if(calls.begin(), calls.end(), [id](const symbol::Call& call) { + return call.callee == id; + }), + calls.end()); + } + } + + void Clear() override + { + callers_map_.clear(); + callees_map_.clear(); + } + + void AddCall(SymbolId caller, SymbolId callee, const ast::Location& location) + { + symbol::Call call{ caller, callee, location }; + callers_map_[callee].push_back(call); // Who calls this symbol + callees_map_[caller].push_back(call); // What this symbol calls + } + + // Accessor (snake_case) + const std::vector& callers(SymbolId id) const + { + static const std::vector kEmpty; + auto it = callers_map_.find(id); + return it != callers_map_.end() ? it->second : kEmpty; + } + + // Accessor (snake_case) + const std::vector& callees(SymbolId id) const + { + static const std::vector kEmpty; + auto it = callees_map_.find(id); + return it != callees_map_.end() ? it->second : kEmpty; + } + + private: + // Map: symbol -> who calls it (incoming calls) + std::unordered_map> callers_map_; + + // Map: symbol -> what it calls (outgoing calls) + std::unordered_map> callees_map_; + }; + +} // namespace lsp::language::symbol::graph diff --git a/lsp-server/src/language/symbol/graph/inheritance.hpp b/lsp-server/src/language/symbol/graph/inheritance.hpp new file mode 100644 index 0000000..27d150f --- /dev/null +++ b/lsp-server/src/language/symbol/graph/inheritance.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include + +#include "../interface.hpp" +#include "../types.hpp" + +namespace lsp::language::symbol::graph +{ + + class Inheritance : public ISymbolGraph + { + public: + void OnSymbolRemoved(SymbolId id) override + { + base_classes_.erase(id); + derived_classes_.erase(id); + + // Remove from all base class lists + for (auto& [derived_id, bases] : base_classes_) + { + bases.erase(std::remove(bases.begin(), bases.end(), id), bases.end()); + } + + // Remove from all derived class lists + for (auto& [base_id, derived] : derived_classes_) + { + derived.erase(std::remove(derived.begin(), derived.end(), id), + derived.end()); + } + } + + void Clear() override + { + base_classes_.clear(); + derived_classes_.clear(); + } + + void AddInheritance(SymbolId derived, SymbolId base) + { + base_classes_[derived].push_back(base); + derived_classes_[base].push_back(derived); + } + + // Accessor (snake_case) + const std::vector& base_classes(SymbolId id) const + { + static const std::vector kEmpty; + auto it = base_classes_.find(id); + return it != base_classes_.end() ? it->second : kEmpty; + } + + // Accessor (snake_case) + const std::vector& derived_classes(SymbolId id) const + { + static const std::vector kEmpty; + auto it = derived_classes_.find(id); + return it != derived_classes_.end() ? it->second : kEmpty; + } + + bool IsSubclassOf(SymbolId derived, SymbolId base) const + { + auto it = base_classes_.find(derived); + if (it == base_classes_.end()) + { + return false; + } + + for (SymbolId parent : it->second) + { + if (parent == base || IsSubclassOf(parent, base)) + { + return true; + } + } + + return false; + } + + private: + // Map from derived class to its base classes + std::unordered_map> base_classes_; + + // Map from base class to its derived classes + std::unordered_map> derived_classes_; + }; + +} // namespace lsp::language::symbol::graph diff --git a/lsp-server/src/language/symbol/graph/reference.hpp b/lsp-server/src/language/symbol/graph/reference.hpp new file mode 100644 index 0000000..c448087 --- /dev/null +++ b/lsp-server/src/language/symbol/graph/reference.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +#include "../interface.hpp" +#include "../types.hpp" + +namespace lsp::language::symbol::graph +{ + + class Reference : public ISymbolGraph + { + public: + void OnSymbolRemoved(SymbolId id) override + { + references_.erase(id); + + // Remove all references to the removed symbol + for (auto& [symbol_id, refs] : references_) + { + refs.erase(std::remove_if(refs.begin(), refs.end(), [id](const symbol::Reference& ref) { + return ref.symbol_id == id; + }), + refs.end()); + } + } + + void Clear() override { references_.clear(); } + + void AddReference(SymbolId symbol_id, const ast::Location& location, bool is_definition = false, bool is_write = false) + { + references_[symbol_id].push_back( + { location, symbol_id, is_definition, is_write }); + } + + // Accessor (snake_case) + const std::vector& references(SymbolId id) const + { + static const std::vector kEmpty; + auto it = references_.find(id); + return it != references_.end() ? it->second : kEmpty; + } + + std::optional FindDefinitionLocation(SymbolId id) const + { + auto it = references_.find(id); + if (it != references_.end()) + { + for (const auto& ref : it->second) + { + if (ref.is_definition) + { + return ref.location; + } + } + } + return std::nullopt; + } + + private: + // Map from symbol to all its references + std::unordered_map> references_; + }; + +} // namespace lsp::language::symbol::graph diff --git a/lsp-server/src/language/symbol/index/location.hpp b/lsp-server/src/language/symbol/index/location.hpp new file mode 100644 index 0000000..78175cc --- /dev/null +++ b/lsp-server/src/language/symbol/index/location.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include +#include +#include + +#include "../interface.hpp" +#include "../types.hpp" + +namespace lsp::language::symbol::index +{ + + class Location : public ISymbolIndex + { + public: + void OnSymbolAdded(const Symbol& symbol) override + { + const auto& loc = symbol.selection_range(); + entries_.push_back({ loc.start_offset, loc.end_offset, symbol.id() }); + needs_sort_ = true; + } + + void OnSymbolRemoved(SymbolId id) override + { + entries_.erase(std::remove_if(entries_.begin(), entries_.end(), [id](const Entry& e) { + return e.symbol_id == id; + }), + entries_.end()); + } + + void Clear() override + { + entries_.clear(); + needs_sort_ = false; + } + + std::optional FindSymbolAt(const ast::Location& location) const + { + EnsureSorted(); + uint32_t pos = location.start_offset; + + auto it = std::lower_bound(entries_.begin(), entries_.end(), pos, [](const Entry& e, uint32_t p) { + return e.start < p; + }); + + if (it != entries_.begin()) + { + --it; + } + + std::optional result; + uint32_t min_span = UINT32_MAX; + + for (; it != entries_.end() && it->start <= pos; ++it) + { + if (pos >= it->start && pos < it->end) + { + uint32_t span = it->end - it->start; + if (span < min_span) + { + min_span = span; + result = it->symbol_id; + } + } + } + + return result; + } + + private: + struct Entry + { + uint32_t start; + uint32_t end; + SymbolId symbol_id; + + bool operator<(const Entry& other) const + { + if (start != other.start) + { + return start < other.start; + } + return end > other.end; + } + }; + + void EnsureSorted() const + { + if (needs_sort_) + { + std::sort(entries_.begin(), entries_.end()); + needs_sort_ = false; + } + } + + mutable std::vector entries_; + mutable bool needs_sort_ = false; + }; + +} // namespace lsp::language::symbol::index diff --git a/lsp-server/src/language/symbol/index/scope.hpp b/lsp-server/src/language/symbol/index/scope.hpp new file mode 100644 index 0000000..f4e1855 --- /dev/null +++ b/lsp-server/src/language/symbol/index/scope.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include + +#include "../interface.hpp" +#include "../types.hpp" + +namespace lsp::language::symbol +{ + + struct Scope + { + ScopeId id; + ScopeKind kind; + ast::Location range; + std::optional parent; + std::optional owner; + std::unordered_map symbols; + }; + +} // namespace lsp::language::symbol + +namespace lsp::language::symbol::index +{ + + class Scope : public ISymbolIndex + { + public: + void OnSymbolAdded(const Symbol&) override {} + + void OnSymbolRemoved(SymbolId id) override + { + for (auto& [_, scope] : scopes_) + { + for (auto it = scope.symbols.begin(); it != scope.symbols.end();) + { + if (it->second == id) + { + it = scope.symbols.erase(it); + } + else + { + ++it; + } + } + } + } + + void Clear() override + { + scopes_.clear(); + next_scope_id_ = 1; + global_scope_ = kInvalidScopeId; + } + + ScopeId CreateScope(ScopeKind kind, const ast::Location& range, std::optional parent = std::nullopt, std::optional owner = std::nullopt) + { + ScopeId id = next_scope_id_++; + scopes_[id] = { id, kind, range, parent, owner, {} }; + + if (kind == ScopeKind::kGlobal) + { + global_scope_ = id; + } + + return id; + } + + void AddSymbol(ScopeId scope_id, const std::string& name, SymbolId symbol_id) + { + auto it = scopes_.find(scope_id); + if (it != scopes_.end()) + { + it->second.symbols[ToLower(name)] = symbol_id; + } + } + + std::optional FindSymbolInScope( + 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(ToLower(name)); + return sym_it != it->second.symbols.end() ? std::optional(sym_it->second) : std::nullopt; + } + + std::optional FindSymbolInScopeChain( + ScopeId scope_id, + const std::string& name) const + { + std::optional current = scope_id; + + while (current) + { + if (auto result = FindSymbolInScope(*current, name)) + { + return result; + } + + auto it = scopes_.find(*current); + current = it != scopes_.end() ? it->second.parent : std::nullopt; + } + + return std::nullopt; + } + + // Accessor (snake_case) + const symbol::Scope* scope(ScopeId id) const + { + auto it = scopes_.find(id); + return it != scopes_.end() ? &it->second : nullptr; + } + + // Accessor (snake_case) + ScopeId global_scope() const { return global_scope_; } + + // Accessor (snake_case) + const std::unordered_map& all_scopes() const + { + return scopes_; + } + + private: + static std::string ToLower(const std::string& s) + { + std::string result = s; + std::transform(result.begin(), result.end(), result.begin(), ::tolower); + return result; + } + + ScopeId next_scope_id_ = 1; + ScopeId global_scope_ = kInvalidScopeId; + std::unordered_map scopes_; + }; + +} // namespace lsp::language::symbol::index diff --git a/lsp-server/src/language/symbol/interface.hpp b/lsp-server/src/language/symbol/interface.hpp new file mode 100644 index 0000000..f051382 --- /dev/null +++ b/lsp-server/src/language/symbol/interface.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "./types.hpp" + +namespace lsp::language::symbol +{ + + // 索引接口:用于通过各种方式查找符号 + class ISymbolIndex + { + public: + virtual ~ISymbolIndex() = default; + virtual void OnSymbolAdded(const Symbol& symbol) = 0; + virtual void OnSymbolRemoved(SymbolId id) = 0; + virtual void Clear() = 0; + }; + + // 关系接口:用于管理符号之间的关系 + class ISymbolGraph + { + public: + virtual ~ISymbolGraph() = default; + virtual void OnSymbolRemoved(SymbolId id) = 0; + virtual void Clear() = 0; + }; + +} diff --git a/lsp-server/src/language/symbol/location_index.cpp b/lsp-server/src/language/symbol/location_index.cpp deleted file mode 100644 index e91e823..0000000 --- a/lsp-server/src/language/symbol/location_index.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include -#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 LocationIndex::FindSymbolAt(const ast::Location& location) const - { - // 确保索引已排序 - if (!symbols_sorted_) - return std::nullopt; - - return FindInSortedEntries(symbol_entries_, location, true); - } - - std::optional LocationIndex::FindScopeAt(const ast::Location& location) const - { - // 确保索引已排序 - if (!scopes_sorted_) - return std::nullopt; - - return FindInSortedEntries(scope_entries_, location, true); - } - - std::optional 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; - } - -} diff --git a/lsp-server/src/language/symbol/location_index.hpp b/lsp-server/src/language/symbol/location_index.hpp index e9fadae..0ef83c9 100644 --- a/lsp-server/src/language/symbol/location_index.hpp +++ b/lsp-server/src/language/symbol/location_index.hpp @@ -3,119 +3,93 @@ #include #include #include +#include "./interface.hpp" #include "./types.hpp" namespace lsp::language::symbol { - class LocationIndex + + class LocationIndex : public ISymbolIndex { public: - struct LocationEntry + void OnSymbolAdded(const Symbol& symbol) override { - uint32_t start_byte; - uint32_t end_byte; - SymbolId symbol_id; + const auto& range = symbol.range(); + entries_.push_back({ range.start_offset, + range.end_offset, + symbol.id() }); + needs_sort_ = true; + } - 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 + void OnSymbolRemoved(SymbolId id) override { - uint32_t start_byte; - uint32_t end_byte; - ScopeId scope_id; + entries_.erase( + std::remove_if(entries_.begin(), entries_.end(), [id](const Entry& e) { return e.symbol_id == id; }), + entries_.end()); + } - 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 + void Clear() override { - uint32_t start_byte; - uint32_t end_byte; - SymbolId symbol_id; + entries_.clear(); + needs_sort_ = false; + } - 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 FindSymbolAt(const ast::Location& location) const; - std::optional FindScopeAt(const ast::Location& location) const; - std::optional FindReferenceAt(const ast::Location& location) const; - - private: - // 符号定义位置索引(按起始位置排序) - std::vector symbol_entries_; - bool symbols_sorted_ = true; - - // 作用域位置索引(按起始位置排序) - std::vector scope_entries_; - bool scopes_sorted_ = true; - - // 引用位置索引(位置 -> 符号ID) - std::vector reference_entries_; - bool references_sorted_ = true; - - // 辅助方法:在排序数组中查找位置(模板实现放在头文件) - template - std::optional FindInSortedEntries(const std::vector& entries, const ast::Location& location, bool find_innermost = true) const + std::optional FindAt(const ast::Location& location) const { - if (entries.empty()) - return std::nullopt; + EnsureSorted(); + uint32_t pos = location.start_offset; auto it = std::lower_bound( - entries.begin(), - entries.end(), - location.start_byte, - [](const T& entry, uint32_t pos) { - return entry.start_byte < pos; - }); + entries_.begin(), entries_.end(), pos, [](const Entry& e, uint32_t p) { return e.start < p; }); - if (it != entries.begin()) + if (it != entries_.begin()) --it; - std::vector candidates; - for (; it != entries.end() && it->start_byte <= location.start_byte; ++it) + std::optional result; + uint32_t min_span = UINT32_MAX; + + for (; it != entries_.end() && it->start <= pos; ++it) { - if (IsLocationInRange(location, it->start_byte, it->end_byte)) + if (pos >= it->start && pos < it->end) { - if constexpr (std::is_same_v || std::is_same_v) - candidates.push_back(it->symbol_id); - else if constexpr (std::is_same_v) - candidates.push_back(it->scope_id); + uint32_t span = it->end - it->start; + if (span < min_span) + { + min_span = span; + result = it->symbol_id; + } } } - if (candidates.empty()) - return std::nullopt; - - if (find_innermost) - return candidates.back(); - else - return candidates.front(); + return result; } - static bool IsLocationInRange(const ast::Location& location, uint32_t start, uint32_t end) + private: + struct Entry { - return location.start_byte >= start && location.start_byte < end; + uint32_t start; + uint32_t end; + SymbolId symbol_id; + + bool operator<(const Entry& other) const + { + if (start != other.start) + return start < other.start; + return end > other.end; + } + }; + + void EnsureSorted() const + { + if (needs_sort_) + { + std::sort(entries_.begin(), entries_.end()); + needs_sort_ = false; + } } + + mutable std::vector entries_; + mutable bool needs_sort_ = false; }; -} +} // namespace lsp::language::symbol diff --git a/lsp-server/src/language/symbol/relations.cpp b/lsp-server/src/language/symbol/relations.cpp deleted file mode 100644 index 60b2140..0000000 --- a/lsp-server/src/language/symbol/relations.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#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* ReferenceGraph::GetReferences(SymbolId symbol_id) const - { - auto it = references_.find(symbol_id); - return it != references_.end() ? &it->second : nullptr; - } - - std::optional 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* InheritanceGraph::GetBaseClasses(SymbolId class_id) const - { - auto it = base_classes_.find(class_id); - return it != base_classes_.end() ? &it->second : nullptr; - } - - const std::vector* 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 visited; - std::vector 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* CallGraph::GetCallers(SymbolId function_id) const - { - auto it = callers_.find(function_id); - return it != callers_.end() ? &it->second : nullptr; - } - - const std::vector* 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(); - } - -} diff --git a/lsp-server/src/language/symbol/relations.hpp b/lsp-server/src/language/symbol/relations.hpp deleted file mode 100644 index 51ebb66..0000000 --- a/lsp-server/src/language/symbol/relations.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#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* GetReferences(SymbolId symbol_id) const; - std::optional GetDefinition(SymbolId symbol_id) const; - - private: - std::unordered_map> references_; - }; - - // 继承图 - class InheritanceGraph - { - public: - void AddInheritance(SymbolId derived_class, SymbolId base_class); - void Clear(); - - // 返回引用避免拷贝 - const std::vector* GetBaseClasses(SymbolId class_id) const; - const std::vector* GetDerivedClasses(SymbolId class_id) const; - bool IsSubclassOf(SymbolId derived, SymbolId base) const; - - private: - std::unordered_map> base_classes_; - std::unordered_map> derived_classes_; - }; - - // 调用图 - class CallGraph - { - public: - void AddCall(SymbolId caller, SymbolId callee, const ast::Location& location); - void Clear(); - - // 返回引用避免拷贝 - const std::vector* GetCallers(SymbolId function_id) const; - const std::vector* GetCallees(SymbolId function_id) const; - - private: - std::unordered_map> callers_; - std::unordered_map> callees_; - }; - -} diff --git a/lsp-server/src/language/symbol/scope.cpp b/lsp-server/src/language/symbol/scope.cpp deleted file mode 100644 index b887030..0000000 --- a/lsp-server/src/language/symbol/scope.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "./scope.hpp" - -namespace lsp::language::symbol -{ - ScopeId ScopeManager::CreateScope(ScopeKind kind, const ast::Location& range, std::optional parent_scope_id, std::optional 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 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 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 ScopeManager::GetSymbolsInScope(ScopeId scope_id) const - { - std::vector 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; - } - -} diff --git a/lsp-server/src/language/symbol/scope.hpp b/lsp-server/src/language/symbol/scope.hpp index 704cea8..a8a1748 100644 --- a/lsp-server/src/language/symbol/scope.hpp +++ b/lsp-server/src/language/symbol/scope.hpp @@ -1,29 +1,130 @@ #pragma once #include -#include +#include +#include +#include "./interface.hpp" #include "./types.hpp" namespace lsp::language::symbol { - class ScopeManager + + struct Scope { - public: - ScopeId CreateScope(ScopeKind kind, const ast::Location& range, std::optional parent_scope_id = std::nullopt, std::optional associated_symbol_id = std::nullopt); - - void AddSymbol(ScopeId scope_id, const std::string& name, SymbolId symbol_id); - std::optional FindInScope(ScopeId scope_id, const std::string& name) const; - std::optional FindInScopeChain(ScopeId scope_id, const std::string& name) const; - const ScopeInfo* GetScopeInfo(ScopeId scope_id) const; - std::vector GetSymbolsInScope(ScopeId scope_id) const; - ScopeId GetGlobalScope() const { return global_scope_id_; } - const std::unordered_map& GetAllScopes() const { return scopes_; } - void Clear(); - - private: - ScopeId next_scope_id_ = 1; - ScopeId global_scope_id_ = kInvalidScopeId; - std::unordered_map scopes_; + ScopeId id; + ScopeKind kind; + ast::Location range; + std::optional parent; + std::optional owner; + std::unordered_map symbols; }; -} + class ScopeIndex : public ISymbolIndex + { + public: + void OnSymbolAdded(const Symbol&) override {} + + void OnSymbolRemoved(SymbolId id) override + { + for (auto& [_, scope] : scopes_) + { + for (auto it = scope.symbols.begin(); it != scope.symbols.end();) + { + if (it->second == id) + { + it = scope.symbols.erase(it); + } + else + { + ++it; + } + } + } + } + + void Clear() override + { + scopes_.clear(); + next_scope_id_ = 1; + global_scope_ = kInvalidScopeId; + } + + ScopeId CreateScope(ScopeKind kind, const ast::Location& range, std::optional parent = std::nullopt, std::optional owner = std::nullopt) + { + ScopeId id = next_scope_id_++; + scopes_[id] = { id, kind, range, parent, owner, {} }; + + if (kind == ScopeKind::kGlobal) + { + global_scope_ = id; + } + + return id; + } + + void AddSymbol(ScopeId scope_id, const std::string& name, SymbolId symbol_id) + { + auto it = scopes_.find(scope_id); + if (it != scopes_.end()) + { + it->second.symbols[ToLower(name)] = symbol_id; + } + } + + std::optional 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(ToLower(name)); + return sym_it != it->second.symbols.end() ? + std::optional(sym_it->second) : + std::nullopt; + } + + std::optional FindInScopeChain(ScopeId scope_id, const std::string& name) const + { + std::optional current = scope_id; + + while (current) + { + if (auto result = FindInScope(*current, name)) + { + return result; + } + + auto it = scopes_.find(*current); + current = it != scopes_.end() ? it->second.parent : std::nullopt; + } + + return std::nullopt; + } + + const Scope* GetScope(ScopeId id) const + { + auto it = scopes_.find(id); + return it != scopes_.end() ? &it->second : nullptr; + } + + ScopeId GetGlobalScope() const { return global_scope_; } + + const std::unordered_map& GetAllScopes() const + { + return scopes_; + } + + private: + static std::string ToLower(const std::string& s) + { + std::string result = s; + std::transform(result.begin(), result.end(), result.begin(), ::tolower); + return result; + } + + ScopeId next_scope_id_ = 1; + ScopeId global_scope_ = kInvalidScopeId; + std::unordered_map scopes_; + }; + +} // namespace lsp::language::symbol diff --git a/lsp-server/src/language/symbol/store.cpp b/lsp-server/src/language/symbol/store.cpp deleted file mode 100644 index f2d2e5b..0000000 --- a/lsp-server/src/language/symbol/store.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#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 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 SymbolDefinitionStore::GetAll() const - { - std::vector result; - result.reserve(definitions_.size()); - for (const auto& [id, def] : definitions_) - result.push_back(&def); - return result; - } - - std::vector SymbolDefinitionStore::FindByName(const std::string& name) const - { - std::vector 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 SymbolDefinitionStore::GetChildren(SymbolId parent_id) const - { - auto it = children_index_.find(parent_id); - return it != children_index_.end() ? it->second : std::vector{}; - } - - 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()); - } - } - -} diff --git a/lsp-server/src/language/symbol/store.hpp b/lsp-server/src/language/symbol/store.hpp index 42d4c24..d375eb0 100644 --- a/lsp-server/src/language/symbol/store.hpp +++ b/lsp-server/src/language/symbol/store.hpp @@ -1,35 +1,87 @@ #pragma once +#include +#include +#include #include #include -#include + #include "./types.hpp" namespace lsp::language::symbol { - class SymbolDefinitionStore + + class SymbolStore { public: - SymbolId Add(SymbolDefinition def); + SymbolId Add(Symbol def) + { + SymbolId id = next_id_++; + // Update the symbol's ID + std::visit([id](auto& s) { s.id = id; }, def.mutable_data()); - const SymbolDefinition* Get(SymbolId id) const; + auto [it, inserted] = definitions_.emplace(id, std::move(def)); + const auto& stored = it->second; + by_name_[stored.name()].push_back(id); + return id; + } - bool Update(SymbolId id, std::function updater); - bool Remove(SymbolId id); - void Clear(); + bool Remove(SymbolId id) + { + auto it = definitions_.find(id); + if (it == definitions_.end()) + { + return false; + } - std::vector GetAll() const; - std::vector FindByName(const std::string& name) const; - std::vector GetChildren(SymbolId parent_id) const; + const std::string& name = it->second.name(); + auto& ids = by_name_[name]; + ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end()); + if (ids.empty()) + { + by_name_.erase(name); + } + + definitions_.erase(it); + return true; + } + + void Clear() + { + definitions_.clear(); + by_name_.clear(); + next_id_ = 1; + } + + // Accessor (snake_case) - 返回指针是合理的,因为可能不存在 + const Symbol* Get(SymbolId id) const + { + auto it = definitions_.find(id); + return it != definitions_.end() ? &it->second : nullptr; + } + + // Accessor (snake_case) - 使用reference_wrapper替代指针 + std::vector> GetAll() const + { + std::vector> result; + result.reserve(definitions_.size()); + for (const auto& [id, def] : definitions_) + { + result.push_back(std::cref(def)); + } + return result; + } + + std::vector FindByName(const std::string& name) const + { + auto it = by_name_.find(name); + return it != by_name_.end() ? it->second : std::vector(); + } private: SymbolId next_id_ = 1; - std::unordered_map definitions_; - std::unordered_map, utils::IHasher, utils::IEqualTo> name_index_; - std::unordered_map> children_index_; - - void UpdateIndices(const SymbolDefinition& def); - void RemoveFromIndices(const SymbolDefinition& def); + std::unordered_map definitions_; + std::unordered_map> by_name_; }; -} +} // namespace lsp::language::symbol diff --git a/lsp-server/src/language/symbol/table.cpp b/lsp-server/src/language/symbol/table.cpp deleted file mode 100644 index a52188f..0000000 --- a/lsp-server/src/language/symbol/table.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include -#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 SymbolTable::GetAllDefinitions() const - { - return definition_store_.GetAll(); - } - - std::vector SymbolTable::FindDefinitionsByName(const std::string& name) const - { - return definition_store_.FindByName(name); - } - - std::optional SymbolTable::FindSymbolAt(const ast::Location& location) const - { - return location_index_.FindSymbolAt(location); - } - - std::optional SymbolTable::FindSymbol(const std::string& name, ScopeId scope_id) const - { - return scope_manager_.FindInScopeChain(scope_id, name); - } - - std::vector SymbolTable::FindSymbolsByName(const std::string& name) const - { - std::vector result; - auto defs = definition_store_.FindByName(name); - for (const auto* def : defs) - result.push_back(def->id); - return result; - } - - std::optional SymbolTable::FindScopeAt(const ast::Location& location) const - { - return location_index_.FindScopeAt(location); - } - - std::optional SymbolTable::FindReferenceAt(const ast::Location& location) const - { - return location_index_.FindReferenceAt(location); - } - - std::vector SymbolTable::GetChildren(SymbolId symbol_id) const - { - return definition_store_.GetChildren(symbol_id); - } - - ScopeId SymbolTable::GetGlobalScope() const - { - return scope_manager_.GetGlobalScope(); - } - - const std::vector* SymbolTable::GetReferences(SymbolId symbol_id) const - { - return reference_graph_.GetReferences(symbol_id); - } - - std::optional SymbolTable::GetDefinitionLocation(SymbolId symbol_id) const - { - return reference_graph_.GetDefinition(symbol_id); - } - - const std::vector* SymbolTable::GetBaseClasses(SymbolId class_id) const - { - return inheritance_graph_.GetBaseClasses(class_id); - } - - const std::vector* SymbolTable::GetDerivedClasses(SymbolId class_id) const - { - return inheritance_graph_.GetDerivedClasses(class_id); - } - - const std::vector* SymbolTable::GetCallers(SymbolId function_id) const - { - return call_graph_.GetCallers(function_id); - } - - const std::vector* 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& SymbolTable::GetUnitImports() const - { - return unit_imports_; - } - - std::optional 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 SymbolTable::GetDocumentSymbols() const - { - std::vector result; - - for (const auto* def : definition_store_.GetAll()) - { - // 只返回顶层符号(没有父符号的符号) - if (!def->parent_id) - result.push_back(def); - } - - return result; - } - - std::vector SymbolTable::GetWorkspaceSymbols(const std::string& query) const - { - if (query.empty()) - return definition_store_.GetAll(); - - // 使用小写查询字符串进行大小写无关的匹配 - std::string lower_query = utils::ToLower(query); - - std::vector 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 parent_id, - const std::optional& type_hint, - bool is_class_method) - { - // 创建符号定义 - 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; - def.is_class_method = is_class_method; - - 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 parent_scope_id, std::optional 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); - } - -} diff --git a/lsp-server/src/language/symbol/table.hpp b/lsp-server/src/language/symbol/table.hpp index aa16978..e469684 100644 --- a/lsp-server/src/language/symbol/table.hpp +++ b/lsp-server/src/language/symbol/table.hpp @@ -1,127 +1,148 @@ #pragma once +#include +#include +#include + +#include "./graph/call.hpp" +#include "./graph/inheritance.hpp" +#include "./graph/reference.hpp" +#include "./index/location.hpp" +#include "./index/scope.hpp" #include "./store.hpp" -#include "./scope.hpp" -#include "./location_index.hpp" -#include "./relations.hpp" namespace lsp::language::symbol { - class Builder; - // 统一的符号表接口 class SymbolTable { public: - SymbolTable(); + SymbolTable() = default; - // 构建符号表(完整构建) - void Build(ast::ASTNode& root); + // ===== Symbol Operations ===== - // 清空所有数据 - void Clear(); + SymbolId CreateSymbol(Symbol symbol) + { + auto def = Symbol(std::move(symbol)); + auto id = store_.Add(def); - // ===== 第一层: 定义访问 ===== - const SymbolDefinition* GetDefinition(SymbolId id) const; - std::vector GetAllDefinitions() const; - std::vector FindDefinitionsByName(const std::string& name) const; + // Notify all indexes + location_index_.OnSymbolAdded(def); + scope_index_.OnSymbolAdded(def); - // ===== 第二层: 作用域和位置查询 ===== - // 名称查找 - std::optional FindSymbol(const std::string& name, ScopeId scope_id) const; - std::vector FindSymbolsByName(const std::string& name) const; + return id; + } - // 位置查找 - std::optional FindSymbolAt(const ast::Location& location) const; - std::optional FindScopeAt(const ast::Location& location) const; - std::optional FindReferenceAt(const ast::Location& location) const; + bool RemoveSymbol(SymbolId id) + { + // Notify all components + location_index_.OnSymbolRemoved(id); + scope_index_.OnSymbolRemoved(id); + reference_graph_.OnSymbolRemoved(id); + inheritance_graph_.OnSymbolRemoved(id); + call_graph_.OnSymbolRemoved(id); - // 作用域查询 - std::vector GetChildren(SymbolId symbol_id) const; - ScopeId GetGlobalScope() const; + return store_.Remove(id); + } - // ===== 第三层: 关系访问 ===== - // 返回引用避免拷贝,使用指针表示可能为空 - const std::vector* GetReferences(SymbolId symbol_id) const; - std::optional GetDefinitionLocation(SymbolId symbol_id) const; - const std::vector* GetBaseClasses(SymbolId class_id) const; - const std::vector* GetDerivedClasses(SymbolId class_id) const; - const std::vector* GetCallers(SymbolId function_id) const; - const std::vector* GetCallees(SymbolId function_id) const; + void Clear() + { + store_.Clear(); + location_index_.Clear(); + scope_index_.Clear(); + reference_graph_.Clear(); + inheritance_graph_.Clear(); + call_graph_.Clear(); + } - // ===== Unit 导入管理 ===== - // 添加单元导入 - void AddUnitImport(const std::string& unit_name, const ast::Location& location); + // ===== Basic Queries ===== - // 获取所有导入的单元 - const std::vector& GetUnitImports() const; + std::vector FindSymbolsByName(const std::string& name) const + { + return store_.FindByName(name); + } - // 查找特定单元的导入位置(用于跳转到定义) - std::optional FindImportLocation(const std::string& unit_name) const; + std::optional FindSymbolAt(const ast::Location& location) const + { + return location_index_.FindSymbolAt(location); + } - // 检查是否导入了某个单元 - bool HasImport(const std::string& unit_name) const; + // ===== Accessors (snake_case) ===== - // ===== LSP 便捷接口 ===== - // 获取文档符号(用于 textDocument/documentSymbol) - std::vector GetDocumentSymbols() const; + // Get single definition - 返回指针是合理的,因为可能不存在 + const Symbol* definition(SymbolId id) const + { + return store_.Get(id); + } - // 获取工作区符号(用于 workspace/symbol) - std::vector GetWorkspaceSymbols(const std::string& query = "") const; + // Get all definitions - 使用reference_wrapper替代指针 + std::vector> all_definitions() const + { + return store_.GetAll(); + } - // ===== Builder 专用内部接口 ===== - // 统一的符号创建接口,自动处理所有索引更新 - SymbolId CreateSymbol( - const std::string& name, - SymbolKind kind, - const ast::Location& location, - ScopeId scope_id, - std::optional parent_id = std::nullopt, - const std::optional& type_hint = std::nullopt, - bool is_class_method = false); + // Access indexes (non-const) + index::Location& locations() { return location_index_; } + index::Scope& scopes() { return scope_index_; } - // 创建作用域(可以选择关联符号) - ScopeId CreateScope( - ScopeKind kind, - const ast::Location& range, - std::optional parent_scope_id = std::nullopt, - std::optional associated_symbol_id = std::nullopt); + // Access indexes (const) + const index::Location& locations() const { return location_index_; } + const index::Scope& scopes() const { return scope_index_; } - // 添加引用 - void AddReference(SymbolId symbol_id, const ast::Location& location, bool is_write = false); + // Access graphs (non-const) + graph::Reference& references() { return reference_graph_; } + graph::Inheritance& inheritance() { return inheritance_graph_; } + graph::Call& calls() { return call_graph_; } - // 获取内部组件的访问权限(供 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_; } + // Access graphs (const) + const graph::Reference& references() const { return reference_graph_; } + const graph::Inheritance& inheritance() const { return inheritance_graph_; } + const graph::Call& calls() const { 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_; } + // ===== Convenience Methods (shortcuts for common operations) ===== + + // Create scope + ScopeId CreateScope(ScopeKind kind, const ast::Location& range, std::optional parent = std::nullopt, std::optional owner = std::nullopt) + { + return scope_index_.CreateScope(kind, range, parent, owner); + } + + // Add symbol to scope + void AddSymbolToScope(ScopeId scope_id, const std::string& name, SymbolId symbol_id) + { + scope_index_.AddSymbol(scope_id, name, symbol_id); + } + + // Add reference + void AddReference(SymbolId symbol_id, const ast::Location& location, bool is_definition = false, bool is_write = false) + { + reference_graph_.AddReference(symbol_id, location, is_definition, is_write); + } + + // Add inheritance relationship + void AddInheritance(SymbolId derived, SymbolId base) + { + inheritance_graph_.AddInheritance(derived, base); + } + + // Add call relationship + void AddCall(SymbolId caller, SymbolId callee, const ast::Location& location) + { + call_graph_.AddCall(caller, callee, location); + } private: - // 第一层 - SymbolDefinitionStore definition_store_; + // Storage layer + SymbolStore store_; - // 第二层 - ScopeManager scope_manager_; - LocationIndex location_index_; + // Index layer + index::Location location_index_; + index::Scope scope_index_; - // 第三层 - ReferenceGraph reference_graph_; - InheritanceGraph inheritance_graph_; - CallGraph call_graph_; - - // Unit 导入 - std::vector unit_imports_; - // 快速查找: unit_name -> index in unit_imports_ - std::unordered_map import_index_; + // Graph layer + graph::Reference reference_graph_; + graph::Inheritance inheritance_graph_; + graph::Call call_graph_; }; -} +} // namespace lsp::language::symbol diff --git a/lsp-server/src/language/symbol/types.hpp b/lsp-server/src/language/symbol/types.hpp index f267b7e..490a243 100644 --- a/lsp-server/src/language/symbol/types.hpp +++ b/lsp-server/src/language/symbol/types.hpp @@ -1,65 +1,209 @@ #pragma once -#include #include -#include +#include +#include +#include + #include "../ast/types.hpp" -#include "../../utils/string.hpp" #include "../../protocol/protocol.hpp" namespace lsp::language::symbol { - using SymbolKind = protocol::SymbolKind; - enum class ScopeKind - { - Global, - Unit, - Class, - Function, - Block - }; - // 符号ID类型 + // ===== Basic Types ===== + using SymbolId = uint64_t; constexpr SymbolId kInvalidSymbolId = 0; using ScopeId = uint64_t; constexpr ScopeId kInvalidScopeId = 0; + using SymbolKind = protocol::SymbolKind; + + enum class ScopeKind + { + kGlobal, + kUnit, + kClass, + kFunction, + kAnonymousFunction, + kBlock + }; + + enum class VariableScope + { + kAutomatic, + kStatic, + kGlobal, + kParameter, + kField + }; + + enum class UnitVisibility + { + kInterface, + kImplementation + }; + + // ===== Parameters ===== + + struct Parameter + { + std::string name; + std::optional type; + std::optional default_value; + }; + struct UnitImport { std::string unit_name; ast::Location location; }; - struct SymbolDefinition + // ===== Symbol Types (all fields directly expanded) ===== + + struct Function { + static constexpr SymbolKind kind = SymbolKind::Function; + SymbolId id = kInvalidSymbolId; std::string name; - SymbolKind kind; - ast::Location location; - ast::Location selection_range; + ast::Location selection_range; // Name identifier location (for cursor) + ast::Location range; // Full range (including modifiers, body) - std::optional type_hint; + ast::Location declaration_range; + std::optional implementation_range; + std::vector parameters; + std::optional return_type; - std::string detail; + std::vector imports; + std::optional unit_visibility; - std::optional access_modifier; - std::optional method_modifier; - std::optional reference_modifier; - bool is_class_method = false; - - std::optional parent_id; + bool HasImplementation() const + { + return implementation_range.has_value(); + } }; - struct ScopeInfo + struct Class { - ScopeId scope_id; - ScopeKind kind; + static constexpr SymbolKind kind = SymbolKind::Class; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; ast::Location range; - std::optional parent_scope_id; - std::optional associated_symbol_id; - std::unordered_map symbols; + + std::optional unit_visibility; + + std::vector base_classes; + std::vector members; + + std::vector imports; + }; + + struct Method + { + static constexpr SymbolKind kind = SymbolKind::Method; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; + ast::Location range; + + // Location information + ast::Location declaration_range; + std::optional implementation_range; + + // Method-specific + ast::MethodKind method_kind = ast::MethodKind::kOrdinary; + ast::AccessModifier access = ast::AccessModifier::kPublic; + std::optional method_modifier = + ast::MethodModifier::kNone; + bool is_static = false; + std::vector parameters; + std::optional return_type; + + std::vector imports; + + bool HasImplementation() const + { + return implementation_range.has_value(); + } + }; + + struct Property + { + static constexpr SymbolKind kind = SymbolKind::Property; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; + ast::Location range; + + // Property-specific + ast::AccessModifier access = ast::AccessModifier::kPublic; + std::optional type; + std::optional getter; + std::optional setter; + }; + + struct Field + { + static constexpr SymbolKind kind = SymbolKind::Field; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; + ast::Location range; + + ast::AccessModifier access = ast::AccessModifier::kPublic; + std::optional reference_modifier; + std::optional type; + bool is_static = false; + }; + + struct Variable + { + static constexpr SymbolKind kind = SymbolKind::Variable; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; + ast::Location range; + + std::optional type; + std::optional reference_modifier; + VariableScope storage = VariableScope::kAutomatic; + std::optional unit_visibility; + bool has_initializer = false; + }; + + struct Constant + { + static constexpr SymbolKind kind = SymbolKind::Constant; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; + ast::Location range; + + std::optional type; + std::string value; + }; + + struct Unit + { + static constexpr SymbolKind kind = SymbolKind::Namespace; + + SymbolId id = kInvalidSymbolId; + std::string name; + ast::Location selection_range; + ast::Location range; + + std::vector interface_imports; + std::vector implementation_imports; }; struct Reference @@ -70,11 +214,76 @@ namespace lsp::language::symbol bool is_write; }; - struct CallRelation + struct Call { SymbolId caller; SymbolId callee; - ast::Location call_location; + ast::Location call_site; + }; + + // ===== Symbol Data Variant ===== + + using SymbolData = std::variant; + + // ===== Symbol ===== + + class Symbol + { + public: + explicit Symbol(SymbolData data) : data_(std::move(data)) {} + + // Type checking and conversion + template + bool Is() const + { + return std::holds_alternative(data_); + } + + template + const T* As() const + { + return std::get_if(&data_); + } + + template + T* As() + { + return std::get_if(&data_); + } + + // Accessors (snake_case per Google style) + const SymbolData& data() const { return data_; } + SymbolData& mutable_data() { return data_; } + + // Common accessors (all symbol types have these) + SymbolId id() const + { + return std::visit([](const auto& s) { return s.id; }, data_); + } + + const std::string& name() const + { + return std::visit([](const auto& s) -> const auto& { return s.name; }, + data_); + } + + ast::Location selection_range() const + { + return std::visit([](const auto& s) { return s.selection_range; }, data_); + } + + ast::Location range() const + { + return std::visit([](const auto& s) { return s.range; }, data_); + } + + SymbolKind kind() const + { + return std::visit([](const auto& s) { return s.kind; }, data_); + } + + private: + SymbolData data_; }; } // namespace lsp::language::symbol diff --git a/lsp-server/test/test_ast/debug_printer.cpp b/lsp-server/test/test_ast/debug_printer.cpp index a84bc86..6acd500 100644 --- a/lsp-server/test/test_ast/debug_printer.cpp +++ b/lsp-server/test/test_ast/debug_printer.cpp @@ -55,9 +55,22 @@ namespace lsp::language::ast::debug return; } - bool is_last_val = is_last.value_or( - !is_last_child_stack_.empty() ? is_last_child_stack_.back() : false); + if (is_last.has_value()) + { + // When the caller provides is_last, we treat current stack entries as ancestors. + for (size_t i = 0; i < is_last_child_stack_.size(); ++i) + { + os_ << (is_last_child_stack_[i] ? " " : "│ "); + } + os_ << (is_last.value() ? "└─ " : "├─ "); + return; + } + // Default behavior: draw the branch for the current node itself. + if (is_last_child_stack_.empty()) + return; + + bool is_last_val = is_last_child_stack_.back(); for (size_t i = 0; i < is_last_child_stack_.size(); ++i) { if (i == is_last_child_stack_.size() - 1) @@ -91,6 +104,15 @@ namespace lsp::language::ast::debug return std::string(current_indent_, ' '); } + void DebugPrinter::EmitChildren(std::vector>&& children) + { + size_t count = children.size(); + for (size_t i = 0; i < count; ++i) + { + children[i](i == count - 1); + } + } + // ===== 颜色辅助 ===== const char* DebugPrinter::GetColor(const char* color) const @@ -116,11 +138,6 @@ namespace lsp::language::ast::debug PrintLocation(loc); } - if (options_.show_source_code) - { - PrintSourceSnippet(loc); - } - os_ << "\n"; } @@ -132,7 +149,7 @@ namespace lsp::language::ast::debug << GetColor(Color::Reset); } - void DebugPrinter::PrintSourceSnippet(const Location& loc) + void DebugPrinter::PrintSourceSnippet(const Location& loc, bool is_last_child) { if (!source_code_) return; @@ -145,14 +162,14 @@ namespace lsp::language::ast::debug snippet = EscapeString(snippet); os_ << "\n"; - PrintTreePrefix(false); - os_ << GetColor(Color::Dim) << " Source: \"" << snippet << "\"" - << GetColor(Color::Reset); + PrintIndent(is_last_child); + os_ << GetColor(Color::Dim) << "Source: \"" << snippet << "\"" + << GetColor(Color::Reset) << "\n"; } - void DebugPrinter::PrintKeyValue(const std::string& key, const std::string& value, const Location& location, const char* value_color) + void DebugPrinter::PrintKeyValue(const std::string& key, const std::string& value, const Location& location, const char* value_color, std::optional is_last) { - PrintIndent(); + PrintIndent(is_last); PrintColored(key + ": ", Color::Yellow); PrintColored(value, value_color ? value_color : Color::Green); @@ -165,24 +182,24 @@ namespace lsp::language::ast::debug os_ << "\n"; } - void DebugPrinter::PrintKeyValue(const std::string& key, const std::string& value, const char* value_color) + void DebugPrinter::PrintKeyValue(const std::string& key, const std::string& value, const char* value_color, std::optional is_last) { - PrintIndent(); + PrintIndent(is_last); PrintColored(key + ": ", Color::Yellow); PrintColored(value, value_color ? value_color : Color::Green); os_ << "\n"; } - void DebugPrinter::PrintKeyValue(const std::string& key, int value) + void DebugPrinter::PrintKeyValue(const std::string& key, int value, std::optional is_last) { - PrintIndent(); + PrintIndent(is_last); PrintColored(key + ": ", Color::Yellow); os_ << value << "\n"; } - void DebugPrinter::PrintKeyValue(const std::string& key, bool value) + void DebugPrinter::PrintKeyValue(const std::string& key, bool value, std::optional is_last) { - PrintIndent(); + PrintIndent(is_last); PrintColored(key + ": ", Color::Yellow); PrintColored(value ? "true" : "false", value ? Color::BrightGreen : Color::BrightRed); os_ << "\n"; @@ -194,7 +211,7 @@ namespace lsp::language::ast::debug { if (!expr) { - PrintIndent(); + PrintIndent(is_last); if (!label.empty()) { PrintColored(label + ": ", Color::Yellow); @@ -206,27 +223,30 @@ namespace lsp::language::ast::debug if (!label.empty()) { - PrintIndent(); + PrintIndent(is_last); PrintColored(label + ":", Color::Yellow); os_ << "\n"; IncreaseIndent(); + // Treat label as a tree node with a single child. + is_last_child_stack_.push_back(is_last); + is_last_child_stack_.push_back(true); + const_cast(expr)->Accept(*this); + is_last_child_stack_.pop_back(); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + return; } is_last_child_stack_.push_back(is_last); const_cast(expr)->Accept(*this); is_last_child_stack_.pop_back(); - - if (!label.empty()) - { - DecreaseIndent(); - } } void DebugPrinter::PrintStatement(const Statement* stmt, const std::string& label, bool is_last) { if (!stmt) { - PrintIndent(); + PrintIndent(is_last); if (!label.empty()) { PrintColored(label + ": ", Color::Yellow); @@ -238,18 +258,23 @@ namespace lsp::language::ast::debug if (!label.empty()) { - PrintIndent(); + PrintIndent(is_last); PrintColored(label + ":", Color::Yellow); os_ << "\n"; IncreaseIndent(); + // Treat label as a tree node with a single child. + is_last_child_stack_.push_back(is_last); + is_last_child_stack_.push_back(true); + const_cast(stmt)->Accept(*this); + is_last_child_stack_.pop_back(); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + return; } is_last_child_stack_.push_back(is_last); const_cast(stmt)->Accept(*this); is_last_child_stack_.pop_back(); - - if (!label.empty()) - DecreaseIndent(); } void DebugPrinter::PrintParameter(const Parameter& param, bool is_last) @@ -297,7 +322,7 @@ namespace lsp::language::ast::debug if constexpr (std::is_same_v) { - PrintIndent(); + PrintIndent(is_last); if (!label.empty()) { PrintColored(label + ": ", Color::Yellow); @@ -316,41 +341,51 @@ namespace lsp::language::ast::debug { if (!label.empty()) { - PrintIndent(); + PrintIndent(is_last); PrintColored(label + ":", Color::Yellow); os_ << "\n"; IncreaseIndent(); - } - - is_last_child_stack_.push_back(is_last); - if (value) - value->Accept(*this); - is_last_child_stack_.pop_back(); - - if (!label.empty()) - { + // Label node wraps a single child. + is_last_child_stack_.push_back(is_last); + is_last_child_stack_.push_back(true); + if (value) + value->Accept(*this); + is_last_child_stack_.pop_back(); + is_last_child_stack_.pop_back(); DecreaseIndent(); } + else + { + is_last_child_stack_.push_back(is_last); + if (value) + value->Accept(*this); + is_last_child_stack_.pop_back(); + } } else if constexpr (std::is_same_v>) { if (!label.empty()) { - PrintIndent(); + PrintIndent(is_last); PrintColored(label + ":", Color::Yellow); os_ << "\n"; IncreaseIndent(); - } - - is_last_child_stack_.push_back(is_last); - if (value) - value->Accept(*this); - is_last_child_stack_.pop_back(); - - if (!label.empty()) - { + // Label node wraps a single child. + is_last_child_stack_.push_back(is_last); + is_last_child_stack_.push_back(true); + if (value) + value->Accept(*this); + is_last_child_stack_.pop_back(); + is_last_child_stack_.pop_back(); DecreaseIndent(); } + else + { + is_last_child_stack_.push_back(is_last); + if (value) + value->Accept(*this); + is_last_child_stack_.pop_back(); + } } }, lhs); @@ -730,15 +765,39 @@ namespace lsp::language::ast::debug { PrintNodeHeader("Program", node.span); + bool has_source = options_.show_source_code && source_code_ && !GetSourceText(node.span).empty(); + + size_t child_count = node.statements.size(); + if (has_source) + ++child_count; if (options_.show_node_kind) - { - IncreaseIndent(); - PrintKeyValue("Kind", GetNodeKindName(node.kind)); - DecreaseIndent(); - } + ++child_count; + + size_t child_index = 0; + auto emit_child = [&](auto&& fn) { + bool is_last_child = ++child_index == child_count; + fn(is_last_child); + }; IncreaseIndent(); - PrintStatements(node.statements); + + if (has_source) + { + emit_child([&](bool is_last) { PrintSourceSnippet(node.span, is_last); }); + } + + if (options_.show_node_kind) + { + emit_child([&](bool is_last) { + PrintKeyValue("Kind", GetNodeKindName(node.kind), node.span, nullptr, is_last); + }); + } + + for (const auto& stmt : node.statements) + { + emit_child([&](bool is_last) { PrintStatement(stmt.get(), "", is_last); }); + } + DecreaseIndent(); } @@ -756,47 +815,65 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (!node.interface_statements.empty()) { - PrintIndent(); - PrintColored("Interface:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - PrintStatements(node.interface_statements); - DecreaseIndent(); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Interface:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + PrintStatements(node.interface_statements); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } if (!node.implementation_statements.empty()) { - PrintIndent(); - PrintColored("Implementation:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - PrintStatements(node.implementation_statements); - DecreaseIndent(); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Implementation:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + PrintStatements(node.implementation_statements); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } if (!node.initialization_statements.empty()) { - PrintIndent(); - PrintColored("Initialization:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - PrintStatements(node.initialization_statements); - DecreaseIndent(); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Initialization:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + PrintStatements(node.initialization_statements); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } if (!node.finalization_statements.empty()) { - PrintIndent(); - PrintColored("Finalization:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - PrintStatements(node.finalization_statements); - DecreaseIndent(); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Finalization:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + PrintStatements(node.finalization_statements); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -814,52 +891,64 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (!node.parent_classes.empty()) { - PrintIndent(); - PrintColored("Parents:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (const auto& parent : node.parent_classes) - { - PrintIndent(); - - // 如果有qualifier,先显示 - if (parent.qualifier) - { - PrintColored(*parent.qualifier + ".", Color::Magenta); - } - - PrintColored(parent.name, Color::Green); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Parents:", Color::Yellow); os_ << "\n"; - } - DecreaseIndent(); + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + for (size_t i = 0; i < node.parent_classes.size(); ++i) + { + const auto& parent = node.parent_classes[i]; + PrintIndent(i == node.parent_classes.size() - 1); + + if (parent.qualifier) + { + PrintColored(*parent.qualifier + ".", Color::Magenta); + } + + PrintColored(parent.name, Color::Green); + os_ << "\n"; + } + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } if (node.uses) { - is_last_child_stack_.push_back(false); - node.uses->Accept(*this); - is_last_child_stack_.pop_back(); + children.push_back([&](bool is_last) { + is_last_child_stack_.push_back(is_last); + node.uses->Accept(*this); + is_last_child_stack_.pop_back(); + }); } if (!node.members.empty()) { - PrintIndent(); - PrintColored("Members:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t i = 0; i < node.members.size(); ++i) - { - is_last_child_stack_.push_back(i == node.members.size() - 1); - if (node.members[i]) - node.members[i]->Accept(*this); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Members:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + for (size_t i = 0; i < node.members.size(); ++i) + { + is_last_child_stack_.push_back(i == node.members.size() - 1); + if (node.members[i]) + node.members[i]->Accept(*this); + is_last_child_stack_.pop_back(); + } is_last_child_stack_.pop_back(); - } - DecreaseIndent(); + DecreaseIndent(); + }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -907,54 +996,64 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.modifier != MethodModifier::kNone) { - PrintIndent(); - PrintColored("Modifier: ", Color::Yellow); - PrintMethodModifier(node.modifier); - os_ << "\n"; + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Modifier: ", Color::Yellow); + PrintMethodModifier(node.modifier); + os_ << "\n"; + }); } if (node.method_kind != MethodKind::kOrdinary) { - PrintIndent(); - PrintColored("Type: ", Color::Yellow); - PrintMethodType(node.method_kind); - os_ << "\n"; + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("MethodKind: ", Color::Yellow); + PrintMethodType(node.method_kind); + os_ << "\n"; + }); } if (node.is_static) - PrintKeyValue("ClassMethod", true); + { + children.push_back([&](bool is_last) { PrintKeyValue("ClassMethod", true, is_last); }); + } if (!node.parameters.empty()) { - PrintIndent(); - PrintColored("Parameters:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t i = 0; i < node.parameters.size(); ++i) - { - if (node.parameters[i]) + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Parameters:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + for (size_t i = 0; i < node.parameters.size(); ++i) { - PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + if (node.parameters[i]) + { + PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + } } - } - DecreaseIndent(); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } if (node.return_type) { - PrintKeyValue("ReturnType", node.return_type->name); + children.push_back([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); }); } if (node.body) { - is_last_child_stack_.push_back(true); - PrintStatement(node.body.get(), "Body", true); - is_last_child_stack_.pop_back(); + children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -972,43 +1071,49 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.type) { - PrintKeyValue("Type", node.type->name); + children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); }); } if (node.index) { - PrintExpression(node.index.value().get(), "Index", false); + children.push_back([&](bool is_last) { PrintExpression(node.index.value().get(), "Index", is_last); }); } if (node.read_accessor) { - PrintIndent(); - PrintColored("Read: ", Color::Yellow); - PrintColored("\"" + node.read_accessor.value() + "\"", Color::Green); - if (options_.show_location && node.read_location) - { - os_ << " "; - PrintLocation(node.read_location.value()); - } - os_ << "\n"; + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Read: ", Color::Yellow); + PrintColored("\"" + node.read_accessor.value() + "\"", Color::Green); + if (options_.show_location && node.read_location) + { + os_ << " "; + PrintLocation(node.read_location.value()); + } + os_ << "\n"; + }); } if (node.write_accessor) { - PrintIndent(); - PrintColored("Write: ", Color::Yellow); - PrintColored("\"" + node.write_accessor.value() + "\"", Color::Green); - if (options_.show_location && node.write_location) - { - os_ << " "; - PrintLocation(node.write_location.value()); - } - os_ << "\n"; + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Write: ", Color::Yellow); + PrintColored("\"" + node.write_accessor.value() + "\"", Color::Green); + if (options_.show_location && node.write_location) + { + os_ << " "; + PrintLocation(node.write_location.value()); + } + os_ << "\n"; + }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -1025,48 +1130,72 @@ namespace lsp::language::ast::debug } os_ << "\n"; + size_t child_count = 0; + if (node.modifier != MethodModifier::kNone) + ++child_count; + if (node.method_kind != MethodKind::kOrdinary) + ++child_count; + if (!node.parameters.empty()) + ++child_count; + if (node.return_type) + ++child_count; + if (node.body) + ++child_count; + + size_t child_index = 0; + auto emit_child = [&](auto&& fn) { + bool is_last_child = ++child_index == child_count; + fn(is_last_child); + }; + IncreaseIndent(); if (node.modifier != MethodModifier::kNone) { - PrintIndent(); - PrintColored("Modifier: ", Color::Yellow); - PrintMethodModifier(node.modifier); - os_ << "\n"; + emit_child([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Modifier: ", Color::Yellow); + PrintMethodModifier(node.modifier); + os_ << "\n"; + }); } if (node.method_kind != MethodKind::kOrdinary) { - PrintIndent(); - PrintColored("Type: ", Color::Yellow); - PrintMethodType(node.method_kind); - os_ << "\n"; + emit_child([&](bool is_last) { + PrintIndent(is_last); + PrintColored("MethodKind: ", Color::Yellow); + PrintMethodType(node.method_kind); + os_ << "\n"; + }); } if (!node.parameters.empty()) { - PrintIndent(); - PrintColored("Parameters:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t i = 0; i < node.parameters.size(); ++i) - { - if (node.parameters[i]) + emit_child([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Parameters:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + for (size_t i = 0; i < node.parameters.size(); ++i) { - PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + if (node.parameters[i]) + { + PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + } } - } - DecreaseIndent(); + DecreaseIndent(); + }); } if (node.return_type) { - PrintKeyValue("ReturnType", node.return_type->name); + emit_child([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); }); } if (node.body) { - PrintStatement(node.body.get(), "Body", true); + emit_child([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); } DecreaseIndent(); @@ -1196,7 +1325,7 @@ namespace lsp::language::ast::debug IncreaseIndent(); - PrintExpression(node.callee.get(), "Function", node.arguments.empty()); + PrintExpression(node.callee.get(), "Callee", node.arguments.empty()); if (!node.arguments.empty()) { @@ -1598,33 +1727,39 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (!node.parameters.empty()) { - PrintIndent(); - PrintColored("Parameters:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t i = 0; i < node.parameters.size(); ++i) - { - if (node.parameters[i]) + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Parameters:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + for (size_t i = 0; i < node.parameters.size(); ++i) { - PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + if (node.parameters[i]) + { + PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + } } - } - DecreaseIndent(); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } if (node.return_type) { - PrintKeyValue("ReturnType", node.return_type->name); + children.push_back([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); }); } if (node.body) { - PrintStatement(node.body.get(), "Body", true); + children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -1880,34 +2015,49 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; - // Print all if/elseif branches + // If/ElseIf branches for (size_t i = 0; i < node.branches.size(); ++i) { const auto& branch = node.branches[i]; - bool is_last_branch = (i == node.branches.size() - 1) && !node.else_body; + children.push_back([&, i](bool is_last) { + PrintIndent(is_last); + PrintColored(i == 0 ? "If Branch:" : "ElseIf Branch:", Color::Yellow); + os_ << "\n"; - PrintIndent(); - PrintColored(i == 0 ? "If Branch:" : "ElseIf Branch:", Color::Yellow); - os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); - IncreaseIndent(); - PrintExpression(branch.condition.get(), "Condition", false); - PrintStatement(branch.body.get(), "Body", is_last_branch); - DecreaseIndent(); + std::vector> branch_children; + branch_children.push_back([&](bool inner_last) { PrintExpression(branch.condition.get(), "Condition", inner_last); }); + if (branch.body) + { + branch_children.push_back([&](bool inner_last) { PrintStatement(branch.body.get(), "Body", inner_last); }); + } + EmitChildren(std::move(branch_children)); + + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } - // Print else branch if exists + // Else branch if (node.else_body) { - PrintIndent(); - PrintColored("Else Branch:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - PrintStatement(node.else_body->get(), "Body", true); - DecreaseIndent(); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Else Branch:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + PrintStatement(node.else_body->get(), "Body", true); + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -1924,10 +2074,15 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); - PrintKeyValue("Key", node.key); - PrintKeyValue("Value", node.value); - PrintExpression(node.collection.get(), "Collection", false); - PrintStatement(node.body.get(), "Body", true); + std::vector> children; + children.push_back([&](bool is_last) { PrintKeyValue("Key", node.key, nullptr, is_last); }); + children.push_back([&](bool is_last) { PrintKeyValue("Value", node.value, nullptr, is_last); }); + children.push_back([&](bool is_last) { PrintExpression(node.collection.get(), "Collection", is_last); }); + if (node.body) + { + children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); + } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -1944,18 +2099,20 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); - PrintKeyValue("Counter", node.counter); - PrintKeyValue("IsDownto", node.is_downto); - PrintExpression(node.start.get(), "Start", false); - PrintExpression(node.end.get(), "End", !node.step && !node.body); + std::vector> children; + children.push_back([&](bool is_last) { PrintKeyValue("Counter", node.counter, nullptr, is_last); }); + children.push_back([&](bool is_last) { PrintKeyValue("IsDownto", node.is_downto, is_last); }); + children.push_back([&](bool is_last) { PrintExpression(node.start.get(), "Start", is_last); }); + children.push_back([&](bool is_last) { PrintExpression(node.end.get(), "End", is_last); }); if (node.step) { - PrintExpression(node.step.get(), "Step", !node.body); + children.push_back([&](bool is_last) { PrintExpression(node.step.get(), "Step", is_last); }); } if (node.body) { - PrintStatement(node.body.get(), "Body", true); + children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -1972,8 +2129,11 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); - PrintExpression(node.condition.get(), "Condition", false); - PrintStatement(node.body.get(), "Body", true); + std::vector> children; + children.push_back([&](bool is_last) { PrintExpression(node.condition.get(), "Condition", is_last); }); + if (node.body) + children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -1990,19 +2150,28 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; - // Print body statements - PrintIndent(); - PrintColored("Body:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t i = 0; i < node.body.size(); ++i) + if (!node.body.empty()) { - PrintStatement(node.body[i].get(), "", i == node.body.size() - 1); + children.push_back([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Body:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); + for (size_t i = 0; i < node.body.size(); ++i) + { + PrintStatement(node.body[i].get(), "", i == node.body.size() - 1); + } + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); } - DecreaseIndent(); - PrintExpression(node.condition.get(), "Condition", true); + children.push_back([&](bool is_last) { PrintExpression(node.condition.get(), "Condition", is_last); }); + + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2019,42 +2188,52 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); - PrintExpression(node.discriminant.get(), "Discriminant", false); + std::vector> children; + + children.push_back([&](bool is_last) { PrintExpression(node.discriminant.get(), "Discriminant", is_last); }); for (size_t i = 0; i < node.branches.size(); ++i) { const auto& branch = node.branches[i]; - bool is_last_branch = (i == node.branches.size() - 1) && !node.else_body; + children.push_back([&, i](bool is_last) { + PrintIndent(is_last); + PrintColored("Branch:", Color::Yellow); + os_ << "\n"; - PrintIndent(); - PrintColored("Branch:", Color::Yellow); - os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(is_last); - IncreaseIndent(); + std::vector> branch_children; + branch_children.push_back([&](bool inner_last) { + PrintIndent(inner_last); + PrintColored("Values:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + is_last_child_stack_.push_back(inner_last); + for (size_t j = 0; j < branch.values.size(); ++j) + { + PrintExpression(branch.values[j].get(), "", j == branch.values.size() - 1); + } + is_last_child_stack_.pop_back(); + DecreaseIndent(); + }); - PrintIndent(); - PrintColored("Values:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t j = 0; j < branch.values.size(); ++j) - { - PrintExpression(branch.values[j].get(), "", j == branch.values.size() - 1); - } - DecreaseIndent(); + if (branch.body) + { + branch_children.push_back([&](bool inner_last) { PrintStatement(branch.body.get(), "Body", inner_last); }); + } + + EmitChildren(std::move(branch_children)); - if (branch.body) - { - is_last_child_stack_.push_back(is_last_branch); - PrintStatement(branch.body.get(), "Body", is_last_branch); is_last_child_stack_.pop_back(); - } - - DecreaseIndent(); + DecreaseIndent(); + }); } if (node.else_body) - PrintStatement(node.else_body->get(), "Else", true); + children.push_back([&](bool is_last) { PrintStatement(node.else_body->get(), "Else", is_last); }); + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2071,17 +2250,18 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); - + std::vector> children; if (node.try_body) { - PrintStatement(node.try_body.get(), "Try", !node.except_body); + children.push_back([&](bool is_last) { PrintStatement(node.try_body.get(), "Try", is_last && !node.except_body); }); } if (node.except_body) { - PrintStatement(node.except_body.get(), "Except", true); + children.push_back([&](bool is_last) { PrintStatement(node.except_body.get(), "Except", is_last); }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2126,7 +2306,9 @@ namespace lsp::language::ast::debug if (node.value) { IncreaseIndent(); + is_last_child_stack_.push_back(true); PrintExpression(node.value->get(), "", true); + is_last_child_stack_.pop_back(); DecreaseIndent(); } } @@ -2144,6 +2326,7 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + is_last_child_stack_.push_back(true); for (size_t i = 0; i < node.units.size(); ++i) { PrintIndent(i == node.units.size() - 1); @@ -2155,6 +2338,7 @@ namespace lsp::language::ast::debug } os_ << "\n"; } + is_last_child_stack_.pop_back(); DecreaseIndent(); } @@ -2171,8 +2355,11 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); - PrintExpression(node.target.get(), "Target", false); - PrintStatement(node.body.get(), "Body", true); + std::vector> children; + children.push_back([&](bool is_last) { PrintExpression(node.target.get(), "Target", is_last && !node.body); }); + if (node.body) + children.push_back([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2191,35 +2378,56 @@ namespace lsp::language::ast::debug } os_ << "\n"; + size_t child_count = (node.parameters.empty() ? 0 : 1); + if (node.return_type) + ++child_count; + if (node.body) + ++child_count; + // Overload is always printed + ++child_count; + + size_t child_index = 0; + auto emit_child = [&](auto&& fn) { + bool is_last_child = ++child_index == child_count; + fn(is_last_child); + }; + IncreaseIndent(); if (!node.parameters.empty()) { - PrintIndent(); - PrintColored("Parameters:", Color::Yellow); - os_ << "\n"; - IncreaseIndent(); - for (size_t i = 0; i < node.parameters.size(); ++i) - { - if (node.parameters[i]) + emit_child([&](bool is_last) { + PrintIndent(is_last); + PrintColored("Parameters:", Color::Yellow); + os_ << "\n"; + IncreaseIndent(); + for (size_t i = 0; i < node.parameters.size(); ++i) { - PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + if (node.parameters[i]) + { + PrintParameter(*node.parameters[i], i == node.parameters.size() - 1); + } } - } - DecreaseIndent(); + DecreaseIndent(); + }); } - PrintIndent(); - std::string overload = node.is_overload ? "true" : "false"; - PrintColored("Overload: " + overload, Color::Cyan); - os_ << "\n"; - DecreaseIndent(); + emit_child([&](bool is_last) { + PrintIndent(is_last); + std::string overload = node.is_overload ? "true" : "false"; + PrintColored("Overload: " + overload, Color::Cyan); + os_ << "\n"; + }); if (node.return_type) - PrintKeyValue("ReturnType", node.return_type->name); + { + emit_child([&](bool is_last) { PrintKeyValue("ReturnType", node.return_type->name, nullptr, is_last); }); + } if (node.body) - PrintStatement(node.body.get(), "Body", true); + { + emit_child([&](bool is_last) { PrintStatement(node.body.get(), "Body", is_last); }); + } DecreaseIndent(); } @@ -2277,17 +2485,19 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.type) { - PrintKeyValue("Type", node.type->name); + children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); }); } if (node.initializer) { - PrintExpression(node.initializer->get(), "InitialValue", true); + children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "InitialValue", is_last); }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2305,15 +2515,19 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.type) { - PrintKeyValue("Type", node.type->name); + children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); }); } if (node.initializer) - PrintExpression(node.initializer->get(), "Initializer", true); + { + children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "Initializer", is_last); }); + } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2331,13 +2545,15 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.type) - PrintKeyValue("Type", node.type->name); + children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); }); if (node.initializer) - PrintExpression(node.initializer->get(), "Initializer", true); + children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "Initializer", is_last); }); + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2355,17 +2571,19 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.type) { - PrintKeyValue("Type", node.type->name); + children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); }); } if (node.value) { - PrintExpression(node.value.get(), "Value", true); + children.push_back([&](bool is_last) { PrintExpression(node.value.get(), "Value", is_last); }); } + EmitChildren(std::move(children)); DecreaseIndent(); } @@ -2383,13 +2601,15 @@ namespace lsp::language::ast::debug os_ << "\n"; IncreaseIndent(); + std::vector> children; if (node.type) - PrintKeyValue("Type", node.type->name); + children.push_back([&](bool is_last) { PrintKeyValue("Type", node.type->name, nullptr, is_last); }); if (node.initializer) - PrintExpression(node.initializer->get(), "Initializer", true); + children.push_back([&](bool is_last) { PrintExpression(node.initializer->get(), "Initializer", is_last); }); + EmitChildren(std::move(children)); DecreaseIndent(); } diff --git a/lsp-server/test/test_ast/debug_printer.hpp b/lsp-server/test/test_ast/debug_printer.hpp index ce0f8ff..33dd05a 100644 --- a/lsp-server/test/test_ast/debug_printer.hpp +++ b/lsp-server/test/test_ast/debug_printer.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../../src/language/ast/types.hpp" #include "../../src/language/ast/deserializer.hpp" @@ -188,6 +189,7 @@ namespace lsp::language::ast::debug void PrintIndent(std::optional is_last = std::nullopt); void PrintTreePrefix(bool is_last = false); std::string GetIndent() const; + void EmitChildren(std::vector>&& children); // 颜色辅助 const char* GetColor(const char* color) const; @@ -196,11 +198,11 @@ namespace lsp::language::ast::debug // 节点信息输出 void PrintNodeHeader(const std::string& type_name, const Location& loc); void PrintLocation(const Location& loc); - void PrintSourceSnippet(const Location& loc); - void PrintKeyValue(const std::string& key, const std::string& value, const Location& location, const char* value_color); - void PrintKeyValue(const std::string& key, const std::string& value, const char* value_color = nullptr); - void PrintKeyValue(const std::string& key, int value); - void PrintKeyValue(const std::string& key, bool value); + void PrintSourceSnippet(const Location& loc, bool is_last_child); + void PrintKeyValue(const std::string& key, const std::string& value, const Location& location, const char* value_color, std::optional is_last = std::nullopt); + void PrintKeyValue(const std::string& key, const std::string& value, const char* value_color = nullptr, std::optional is_last = std::nullopt); + void PrintKeyValue(const std::string& key, int value, std::optional is_last = std::nullopt); + void PrintKeyValue(const std::string& key, bool value, std::optional is_last = std::nullopt); // 表达式和语句打印 void PrintExpression(const Expression* expr, const std::string& label = "", bool is_last = false); diff --git a/lsp-server/test/test_symbol/CMakeLists.txt b/lsp-server/test/test_symbol/CMakeLists.txt index 08645bf..284d064 100644 --- a/lsp-server/test/test_symbol/CMakeLists.txt +++ b/lsp-server/test/test_symbol/CMakeLists.txt @@ -68,17 +68,11 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) set(SOURCES ./test.cpp ./debug_printer.cpp + ../../src/utils/string.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/scanner.c ../../src/tree-sitter/parser.c) @@ -104,4 +98,3 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") $<$:-O3> ) endif() - diff --git a/lsp-server/test/test_symbol/debug_printer.cpp b/lsp-server/test/test_symbol/debug_printer.cpp index 3b763e9..493abd6 100644 --- a/lsp-server/test/test_symbol/debug_printer.cpp +++ b/lsp-server/test/test_symbol/debug_printer.cpp @@ -1,9 +1,70 @@ -#include #include +#include +#include +#include +#include +#include +#include #include "./debug_printer.hpp" +namespace +{ + using namespace lsp::language; + using namespace lsp::language::symbol; + + const char* AccessModifierToString(ast::AccessModifier access) + { + switch (access) + { + case ast::AccessModifier::kPublic: + return "public"; + case ast::AccessModifier::kProtected: + return "protected"; + case ast::AccessModifier::kPrivate: + return "private"; + } + return "public"; + } + + const char* VariableScopeToString(VariableScope scope) + { + switch (scope) + { + case VariableScope::kAutomatic: + return "auto"; + case VariableScope::kStatic: + return "static"; + case VariableScope::kGlobal: + return "global"; + case VariableScope::kParameter: + return "param"; + case VariableScope::kField: + return "field"; + } + return "auto"; + } +} // namespace + namespace lsp::language::symbol::debug { + namespace Color + { + constexpr const char* Reset = "\033[0m"; + constexpr const char* Bold = "\033[1m"; + constexpr const char* Dim = "\033[2m"; + 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* BrightBlue = "\033[94m"; + constexpr const char* BrightMagenta = "\033[95m"; + constexpr const char* BrightGreen = "\033[92m"; + constexpr const char* Gray = "\033[90m"; + } + // ==================== PrintOptions ==================== PrintOptions PrintOptions::Default() @@ -41,34 +102,37 @@ namespace lsp::language::symbol::debug void Statistics::Compute(const SymbolTable& table) { - auto all_defs = table.GetAllDefinitions(); + auto all_defs = table.all_definitions(); total_symbols = all_defs.size(); symbol_counts.clear(); + scope_counts.clear(); + symbols_with_refs = 0; + total_references = 0; + max_references = 0; + most_referenced = kInvalidSymbolId; - for (const auto* def : all_defs) + for (const auto& ref : all_defs) { - symbol_counts[def->kind]++; + const auto& sym = ref.get(); + symbol_counts[sym.kind()]++; - auto refs = table.GetReferences(def->id); - if (refs && !refs->empty()) + const auto& refs = table.references().references(sym.id()); + if (!refs.empty()) { symbols_with_refs++; - total_references += refs->size(); - - if (refs->size() > max_references) + total_references += refs.size(); + if (refs.size() > max_references) { - max_references = refs->size(); - most_referenced = def->id; + max_references = refs.size(); + most_referenced = sym.id(); } } } - // 统计作用域 - const auto& all_scopes = table.GetScopeManager().GetAllScopes(); - total_scopes = all_scopes.size(); - - for (const auto& [id, info] : all_scopes) + const auto& scopes = table.scopes().all_scopes(); + total_scopes = scopes.size(); + for (const auto& [_, info] : scopes) { scope_counts[info.kind]++; } @@ -86,7 +150,6 @@ namespace lsp::language::symbol::debug os << "╚════════════════════════════════════════════════════════════╝" << color(Color::Reset) << "\n\n"; - // 总体统计 os << color(Color::Bold) << "Overview:" << color(Color::Reset) << "\n"; os << " Total Symbols: " << color(Color::Cyan) << total_symbols << color(Color::Reset) << "\n"; os << " Total Scopes: " << color(Color::Cyan) << total_scopes << color(Color::Reset) << "\n"; @@ -101,7 +164,6 @@ namespace lsp::language::symbol::debug os << "\n"; - // 符号类型分布 os << color(Color::Bold) << "Symbol Distribution:" << color(Color::Reset) << "\n"; struct KindInfo @@ -112,15 +174,10 @@ namespace lsp::language::symbol::debug }; KindInfo kinds[] = { - { SymbolKind::Module, "Modules", "📦" }, { SymbolKind::Namespace, "Namespace", "🗃️" }, { SymbolKind::Class, "Classes", "🏛️" }, - { SymbolKind::Interface, "Interfaces", "🔌" }, - { SymbolKind::Struct, "Structs", "📐" }, - { SymbolKind::Enum, "Enums", "🔢" }, { SymbolKind::Function, "Functions", "🎄" }, { SymbolKind::Method, "Methods", "🪀" }, - { SymbolKind::Constructor, "Constructors", "🔨" }, { SymbolKind::Property, "Properties", "📋" }, { SymbolKind::Field, "Fields", "📌" }, { SymbolKind::Variable, "Variables", "📊" }, @@ -139,39 +196,15 @@ namespace lsp::language::symbol::debug } } - os << "\n"; - - // 作用域分布 if (!scope_counts.empty()) { - os << color(Color::Bold) << "Scope Distribution:" << color(Color::Reset) << "\n"; - - struct ScopeKindInfo + os << "\n" + << color(Color::Bold) << "Scope Distribution:" << color(Color::Reset) << "\n"; + for (const auto& [kind, count] : scope_counts) { - ScopeKind kind; - const char* name; - }; - - ScopeKindInfo scope_kinds[] = { - { ScopeKind::Global, "Global" }, - { ScopeKind::Unit, "Unit" }, - { ScopeKind::Class, "Class" }, - { ScopeKind::Function, "Function" }, - { ScopeKind::Block, "Block" } - }; - - for (const auto& scope_info : scope_kinds) - { - auto it = scope_counts.find(scope_info.kind); - if (it != scope_counts.end() && it->second > 0) - { - os << " " << std::setw(15) << std::left << scope_info.name - << ": " << color(Color::BrightMagenta) << std::setw(5) << std::right - << it->second << color(Color::Reset) << "\n"; - } + os << " " << std::setw(12) << std::left << static_cast(kind) + << ": " << color(Color::BrightMagenta) << count << color(Color::Reset) << "\n"; } - - os << "\n"; } } @@ -179,749 +212,40 @@ namespace lsp::language::symbol::debug DebugPrinter::DebugPrinter(const SymbolTable& table, const PrintOptions& options) : table_(table), options_(options) { - stats_.Compute(table); + stats_.Compute(table_); } - // ===== 顶层打印 ===== - - void DebugPrinter::PrintAll(std::ostream& os) + void DebugPrinter::PrintSeparator(std::ostream& os, char ch, int width) const { - PrintHeader("SYMBOL TABLE DUMP", os); - - PrintSubHeader("1. Overview", os); - PrintOverview(os); - - PrintSubHeader("2. Symbol Definitions", os); - PrintSymbolList(os); - - PrintSubHeader("3. Scope Hierarchy", os); - PrintScopeHierarchy(os); - - PrintSubHeader("4. References", os); - PrintAllReferences(os); - - PrintSubHeader("5. Inheritance", os); - PrintAllInheritance(os); - - PrintSubHeader("6. Call Graph", os); - PrintAllCalls(os); - - PrintSubHeader("7. Statistics", os); - PrintStatistics(os); - } - - void DebugPrinter::PrintOverview(std::ostream& os) - { - auto all_defs = table_.GetAllDefinitions(); - - os << "\n"; - os << Color(Color::Bold) << "Symbol Table Overview" << Color(Color::Reset) << "\n"; - os << " Total Symbols: " << Color(Color::Cyan) << all_defs.size() << Color(Color::Reset) << "\n"; - os << " Total Scopes: " << Color(Color::Cyan) << stats_.total_scopes << Color(Color::Reset) << "\n"; - os << "\n"; - - // 按类型分组显示 - std::unordered_map> by_kind; - for (const auto* def : all_defs) - { - by_kind[def->kind].push_back(def); - } - - // 定义固定的类型顺序 - std::vector kind_order = { - SymbolKind::Module, - SymbolKind::Class, - SymbolKind::Interface, - SymbolKind::Struct, - SymbolKind::Enum, - SymbolKind::Function, - SymbolKind::Method, - SymbolKind::Constructor, - SymbolKind::Property, - SymbolKind::Field, - SymbolKind::Variable, - SymbolKind::Constant - }; - - // 按固定顺序遍历类型 - for (const auto& kind : kind_order) - { - auto it = by_kind.find(kind); - if (it == by_kind.end() || it->second.empty()) - continue; - - auto& symbols = it->second; - - // 按位置排序同类型的符号 - std::sort(symbols.begin(), symbols.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) { - if (a->location.start_line != b->location.start_line) - return a->location.start_line < b->location.start_line; - if (a->location.start_column != b->location.start_column) - return a->location.start_column < b->location.start_column; - return true; - }); - - os << " " << SymbolIcon(kind) << " " - << Color(Color::Bold) << FormatSymbolKind(kind) - << Color(Color::Reset) << " (" << symbols.size() << ")\n"; - - if (!options_.compact_mode) - { - for (const auto* sym : symbols) - { - os << " " << Color(Color::Dim) << "• " << Color(Color::Reset) - << ColorizeSymbolName(sym->name, kind); - - if (options_.show_location) - { - os << " " << Color(Color::Dim) - << FormatLocation(sym->location) << Color(Color::Reset); - } - - os << "\n"; - } - } - } - + for (int i = 0; i < width; ++i) + os << ch; os << "\n"; } - void DebugPrinter::PrintStatistics(std::ostream& os) + std::string DebugPrinter::Color(const char* color_code) const { - stats_.Print(os, options_.use_color); + return options_.use_color ? color_code : ""; } - // ===== 符号打印 ===== - - void DebugPrinter::PrintSymbol(SymbolId id, std::ostream& os, int depth) + std::string DebugPrinter::Bold(const std::string& text) const { - const auto* def = table_.GetDefinition(id); - if (!def) - return; - - os << Indent(depth); - os << SymbolIcon(def->kind) << " "; - os << ColorizeSymbolName(def->name, def->kind); - - if (options_.show_location) - { - os << " " << Color(Color::Dim) << FormatLocation(def->location) << Color(Color::Reset); - } - - os << "\n"; - - if (options_.show_details && !options_.compact_mode) - { - os << Indent(depth + 1) << Color(Color::Dim) << "Kind: " << Color(Color::Reset) - << FormatSymbolKind(def->kind) << "\n"; - - if (def->type_hint) - { - os << Indent(depth + 1) << Color(Color::Dim) << "Type: " << Color(Color::Reset) - << *def->type_hint << "\n"; - } - - if (!def->detail.empty()) - { - os << Indent(depth + 1) << Color(Color::Dim) << "Detail: " << Color(Color::Reset) - << def->detail << "\n"; - } - - if (def->access_modifier) - { - const char* access_str = "public"; - switch (*def->access_modifier) - { - case ast::AccessModifier::kPublic: - access_str = "public"; - break; - case ast::AccessModifier::kProtected: - access_str = "protected"; - break; - case ast::AccessModifier::kPrivate: - access_str = "private"; - break; - } - os << Indent(depth + 1) << Color(Color::Dim) << "Access: " << Color(Color::Reset) - << access_str << "\n"; - } - } + return options_.use_color ? std::string(Color::Bold) + text + Color::Reset : text; } - void DebugPrinter::PrintSymbolTree(SymbolId id, std::ostream& os, int depth) + std::string DebugPrinter::Dim(const std::string& text) const { - if (options_.max_depth >= 0 && depth > options_.max_depth) - return; - - PrintSymbol(id, os, depth); - - if (options_.show_children) - { - auto children = table_.GetChildren(id); - - // 按位置排序子符号 - std::vector sorted_children(children.begin(), children.end()); - std::sort(sorted_children.begin(), sorted_children.end(), [this](SymbolId a, SymbolId b) { - const auto* def_a = table_.GetDefinition(a); - const auto* def_b = table_.GetDefinition(b); - if (!def_a || !def_b) - return false; - - if (def_a->location.start_line != def_b->location.start_line) - return def_a->location.start_line < def_b->location.start_line; - if (def_a->location.start_column != def_b->location.start_column) - return def_a->location.start_column < def_b->location.start_column; - return true; - }); - - for (SymbolId child_id : sorted_children) - { - PrintSymbolTree(child_id, os, depth + 1); - } - } + return options_.use_color ? std::string(Color::Dim) + text + Color::Reset : text; } - void DebugPrinter::PrintSymbolList(std::ostream& os) - { - auto all_defs = table_.GetAllDefinitions(); - - if (all_defs.empty()) - { - os << Color(Color::Dim) << " (no symbols)\n" - << Color(Color::Reset); - return; - } - - // 按层级排序(顶层优先) - std::vector top_level; - for (const auto* def : all_defs) - { - if (!def->parent_id) - top_level.push_back(def); - } - - // 按位置排序顶层符号 - std::sort(top_level.begin(), top_level.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) { - if (a->location.start_line != b->location.start_line) - return a->location.start_line < b->location.start_line; - if (a->location.start_column != b->location.start_column) - return a->location.start_column < b->location.start_column; - return true; - }); - - for (const auto* def : top_level) - { - PrintSymbolTree(def->id, os, 0); - } - } - - void DebugPrinter::PrintSymbolsByKind(SymbolKind kind, std::ostream& os) - { - auto all_defs = table_.GetAllDefinitions(); - - os << "\n" - << Color(Color::Bold) << FormatSymbolKind(kind) << "s:" << Color(Color::Reset) << "\n\n"; - - // 收集并排序符号 - std::vector symbols; - for (const auto* def : all_defs) - { - if (def->kind == kind) - { - symbols.push_back(def); - } - } - - if (symbols.empty()) - { - os << Color(Color::Dim) << " (none)\n" - << Color(Color::Reset); - } - else - { - // 按位置排序 - std::sort(symbols.begin(), symbols.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) { - if (a->location.start_line != b->location.start_line) - return a->location.start_line < b->location.start_line; - if (a->location.start_column != b->location.start_column) - return a->location.start_column < b->location.start_column; - return true; - }); - - for (const auto* def : symbols) - { - PrintSymbol(def->id, os, 0); - } - } - - os << "\n"; - } - - // ===== 作用域打印 ===== - - void DebugPrinter::PrintScope(ScopeId id, std::ostream& os, int depth) - { - const auto* info = table_.GetScopeManager().GetScopeInfo(id); - if (!info) - return; - - os << Indent(depth); - os << "🔷 " << Color(Color::Bold) << FormatScopeKind(info->kind) << Color(Color::Reset); - os << " (id=" << id << ")"; - - if (options_.show_location) - { - os << " " << Color(Color::Dim) << FormatLocation(info->range) << Color(Color::Reset); - } - - os << "\n"; - - if (!options_.compact_mode && !info->symbols.empty()) - { - os << Indent(depth + 1) << Color(Color::Dim) << "Symbols: " << info->symbols.size() << Color(Color::Reset) << "\n"; - - // 收集符号并按位置排序 - std::vector> sorted_symbols( - info->symbols.begin(), info->symbols.end()); - - std::sort(sorted_symbols.begin(), sorted_symbols.end(), [this](const auto& a, const auto& b) { - // 按符号定义的位置排序 - const auto* def_a = table_.GetDefinition(a.second); - const auto* def_b = table_.GetDefinition(b.second); - if (!def_a || !def_b) - return false; - - if (def_a->location.start_line != def_b->location.start_line) - return def_a->location.start_line < def_b->location.start_line; - if (def_a->location.start_column != def_b->location.start_column) - return def_a->location.start_column < def_b->location.start_column; - return true; - }); - - for (const auto& [name, sym_id] : sorted_symbols) - { - os << Indent(depth + 2) << "• " << name << "\n"; - } - } - } - - void DebugPrinter::PrintScopeTree(ScopeId id, std::ostream& os, int depth) - { - if (options_.max_depth >= 0 && depth > options_.max_depth) - return; - - PrintScope(id, os, depth); - - // 查找并收集子作用域 - const auto& all_scopes = table_.GetScopeManager().GetAllScopes(); - - std::vector> children; - for (const auto& [child_id, info] : all_scopes) - { - if (info.parent_scope_id && *info.parent_scope_id == id) - { - children.push_back({ child_id, &info }); - } - } - - // 按位置排序子作用域 - std::sort(children.begin(), children.end(), [](const auto& a, const auto& b) { - if (a.second->range.start_line != b.second->range.start_line) - return a.second->range.start_line < b.second->range.start_line; - if (a.second->range.start_column != b.second->range.start_column) - return a.second->range.start_column < b.second->range.start_column; - return true; - }); - - // 递归打印子作用域 - for (const auto& [child_id, info] : children) - { - PrintScopeTree(child_id, os, depth + 1); - } - } - - void DebugPrinter::PrintScopeHierarchy(std::ostream& os) - { - ScopeId global_scope = table_.GetGlobalScope(); - if (global_scope == kInvalidScopeId) - { - os << Color(Color::Dim) << " (no scopes)\n" - << Color(Color::Reset); - return; - } - - PrintScopeTree(global_scope, os, 0); - } - - // ===== 关系打印 ===== - - void DebugPrinter::PrintReferences(SymbolId id, std::ostream& os) - { - const auto* def = table_.GetDefinition(id); - if (!def) - return; - - os << "\n" - << Color(Color::Bold) << "References for: " << def->name << Color(Color::Reset) << "\n"; - - auto refs = table_.GetReferences(id); - if (!refs || refs->empty()) - { - os << Color(Color::Dim) << " (no references)\n" - << Color(Color::Reset); - return; - } - - os << " Total: " << refs->size() << "\n\n"; - - for (const auto& ref : *refs) - { - os << " "; - - if (ref.is_definition) - os << Color(Color::Green) << "[DEF]" << Color(Color::Reset) << " "; - else if (ref.is_write) - os << Color(Color::Yellow) << "[WRITE]" << Color(Color::Reset) << " "; - else - os << Color(Color::Cyan) << "[READ]" << Color(Color::Reset) << " "; - - os << FormatLocation(ref.location) << "\n"; - } - - os << "\n"; - } - - void DebugPrinter::PrintInheritance(SymbolId class_id, std::ostream& os) - { - const auto* def = table_.GetDefinition(class_id); - if (!def || def->kind != SymbolKind::Class) - return; - - os << "\n" - << Color(Color::Bold) << "Inheritance for: " << def->name << Color(Color::Reset) << "\n\n"; - - // 基类 - auto bases = table_.GetBaseClasses(class_id); - if (bases && !bases->empty()) - { - os << " " << Color(Color::Green) << "Base Classes:" << Color(Color::Reset) << "\n"; - for (SymbolId base_id : *bases) - { - const auto* base_def = table_.GetDefinition(base_id); - if (base_def) - { - os << " ↑ " << base_def->name << "\n"; - } - } - } - - // 派生类 - auto derived = table_.GetDerivedClasses(class_id); - if (derived && !derived->empty()) - { - os << " " << Color(Color::Yellow) << "Derived Classes:" << Color(Color::Reset) << "\n"; - for (SymbolId derived_id : *derived) - { - const auto* derived_def = table_.GetDefinition(derived_id); - if (derived_def) - { - os << " ↓ " << derived_def->name << "\n"; - } - } - } - - os << "\n"; - } - - void DebugPrinter::PrintCallGraph(SymbolId function_id, std::ostream& os) - { - const auto* def = table_.GetDefinition(function_id); - if (!def) - return; - - os << "\n" - << Color(Color::Bold) << "Call Graph for: " << def->name << Color(Color::Reset) << "\n\n"; - - // 调用者 - auto callers = table_.GetCallers(function_id); - if (callers && !callers->empty()) - { - os << " " << Color(Color::Green) << "Called by:" << Color(Color::Reset) << "\n"; - for (const auto& rel : *callers) - { - const auto* caller_def = table_.GetDefinition(rel.caller); - if (caller_def) - { - os << " ← " << caller_def->name - << " " << Color(Color::Dim) << FormatLocation(rel.call_location) << Color(Color::Reset) << "\n"; - } - } - } - - // 被调用的 - auto callees = table_.GetCallees(function_id); - if (callees && !callees->empty()) - { - os << " " << Color(Color::Yellow) << "Calls:" << Color(Color::Reset) << "\n"; - for (const auto& rel : *callees) - { - const auto* callee_def = table_.GetDefinition(rel.callee); - if (callee_def) - { - os << " → " << callee_def->name - << " " << Color(Color::Dim) << FormatLocation(rel.call_location) << Color(Color::Reset) << "\n"; - } - } - } - - os << "\n"; - } - - void DebugPrinter::PrintAllReferences(std::ostream& os) - { - auto all_defs = table_.GetAllDefinitions(); - - // 按位置排序 - std::vector sorted_defs(all_defs.begin(), all_defs.end()); - std::sort(sorted_defs.begin(), sorted_defs.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) { - if (a->location.start_line != b->location.start_line) - return a->location.start_line < b->location.start_line; - if (a->location.start_column != b->location.start_column) - return a->location.start_column < b->location.start_column; - return true; - }); - - for (const auto* def : sorted_defs) - { - auto refs = table_.GetReferences(def->id); - if (refs && refs->size() > 1) // >1 因为定义本身算一个引用 - { - PrintReferences(def->id, os); - } - } - } - - void DebugPrinter::PrintAllInheritance(std::ostream& os) - { - auto all_defs = table_.GetAllDefinitions(); - - // 按位置排序 - std::vector sorted_defs(all_defs.begin(), all_defs.end()); - std::sort(sorted_defs.begin(), sorted_defs.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) { - if (a->location.start_line != b->location.start_line) - return a->location.start_line < b->location.start_line; - if (a->location.start_column != b->location.start_column) - return a->location.start_column < b->location.start_column; - return true; - }); - - bool found = false; - for (const auto* def : sorted_defs) - { - if (def->kind == SymbolKind::Class) - { - auto bases = table_.GetBaseClasses(def->id); - auto derived = table_.GetDerivedClasses(def->id); - - if ((bases && !bases->empty()) || (derived && !derived->empty())) - { - PrintInheritance(def->id, os); - found = true; - } - } - } - - if (!found) - { - os << Color(Color::Dim) << " (no inheritance relationships)\n" - << Color(Color::Reset); - } - } - - void DebugPrinter::PrintAllCalls(std::ostream& os) - { - auto all_defs = table_.GetAllDefinitions(); - - // 按位置排序 - std::vector sorted_defs(all_defs.begin(), all_defs.end()); - std::sort(sorted_defs.begin(), sorted_defs.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) { - if (a->location.start_line != b->location.start_line) - return a->location.start_line < b->location.start_line; - if (a->location.start_column != b->location.start_column) - return a->location.start_column < b->location.start_column; - return true; - }); - - bool found = false; - for (const auto* def : sorted_defs) - { - if (def->kind == SymbolKind::Function || def->kind == SymbolKind::Method) - { - auto callers = table_.GetCallers(def->id); - auto callees = table_.GetCallees(def->id); - - if ((callers && !callers->empty()) || (callees && !callees->empty())) - { - PrintCallGraph(def->id, os); - found = true; - } - } - } - - if (!found) - { - os << Color(Color::Dim) << " (no call relationships)\n" - << Color(Color::Reset); - } - } - - // ===== 搜索和查询 ===== - - void DebugPrinter::FindAndPrint(const std::string& name, std::ostream& os) - { - auto symbols = table_.FindSymbolsByName(name); - - os << "\n" - << Color(Color::Bold) << "Search results for: '" << name << "'" << Color(Color::Reset) << "\n"; - os << "Found " << symbols.size() << " symbol(s)\n\n"; - - if (symbols.empty()) - { - os << Color(Color::Dim) << " (no matches)\n" - << Color(Color::Reset); - return; - } - - // 按位置排序结果 - std::vector sorted_symbols(symbols.begin(), symbols.end()); - std::sort(sorted_symbols.begin(), sorted_symbols.end(), [this](SymbolId a, SymbolId b) { - const auto* def_a = table_.GetDefinition(a); - const auto* def_b = table_.GetDefinition(b); - if (!def_a || !def_b) - return false; - - if (def_a->location.start_line != def_b->location.start_line) - return def_a->location.start_line < def_b->location.start_line; - if (def_a->location.start_column != def_b->location.start_column) - return def_a->location.start_column < def_b->location.start_column; - return true; - }); - - for (SymbolId id : sorted_symbols) - { - const auto* def = table_.GetDefinition(id); - if (!def) - continue; - - PrintSymbol(id, os, 0); - - if (options_.show_references) - { - PrintReferences(id, os); - } - - os << "\n"; - } - } - - void DebugPrinter::FindAtLocation(const ast::Location& loc, std::ostream& os) - { - os << "\n" - << Color(Color::Bold) << "Symbols at location: " - << FormatLocation(loc) << Color(Color::Reset) << "\n\n"; - - // 查找符号 - auto symbol_id = table_.FindSymbolAt(loc); - if (symbol_id) - { - os << "Symbol: "; - PrintSymbol(*symbol_id, os, 0); - } - else - { - os << "Symbol: " << Color(Color::Dim) << "(none)\n" - << Color(Color::Reset); - } - - // 查找作用域 - auto scope_id = table_.FindScopeAt(loc); - if (scope_id) - { - os << "Scope: "; - PrintScope(*scope_id, os, 0); - } - else - { - os << "Scope: " << Color(Color::Dim) << "(none)\n" - << Color(Color::Reset); - } - - // 查找引用 - auto ref_id = table_.FindReferenceAt(loc); - if (ref_id) - { - os << "Reference to: "; - PrintSymbol(*ref_id, os, 0); - } - - os << "\n"; - } - - // ===== 辅助方法 ===== - std::string DebugPrinter::Indent(int depth) const { - return std::string(depth * options_.indent_size, ' '); - } - - std::string DebugPrinter::ColorizeSymbolKind(SymbolKind kind) const - { - if (!options_.use_color) - return ""; - - switch (kind) - { - case SymbolKind::Module: - return Color::BrightMagenta; - case SymbolKind::Class: - return Color::BrightYellow; - case SymbolKind::Function: - return Color::BrightBlue; - case SymbolKind::Method: - return Color::BrightCyan; - case SymbolKind::Constructor: - return Color::BrightGreen; - case SymbolKind::Interface: - return Color::BrightMagenta; - case SymbolKind::Struct: - return Color::BrightYellow; - case SymbolKind::Enum: - return Color::BrightCyan; - case SymbolKind::Property: - return Color::Magenta; - case SymbolKind::Field: - return Color::Yellow; - case SymbolKind::Variable: - return Color::White; - case SymbolKind::Constant: - return Color::BrightRed; - default: - return Color::Reset; - } - } - - std::string DebugPrinter::ColorizeSymbolName(const std::string& name, SymbolKind kind) const - { - if (!options_.use_color) - return name; - return std::string(ColorizeSymbolKind(kind)) + name + Color::Reset; + return std::string(static_cast(depth * options_.indent_size), ' '); } std::string DebugPrinter::FormatLocation(const ast::Location& loc) const { std::ostringstream oss; - oss << "[" << loc.start_line << ":" << loc.start_column - << "-" << loc.end_line << ":" << loc.end_column << "]"; + oss << loc.start_line << ":" << loc.start_column << "-" << loc.end_line << ":" << loc.end_column; return oss.str(); } @@ -929,28 +253,18 @@ namespace lsp::language::symbol::debug { switch (kind) { - case SymbolKind::Module: - return "Module"; case SymbolKind::Namespace: return "Namespace"; case SymbolKind::Class: return "Class"; - case SymbolKind::Interface: - return "Interface"; - case SymbolKind::Struct: - return "Struct"; - case SymbolKind::Enum: - return "Enum"; - case SymbolKind::Function: - return "Function"; case SymbolKind::Method: return "Method"; - case SymbolKind::Constructor: - return "Constructor"; case SymbolKind::Property: return "Property"; case SymbolKind::Field: return "Field"; + case SymbolKind::Function: + return "Function"; case SymbolKind::Variable: return "Variable"; case SymbolKind::Constant: @@ -964,15 +278,17 @@ namespace lsp::language::symbol::debug { switch (kind) { - case ScopeKind::Global: + case ScopeKind::kGlobal: return "Global"; - case ScopeKind::Unit: + case ScopeKind::kUnit: return "Unit"; - case ScopeKind::Class: + case ScopeKind::kClass: return "Class"; - case ScopeKind::Function: + case ScopeKind::kFunction: return "Function"; - case ScopeKind::Block: + case ScopeKind::kAnonymousFunction: + return "AnonymousFunction"; + case ScopeKind::kBlock: return "Block"; default: return "Unknown"; @@ -981,117 +297,646 @@ namespace lsp::language::symbol::debug std::string DebugPrinter::SymbolIcon(SymbolKind kind) const { - if (!options_.use_color) - return ""; - switch (kind) { - case SymbolKind::Module: - return "📦"; case SymbolKind::Namespace: return "🗃️"; case SymbolKind::Class: return "🏛️"; - case SymbolKind::Interface: - return "🔌"; - case SymbolKind::Struct: - return "📐"; - case SymbolKind::Enum: - return "🔢"; - case SymbolKind::Function: - return "🎄"; case SymbolKind::Method: - return "🪀"; - case SymbolKind::Constructor: - return "🔨"; + return "🔧"; // Default, will be overridden in GetSymbolIcon case SymbolKind::Property: return "📋"; case SymbolKind::Field: return "📌"; + case SymbolKind::Function: + return "🌲"; // Default, will be overridden in GetSymbolIcon case SymbolKind::Variable: return "📊"; case SymbolKind::Constant: return "🔒"; default: - return "•"; + return "❓"; } } - void DebugPrinter::PrintSeparator(std::ostream& os, char ch, int width) const + std::string DebugPrinter::GetSymbolIcon(const Symbol& symbol) const { - os << std::string(width, ch) << "\n"; + // Check if it's a Method with declaration/implementation distinction + if (const auto* method = symbol.As()) + { + bool has_decl = method->declaration_range.start_line != 0; + bool has_impl = method->implementation_range.has_value(); + + if (has_decl && has_impl) + { + // Has both declaration and implementation + if (symbol.selection_range().start_line == method->declaration_range.start_line) + { + return "🔷"; // Declaration: blue diamond (interface/contract) + } + else if (has_impl && symbol.selection_range().start_line == method->implementation_range->start_line) + { + return "🔶"; // Implementation: orange diamond (concrete/실행) + } + } + return "🔧"; // Default method icon (wrench/tool) + } + + // Check if it's a Function with declaration/implementation distinction + if (const auto* func = symbol.As()) + { + bool has_decl = func->declaration_range.start_line != 0; + bool has_impl = func->implementation_range.has_value(); + + if (has_decl && has_impl) + { + // Has both declaration and implementation + if (symbol.selection_range().start_line == func->declaration_range.start_line) + { + return "🌳"; // Declaration: deciduous tree (interface/skeleton) + } + else if (has_impl && symbol.selection_range().start_line == func->implementation_range->start_line) + { + return "🎄"; // Implementation: christmas tree (decorated/complete) + } + } + return "🌲"; // Default function icon (evergreen tree) + } + + // For other types, use the default icon + return SymbolIcon(symbol.kind()); + } + + std::string DebugPrinter::ColorizeSymbolKind(SymbolKind kind) const + { + return Color(Color::Blue) + FormatSymbolKind(kind) + Color(Color::Reset); + } + + std::string DebugPrinter::ColorizeSymbolName(const std::string& name, SymbolKind /*kind*/) const + { + return Color(Color::Yellow) + name + Color(Color::Reset); } void DebugPrinter::PrintHeader(const std::string& title, std::ostream& os) const { - os << "\n"; - os << Color(Color::Bold) << "╔" << std::string(78, '=') << "╗\n"; - os << "║ " << std::setw(74) << std::left << title << " ║\n"; - os << "╚" << std::string(78, '=') << "╝" << Color(Color::Reset) << "\n\n"; + os << "\n" + << Bold(title) << "\n"; + PrintSeparator(os, '=', 60); } void DebugPrinter::PrintSubHeader(const std::string& title, std::ostream& os) const { + os << "\n" + << Bold(title) << "\n"; + PrintSeparator(os, '-', 40); + } + + void DebugPrinter::PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth) + { + std::visit( + [&](const auto& data) { + // Tree connector prefix based on depth + std::string prefix; + if (depth > 0) + { + prefix = Indent(depth - 1) + Color(Color::Gray) + "├─ " + Color(Color::Reset); + } + else + { + prefix = ""; + } + + os << prefix << GetSymbolIcon(symbol) << " " + << ColorizeSymbolName(symbol.name(), symbol.kind()) + << " " << Color(Color::Dim) << "(" << FormatSymbolKind(symbol.kind()) << ")" << Color(Color::Reset); + + if (options_.show_location) + { + os << " " << Color(Color::Gray) << "@ " << FormatLocation(symbol.selection_range()) << Color(Color::Reset); + } + + // Type-specific details + if constexpr (std::is_same_v, Function>) + { + if (options_.show_details) + { + os << " " << Color(Color::BrightGreen) << "→ " << (data.return_type ? *data.return_type : "void") << Color(Color::Reset); + if (!data.parameters.empty()) + { + os << " " << Color(Color::Dim) << "("; + for (size_t i = 0; i < data.parameters.size(); ++i) + { + const auto& p = data.parameters[i]; + os << p.name; + if (p.type) + os << ":" << *p.type; + if (i + 1 < data.parameters.size()) + os << ", "; + } + os << ")" << Color(Color::Reset); + } + } + } + else if constexpr (std::is_same_v, Method>) + { + if (options_.show_details) + { + os << " " << Color(Color::Cyan) << "[" << AccessModifierToString(data.access) << "]" << Color(Color::Reset); + + if (data.is_static) + os << " " << Color(Color::Yellow) << "static" << Color(Color::Reset); + + if (data.return_type) + os << " " << Color(Color::BrightGreen) << "→ " << *data.return_type << Color(Color::Reset); + + if (!data.parameters.empty()) + { + os << " " << Color(Color::Dim) << "("; + for (size_t i = 0; i < data.parameters.size(); ++i) + { + const auto& p = data.parameters[i]; + os << p.name; + if (p.type) + os << ":" << *p.type; + if (i + 1 < data.parameters.size()) + os << ", "; + } + os << ")" << Color(Color::Reset); + } + } + } + else if constexpr (std::is_same_v, Property>) + { + if (options_.show_details) + { + os << " " << Color(Color::Cyan) << "[" << AccessModifierToString(data.access) << "]" << Color(Color::Reset); + if (data.type) + os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset); + } + } + else if constexpr (std::is_same_v, Field>) + { + if (options_.show_details) + { + os << " " << Color(Color::Cyan) << "[" << AccessModifierToString(data.access) << "]" << Color(Color::Reset); + if (data.type) + os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset); + if (data.is_static) + os << " " << Color(Color::Yellow) << "static" << Color(Color::Reset); + } + } + else if constexpr (std::is_same_v, Variable>) + { + if (options_.show_details) + { + os << " " << Color(Color::Dim) << "(" << VariableScopeToString(data.storage) << ")" << Color(Color::Reset); + if (data.type) + os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset); + if (data.has_initializer) + os << " " << Color(Color::Gray) << "= ..." << Color(Color::Reset); + } + } + else if constexpr (std::is_same_v, Constant>) + { + if (options_.show_details) + { + if (data.type) + os << " " << Color(Color::BrightGreen) << ":" << *data.type << Color(Color::Reset); + os << " " << Color(Color::Gray) << "= " << data.value << Color(Color::Reset); + } + } + + const auto& refs = table_.references().references(symbol.id()); + if (options_.show_references && !refs.empty()) + { + os << " " << Dim("[refs: " + std::to_string(refs.size()) + "]"); + } + + os << "\n"; + }, + symbol.data()); + } + + void DebugPrinter::PrintSymbol(SymbolId id, std::ostream& os, int depth) + { + const auto* sym = table_.definition(id); + if (!sym) + { + os << Indent(depth) << "❓ Unknown symbol: " << id << "\n"; + return; + } + + PrintSymbolData(*sym, os, depth); + } + + void DebugPrinter::PrintSymbolWithChildren(SymbolId id, const std::unordered_multimap& children, std::ostream& os, int depth, int current_depth) + { + if (options_.max_depth >= 0 && current_depth > options_.max_depth) + return; + + PrintSymbol(id, os, depth); + + if (!options_.show_children) + return; + + auto range = children.equal_range(id); + std::vector child_list; + for (auto it = range.first; it != range.second; ++it) + { + child_list.push_back(it->second); + } + + // Sort children by location for consistent output + std::sort(child_list.begin(), child_list.end(), [this](SymbolId a, SymbolId b) { + const auto* sym_a = table_.definition(a); + const auto* sym_b = table_.definition(b); + if (!sym_a || !sym_b) + return a < b; + + auto loc_a = sym_a->selection_range(); + auto loc_b = sym_b->selection_range(); + + if (loc_a.start_line != loc_b.start_line) + return loc_a.start_line < loc_b.start_line; + return loc_a.start_column < loc_b.start_column; + }); + + for (auto child_id : child_list) + { + PrintSymbolWithChildren(child_id, children, os, depth + 1, current_depth + 1); + } + } + + void DebugPrinter::PrintSymbolTree(SymbolId id, std::ostream& os, int depth) + { + std::unordered_multimap children; + for (const auto& [scope_id, scope] : table_.scopes().all_scopes()) + { + if (scope.owner) + { + for (const auto& [_, sym_id] : scope.symbols) + { + children.emplace(*scope.owner, sym_id); + } + } + } + + PrintSymbolWithChildren(id, children, os, depth, 0); + } + + void DebugPrinter::PrintSymbolList(std::ostream& os) + { + PrintHeader("Symbols", os); + + auto all_defs = table_.all_definitions(); + + // Group symbols by their parent (class/namespace) + std::unordered_multimap children; + std::unordered_set has_parent; + + for (const auto& [scope_id, scope] : table_.scopes().all_scopes()) + { + if (scope.owner) + { + for (const auto& [_, sym_id] : scope.symbols) + { + children.emplace(*scope.owner, sym_id); + has_parent.insert(sym_id); + } + } + } + + // Find top-level symbols (no parent) + std::vector top_level; + for (const auto& ref : all_defs) + { + const auto& sym = ref.get(); + if (has_parent.find(sym.id()) == has_parent.end()) + { + top_level.push_back(&sym); + } + } + + // Sort top-level symbols by location + std::sort(top_level.begin(), top_level.end(), [](const Symbol* a, const Symbol* b) { + auto loc_a = a->selection_range(); + auto loc_b = b->selection_range(); + if (loc_a.start_line != loc_b.start_line) + return loc_a.start_line < loc_b.start_line; + return loc_a.start_column < loc_b.start_column; + }); + + // Print each top-level symbol with its children + for (const auto* sym : top_level) + { + PrintSymbolWithChildren(sym->id(), children, os, 0, 0); + } + } + + void DebugPrinter::PrintSymbolsByKind(SymbolKind kind, std::ostream& os) + { + PrintSubHeader("Symbols of kind: " + FormatSymbolKind(kind), os); + auto all_defs = table_.all_definitions(); + for (const auto& ref : all_defs) + { + const auto& sym = ref.get(); + if (sym.kind() == kind) + { + PrintSymbolData(sym, os, 0); + } + } + } + + void DebugPrinter::PrintScope(ScopeId id, std::ostream& os, int depth) + { + const auto* scope = table_.scopes().scope(id); + if (!scope) + { + os << Indent(depth) << "❓ Unknown scope: " << id << "\n"; + return; + } + + os << Indent(depth) << "📁 " << FormatScopeKind(scope->kind) + << " (id=" << id << ")"; + if (scope->owner) + { + os << " owner=" << *scope->owner; + } os << "\n"; - os << Color(Color::Bold) << Color(Color::BrightCyan) - << "┌─ " << title << " " << std::string(73 - title.length(), '-') << "\n" - << Color(Color::Reset); + + for (const auto& [name, sym_id] : scope->symbols) + { + os << Indent(depth + 1) << "• " << name << " (id=" << sym_id << ")\n"; + } } - std::string DebugPrinter::Color(const char* color_code) const + void DebugPrinter::PrintScopeTree(ScopeId id, std::ostream& os, int depth) { - return options_.use_color ? color_code : ""; + const auto& all_scopes = table_.scopes().all_scopes(); + std::unordered_multimap children; + for (const auto& [scope_id, scope] : all_scopes) + { + if (scope.parent) + { + children.emplace(*scope.parent, scope_id); + } + } + + std::function dfs = [&](ScopeId sid, int d) { + PrintScope(sid, os, d); + auto range = children.equal_range(sid); + for (auto it = range.first; it != range.second; ++it) + { + dfs(it->second, d + 1); + } + }; + + dfs(id, depth); } - std::string DebugPrinter::Bold(const std::string& text) const + void DebugPrinter::PrintScopeHierarchy(std::ostream& os) { - if (!options_.use_color) - return text; - return std::string(Color::Bold) + text + Color::Reset; + PrintHeader("Scopes", os); + const auto& scopes = table_.scopes().all_scopes(); + if (scopes.empty()) + { + os << "No scopes available\n"; + return; + } + + auto global = table_.scopes().global_scope(); + if (global == kInvalidScopeId && !scopes.empty()) + { + global = scopes.begin()->first; + } + PrintScopeTree(global, os, 0); } - std::string DebugPrinter::Dim(const std::string& text) const + void DebugPrinter::PrintReferences(SymbolId id, std::ostream& os) { - if (!options_.use_color) - return text; - return std::string(Color::Dim) + text + Color::Reset; + const auto& refs = table_.references().references(id); + if (refs.empty()) + return; + + PrintSubHeader("References for symbol " + std::to_string(id), os); + for (const auto& ref : refs) + { + os << " - " << FormatLocation(ref.location); + if (ref.is_definition) + os << " (def)"; + if (ref.is_write) + os << " (write)"; + os << "\n"; + } } - // ==================== 快速打印函数 ==================== + void DebugPrinter::PrintInheritance(SymbolId class_id, std::ostream& os) + { + const auto& bases = table_.inheritance().base_classes(class_id); + const auto& derived = table_.inheritance().derived_classes(class_id); + + PrintSubHeader("Inheritance for class " + std::to_string(class_id), os); + if (bases.empty() && derived.empty()) + { + os << " (no inheritance info)\n"; + return; + } + + if (!bases.empty()) + { + os << " Base classes: "; + for (size_t i = 0; i < bases.size(); ++i) + { + os << bases[i]; + if (i + 1 < bases.size()) + os << ", "; + } + os << "\n"; + } + if (!derived.empty()) + { + os << " Derived classes: "; + for (size_t i = 0; i < derived.size(); ++i) + { + os << derived[i]; + if (i + 1 < derived.size()) + os << ", "; + } + os << "\n"; + } + } + + void DebugPrinter::PrintCallGraph(SymbolId function_id, std::ostream& os) + { + const auto& incoming = table_.calls().callers(function_id); + const auto& outgoing = table_.calls().callees(function_id); + PrintSubHeader("Call graph for " + std::to_string(function_id), os); + if (incoming.empty() && outgoing.empty()) + { + os << " (no call info)\n"; + return; + } + + if (!incoming.empty()) + { + os << " Called by: "; + for (size_t i = 0; i < incoming.size(); ++i) + { + os << incoming[i].caller; + if (i + 1 < incoming.size()) + os << ", "; + } + os << "\n"; + } + + if (!outgoing.empty()) + { + os << " Calls: "; + for (size_t i = 0; i < outgoing.size(); ++i) + { + os << outgoing[i].callee; + if (i + 1 < outgoing.size()) + os << ", "; + } + os << "\n"; + } + } + + void DebugPrinter::PrintAllReferences(std::ostream& os) + { + PrintHeader("References", os); + auto all_defs = table_.all_definitions(); + for (const auto& ref : all_defs) + { + const auto& sym = ref.get(); + PrintReferences(sym.id(), os); + } + } + + void DebugPrinter::PrintAllInheritance(std::ostream& os) + { + PrintHeader("Inheritance Graph", os); + auto all_defs = table_.all_definitions(); + for (const auto& ref : all_defs) + { + const auto& sym = ref.get(); + if (sym.kind() == SymbolKind::Class) + { + PrintInheritance(sym.id(), os); + } + } + } + + void DebugPrinter::PrintAllCalls(std::ostream& os) + { + PrintHeader("Call Graph", os); + auto all_defs = table_.all_definitions(); + for (const auto& ref : all_defs) + { + const auto& sym = ref.get(); + if (sym.kind() == SymbolKind::Function || sym.kind() == SymbolKind::Method) + { + PrintCallGraph(sym.id(), os); + } + } + } + + void DebugPrinter::FindAndPrint(const std::string& name, std::ostream& os) + { + PrintHeader("Search: " + name, os); + auto matches = table_.FindSymbolsByName(name); + if (matches.empty()) + { + os << "No symbols found matching \"" << name << "\"\n"; + return; + } + + for (auto id : matches) + { + PrintSymbol(id, os); + PrintReferences(id, os); + } + } + + void DebugPrinter::FindAtLocation(const ast::Location& loc, std::ostream& os) + { + auto id = table_.FindSymbolAt(loc); + if (!id) + { + os << "No symbol found at location " << FormatLocation(loc) << "\n"; + return; + } + PrintSymbol(*id, os); + } + + void DebugPrinter::PrintOverview(std::ostream& os) + { + PrintHeader("Overview", os); + os << "Symbols: " << stats_.total_symbols << "\n"; + os << "Scopes: " << stats_.total_scopes << "\n"; + os << "Refs: " << stats_.total_references << "\n"; + } + + void DebugPrinter::PrintStatistics(std::ostream& os) + { + stats_.Print(os, options_.use_color); + } + + void DebugPrinter::PrintAll(std::ostream& os) + { + PrintOverview(os); + PrintSymbolList(os); + PrintScopeHierarchy(os); + + if (options_.show_references) + { + PrintAllReferences(os); + } + PrintAllInheritance(os); + PrintAllCalls(os); + PrintStatistics(os); + } + + // ==================== Free functions ==================== void Print(const SymbolTable& table, std::ostream& os) { - DebugPrinter printer(table); + DebugPrinter printer(table, PrintOptions::Default()); printer.PrintAll(os); } void PrintOverview(const SymbolTable& table, std::ostream& os) { - DebugPrinter printer(table); + DebugPrinter printer(table, PrintOptions::Default()); printer.PrintOverview(os); } void PrintStats(const SymbolTable& table, std::ostream& os) { - DebugPrinter printer(table); + DebugPrinter printer(table, PrintOptions::Default()); printer.PrintStatistics(os); } void PrintSymbolTree(const SymbolTable& table, std::ostream& os) { - DebugPrinter printer(table); - printer.PrintSymbolList(os); + DebugPrinter printer(table, PrintOptions::Default()); + auto defs = table.all_definitions(); + for (const auto& ref : defs) + { + printer.PrintSymbolTree(ref.get().id(), os); + } } void PrintScopeTree(const SymbolTable& table, std::ostream& os) { - DebugPrinter printer(table); + DebugPrinter printer(table, PrintOptions::Default()); printer.PrintScopeHierarchy(os); } void Find(const SymbolTable& table, const std::string& name, std::ostream& os) { - DebugPrinter printer(table); + DebugPrinter printer(table, PrintOptions::Default()); printer.FindAndPrint(name, os); } @@ -1099,7 +944,7 @@ namespace lsp::language::symbol::debug { DebugPrinter printer(table, PrintOptions::Compact()); printer.PrintOverview(os); - printer.PrintStatistics(os); + printer.PrintSymbolList(os); } void PrintVerbose(const SymbolTable& table, std::ostream& os) diff --git a/lsp-server/test/test_symbol/debug_printer.hpp b/lsp-server/test/test_symbol/debug_printer.hpp index 8ac84c1..141c2ee 100644 --- a/lsp-server/test/test_symbol/debug_printer.hpp +++ b/lsp-server/test/test_symbol/debug_printer.hpp @@ -2,39 +2,11 @@ #include #include +#include #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"; - } // ==================== 打印选项 ==================== @@ -134,32 +106,21 @@ namespace lsp::language::symbol::debug 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 PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth); + void PrintSymbolWithChildren(SymbolId id, const std::unordered_multimap& children, std::ostream& os, int depth, int current_depth); + std::string GetSymbolIcon(const Symbol& symbol) 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 diff --git a/lsp-server/test/test_symbol/test.cpp b/lsp-server/test/test_symbol/test.cpp index 8b8a719..4bd7a91 100644 --- a/lsp-server/test/test_symbol/test.cpp +++ b/lsp-server/test/test_symbol/test.cpp @@ -1,8 +1,15 @@ -#include +#include +#include +#include #include +#include +#include #include #include -#include +#include +#include +#include +#include extern "C" { #include @@ -256,17 +263,28 @@ 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::kVarDeclaration: return "VarDeclaration"; - case ast::NodeKind::kConstDeclaration: return "ConstDeclaration"; - case ast::NodeKind::kIfStatement: return "IfStatement"; - case ast::NodeKind::kForInStatement: return "ForInStatement"; - case ast::NodeKind::kWhileStatement: return "WhileStatement"; - // ... 添加其他类型 - default: return "Unknown"; + case ast::NodeKind::kProgram: + return "Program"; + case ast::NodeKind::kFunctionDefinition: + return "FunctionDefinition"; + case ast::NodeKind::kFunctionDeclaration: + return "FunctionDeclaration"; + case ast::NodeKind::kClassDefinition: + return "ClassDefinition"; + case ast::NodeKind::kUnitDefinition: + return "UnitDefinition"; + case ast::NodeKind::kVarDeclaration: + return "VarDeclaration"; + case ast::NodeKind::kConstDeclaration: + return "ConstDeclaration"; + case ast::NodeKind::kIfStatement: + return "IfStatement"; + case ast::NodeKind::kForInStatement: + return "ForInStatement"; + case ast::NodeKind::kWhileStatement: + return "WhileStatement"; + default: + return "Unknown"; } } @@ -284,11 +302,9 @@ void PrintASTStructure(const ast::ParseResult& parse_result, std::ostream& os) 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(stmt.get())) { os << " - Function: " << func_def->name; @@ -308,11 +324,591 @@ void PrintASTStructure(const ast::ParseResult& parse_result, std::ostream& os) os << "\n"; } +// ==================== 符号表构建器 ==================== + +class SymbolBuilder +{ +public: + explicit SymbolBuilder(symbol::SymbolTable& table) : table_(table) {} + + void Build(const ast::Program& program) + { + EnterScope(symbol::ScopeKind::kGlobal, program.span, std::nullopt); + + for (const auto& stmt : program.statements) + { + HandleStatement(stmt); + } + + LeaveScope(); + } + +private: + static std::string ToLower(std::string s) + { + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); + return s; + } + + std::optional ExtractTypeName(const std::optional& type) const + { + if (type) + return type->name; + return std::nullopt; + } + + std::vector BuildParameters(const std::vector>& parameters) const + { + std::vector result; + result.reserve(parameters.size()); + + for (const auto& param : parameters) + { + if (!param) + continue; + + symbol::Parameter p; + p.name = param->name; + if (param->type) + { + p.type = param->type->name; + } + if (param->default_value) + { + p.default_value = ""; + } + result.push_back(std::move(p)); + } + + return result; + } + + symbol::SymbolId AddSymbol(symbol::Symbol symbol, const std::string& name) + { + auto id = table_.CreateSymbol(std::move(symbol)); + auto scope = CurrentScope(); + if (scope != symbol::kInvalidScopeId) + { + table_.AddSymbolToScope(scope, name, id); + } + name_index_[ToLower(name)] = id; + return id; + } + + void EnterScope(symbol::ScopeKind kind, const ast::Location& range, std::optional owner) + { + std::optional parent_scope = std::nullopt; + if (!scope_stack_.empty()) + { + parent_scope = scope_stack_.back(); + } + auto id = table_.CreateScope(kind, range, parent_scope, owner); + if (owner) + { + scope_by_owner_[*owner] = id; + } + scope_stack_.push_back(id); + } + + void LeaveScope() + { + if (!scope_stack_.empty()) + { + scope_stack_.pop_back(); + } + } + + symbol::ScopeId CurrentScope() const + { + return scope_stack_.empty() ? symbol::kInvalidScopeId : scope_stack_.back(); + } + + void HandleStatement(const ast::StatementPtr& stmt) + { + if (!stmt) + return; + + switch (stmt->kind) + { + case ast::NodeKind::kFunctionDefinition: + HandleFunctionDefinition(*static_cast(stmt.get())); + break; + case ast::NodeKind::kFunctionDeclaration: + HandleFunctionDeclaration(*static_cast(stmt.get())); + break; + case ast::NodeKind::kMethodDeclaration: + HandleMethodDeclaration(*static_cast(stmt.get()), std::nullopt, ast::AccessModifier::kPublic); + break; + case ast::NodeKind::kPropertyDeclaration: + HandlePropertyDeclaration(*static_cast(stmt.get()), std::nullopt, ast::AccessModifier::kPublic); + break; + case ast::NodeKind::kClassDefinition: + HandleClassDefinition(*static_cast(stmt.get())); + break; + case ast::NodeKind::kUnitDefinition: + HandleUnitDefinition(*static_cast(stmt.get())); + break; + case ast::NodeKind::kVarDeclaration: + HandleVariable(*static_cast(stmt.get()), symbol::VariableScope::kAutomatic); + break; + case ast::NodeKind::kStaticDeclaration: + HandleStatic(*static_cast(stmt.get())); + break; + case ast::NodeKind::kGlobalDeclaration: + HandleGlobalDeclaration(*static_cast(stmt.get())); + break; + case ast::NodeKind::kConstDeclaration: + HandleConstant(*static_cast(stmt.get())); + break; + case ast::NodeKind::kExternalMethodDefinition: + HandleExternalMethod(*static_cast(stmt.get())); + break; + case ast::NodeKind::kBlockStatement: + HandleBlock(*static_cast(stmt.get()), true); + break; + case ast::NodeKind::kIfStatement: + HandleIfStatement(*static_cast(stmt.get())); + break; + case ast::NodeKind::kForInStatement: + HandleForInStatement(*static_cast(stmt.get())); + break; + case ast::NodeKind::kForToStatement: + HandleForToStatement(*static_cast(stmt.get())); + break; + case ast::NodeKind::kWhileStatement: + HandleWhileStatement(*static_cast(stmt.get())); + break; + case ast::NodeKind::kRepeatStatement: + HandleRepeatStatement(*static_cast(stmt.get())); + break; + case ast::NodeKind::kCaseStatement: + HandleCaseStatement(*static_cast(stmt.get())); + break; + case ast::NodeKind::kTryStatement: + HandleTryStatement(*static_cast(stmt.get())); + break; + default: + break; + } + } + + void HandleFunctionDeclaration(ast::FunctionDeclaration& node) + { + symbol::Function fn; + fn.name = node.name; + fn.selection_range = node.span; + fn.range = node.span; + fn.declaration_range = node.span; + fn.parameters = BuildParameters(node.parameters); + fn.return_type = ExtractTypeName(node.return_type); + + AddSymbol(symbol::Symbol(std::move(fn)), node.name); + } + + void HandleFunctionDefinition(ast::FunctionDefinition& node) + { + symbol::Function fn; + fn.name = node.name; + fn.selection_range = node.location; + fn.range = node.span; + fn.declaration_range = node.location; + fn.implementation_range = node.location; + fn.parameters = BuildParameters(node.parameters); + fn.return_type = ExtractTypeName(node.return_type); + + auto fn_id = AddSymbol(symbol::Symbol(std::move(fn)), node.name); + + if (node.body) + { + EnterScope(symbol::ScopeKind::kFunction, node.body->span, fn_id); + for (const auto& param : node.parameters) + { + if (!param) + continue; + symbol::Variable var; + var.name = param->name; + var.selection_range = param->location; + var.range = param->location; + var.storage = symbol::VariableScope::kParameter; + var.type = param->type ? std::optional(param->type->name) : std::nullopt; + AddSymbol(symbol::Symbol(std::move(var)), param->name); + } + + HandleBlock(*node.body, false); + LeaveScope(); + } + } + + void HandleClassDefinition(ast::ClassDefinition& node) + { + symbol::Class cls; + cls.name = node.name; + cls.selection_range = node.location; + cls.range = node.span; + + auto class_id = AddSymbol(symbol::Symbol(std::move(cls)), node.name); + + EnterScope(symbol::ScopeKind::kClass, node.span, class_id); + + for (const auto& parent : node.parent_classes) + { + auto it = name_index_.find(ToLower(parent.name)); + if (it != name_index_.end()) + { + table_.AddInheritance(class_id, it->second); + } + } + + for (auto& member : node.members) + { + if (member) + HandleClassMember(*member); + } + + LeaveScope(); + } + + void HandleClassMember(ast::ClassMember& member) + { + std::visit( + [&](auto& ptr) { + using T = std::decay_t; + if (!ptr) + return; + + if constexpr (std::is_same_v>) + { + HandleFieldDeclaration(*ptr, member.access_modifier, false); + } + else if constexpr (std::is_same_v>) + { + HandleStatic(*ptr, member.access_modifier, true); + } + else if constexpr (std::is_same_v>) + { + HandleMethodDeclaration(*ptr, CurrentScopeOwner(), member.access_modifier); + } + else if constexpr (std::is_same_v>) + { + HandlePropertyDeclaration(*ptr, CurrentScopeOwner(), member.access_modifier); + } + }, + member.member); + } + + std::optional CurrentScopeOwner() const + { + if (scope_stack_.empty()) + return std::nullopt; + + auto current = scope_stack_.back(); + for (const auto& [owner, scope_id] : scope_by_owner_) + { + if (scope_id == current) + { + return owner; + } + } + return std::nullopt; + } + + void HandleMethodDeclaration(ast::MethodDeclaration& node, std::optional /*owner*/, ast::AccessModifier access) + { + symbol::Method method; + method.name = node.name; + method.selection_range = node.location; + method.range = node.span; + method.declaration_range = node.location; + if (node.body) + { + method.implementation_range = node.body->span; + } + method.method_kind = node.method_kind; + method.method_modifier = node.modifier; + method.is_static = node.is_static; + method.access = access; + method.parameters = BuildParameters(node.parameters); + method.return_type = ExtractTypeName(node.return_type); + + auto method_id = AddSymbol(symbol::Symbol(std::move(method)), node.name); + + if (node.body) + { + EnterScope(symbol::ScopeKind::kFunction, node.body->span, method_id); + for (const auto& param : node.parameters) + { + if (!param) + continue; + symbol::Variable var; + var.name = param->name; + var.selection_range = param->location; + var.range = param->location; + var.storage = symbol::VariableScope::kParameter; + var.type = param->type ? std::optional(param->type->name) : std::nullopt; + AddSymbol(symbol::Symbol(std::move(var)), param->name); + } + + HandleBlock(*node.body, false); + LeaveScope(); + } + } + + void HandlePropertyDeclaration(ast::PropertyDeclaration& node, std::optional, ast::AccessModifier access) + { + symbol::Property property; + property.name = node.name; + property.selection_range = node.location; + property.range = node.span; + property.access = access; + property.type = ExtractTypeName(node.type); + + AddSymbol(symbol::Symbol(std::move(property)), node.name); + } + + void HandleFieldDeclaration(ast::FieldDeclaration& node, ast::AccessModifier access, bool is_static) + { + symbol::Field field; + field.name = node.name; + field.selection_range = node.location; + field.range = node.span; + field.access = access; + field.reference_modifier = node.reference_modifier; + field.type = ExtractTypeName(node.type); + field.is_static = is_static; + + AddSymbol(symbol::Symbol(std::move(field)), node.name); + } + + void HandleVariable(ast::VarDeclaration& node, symbol::VariableScope storage) + { + symbol::Variable var; + var.name = node.name; + var.selection_range = node.location; + var.range = node.span; + var.storage = storage; + var.type = ExtractTypeName(node.type); + var.has_initializer = node.initializer.has_value(); + + AddSymbol(symbol::Symbol(std::move(var)), node.name); + } + + void HandleStatic(ast::StaticDeclaration& node, ast::AccessModifier access = ast::AccessModifier::kPublic, bool is_class_member = false) + { + if (is_class_member) + { + symbol::Field field; + field.name = node.name; + field.selection_range = node.location; + field.range = node.span; + field.access = access; + field.reference_modifier = node.reference_modifier; + field.type = ExtractTypeName(node.type); + field.is_static = true; + AddSymbol(symbol::Symbol(std::move(field)), node.name); + } + else + { + symbol::Variable var; + var.name = node.name; + var.selection_range = node.location; + var.range = node.span; + var.storage = symbol::VariableScope::kStatic; + var.reference_modifier = node.reference_modifier; + var.type = ExtractTypeName(node.type); + var.has_initializer = node.initializer.has_value(); + AddSymbol(symbol::Symbol(std::move(var)), node.name); + } + } + + void HandleConstant(ast::ConstDeclaration& node) + { + symbol::Constant constant; + constant.name = node.name; + constant.selection_range = node.location; + constant.range = node.span; + constant.type = ExtractTypeName(node.type); + constant.value = ""; + + AddSymbol(symbol::Symbol(std::move(constant)), node.name); + } + + void HandleGlobalDeclaration(ast::GlobalDeclaration& node) + { + symbol::Variable var; + var.name = node.name; + var.selection_range = node.location; + var.range = node.span; + var.storage = symbol::VariableScope::kGlobal; + var.type = ExtractTypeName(node.type); + var.has_initializer = node.initializer.has_value(); + + AddSymbol(symbol::Symbol(std::move(var)), node.name); + } + + void HandleExternalMethod(ast::ExternalMethodDefinition& node) + { + // Try to find owner class scope + auto owner_it = name_index_.find(ToLower(node.owner_class.name)); + std::optional owner_id; + std::optional owner_scope; + if (owner_it != name_index_.end()) + { + owner_id = owner_it->second; + auto scope_it = scope_by_owner_.find(*owner_id); + if (scope_it != scope_by_owner_.end()) + { + owner_scope = scope_it->second; + } + } + + symbol::Method method; + method.name = node.name; + method.selection_range = node.location; + method.range = node.span; + method.declaration_range = node.location; + method.implementation_range = node.location; + method.method_kind = node.method_kind; + method.method_modifier = node.modifier; + method.is_static = node.is_static; + method.parameters = BuildParameters(node.parameters); + method.return_type = ExtractTypeName(node.return_type); + + bool pushed_owner = false; + if (owner_scope) + { + scope_stack_.push_back(*owner_scope); + pushed_owner = true; + } + + auto method_id = AddSymbol(symbol::Symbol(std::move(method)), node.name); + + if (node.body) + { + EnterScope(symbol::ScopeKind::kFunction, node.body->span, method_id); + HandleBlock(*node.body, false); + LeaveScope(); + } + + if (pushed_owner) + { + scope_stack_.pop_back(); + } + } + + void HandleUnitDefinition(ast::UnitDefinition& node) + { + symbol::Unit unit; + unit.name = node.name; + unit.selection_range = node.location; + unit.range = node.span; + + auto unit_id = AddSymbol(symbol::Symbol(std::move(unit)), node.name); + EnterScope(symbol::ScopeKind::kUnit, node.span, unit_id); + + for (auto& stmt : node.interface_statements) + { + HandleStatement(stmt); + } + for (auto& stmt : node.implementation_statements) + { + HandleStatement(stmt); + } + + LeaveScope(); + } + + void HandleBlock(ast::BlockStatement& block, bool create_scope) + { + std::optional scope_holder; + if (create_scope) + { + EnterScope(symbol::ScopeKind::kBlock, block.span, std::nullopt); + scope_holder = CurrentScope(); + } + + for (auto& stmt : block.statements) + { + HandleStatement(stmt); + } + + if (scope_holder) + { + LeaveScope(); + } + } + + void HandleIfStatement(ast::IfStatement& node) + { + for (auto& branch : node.branches) + { + if (branch.body) + HandleStatement(branch.body); + } + + if (node.else_body && *node.else_body) + { + HandleStatement(*node.else_body); + } + } + + void HandleForInStatement(ast::ForInStatement& node) + { + if (node.body) + HandleStatement(node.body); + } + + void HandleForToStatement(ast::ForToStatement& node) + { + if (node.body) + HandleStatement(node.body); + } + + void HandleWhileStatement(ast::WhileStatement& node) + { + if (node.body) + HandleStatement(node.body); + } + + void HandleRepeatStatement(ast::RepeatStatement& node) + { + for (auto& stmt : node.body) + { + HandleStatement(stmt); + } + } + + void HandleCaseStatement(ast::CaseStatement& node) + { + for (auto& branch : node.branches) + { + if (branch.body) + HandleStatement(branch.body); + } + if (node.else_body && *node.else_body) + { + HandleStatement(*node.else_body); + } + } + + void HandleTryStatement(ast::TryStatement& node) + { + if (node.try_body) + HandleBlock(*node.try_body, true); + if (node.except_body) + HandleBlock(*node.except_body, true); + } + +private: + symbol::SymbolTable& table_; + std::vector scope_stack_; + std::unordered_map name_index_; + std::unordered_map scope_by_owner_; +}; + // ==================== 主分析函数 ==================== void AnalyzeFile(const Options& options) { - // 打印头部 if (!options.compact_mode) { std::cout << "\n╔════════════════════════════════════════════════════════════╗\n"; @@ -321,7 +917,6 @@ void AnalyzeFile(const Options& options) std::cout << "Input file: " << options.input_file << "\n"; } - // 1. 读取源文件 if (options.verbose) std::cout << "Reading file...\n"; @@ -335,7 +930,6 @@ void AnalyzeFile(const Options& options) std::cout << "----------------------------------------\n\n"; } - // 2. 使用 Tree-Sitter 解析 if (options.verbose) std::cout << "Parsing with Tree-Sitter...\n"; @@ -349,7 +943,6 @@ void AnalyzeFile(const Options& options) std::cout << "Root node child count: " << ts_node_child_count(root) << "\n\n"; } - // 3. 反序列化为 AST if (options.verbose) std::cout << "Deserializing to AST...\n"; @@ -373,14 +966,14 @@ void AnalyzeFile(const Options& options) 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); + SymbolBuilder builder(table); + builder.Build(*parse_result.root); auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start); @@ -388,7 +981,6 @@ void AnalyzeFile(const Options& options) if (options.verbose) std::cout << "Symbol table built in " << duration.count() << " ms\n\n"; - // 5. 准备输出流 std::ostream* out = &std::cout; std::ofstream file_out; @@ -402,7 +994,6 @@ void AnalyzeFile(const Options& options) } out = &file_out; - // 写入文件头 *out << "Symbol Table Analysis\n"; *out << "Source: " << options.input_file << "\n"; auto now = std::chrono::system_clock::now(); @@ -411,9 +1002,6 @@ void AnalyzeFile(const Options& options) *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(); @@ -427,38 +1015,30 @@ void AnalyzeFile(const Options& options) 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) @@ -491,7 +1071,6 @@ void AnalyzeFile(const Options& options) printed_anything = true; } - // 总是打印统计信息 if (printed_anything) { *out << "\n"; @@ -499,24 +1078,22 @@ void AnalyzeFile(const Options& options) 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 << "Smary:\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 << " Symbols: " << table.all_definitions().size() << "\n"; + std::cout << " Scopes: " << table.scopes().all_scopes().size() << "\n"; std::cout << " Parse Errors: " << parse_result.errors.size() << "\n"; std::cout << " Build Time: " << duration.count() << " ms\n";