263 lines
7.4 KiB
C++
263 lines
7.4 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
extern "C" {
|
|
#include <tree_sitter/api.h>
|
|
}
|
|
|
|
extern "C" const TSLanguage* tree_sitter_tsf(void);
|
|
|
|
#include "../../src/language/ast/deserializer.hpp"
|
|
#include "./debug_printer.hpp"
|
|
|
|
using namespace lsp::language::ast;
|
|
|
|
// ==================== 文件读取 ====================
|
|
|
|
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;
|
|
};
|
|
|
|
// ==================== 主程序 ====================
|
|
|
|
void PrintUsage(const char* program_name)
|
|
{
|
|
std::cout << "Usage: " << program_name << " <file_path> [options]\n";
|
|
std::cout << "\nOptions:\n";
|
|
std::cout << " -v, --verbose Show verbose output with source code\n";
|
|
std::cout << " -c, --compact Use compact output mode\n";
|
|
std::cout << " -s, --show-source Show source code snippets (default: off)\n";
|
|
std::cout << " -l, --hide-location Hide location information\n";
|
|
std::cout << " -n, --no-colors Disable colored output\n";
|
|
std::cout << " -t, --no-tree Disable tree characters\n";
|
|
std::cout << " -k, --show-kind Show node kind enums\n";
|
|
std::cout << " -i, --incremental Test incremental parsing\n";
|
|
std::cout << " -h, --help Show this help message\n";
|
|
std::cout << "\nPreset Modes:\n";
|
|
std::cout << " --verbose Equivalent to: -s -k\n";
|
|
std::cout << " --compact Equivalent to: -c -l -t\n";
|
|
std::cout << "\nExamples:\n";
|
|
std::cout << " " << program_name << " test.tsf\n";
|
|
std::cout << " " << program_name << " test.tsf --verbose\n";
|
|
std::cout << " " << program_name << " test.tsf --compact\n";
|
|
std::cout << " " << program_name << " test.tsf -s -n # Show source without colors\n";
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
if (argc < 2)
|
|
{
|
|
PrintUsage(argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
std::string filepath;
|
|
bool test_incremental = false;
|
|
|
|
// 默认打印选项
|
|
debug::PrintOptions opts = debug::PrintOptions::Default();
|
|
|
|
// 解析命令行参数
|
|
for (int i = 1; i < argc; ++i)
|
|
{
|
|
std::string arg = argv[i];
|
|
if (arg == "-h" || arg == "--help")
|
|
{
|
|
PrintUsage(argv[0]);
|
|
return 0;
|
|
}
|
|
else if (arg == "-v" || arg == "--verbose")
|
|
{
|
|
opts = debug::PrintOptions::Verbose();
|
|
}
|
|
else if (arg == "-c" || arg == "--compact")
|
|
{
|
|
opts = debug::PrintOptions::Compact();
|
|
}
|
|
else if (arg == "-s" || arg == "--show-source")
|
|
{
|
|
opts.show_source_code = true;
|
|
}
|
|
else if (arg == "-l" || arg == "--hide-location")
|
|
{
|
|
opts.show_location = false;
|
|
}
|
|
else if (arg == "-n" || arg == "--no-colors")
|
|
{
|
|
opts.use_colors = false;
|
|
}
|
|
else if (arg == "-t" || arg == "--no-tree")
|
|
{
|
|
opts.use_tree_chars = false;
|
|
}
|
|
else if (arg == "-k" || arg == "--show-kind")
|
|
{
|
|
opts.show_node_kind = true;
|
|
}
|
|
else if (arg == "-i" || arg == "--incremental")
|
|
{
|
|
test_incremental = true;
|
|
}
|
|
else if (filepath.empty())
|
|
{
|
|
filepath = arg;
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "Unknown argument: " << arg << "\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
// 读取文件
|
|
std::cout << "Reading file: " << filepath << "\n";
|
|
std::string source = ReadFile(filepath);
|
|
std::cout << "File size: " << source.length() << " bytes\n\n";
|
|
|
|
// 创建 Tree-Sitter 解析器
|
|
TreeSitterParser ts_parser;
|
|
[[maybe_unused]]TSTree* tree = ts_parser.Parse(source);
|
|
TSNode root = ts_parser.GetRootNode();
|
|
|
|
// 创建 AST 反序列化器
|
|
Deserializer deserializer;
|
|
|
|
ParseResult result;
|
|
if (test_incremental)
|
|
{
|
|
std::cout << "Using incremental parsing...\n\n";
|
|
auto inc_result = deserializer.ParseIncremental(root, source);
|
|
result = std::move(inc_result.result);
|
|
|
|
std::cout << "Incremental Parse Statistics:\n";
|
|
std::cout << " Nodes parsed: " << inc_result.nodes_parsed << "\n";
|
|
std::cout << " Nodes unchanged: " << inc_result.nodes_unchanged << "\n";
|
|
std::cout << " Total nodes: " << inc_result.TotalNodes() << "\n";
|
|
std::cout << " Change rate: " << (inc_result.ChangeRate() * 100) << "%\n\n";
|
|
}
|
|
else
|
|
{
|
|
result = deserializer.Parse(root, source);
|
|
}
|
|
|
|
// 打印 AST 结果(带源码)
|
|
DebugPrint(result, source, opts);
|
|
|
|
// 打印摘要
|
|
std::cout << "\n";
|
|
std::cout << debug::Color::BrightBlue << "========================================\n"
|
|
<< debug::Color::Reset;
|
|
std::cout << debug::Color::BrightCyan << "Summary:\n"
|
|
<< debug::Color::Reset;
|
|
std::cout << " File: " << filepath << "\n";
|
|
std::cout << " Size: " << source.length() << " bytes\n";
|
|
|
|
if (result.root)
|
|
{
|
|
std::cout << " Statements: " << result.root->statements.size() << "\n";
|
|
}
|
|
|
|
std::cout << " Errors: ";
|
|
if (result.HasErrors())
|
|
{
|
|
std::cout << debug::Color::BrightRed << result.errors.size() << " ✗" << debug::Color::Reset << "\n";
|
|
std::cout << " Status: " << debug::Color::BrightRed << "FAILED" << debug::Color::Reset << "\n";
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
std::cout << debug::Color::BrightGreen << "0 ✓" << debug::Color::Reset << "\n";
|
|
std::cout << " Status: " << debug::Color::BrightGreen << "SUCCESS" << debug::Color::Reset << "\n";
|
|
return 0;
|
|
}
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << debug::Color::BrightRed << "Error: " << e.what() << debug::Color::Reset << "\n";
|
|
return 1;
|
|
}
|
|
}
|