|
diff --git a/file.c b/file.c
|
| ... |
| 4 |
#include "file.h" |
4 |
#include "file.h" |
| 5 |
|
5 |
|
| 6 |
struct FileContent read_entire_file(const char *file_path) { |
6 |
struct FileContent read_entire_file(const char *file_path) { |
| 7 |
struct FileContent file_data; |
7 |
struct FileContent file_data; |
| 8 |
file_data.content = NULL; |
8 |
file_data.content = NULL; |
| 9 |
file_data.count = 0; |
9 |
file_data.count = 0; |
| 10 |
|
10 |
|
| 11 |
FILE *file = fopen(file_path, "rb"); |
11 |
FILE *file = fopen(file_path, "rb"); |
| 12 |
if (file == NULL) { |
12 |
if (file == NULL) { |
| 13 |
perror("Error opening file"); |
13 |
perror("Error opening file"); |
| 14 |
return file_data; |
14 |
return file_data; |
| 15 |
} |
15 |
} |
| 16 |
|
16 |
|
| 17 |
fseek(file, 0, SEEK_END); |
17 |
fseek(file, 0, SEEK_END); |
| 18 |
long file_size = ftell(file); |
18 |
long file_size = ftell(file); |
| 19 |
fseek(file, 0, SEEK_SET); |
19 |
fseek(file, 0, SEEK_SET); |
| 20 |
|
20 |
|
| 21 |
if (file_size == -1) { |
21 |
if (file_size == -1) { |
| 22 |
perror("Error getting file size"); |
22 |
perror("Error getting file size"); |
| 23 |
return file_data; |
23 |
return file_data; |
| 24 |
} |
24 |
} |
| 25 |
|
25 |
|
| 26 |
file_data.content = (const char *)malloc(file_size); |
26 |
file_data.content = (const char *)malloc(file_size); |
| 27 |
if (file_data.content == NULL) { |
27 |
if (file_data.content == NULL) { |
| 28 |
perror("Error allocating memory"); |
28 |
perror("Error allocating memory"); |
| 29 |
return file_data; |
29 |
return file_data; |
| 30 |
} |
30 |
} |
| 31 |
|
31 |
|
| 32 |
size_t bytes_read = fread((void *)file_data.content, 1, file_size, file); |
32 |
size_t bytes_read = fread((void *)file_data.content, 1, file_size, file); |
| 33 |
if (bytes_read != (size_t)file_size) { |
33 |
if (bytes_read != (size_t)file_size) { |
| 34 |
perror("Error reading file"); |
34 |
perror("Error reading file"); |
| 35 |
free((void *)file_data.content); |
35 |
free((void *)file_data.content); |
| 36 |
file_data.content = NULL; |
36 |
file_data.content = NULL; |
| 37 |
return file_data; |
37 |
return file_data; |
| 38 |
} |
38 |
} |
| 39 |
|
39 |
|
| 40 |
file_data.count = bytes_read; |
40 |
file_data.count = bytes_read; |
| 41 |
|
41 |
|
| 42 |
fclose(file); |
42 |
fclose(file); |
| 43 |
return file_data; |
43 |
return file_data; |
| 44 |
} |
44 |
} |
|
diff --git a/main.c b/main.c
|
| ... |
| 10 |
#define DEBUG 1 |
10 |
#define DEBUG 1 |
| 11 |
|
11 |
|
| 12 |
typedef struct { |
12 |
typedef struct { |
| 13 |
const char *fname; |
13 |
const char *fname; |
| 14 |
const char *ftype; |
14 |
const char *ftype; |
| 15 |
const char *fparams; |
15 |
const char *fparams; |
| 16 |
size_t lineno; |
16 |
size_t lineno; |
| 17 |
} Function; |
17 |
} Function; |
| 18 |
|
18 |
|
| 19 |
const char *extract_value(TSNode captured_node, const char *source_code) { |
19 |
const char *extract_value(TSNode captured_node, const char *source_code) { |
| 20 |
size_t start = ts_node_start_byte(captured_node); |
20 |
size_t start = ts_node_start_byte(captured_node); |
| 21 |
size_t end = ts_node_end_byte(captured_node); |
21 |
size_t end = ts_node_end_byte(captured_node); |
| 22 |
size_t length = end - start; |
22 |
size_t length = end - start; |
| 23 |
char *buffer = malloc(length + 1); // +1 for the null terminator |
23 |
char *buffer = malloc(length + 1); // +1 for the null terminator |
| 24 |
|
24 |
|
| 25 |
if (buffer != NULL) { |
25 |
if (buffer != NULL) { |
| 26 |
snprintf(buffer, length + 1, "%.*s", (int)length, &source_code[start]); |
26 |
snprintf(buffer, length + 1, "%.*s", (int)length, &source_code[start]); |
| 27 |
return buffer; |
27 |
return buffer; |
| 28 |
} |
28 |
} |
| 29 |
|
29 |
|
| 30 |
return NULL; |
30 |
return NULL; |
| 31 |
} |
31 |
} |
| 32 |
|
32 |
|
| 33 |
void parse_source_file(const char *file_path, const char *source_code, TSLanguage *language) { |
33 |
void parse_source_file(const char *file_path, const char *source_code, TSLanguage *language) { |
| 34 |
TSParser *parser = ts_parser_new(); |
34 |
TSParser *parser = ts_parser_new(); |
| 35 |
ts_parser_set_language(parser, language); |
35 |
ts_parser_set_language(parser, language); |
| 36 |
|
36 |
|
| 37 |
TSTree *tree = ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
37 |
TSTree *tree = ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
| 38 |
TSNode root_node = ts_tree_root_node(tree); |
38 |
TSNode root_node = ts_tree_root_node(tree); |
|
|
39 |
|
|
|
40 |
const char *query_string = "(function_definition type: (primitive_type) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))"; |
|
|
41 |
|
|
|
42 |
uint32_t error_offset; |
|
|
43 |
TSQueryError error_type; |
|
|
44 |
TSQuery *query = ts_query_new(language, query_string, strlen(query_string), &error_offset, &error_type); |
| 39 |
|
45 |
|
| 40 |
const char *query_string = "(function_definition type: (primitive_type) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))"; |
46 |
TSQueryCursor *query_cursor = ts_query_cursor_new(); |
|
|
47 |
ts_query_cursor_exec(query_cursor, query, root_node); |
| 41 |
|
48 |
|
| 42 |
uint32_t error_offset; |
49 |
if (query != NULL) { |
| 43 |
TSQueryError error_type; |
50 |
TSQueryMatch match; |
| 44 |
TSQuery *query = ts_query_new(language, query_string, strlen(query_string), &error_offset, &error_type); |
51 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
|
|
52 |
Function fn = {0}; |
| 45 |
|
53 |
|
| 46 |
TSQueryCursor *query_cursor = ts_query_cursor_new(); |
54 |
for (unsigned i = 0; i < match.capture_count; i++) { |
| 47 |
ts_query_cursor_exec(query_cursor, query, root_node); |
55 |
TSQueryCapture capture = match.captures[i]; |
|
|
56 |
TSNode captured_node = capture.node; |
| 48 |
|
57 |
|
| 49 |
if (query != NULL) { |
58 |
/* fprintf(stderr, "Query: %p, Capture index: %u\n", (void *)query, capture.index); */ |
| 50 |
TSQueryMatch match; |
|
|
| 51 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
|
|
| 52 |
Function fn = {0}; |
|
|
| 53 |
|
59 |
|
| 54 |
for (unsigned i = 0; i < match.capture_count; i++) { |
60 |
uint32_t capture_name_length; |
| 55 |
TSQueryCapture capture = match.captures[i]; |
61 |
const char *capture_name = ts_query_capture_name_for_id(query, capture.index, &capture_name_length); |
| 56 |
TSNode captured_node = capture.node; |
|
|
| 57 |
|
62 |
|
| 58 |
/* fprintf(stderr, "Query: %p, Capture index: %u\n", (void *)query, capture.index); */ |
63 |
if (strcmp(capture_name, "fname") == 0) { |
|
|
64 |
fn.fname = extract_value(captured_node, source_code); |
| 59 |
|
65 |
|
| 60 |
uint32_t capture_name_length; |
66 |
TSPoint start_point = ts_node_start_point(captured_node); |
| 61 |
const char *capture_name = ts_query_capture_name_for_id(query, capture.index, &capture_name_length); |
67 |
fn.lineno = start_point.row; |
|
|
68 |
} |
| 62 |
|
69 |
|
| 63 |
if (strcmp(capture_name, "fname") == 0) { |
70 |
if (strcmp(capture_name, "ftype") == 0) { |
| 64 |
fn.fname = extract_value(captured_node, source_code); |
71 |
fn.ftype = extract_value(captured_node, source_code); |
|
|
72 |
} |
| 65 |
|
73 |
|
| 66 |
TSPoint start_point = ts_node_start_point(captured_node); |
74 |
if (strcmp(capture_name, "fparams") == 0) { |
| 67 |
fn.lineno = start_point.row; |
75 |
fn.fparams = extract_value(captured_node, source_code); |
| 68 |
} |
76 |
} |
|
|
77 |
} |
| 69 |
|
78 |
|
| 70 |
if (strcmp(capture_name, "ftype") == 0) { |
79 |
printf("%s:%zu\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, fn.fparams); |
| 71 |
fn.ftype = extract_value(captured_node, source_code); |
|
|
| 72 |
} |
80 |
} |
| 73 |
|
81 |
} else { |
| 74 |
if (strcmp(capture_name, "fparams") == 0) { |
82 |
if (DEBUG) { |
| 75 |
fn.fparams = extract_value(captured_node, source_code); |
83 |
printf("Query creation failed at offset %u with error type %d\n", error_offset, error_type); |
| 76 |
} |
84 |
} |
| 77 |
} |
|
|
| 78 |
|
|
|
| 79 |
printf("%s:%zu\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, fn.fparams); |
|
|
| 80 |
|
|
|
| 81 |
} |
85 |
} |
| 82 |
} else { |
|
|
| 83 |
if (DEBUG) { |
|
|
| 84 |
printf("Query creation failed at offset %u with error type %d\n", error_offset, error_type); |
|
|
| 85 |
} |
|
|
| 86 |
} |
|
|
| 87 |
|
86 |
|
| 88 |
ts_query_cursor_delete(query_cursor); |
87 |
ts_query_cursor_delete(query_cursor); |
| 89 |
ts_query_delete(query); |
88 |
ts_query_delete(query); |
| 90 |
ts_tree_delete(tree); |
89 |
ts_tree_delete(tree); |
| 91 |
ts_parser_delete(parser); |
90 |
ts_parser_delete(parser); |
| 92 |
} |
91 |
} |
| 93 |
|
92 |
|
| 94 |
const char *get_file_extension(const char *file_path) { |
93 |
const char *get_file_extension(const char *file_path) { |
| 95 |
const char *extension = strrchr(file_path, '.'); |
94 |
const char *extension = strrchr(file_path, '.'); |
| 96 |
if (extension != NULL) { |
95 |
if (extension != NULL) { |
| 97 |
return extension + 1; |
96 |
return extension + 1; |
| 98 |
} |
97 |
} |
| 99 |
return NULL; |
98 |
return NULL; |
| 100 |
} |
99 |
} |
| 101 |
|
100 |
|
| 102 |
int main(void) { |
101 |
int main(void) { |
| 103 |
const char *file_path = "examples/cmdline.c"; |
102 |
const char *file_path = "examples/cmdline.c"; |
| 104 |
/* const char *file_path = "examples/tabs.py"; */ |
103 |
/* const char *file_path = "examples/tabs.py"; */ |
| 105 |
const char *extension = get_file_extension(file_path); |
104 |
const char *extension = get_file_extension(file_path); |
| 106 |
|
105 |
|
| 107 |
TSLanguage *tree_sitter_c(void); |
106 |
TSLanguage *tree_sitter_c(void); |
| 108 |
TSLanguage *tree_sitter_python(void); |
107 |
TSLanguage *tree_sitter_python(void); |
| 109 |
|
108 |
|
| 110 |
struct FileContent source_file = read_entire_file(file_path); |
109 |
struct FileContent source_file = read_entire_file(file_path); |
| 111 |
if (source_file.content != NULL) { |
110 |
if (source_file.content != NULL) { |
| 112 |
if (DEBUG) { |
111 |
if (DEBUG) { |
| 113 |
/* fprintf(stdout, "File contents:\n%s\n", source_file.content); */ |
112 |
/* fprintf(stdout, "File contents:\n%s\n", source_file.content); */ |
| 114 |
/* fprintf(stdout, "Count of characters: %zu\n", source_file.count); */ |
113 |
/* fprintf(stdout, "Count of characters: %zu\n", source_file.count); */ |
| 115 |
} |
114 |
} |
| 116 |
|
115 |
|
| 117 |
if (extension != NULL) { |
116 |
if (extension != NULL) { |
| 118 |
if (DEBUG) { |
117 |
if (DEBUG) { |
| 119 |
fprintf(stdout, "File extension: %s\n", extension); |
118 |
fprintf(stdout, "File extension: %s\n", extension); |
| 120 |
} |
119 |
} |
| 121 |
|
120 |
|
| 122 |
if (strcmp(extension, "c") == 0) { |
121 |
if (strcmp(extension, "c") == 0) { |
| 123 |
parse_source_file(file_path, source_file.content, tree_sitter_c()); |
122 |
parse_source_file(file_path, source_file.content, tree_sitter_c()); |
| 124 |
} |
123 |
} |
| 125 |
|
124 |
|
| 126 |
if (strcmp(extension, "py") == 0) { |
125 |
if (strcmp(extension, "py") == 0) { |
| 127 |
parse_source_file(file_path, source_file.content, tree_sitter_python()); |
126 |
parse_source_file(file_path, source_file.content, tree_sitter_python()); |
| 128 |
} |
127 |
} |
| 129 |
} else { |
128 |
} else { |
| 130 |
if (DEBUG) { |
129 |
if (DEBUG) { |
| 131 |
fprintf(stderr,"No file extension found.\n"); |
130 |
fprintf(stderr,"No file extension found.\n"); |
| 132 |
} |
131 |
} |
| 133 |
} |
132 |
} |
| 134 |
|
133 |
|
| 135 |
free((void *)source_file.content); |
134 |
free((void *)source_file.content); |
| 136 |
} else { |
135 |
} else { |
| 137 |
if (DEBUG) { |
136 |
if (DEBUG) { |
| 138 |
fprintf(stderr, "Failed to read file.\n"); |
137 |
fprintf(stderr, "Failed to read file.\n"); |
|
|
138 |
} |
| 139 |
} |
139 |
} |
| 140 |
} |
|
|
| 141 |
|
140 |
|
| 142 |
return 0; |
141 |
return 0; |
| 143 |
} |
142 |
} |