3#include <unordered_map>
12bool TreeSitterParser::is_function_empty(TSNode body) {
13 if (ts_node_is_null(body))
return true;
15 uint32_t n = ts_node_named_child_count(body);
20std::string TreeSitterParser::detect_language(
const fs::path& path) {
23 std::string ext = fs::path(path).extension().string();
25 auto it = ext_map.find(ext);
26 if (it != ext_map.end()) {
33std::string TreeSitterParser::get_full_signature(TSNode func_node,
const std::string& source) {
34 uint32_t signature_start = ts_node_start_byte(func_node);
36 TSNode body = get_body(func_node);
38 uint32_t signature_end = ts_node_start_byte(body);
40 return source.substr(signature_start, signature_end - signature_start);
43static const char* field_names[] = {
48 std::string type_identifier_fallback;
50 for (
const auto& field_name : field_names) {
51 TSNode name = ts_node_child_by_field_name(node, field_name, strlen(field_name));
52 if (!ts_node_is_null(name)) {
53 std::string_view type = ts_node_type(name);
54 if (type ==
"identifier") {
58 if (type ==
"qualified_identifier") {
59 TSNode qualified_identifier_name = ts_node_child_by_field_name(name,
"name", strlen(
"name"));
60 if (!ts_node_is_null(qualified_identifier_name)) {
62 qualified_identifier_name,
70 ts_node_start_byte(qualified_identifier_name),
71 ts_node_end_byte(qualified_identifier_name) - ts_node_start_byte(qualified_identifier_name)
76 if (type ==
"type_identifier") {
77 if (type_identifier_fallback.empty())
83 uint32_t count = ts_node_child_count(node);
84 for (uint32_t i = 0; i < count; i++) {
85 TSNode child = ts_node_child(node, i);
87 if (!result.empty())
return result;
90 if (!type_identifier_fallback.empty())
91 return type_identifier_fallback;
96std::string TreeSitterParser::get_function_name(TSNode func_node,
const std::string& source) {
100TSNode TreeSitterParser::get_body(TSNode node) {
101 TSNode body = ts_node_child_by_field_name(node,
"body", strlen(
"body"));
103 if (!ts_node_is_null(body))
106 uint32_t count = ts_node_child_count(node);
108 for (uint32_t i = 0; i < count; i++) {
109 TSNode child = ts_node_child(node, i);
110 std::string_view type = ts_node_type(child);
119bool TreeSitterParser::should_ignore(TSNode node) {
123 std::function<void(TSNode)> dfs = [&](TSNode n) {
126 if (ts_node_is_error(n))
129 uint32_t child_count = ts_node_child_count(n);
130 for (uint32_t i = 0; i < child_count; i++)
131 dfs(ts_node_child(n, i));
136 if (size == 0)
return false;
138 double ratio =
static_cast<double>(errors) /
static_cast<double>(size);
139 int threshold = 1 +
static_cast<int>(std::log2(size));
141 return (errors > threshold) || (ratio > 0.1);
144void TreeSitterParser::collect_functions(
146 const std::string& source,
147 const fs::path& relative_path,
148 const std::shared_ptr<TSTree>& tree,
152 std::string_view type = ts_node_type(node);
154 TSPoint start = ts_node_start_point(node);
155 TSPoint end = ts_node_end_point(node);
157 if (TreeSitterParser::should_ignore(node)) {
162 TSNode body = get_body(node);
164 if (is_function_empty(body))
return;
166 std::string function_name = get_function_name(node, source);
167 if (function_name.empty())
return;
169 TSPoint body_start = ts_node_start_point(body);
170 uint32_t start_byte = ts_node_start_byte(node);
171 uint32_t end_byte = ts_node_end_byte(node);
173 std::string signature = get_full_signature(node, source);
174 std::string code = source.substr(start_byte + signature.size(), end_byte - (start_byte + signature.size()));
177 function.
path = relative_path.string();
180 auto source = std::make_shared<SourceFeature>();
184 auto ast = std::make_shared<ASTFeature>();
189 auto metadata = std::make_shared<MetadataFeature>();
190 metadata->signature = signature;
191 metadata->line_declaration = start.row;
192 metadata->start_number_line = body_start.row;
193 metadata->end_number_line = end.row;
199 uint32_t count = ts_node_child_count(node);
200 for (uint32_t i = 0; i < count; i++) {
202 ts_node_child(node, i),
212std::shared_ptr<TSTree> TreeSitterParser::parse_source(
213 const fs::path& file_path,
214 const std::string& source_code
216 auto lang_name = detect_language(file_path);
218 if (lang_name.empty())
return nullptr;
221 auto it = language_map.find(lang_name);
222 if (it == language_map.end()) {
223 std::cerr <<
"Language not found: " << lang_name <<
"\n";
226 TSLanguage* language = it->second();
228 static TSLanguage* current_language =
nullptr;
229 static std::unique_ptr<TSParser,
decltype(&ts_parser_delete)> parser(
233 if (current_language != language) {
234 if (!ts_parser_set_language(parser.get(), language)) {
237 current_language = language;
240 return std::shared_ptr<TSTree>(
241 ts_parser_parse_string(
252 const fs::path& file_path,
253 const fs::path& relative_path,
254 const std::string& source_code,
258 std::shared_ptr<TSTree> tree = parse_source(file_path, source_code);
261 TSNode root_node = ts_tree_root_node(tree.get());
263 collect_functions(root_node, source_code, relative_path, tree, callback, stats);
269 const fs::path& file_path,
270 const fs::path& relative_path,
271 const std::string& source_code,
275 std::shared_ptr<TSTree> tree = parse_source(file_path, source_code);
278 TSNode root_node = ts_tree_root_node(tree.get());
279 TSPoint end = ts_node_end_point(root_node);
282 function.
path = relative_path.string();
285 auto source = std::make_shared<SourceFeature>();
286 source->code = source_code;
289 auto ast = std::make_shared<ASTFeature>();
291 ast->root = root_node;
294 auto metadata = std::make_shared<MetadataFeature>();
295 metadata->signature =
"";
296 metadata->line_declaration = 0;
297 metadata->start_number_line = 0;
298 metadata->end_number_line = end.row;
std::string function_name
Name of the function.
void add_feature(std::shared_ptr< T > feature)
static void process_file_as_unit(const fs::path &file_path, const fs::path &relative_path, const std::string &source_code, std::function< void(const FunctionData &)> callback, SkipStats &stats)
static void process_file(const fs::path &file_path, const fs::path &relative_path, const std::string &source_code, std::function< void(const FunctionData &)> callback, SkipStats &stats)
std::unordered_map< std::string, std::string > get_extension_map()
std::string extract_name_generic(TSNode node, const std::string &source)
std::unordered_map< std::string, TSLanguage *(*)()> get_language_map()
Defines utility functions used across all files.