cgen/src/main.c
2024-12-14 18:48:07 -05:00

142 lines
3.2 KiB
C

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tree_sitter/api.h>
#include "gen/gen_enum_tsq.h"
TSLanguage const *tree_sitter_c(void);
char const *USAGE = "\
cgen <mode>\
";
size_t read_stdin(char *buf, size_t buf_cap) {
char *at = buf;
char *end = buf + buf_cap;
for (; at < end; ++at) {
if ((*at = fgetc(stdin)) == EOF) {
break;
}
}
if (at < end) { *at = '\0'; }
return at - buf;
}
void gen_enum_strs() {
size_t buf_cap = 2 << 16;
char *buf = calloc(buf_cap, sizeof(*buf));
size_t buf_len = read_stdin(buf, buf_cap);
TSParser *parser = ts_parser_new();
TSLanguage const *lang_c = tree_sitter_c();
ts_parser_set_language(parser, lang_c);
TSTree *tree = ts_parser_parse_string(parser, nullptr, buf, buf_len);
TSNode root_node = ts_tree_root_node(tree);
uint32_t err_offset = 0;
TSQueryError err = {};
TSQuery *query = ts_query_new(
lang_c,
(char*)src_gen_enum_tsq,
src_gen_enum_tsq_len,
&err_offset,
&err
);
if (err != TSQueryErrorNone) {
printf("query error %d near: %s\n", err, src_gen_enum_tsq + err_offset);
assert(false);
}
uint32_t cap_id_poison = 2 << 16;
uint32_t cap_id_enum_name = cap_id_poison;
uint32_t cap_id_enum_variant = cap_id_poison;
uint32_t cap_id_enum_declarator_name = cap_id_poison;
uint32_t cap_count = ts_query_capture_count(query);
for (uint32_t i = 0; i < cap_count; ++i) {
uint32_t len = 0;
char const *name = ts_query_capture_name_for_id(query, i, &len);
if (!strncmp(name, "enum_name", len)) {
cap_id_enum_name = i;
}
if (!strncmp(name, "enum_variant", len)) {
cap_id_enum_variant = i;
}
if (!strncmp(name, "enum_declarator_name", len)) {
cap_id_enum_declarator_name = i;
}
}
TSQueryCursor *qc = ts_query_cursor_new();
ts_query_cursor_exec(qc, query, root_node);
TSQueryMatch match = {};
while (ts_query_cursor_next_match(qc, &match)) {
char const *poison = "POISON";
char const *enum_name = poison;
size_t enum_name_len = strlen(poison);
size_t enum_variants_cap = 512;
struct {
char const *start;
size_t len;
} enum_variants[enum_variants_cap] = {};
size_t enum_variants_len = 0;
for (uint32_t i = 0; i < match.capture_count; ++i) {
TSQueryCapture cap = match.captures[i];
uint32_t start = ts_node_start_byte(cap.node);
uint32_t end = ts_node_end_byte(cap.node);
uint32_t len = end - start;
char const *at = buf + start;
if (
cap.index == cap_id_enum_name
|| cap.index == cap_id_enum_declarator_name
) {
enum_name = at;
enum_name_len = len;
}
if (
cap.index == cap_id_enum_variant
&& enum_variants_len < enum_variants_cap
) {
enum_variants[enum_variants_len].len = len;
enum_variants[enum_variants_len].start = at;
enum_variants_len++;
}
}
printf("char const *%.*s_strs[] = {\n", (int)enum_name_len, enum_name);
for (size_t i = 0; i < enum_variants_len; ++i) {
typeof(enum_variants[0]) evar = enum_variants[i];
printf("\t[%.*s] = \"%.*s\",\n", (int)evar.len, evar.start, (int)evar.len, evar.start);
}
printf("};\n");
}
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("%s", USAGE);
exit(1);
}
char const *mode = argv[1];
if (!strcmp(mode, "enum-strs")) {
gen_enum_strs();
}
return 0;
}