475 lines
14 KiB
C++
475 lines
14 KiB
C++
module;
|
|
|
|
import std;
|
|
|
|
export module lsp.test.symbol.debug_printer;
|
|
|
|
import lsp.protocol;
|
|
import lsp.language.ast;
|
|
import lsp.language.symbol;
|
|
|
|
export namespace lsp::language::symbol::debug
|
|
{
|
|
using SymbolKind = protocol::SymbolKind;
|
|
|
|
struct PrintOptions
|
|
{
|
|
bool use_color = true;
|
|
bool show_location = true;
|
|
bool show_details = true;
|
|
bool show_children = true;
|
|
bool compact_mode = false;
|
|
int indent_size = 2;
|
|
int max_depth = -1;
|
|
|
|
static PrintOptions Default()
|
|
{
|
|
return PrintOptions();
|
|
}
|
|
|
|
static PrintOptions Compact()
|
|
{
|
|
PrintOptions opts;
|
|
opts.compact_mode = true;
|
|
opts.show_children = true;
|
|
opts.show_details = false;
|
|
opts.indent_size = 0;
|
|
return opts;
|
|
}
|
|
|
|
static PrintOptions Verbose()
|
|
{
|
|
PrintOptions opts;
|
|
opts.show_children = true;
|
|
opts.show_details = true;
|
|
return opts;
|
|
}
|
|
|
|
static PrintOptions NoColor()
|
|
{
|
|
PrintOptions opts;
|
|
opts.use_color = false;
|
|
return opts;
|
|
}
|
|
};
|
|
|
|
struct Statistics
|
|
{
|
|
std::size_t total_symbols = 0;
|
|
std::size_t total_scopes = 0;
|
|
|
|
std::unordered_map<SymbolKind, std::size_t> symbol_counts;
|
|
std::unordered_map<ScopeKind, std::size_t> scope_counts;
|
|
|
|
void Compute(const SymbolTable& table);
|
|
void Print(std::ostream& os, bool use_color = true) const;
|
|
};
|
|
|
|
class DebugPrinter
|
|
{
|
|
public:
|
|
explicit DebugPrinter(const SymbolTable& table, const PrintOptions& options = PrintOptions::Default());
|
|
|
|
void PrintAll(std::ostream& os = std::cout);
|
|
void PrintOverview(std::ostream& os = std::cout);
|
|
void PrintStatistics(std::ostream& os = std::cout);
|
|
|
|
void PrintSymbol(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
|
void PrintSymbolTree(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
|
void PrintSymbolList(std::ostream& os = std::cout);
|
|
void PrintSymbolsByKind(SymbolKind kind, std::ostream& os = std::cout);
|
|
|
|
void PrintScope(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
|
void PrintScopeTree(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
|
void PrintScopeHierarchy(std::ostream& os = std::cout);
|
|
|
|
void FindAndPrint(const std::string& name, std::ostream& os = std::cout);
|
|
void FindAtLocation(const ast::Location& loc, std::ostream& os = std::cout);
|
|
|
|
void SetOptions(const PrintOptions& options) { options_ = options; }
|
|
const PrintOptions& GetOptions() const { return options_; }
|
|
|
|
private:
|
|
const SymbolTable& table_;
|
|
PrintOptions options_;
|
|
Statistics stats_;
|
|
|
|
std::string Indent(int depth) const;
|
|
std::string ColorizeSymbolKind(SymbolKind kind) const;
|
|
std::string ColorizeSymbolName(const std::string& name, SymbolKind kind) const;
|
|
std::string FormatLocation(const ast::Location& loc) const;
|
|
std::string FormatSymbolKind(SymbolKind kind) const;
|
|
std::string FormatScopeKind(ScopeKind kind) const;
|
|
std::string SymbolIcon(SymbolKind kind) const;
|
|
|
|
void PrintSeparator(std::ostream& os, char ch = '=', int width = 80) const;
|
|
void PrintHeader(const std::string& title, std::ostream& os) const;
|
|
void PrintSubHeader(const std::string& title, std::ostream& os) const;
|
|
|
|
std::string Color(const char* color_code) const;
|
|
std::string Bold(const std::string& text) const;
|
|
std::string Dim(const std::string& text) const;
|
|
|
|
void PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth);
|
|
void PrintSymbolWithChildren(SymbolId id, const std::unordered_multimap<SymbolId, SymbolId>& 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
|
|
{
|
|
using namespace lsp::language;
|
|
using namespace lsp::language::symbol;
|
|
using lsp::protocol::SymbolKind;
|
|
|
|
[[maybe_unused]] 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";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
std::string ScopeKindToString(ScopeKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case ScopeKind::kGlobal:
|
|
return "Global";
|
|
case ScopeKind::kUnit:
|
|
return "Unit";
|
|
case ScopeKind::kClass:
|
|
return "Class";
|
|
case ScopeKind::kFunction:
|
|
return "Function";
|
|
case ScopeKind::kAnonymousFunction:
|
|
return "AnonymousFunction";
|
|
case ScopeKind::kBlock:
|
|
return "Block";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
std::string SymbolKindToString(SymbolKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case SymbolKind::File:
|
|
return "File";
|
|
case SymbolKind::Module:
|
|
return "Module";
|
|
case SymbolKind::Namespace:
|
|
return "Namespace";
|
|
case SymbolKind::Package:
|
|
return "Package";
|
|
case SymbolKind::Class:
|
|
return "Class";
|
|
case SymbolKind::Method:
|
|
return "Method";
|
|
case SymbolKind::Property:
|
|
return "Property";
|
|
case SymbolKind::Field:
|
|
return "Field";
|
|
case SymbolKind::Constructor:
|
|
return "Constructor";
|
|
case SymbolKind::Enum:
|
|
return "Enum";
|
|
case SymbolKind::Interface:
|
|
return "Interface";
|
|
case SymbolKind::Function:
|
|
return "Function";
|
|
case SymbolKind::Variable:
|
|
return "Variable";
|
|
case SymbolKind::Constant:
|
|
return "Constant";
|
|
case SymbolKind::String:
|
|
return "String";
|
|
case SymbolKind::Number:
|
|
return "Number";
|
|
case SymbolKind::Boolean:
|
|
return "Boolean";
|
|
case SymbolKind::Array:
|
|
return "Array";
|
|
case SymbolKind::Object:
|
|
return "Object";
|
|
case SymbolKind::Key:
|
|
return "Key";
|
|
case SymbolKind::Null:
|
|
return "Null";
|
|
case SymbolKind::EnumMember:
|
|
return "EnumMember";
|
|
case SymbolKind::Struct:
|
|
return "Struct";
|
|
case SymbolKind::Event:
|
|
return "Event";
|
|
case SymbolKind::Operator:
|
|
return "Operator";
|
|
case SymbolKind::TypeParameter:
|
|
return "TypeParameter";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace lsp::language::symbol::debug
|
|
{
|
|
void Statistics::Compute(const SymbolTable& table)
|
|
{
|
|
total_symbols = table.all_definitions().size();
|
|
total_scopes = 0;
|
|
// 不再深入统计,避免依赖内部存储。
|
|
}
|
|
|
|
DebugPrinter::DebugPrinter(const SymbolTable& table, const PrintOptions& options) :
|
|
table_(table), options_(options)
|
|
{
|
|
stats_.Compute(table_);
|
|
}
|
|
|
|
void DebugPrinter::PrintAll(std::ostream& os)
|
|
{
|
|
PrintOverview(os);
|
|
os << "\n";
|
|
PrintStatistics(os);
|
|
os << "\nSymbols:\n";
|
|
PrintSymbolList(os);
|
|
}
|
|
|
|
void DebugPrinter::PrintOverview(std::ostream& os)
|
|
{
|
|
PrintHeader("Symbol Table Overview", os);
|
|
os << "Total Symbols: " << stats_.total_symbols << "\n";
|
|
os << "Total Scopes : " << stats_.total_scopes << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintStatistics(std::ostream& os)
|
|
{
|
|
stats_.Print(os, options_.use_color);
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbol(SymbolId id, std::ostream& os, int depth)
|
|
{
|
|
auto symbol = table_.definition(id);
|
|
if (!symbol)
|
|
{
|
|
os << Indent(depth) << "<invalid symbol>\n";
|
|
return;
|
|
}
|
|
PrintSymbolData(*symbol, os, depth);
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolTree(SymbolId id, std::ostream& os, int depth)
|
|
{
|
|
auto symbol = table_.definition(id);
|
|
if (!symbol)
|
|
return;
|
|
|
|
PrintSymbolData(*symbol, os, depth);
|
|
|
|
// Example placeholder for children traversal
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolList(std::ostream& os)
|
|
{
|
|
for (const auto& sym : table_.all_definitions())
|
|
PrintSymbol(sym.get().id(), os, 0);
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolsByKind(SymbolKind kind, std::ostream& os)
|
|
{
|
|
for (const auto& sym : table_.all_definitions())
|
|
{
|
|
if (sym.get().kind() == kind)
|
|
PrintSymbol(sym.get().id(), os, 0);
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintScope(ScopeId id, std::ostream& os, int depth)
|
|
{
|
|
os << Indent(depth) << "Scope " << id << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintScopeTree(ScopeId id, std::ostream& os, int depth)
|
|
{
|
|
PrintScope(id, os, depth);
|
|
}
|
|
|
|
void DebugPrinter::PrintScopeHierarchy(std::ostream& os)
|
|
{
|
|
PrintScopeTree(ScopeId{ 0 }, os, 0);
|
|
}
|
|
|
|
void DebugPrinter::FindAndPrint(const std::string& name, std::ostream& os)
|
|
{
|
|
auto ids = table_.FindSymbolsByName(name);
|
|
for (auto id : ids)
|
|
PrintSymbol(id, os, 0);
|
|
}
|
|
|
|
void DebugPrinter::FindAtLocation(const ast::Location& loc, std::ostream& os)
|
|
{
|
|
auto id = table_.FindSymbolAt(loc);
|
|
if (id)
|
|
PrintSymbol(*id, os, 0);
|
|
else
|
|
os << "No symbol at location.\n";
|
|
}
|
|
|
|
std::string DebugPrinter::Indent(int depth) const
|
|
{
|
|
return std::string(depth * options_.indent_size, ' ');
|
|
}
|
|
|
|
std::string DebugPrinter::ColorizeSymbolKind(SymbolKind kind) const
|
|
{
|
|
return options_.use_color ? Bold(SymbolKindToString(kind)) : SymbolKindToString(kind);
|
|
}
|
|
|
|
std::string DebugPrinter::ColorizeSymbolName(const std::string& name, SymbolKind) const
|
|
{
|
|
return options_.use_color ? Bold(name) : name;
|
|
}
|
|
|
|
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 << "]";
|
|
return oss.str();
|
|
}
|
|
|
|
std::string DebugPrinter::FormatSymbolKind(SymbolKind kind) const
|
|
{
|
|
return SymbolKindToString(kind);
|
|
}
|
|
|
|
std::string DebugPrinter::FormatScopeKind(ScopeKind kind) const
|
|
{
|
|
return ScopeKindToString(kind);
|
|
}
|
|
|
|
void DebugPrinter::PrintSeparator(std::ostream& os, char ch, int width) const
|
|
{
|
|
os << std::string(width, ch) << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintHeader(const std::string& title, std::ostream& os) const
|
|
{
|
|
PrintSeparator(os);
|
|
os << title << "\n";
|
|
PrintSeparator(os);
|
|
}
|
|
|
|
void DebugPrinter::PrintSubHeader(const std::string& title, std::ostream& os) const
|
|
{
|
|
os << title << "\n";
|
|
PrintSeparator(os, '-', 40);
|
|
}
|
|
|
|
std::string DebugPrinter::Color(const char* color_code) const
|
|
{
|
|
return options_.use_color ? std::string(color_code) : std::string();
|
|
}
|
|
|
|
std::string DebugPrinter::Bold(const std::string& text) const
|
|
{
|
|
return Color("\033[1m") + text + Color("\033[0m");
|
|
}
|
|
|
|
std::string DebugPrinter::Dim(const std::string& text) const
|
|
{
|
|
return Color("\033[2m") + text + Color("\033[0m");
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolData(const Symbol& symbol, std::ostream& os, int depth)
|
|
{
|
|
os << Indent(depth) << ColorizeSymbolName(symbol.name(), symbol.kind())
|
|
<< " (" << FormatSymbolKind(symbol.kind()) << ")";
|
|
|
|
if (options_.show_location)
|
|
os << " " << FormatLocation(symbol.selection_range());
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
std::string DebugPrinter::GetSymbolIcon(const Symbol& symbol) const
|
|
{
|
|
(void)symbol;
|
|
return {};
|
|
}
|
|
|
|
void Statistics::Print(std::ostream& os, bool use_color) const
|
|
{
|
|
auto bold = [&](const std::string& txt) { return use_color ? "\033[1m" + txt + "\033[0m" : txt; };
|
|
os << bold("Symbols: ") << total_symbols << "\n";
|
|
os << bold("Scopes : ") << total_scopes << "\n";
|
|
}
|
|
|
|
void Print(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintAll(os);
|
|
}
|
|
|
|
void PrintOverview(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintOverview(os);
|
|
}
|
|
|
|
void PrintStats(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintStatistics(os);
|
|
}
|
|
|
|
void PrintSymbolTree(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintSymbolTree(SymbolId{ 0 }, os, 0);
|
|
}
|
|
|
|
void PrintScopeTree(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintScopeTree(ScopeId{ 0 }, os, 0);
|
|
}
|
|
|
|
void Find(const SymbolTable& table, const std::string& name, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.FindAndPrint(name, os);
|
|
}
|
|
|
|
void PrintCompact(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table, PrintOptions::Compact());
|
|
printer.PrintOverview(os);
|
|
printer.PrintSymbolList(os);
|
|
}
|
|
|
|
void PrintVerbose(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table, PrintOptions::Verbose());
|
|
printer.PrintAll(os);
|
|
}
|
|
}
|