#include <stdio.h> #include <string.h> #include <tree_sitter/api.h> extern const TSLanguage * tree_sitter_c(void); typedef struct { const char * const string; const int case_number; } tbcase_t; const tbcase_t tb_enter_cases[] = { (tbcase_t) { .string = "function_definition", .case_number = 1 }, (tbcase_t) { .string = "number_literal", .case_number = 2 }, (tbcase_t) { .string = NULL, .case_number = 0 }, }; const tbcase_t tb_leave_cases[] = { (tbcase_t) { .string = "function_definition", .case_number = 3 }, (tbcase_t) { .string = NULL, .case_number = 0 }, }; // XXX better search algo int determine_case(tbcase_t * ordered_array, const char * const string) { tbcase_t * c; for (; c->string != NULL; c++) { if (!strcmp(c->string, string)) { break; } } return c->case_number; } int tbtraverse(const char * const code) { // init TSParser * parser; TSTree * tree; TSTreeCursor cursor; TSNode current_node; TSNode previous_node; int tb_case; parser = ts_parser_new(); ts_parser_set_language(parser, tree_sitter_c()); tree = ts_parser_parse_string(parser, NULL, code, strlen(code)); cursor = ts_tree_cursor_new(ts_tree_root_node(tree)); current_node = ts_tree_root_node(tree); // meat while (true) { current_node = ts_tree_cursor_current_node(&cursor); int tblen = ts_node_end_byte(current_node) - ts_node_start_byte(current_node); char * tbtext = (char *)malloc(sizeof(char) * (tblen + 1)); memcpy(tbtext, code + ts_node_start_byte(current_node), tblen); tbtext[tblen] = '\0'; tb_case = determine_case(tb_enter_cases, ts_node_type(current_node)); // XXX INJECTION eval: switch (tb_case) { case 1: { puts("ack"); puts(tbtext); } break; case 2: { puts("++"); } break; case 3: { puts("^^df"); } break; [[likely]] default: { ; } break; } free(tbtext); if (ts_tree_cursor_goto_first_child(&cursor) || ts_tree_cursor_goto_next_sibling(&cursor)) { current_node = ts_tree_cursor_current_node(&cursor); tb_case = determine_case(tb_leave_cases, ts_node_type); goto eval; } while (ts_tree_cursor_goto_parent(&cursor)) { current_node = ts_tree_cursor_current_node(&cursor); if (ts_tree_cursor_goto_next_sibling(&cursor)) { tb_case = determine_case(tb_leave_cases, ts_node_type); goto eval; } } break; } // deinit ts_tree_delete(tree); ts_parser_delete(parser); ts_tree_cursor_delete(&cursor); return 0; } // @BAKE g++ $@ $(pkg-config --cflags --libs tree-sitter tree-sitter-c) -ggdb signed main() { tbtraverse("int main() { return 0; }"); }