add symbol table and test file
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
cmake_minimum_required(VERSION 4.0)
|
||||
|
||||
project(test_symbol)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
|
||||
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if (DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
message(STATUS ">>> CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
|
||||
endif()
|
||||
if (DEFINED VCPKG_TARGET_TRIPLET)
|
||||
message(STATUS ">>> VCPKG_TARGET_TRIPLET: ${VCPKG_TARGET_TRIPLET}")
|
||||
endif()
|
||||
|
||||
# 设置默认构建类型
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE
|
||||
"Release"
|
||||
CACHE STRING "Build type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
|
||||
"MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# MinGW/MSYS2 静态链接
|
||||
if(MINGW)
|
||||
add_link_options(-static -static-libgcc -static-libstdc++)
|
||||
elseif(UNIX AND NOT APPLE) # Linux 静态链接
|
||||
add_link_options(-static-libgcc -static-libstdc++)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib" ".dll.a")
|
||||
else()
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
|
||||
endif()
|
||||
|
||||
find_package(glaze CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(Taskflow REQUIRED)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
find_package(unofficial-tree-sitter CONFIG REQUIRED)
|
||||
set(TREESITTER_TARGET unofficial::tree-sitter::tree-sitter)
|
||||
else()
|
||||
# find_package(PkgConfig REQUIRED)
|
||||
# pkg_check_modules(TREESITTER tree-sitter)
|
||||
find_library(TREESITTER_LIBRARY tree-sitter) # use ${TREESITTER_LIBRARY}
|
||||
set(TREESITTER_TARGET ${TREESITTER_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(NOT TARGET spdlog::spdlog_header_only)
|
||||
message(WARNING "spdlog header-only target not found, using shared library")
|
||||
endif()
|
||||
if(NOT TARGET fmt::fmt-header-only)
|
||||
message(WARNING "fmt header-only target not found, using shared library")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(SOURCES
|
||||
./test.cpp
|
||||
./debug_printer.cpp
|
||||
../../src/language/ast/deserializer.cpp
|
||||
../../src/language/ast/detail.cpp
|
||||
../../src/language/ast/tree_sitter_utils.cpp
|
||||
../../src/language/symbol/builder.cpp
|
||||
../../src/language/symbol/location_index.cpp
|
||||
../../src/language/symbol/relations.cpp
|
||||
../../src/language/symbol/store.cpp
|
||||
../../src/language/symbol/scope.cpp
|
||||
../../src/language/symbol/table.cpp
|
||||
../../src/language/symbol/builder.cpp
|
||||
../../src/utils/string.cpp
|
||||
../../src/tree-sitter/parser.c)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE src)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SPDLOG_HEADER_ONLY
|
||||
FMT_HEADER_ONLY)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
glaze::glaze
|
||||
Taskflow::Taskflow
|
||||
spdlog::spdlog_header_only
|
||||
fmt::fmt-header-only
|
||||
${TREESITTER_TARGET} # 使用变量,避免条件判断
|
||||
$<$<PLATFORM_ID:Linux>:Threads::Threads> # 使用生成器表达式
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
-Wall -Wextra -Wpedantic
|
||||
$<$<CONFIG:Debug>:-g -O0>
|
||||
$<$<CONFIG:Release>:-O3>
|
||||
)
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "../../src/language/symbol/table.hpp"
|
||||
|
||||
namespace lsp::language::symbol::debug
|
||||
{
|
||||
// ==================== 颜色和样式 ====================
|
||||
|
||||
namespace Color
|
||||
{
|
||||
// ANSI 颜色码
|
||||
constexpr const char* Reset = "\033[0m";
|
||||
constexpr const char* Bold = "\033[1m";
|
||||
constexpr const char* Dim = "\033[2m";
|
||||
|
||||
// 前景色
|
||||
constexpr const char* Black = "\033[30m";
|
||||
constexpr const char* Red = "\033[31m";
|
||||
constexpr const char* Green = "\033[32m";
|
||||
constexpr const char* Yellow = "\033[33m";
|
||||
constexpr const char* Blue = "\033[34m";
|
||||
constexpr const char* Magenta = "\033[35m";
|
||||
constexpr const char* Cyan = "\033[36m";
|
||||
constexpr const char* White = "\033[37m";
|
||||
|
||||
// 亮色
|
||||
constexpr const char* BrightBlack = "\033[90m";
|
||||
constexpr const char* BrightRed = "\033[91m";
|
||||
constexpr const char* BrightGreen = "\033[92m";
|
||||
constexpr const char* BrightYellow = "\033[93m";
|
||||
constexpr const char* BrightBlue = "\033[94m";
|
||||
constexpr const char* BrightMagenta = "\033[95m";
|
||||
constexpr const char* BrightCyan = "\033[96m";
|
||||
constexpr const char* BrightWhite = "\033[97m";
|
||||
}
|
||||
|
||||
// ==================== 打印选项 ====================
|
||||
|
||||
struct PrintOptions
|
||||
{
|
||||
bool use_color = true; // 使用颜色
|
||||
bool show_location = true; // 显示位置信息
|
||||
bool show_details = true; // 显示详细信息
|
||||
bool show_children = true; // 显示子符号
|
||||
bool show_references = false; // 显示引用列表
|
||||
bool compact_mode = false; // 紧凑模式
|
||||
int indent_size = 2; // 缩进大小
|
||||
int max_depth = -1; // 最大深度 (-1 = 无限制)
|
||||
|
||||
static PrintOptions Default();
|
||||
static PrintOptions Compact();
|
||||
static PrintOptions Verbose();
|
||||
static PrintOptions NoColor();
|
||||
};
|
||||
|
||||
// ==================== 统计信息 ====================
|
||||
|
||||
struct Statistics
|
||||
{
|
||||
size_t total_symbols = 0;
|
||||
size_t total_scopes = 0;
|
||||
size_t total_references = 0;
|
||||
|
||||
std::unordered_map<SymbolKind, size_t> symbol_counts;
|
||||
std::unordered_map<ScopeKind, size_t> scope_counts;
|
||||
|
||||
size_t symbols_with_refs = 0;
|
||||
size_t max_references = 0;
|
||||
SymbolId most_referenced = kInvalidSymbolId;
|
||||
|
||||
void Compute(const SymbolTable& table);
|
||||
void Print(std::ostream& os, bool use_color = true) const;
|
||||
};
|
||||
|
||||
// ==================== 核心打印器 ====================
|
||||
|
||||
class DebugPrinter
|
||||
{
|
||||
public:
|
||||
explicit DebugPrinter(const SymbolTable& table, const PrintOptions& options = PrintOptions::Default());
|
||||
|
||||
// ===== 顶层打印接口 =====
|
||||
void PrintAll(std::ostream& os = std::cout);
|
||||
void PrintOverview(std::ostream& os = std::cout);
|
||||
void PrintStatistics(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 符号打印 =====
|
||||
void PrintSymbol(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolTree(SymbolId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintSymbolList(std::ostream& os = std::cout);
|
||||
void PrintSymbolsByKind(SymbolKind kind, std::ostream& os = std::cout);
|
||||
|
||||
// ===== 作用域打印 =====
|
||||
void PrintScope(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeTree(ScopeId id, std::ostream& os = std::cout, int depth = 0);
|
||||
void PrintScopeHierarchy(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 关系打印 =====
|
||||
void PrintReferences(SymbolId id, std::ostream& os = std::cout);
|
||||
void PrintInheritance(SymbolId class_id, std::ostream& os = std::cout);
|
||||
void PrintCallGraph(SymbolId function_id, std::ostream& os = std::cout);
|
||||
void PrintAllReferences(std::ostream& os = std::cout);
|
||||
void PrintAllInheritance(std::ostream& os = std::cout);
|
||||
void PrintAllCalls(std::ostream& os = std::cout);
|
||||
|
||||
// ===== 搜索和查询 =====
|
||||
void FindAndPrint(const std::string& name, std::ostream& os = std::cout);
|
||||
void FindAtLocation(const ast::Location& loc, std::ostream& os = std::cout);
|
||||
|
||||
// ===== 选项管理 =====
|
||||
void SetOptions(const PrintOptions& options) { options_ = options; }
|
||||
const PrintOptions& GetOptions() const { return options_; }
|
||||
|
||||
private:
|
||||
const SymbolTable& table_;
|
||||
PrintOptions options_;
|
||||
Statistics stats_;
|
||||
|
||||
// ===== 辅助方法 =====
|
||||
std::string Indent(int depth) const;
|
||||
std::string ColorizeSymbolKind(SymbolKind kind) const;
|
||||
std::string ColorizeSymbolName(const std::string& name, SymbolKind kind) const;
|
||||
std::string FormatLocation(const ast::Location& loc) const;
|
||||
std::string FormatSymbolKind(SymbolKind kind) const;
|
||||
std::string FormatScopeKind(ScopeKind kind) const;
|
||||
std::string SymbolIcon(SymbolKind kind) const;
|
||||
|
||||
void PrintSeparator(std::ostream& os, char ch = '=', int width = 80) const;
|
||||
void PrintHeader(const std::string& title, std::ostream& os) const;
|
||||
void PrintSubHeader(const std::string& title, std::ostream& os) const;
|
||||
|
||||
std::string Color(const char* color_code) const;
|
||||
std::string Bold(const std::string& text) const;
|
||||
std::string Dim(const std::string& text) const;
|
||||
};
|
||||
|
||||
// ==================== 快速打印函数 ====================
|
||||
|
||||
// 打印所有内容(带统计)
|
||||
void Print(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印概览
|
||||
void PrintOverview(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印统计信息
|
||||
void PrintStats(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印符号树
|
||||
void PrintSymbolTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 打印作用域树
|
||||
void PrintScopeTree(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 搜索并打印
|
||||
void Find(const SymbolTable& table, const std::string& name, std::ostream& os = std::cout);
|
||||
|
||||
// 紧凑打印
|
||||
void PrintCompact(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
// 详细打印
|
||||
void PrintVerbose(const SymbolTable& table, std::ostream& os = std::cout);
|
||||
|
||||
} // namespace lsp::language::symbol::debug
|
||||
@@ -0,0 +1,557 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
|
||||
extern "C" const TSLanguage* tree_sitter_tsf(void);
|
||||
|
||||
#include "../../src/language/ast/deserializer.hpp"
|
||||
#include "../../src/language/symbol/table.hpp"
|
||||
#include "./debug_printer.hpp"
|
||||
|
||||
using namespace lsp::language;
|
||||
|
||||
// ==================== 文件读取 ====================
|
||||
|
||||
std::string ReadFile(const std::string& filepath)
|
||||
{
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open())
|
||||
{
|
||||
throw std::runtime_error("Cannot open file: " + filepath);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << file.rdbuf();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ==================== Tree-Sitter 解析器 ====================
|
||||
|
||||
class TreeSitterParser
|
||||
{
|
||||
public:
|
||||
TreeSitterParser()
|
||||
{
|
||||
parser_ = ts_parser_new();
|
||||
if (!parser_)
|
||||
{
|
||||
throw std::runtime_error("Failed to create parser");
|
||||
}
|
||||
|
||||
if (!ts_parser_set_language(parser_, tree_sitter_tsf()))
|
||||
{
|
||||
ts_parser_delete(parser_);
|
||||
throw std::runtime_error("Failed to set language");
|
||||
}
|
||||
}
|
||||
|
||||
~TreeSitterParser()
|
||||
{
|
||||
if (tree_)
|
||||
{
|
||||
ts_tree_delete(tree_);
|
||||
}
|
||||
if (parser_)
|
||||
{
|
||||
ts_parser_delete(parser_);
|
||||
}
|
||||
}
|
||||
|
||||
TSTree* Parse(const std::string& source)
|
||||
{
|
||||
if (tree_)
|
||||
{
|
||||
ts_tree_delete(tree_);
|
||||
tree_ = nullptr;
|
||||
}
|
||||
|
||||
tree_ = ts_parser_parse_string(
|
||||
parser_,
|
||||
nullptr,
|
||||
source.c_str(),
|
||||
source.length());
|
||||
|
||||
if (!tree_)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse source");
|
||||
}
|
||||
|
||||
return tree_;
|
||||
}
|
||||
|
||||
TSNode GetRootNode()
|
||||
{
|
||||
if (!tree_)
|
||||
{
|
||||
throw std::runtime_error("No tree available");
|
||||
}
|
||||
return ts_tree_root_node(tree_);
|
||||
}
|
||||
|
||||
private:
|
||||
TSParser* parser_ = nullptr;
|
||||
TSTree* tree_ = nullptr;
|
||||
};
|
||||
|
||||
// ==================== 命令行选项 ====================
|
||||
|
||||
struct Options
|
||||
{
|
||||
std::string input_file;
|
||||
std::string output_file;
|
||||
bool print_all = true;
|
||||
bool print_definitions = false;
|
||||
bool print_scopes = false;
|
||||
bool print_references = false;
|
||||
bool print_inheritance = false;
|
||||
bool print_calls = false;
|
||||
bool compact_mode = false;
|
||||
bool statistics_only = false;
|
||||
std::string search_symbol;
|
||||
bool verbose = false;
|
||||
bool show_ast = false;
|
||||
bool no_color = false;
|
||||
bool print_overview = false;
|
||||
};
|
||||
|
||||
void PrintUsage(const char* program_name)
|
||||
{
|
||||
std::cout << "Symbol Table Analyzer - Analyze source code symbols\n\n";
|
||||
std::cout << "Usage: " << program_name << " <input_file> [options]\n\n";
|
||||
std::cout << "Options:\n";
|
||||
std::cout << " -o, --output <file> Write output to file instead of stdout\n";
|
||||
std::cout << " -d, --definitions Print only symbol definitions\n";
|
||||
std::cout << " -s, --scopes Print only scope hierarchy\n";
|
||||
std::cout << " -r, --references Print only references\n";
|
||||
std::cout << " -i, --inheritance Print only inheritance graph\n";
|
||||
std::cout << " -c, --calls Print only call graph\n";
|
||||
std::cout << " -C, --compact Use compact output format\n";
|
||||
std::cout << " -S, --stats Print statistics only\n";
|
||||
std::cout << " -O, --overview Print overview only\n";
|
||||
std::cout << " -f, --find <name> Search for a specific symbol\n";
|
||||
std::cout << " -v, --verbose Enable verbose output\n";
|
||||
std::cout << " -a, --ast Show AST structure\n";
|
||||
std::cout << " --no-color Disable colored output\n";
|
||||
std::cout << " -h, --help Show this help message\n\n";
|
||||
std::cout << "Examples:\n";
|
||||
std::cout << " " << program_name << " program.tsf\n";
|
||||
std::cout << " " << program_name << " program.tsf -o symbols.txt\n";
|
||||
std::cout << " " << program_name << " program.tsf --definitions --scopes\n";
|
||||
std::cout << " " << program_name << " program.tsf --find MyClass\n";
|
||||
std::cout << " " << program_name << " program.tsf --compact --stats\n";
|
||||
std::cout << " " << program_name << " program.tsf --overview\n";
|
||||
}
|
||||
|
||||
bool ParseArguments(int argc, char* argv[], Options& options)
|
||||
{
|
||||
if (argc < 2)
|
||||
return false;
|
||||
|
||||
options.input_file = argv[1];
|
||||
bool any_specific_print = false;
|
||||
|
||||
for (int i = 2; i < argc; ++i)
|
||||
{
|
||||
std::string arg = argv[i];
|
||||
|
||||
if (arg == "-h" || arg == "--help")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (arg == "-o" || arg == "--output")
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
options.output_file = argv[++i];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: " << arg << " requires an argument\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (arg == "-d" || arg == "--definitions")
|
||||
{
|
||||
options.print_definitions = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-s" || arg == "--scopes")
|
||||
{
|
||||
options.print_scopes = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-r" || arg == "--references")
|
||||
{
|
||||
options.print_references = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-i" || arg == "--inheritance")
|
||||
{
|
||||
options.print_inheritance = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-c" || arg == "--calls")
|
||||
{
|
||||
options.print_calls = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-C" || arg == "--compact")
|
||||
{
|
||||
options.compact_mode = true;
|
||||
}
|
||||
else if (arg == "-S" || arg == "--stats")
|
||||
{
|
||||
options.statistics_only = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-O" || arg == "--overview")
|
||||
{
|
||||
options.print_overview = true;
|
||||
any_specific_print = true;
|
||||
}
|
||||
else if (arg == "-f" || arg == "--find")
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
options.search_symbol = argv[++i];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: " << arg << " requires an argument\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (arg == "-v" || arg == "--verbose")
|
||||
{
|
||||
options.verbose = true;
|
||||
}
|
||||
else if (arg == "-a" || arg == "--ast")
|
||||
{
|
||||
options.show_ast = true;
|
||||
}
|
||||
else if (arg == "--no-color")
|
||||
{
|
||||
options.no_color = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: Unknown option: " << arg << "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_specific_print)
|
||||
options.print_all = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string NodeKindToString(ast::NodeKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ast::NodeKind::kProgram: return "Program";
|
||||
case ast::NodeKind::kFunctionDefinition: return "FunctionDefinition";
|
||||
case ast::NodeKind::kClassDefinition: return "ClassDefinition";
|
||||
case ast::NodeKind::kUnitDefinition: return "UnitDefinition";
|
||||
case ast::NodeKind::kVarStatement: return "VarStatement";
|
||||
case ast::NodeKind::kConstStatement: return "ConstStatement";
|
||||
case ast::NodeKind::kIfStatement: return "IfStatement";
|
||||
case ast::NodeKind::kForInStatement: return "ForInStatement";
|
||||
case ast::NodeKind::kWhileStatement: return "WhileStatement";
|
||||
// ... 添加其他类型
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintASTStructure(const ast::ParseResult& parse_result, std::ostream& os)
|
||||
{
|
||||
os << "\n╔════════════════════════════════════════════════════════════╗\n";
|
||||
os << "║ AST STRUCTURE ║\n";
|
||||
os << "╚════════════════════════════════════════════════════════════╝\n\n";
|
||||
|
||||
os << "Statements: " << parse_result.root->statements.size() << "\n\n";
|
||||
|
||||
for (size_t i = 0; i < parse_result.root->statements.size(); ++i)
|
||||
{
|
||||
const auto& stmt = parse_result.root->statements[i];
|
||||
if (!stmt)
|
||||
continue;
|
||||
|
||||
// 修复:使用 kind 和 span
|
||||
os << "[" << i << "] " << NodeKindToString(stmt->kind)
|
||||
<< " at [" << stmt->span.start_line << ":" << stmt->span.start_column << "]";
|
||||
|
||||
// 打印特定类型的详细信息
|
||||
if (auto* func_def = dynamic_cast<ast::FunctionDefinition*>(stmt.get()))
|
||||
{
|
||||
os << " - Function: " << func_def->name;
|
||||
}
|
||||
else if (auto* class_def = dynamic_cast<ast::ClassDefinition*>(stmt.get()))
|
||||
{
|
||||
os << " - Class: " << class_def->name;
|
||||
}
|
||||
else if (auto* unit_def = dynamic_cast<ast::UnitDefinition*>(stmt.get()))
|
||||
{
|
||||
os << " - Unit: " << unit_def->name;
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
// ==================== 主分析函数 ====================
|
||||
|
||||
void AnalyzeFile(const Options& options)
|
||||
{
|
||||
// 打印头部
|
||||
if (!options.compact_mode)
|
||||
{
|
||||
std::cout << "\n╔════════════════════════════════════════════════════════════╗\n";
|
||||
std::cout << "║ SYMBOL TABLE ANALYZER ║\n";
|
||||
std::cout << "╚════════════════════════════════════════════════════════════╝\n\n";
|
||||
std::cout << "Input file: " << options.input_file << "\n";
|
||||
}
|
||||
|
||||
// 1. 读取源文件
|
||||
if (options.verbose)
|
||||
std::cout << "Reading file...\n";
|
||||
|
||||
std::string source = ReadFile(options.input_file);
|
||||
|
||||
if (options.verbose)
|
||||
{
|
||||
std::cout << "File size: " << source.length() << " bytes\n";
|
||||
std::cout << "----------------------------------------\n";
|
||||
std::cout << source << "\n";
|
||||
std::cout << "----------------------------------------\n\n";
|
||||
}
|
||||
|
||||
// 2. 使用 Tree-Sitter 解析
|
||||
if (options.verbose)
|
||||
std::cout << "Parsing with Tree-Sitter...\n";
|
||||
|
||||
TreeSitterParser ts_parser;
|
||||
[[maybe_unused]] TSTree* tree = ts_parser.Parse(source);
|
||||
TSNode root = ts_parser.GetRootNode();
|
||||
|
||||
if (options.verbose)
|
||||
{
|
||||
std::cout << "Root node type: " << ts_node_type(root) << "\n";
|
||||
std::cout << "Root node child count: " << ts_node_child_count(root) << "\n\n";
|
||||
}
|
||||
|
||||
// 3. 反序列化为 AST
|
||||
if (options.verbose)
|
||||
std::cout << "Deserializing to AST...\n";
|
||||
|
||||
ast::Deserializer deserializer;
|
||||
ast::ParseResult parse_result = deserializer.Parse(root, source);
|
||||
|
||||
if (parse_result.HasErrors())
|
||||
{
|
||||
std::cerr << "\n⚠️ Parse Errors:\n";
|
||||
for (const auto& error : parse_result.errors)
|
||||
{
|
||||
std::cerr << " [" << error.location.start_line << ":"
|
||||
<< error.location.start_column << "] "
|
||||
<< error.message << "\n";
|
||||
}
|
||||
std::cerr << "\n";
|
||||
}
|
||||
|
||||
if (options.show_ast)
|
||||
{
|
||||
PrintASTStructure(parse_result, std::cout);
|
||||
}
|
||||
|
||||
// 4. 构建符号表
|
||||
if (options.verbose)
|
||||
std::cout << "Building symbol table...\n";
|
||||
|
||||
symbol::SymbolTable table;
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
table.Build(*parse_result.root);
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
|
||||
if (options.verbose)
|
||||
std::cout << "Symbol table built in " << duration.count() << " ms\n\n";
|
||||
|
||||
// 5. 准备输出流
|
||||
std::ostream* out = &std::cout;
|
||||
std::ofstream file_out;
|
||||
|
||||
if (!options.output_file.empty())
|
||||
{
|
||||
file_out.open(options.output_file);
|
||||
if (!file_out.is_open())
|
||||
{
|
||||
std::cerr << "Error: Cannot write to file: " << options.output_file << "\n";
|
||||
return;
|
||||
}
|
||||
out = &file_out;
|
||||
|
||||
// 写入文件头
|
||||
*out << "Symbol Table Analysis\n";
|
||||
*out << "Source: " << options.input_file << "\n";
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto time = std::chrono::system_clock::to_time_t(now);
|
||||
*out << "Generated: " << std::ctime(&time);
|
||||
*out << std::string(80, '=') << "\n\n";
|
||||
}
|
||||
|
||||
// 6. ✅ 使用新的 debug_print API
|
||||
|
||||
// 配置打印选项
|
||||
symbol::debug::PrintOptions print_opts;
|
||||
if (options.compact_mode)
|
||||
print_opts = symbol::debug::PrintOptions::Compact();
|
||||
else if (options.verbose)
|
||||
print_opts = symbol::debug::PrintOptions::Verbose();
|
||||
else
|
||||
print_opts = symbol::debug::PrintOptions::Default();
|
||||
|
||||
if (options.no_color || !options.output_file.empty())
|
||||
print_opts.use_color = false;
|
||||
|
||||
print_opts.show_references = options.print_references || options.verbose;
|
||||
|
||||
// 创建打印器
|
||||
symbol::debug::DebugPrinter printer(table, print_opts);
|
||||
|
||||
// 7. 执行查询或打印
|
||||
if (!options.search_symbol.empty())
|
||||
{
|
||||
// 搜索符号
|
||||
printer.FindAndPrint(options.search_symbol, *out);
|
||||
}
|
||||
else if (options.statistics_only)
|
||||
{
|
||||
// 只打印统计
|
||||
printer.PrintStatistics(*out);
|
||||
}
|
||||
else if (options.print_overview)
|
||||
{
|
||||
// 只打印概览
|
||||
printer.PrintOverview(*out);
|
||||
}
|
||||
else if (options.compact_mode)
|
||||
{
|
||||
// 紧凑模式
|
||||
symbol::debug::PrintCompact(table, *out);
|
||||
}
|
||||
else if (options.print_all)
|
||||
{
|
||||
// 打印所有内容
|
||||
printer.PrintAll(*out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 自定义打印
|
||||
bool printed_anything = false;
|
||||
|
||||
if (options.print_definitions)
|
||||
{
|
||||
printer.PrintSymbolList(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_scopes)
|
||||
{
|
||||
printer.PrintScopeHierarchy(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_references)
|
||||
{
|
||||
printer.PrintAllReferences(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_inheritance)
|
||||
{
|
||||
printer.PrintAllInheritance(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
if (options.print_calls)
|
||||
{
|
||||
printer.PrintAllCalls(*out);
|
||||
printed_anything = true;
|
||||
}
|
||||
|
||||
// 总是打印统计信息
|
||||
if (printed_anything)
|
||||
{
|
||||
*out << "\n";
|
||||
}
|
||||
printer.PrintStatistics(*out);
|
||||
}
|
||||
|
||||
// 8. 完成
|
||||
if (file_out.is_open())
|
||||
{
|
||||
file_out.close();
|
||||
std::cout << "✓ Symbol table exported to: " << options.output_file << "\n";
|
||||
}
|
||||
|
||||
// 9. 打印摘要
|
||||
if (!options.compact_mode)
|
||||
{
|
||||
std::cout << "\n========================================\n";
|
||||
std::cout << "Summary:\n";
|
||||
std::cout << " File: " << options.input_file << "\n";
|
||||
std::cout << " Size: " << source.length() << " bytes\n";
|
||||
std::cout << " Lines: " << std::count(source.begin(), source.end(), '\n') + 1 << "\n";
|
||||
std::cout << " Statements: " << parse_result.root->statements.size() << "\n";
|
||||
std::cout << " Symbols: " << table.GetAllDefinitions().size() << "\n";
|
||||
std::cout << " Scopes: " << table.GetScopeManager().GetAllScopes().size() << "\n";
|
||||
std::cout << " Parse Errors: " << parse_result.errors.size() << "\n";
|
||||
std::cout << " Build Time: " << duration.count() << " ms\n";
|
||||
|
||||
if (parse_result.HasErrors())
|
||||
{
|
||||
std::cout << " Status: ⚠️ COMPLETED WITH ERRORS\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " Status: ✓ SUCCESS\n";
|
||||
}
|
||||
std::cout << "========================================\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 主程序 ====================
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Options options;
|
||||
|
||||
if (!ParseArguments(argc, argv, options))
|
||||
{
|
||||
PrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AnalyzeFile(options);
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "❌ Fatal error: " << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
function f1(a: string; b: boolean = true): integer;
|
||||
begin
|
||||
end;
|
||||
|
||||
function f2(a, b, c);overload;
|
||||
begin
|
||||
end;
|
||||
|
||||
// var d := 1;
|
||||
// c := false;
|
||||
// f := fa();
|
||||
Reference in New Issue
Block a user