new table format, templating mt_printf

This commit is contained in:
Krzosa Karol
2025-01-21 13:44:41 +01:00
parent 4679f0da48
commit 2b4d641857
10 changed files with 151 additions and 130 deletions

View File

@@ -2,7 +2,6 @@ void mt_app(ma_arena_t *arena) {
sb8_t *h = sb8_serial_begin(arena);
sb8_t *c = sb8_serial_begin(arena);
ast_t *keys = mtt_parse(arena, __FILE__, S8_CODE(
// javascript filter out
{ name js1 js2 jf windows1 windows2 }
@@ -89,7 +88,7 @@ void mt_app(ma_arena_t *arena) {
c->indent += 1;
{
sb8_stmtf(c, "if (0) {}");
for (mtt_iter_t it = mtt_iterate(c->arena, keys); mtt_is_valid(it); mtt_advance(&it)) {
for (ast_t *it = keys->first; it; it = it->next) {
assert(mtt(it, "jf")->integer == 0 || mtt(it, "jf")->integer == 1);
s8_t js[] = {mtts(it, "js1"), mtts(it, "js2")};
for (i32 i = 0; i < lengthof(js); i += 1) {
@@ -111,7 +110,7 @@ void mt_app(ma_arena_t *arena) {
sb8_stmtf(c, "switch(wparam) {");
c->indent += 1;
{
for (mtt_iter_t it = mtt_iterate(c->arena, keys); mtt_is_valid(it); mtt_advance(&it)) {
for (ast_t *it = keys->first; it; it = it->next) {
s8_t w[] = {mtts(it, "windows1"), mtts(it, "windows2")};
for (i32 i = 0; i < lengthof(w); i += 1) {
if (s8_are_equal(w[i], s8_lit("XXX"))) continue;

View File

@@ -6,10 +6,10 @@
#include "core_unicode.h"
#include "core_arena.h"
#include "core_string.h"
#include "core_lexer.h"
#include "core_math.h"
#include "core_log.h"
#include "core_type_info.h"
#include "core_lexer.h"
#include "core_log.h"
#include "core_intrin.h"
#include "core_platform.h"
#include "core_hash_table.h"

View File

@@ -159,3 +159,18 @@ fn void parser_panicf(lex_t *token, const char *str, ...);
fn void parser_eat_until(parser_t *par, lex_kind_t kind);
fn void parser_eat_including(parser_t *par, lex_kind_t kind);
gb_read_only lex_t lex_null;
gb_read_only type_member_t members__lex_kind_t[] = {
#define X(KIND, STR, SIMPLE) {.name = s8_const_lit("lex_kind_" #KIND), .value = KIND},
LEX_KIND_XLIST
#undef X
};
DEFINE_ENUM(lex_kind_t);
gb_read_only type_member_t members__lex_suffix_t[] = {
#define X(KIND) {.name = s8_const_lit(#KIND), .value = KIND},
LEX_SUFFIX_XLIST
#undef X
};
DEFINE_ENUM(lex_suffix_t);

View File

@@ -1,22 +1,4 @@
/*
** design:
** two modes of working:
** optional immediate dump to console
** optional store and retrieval data structure
**
** [ ] console
** [ ] silence very particular messages (use case: user tries to tokenize c code,
** cares only about particular decls,
** does not want to see error flood)
** [ ] graphical integrated into application
** [ ] little counter of unread warnings/errors, somewhere in the corner, that you can click on
** [ ] hierarchy which you can traverse, dive into things which interest you
** [ ] support for very arbitrary logs: "log_triangle", which would show debug points on screen
**
**
**
*/
typedef enum { // AFTER_CHANGING: modify type_info and log_level_str
typedef enum {
log_level_debug,
log_level_info,
log_level_warning,

View File

@@ -33,6 +33,7 @@ struct sb8_t {
// WARNING: remember to update typeinfo after editing this
i32 indent;
void *user_data;
};
typedef i32 s8_seek_t;

View File

@@ -20,6 +20,7 @@ enum {
type_kind_usize,
type_kind_int,
type_kind_char,
type_kind_void,
type_kind_pointer,
type_kind_array,
@@ -28,7 +29,7 @@ enum {
type_kind_enum,
type_kind_first_basic = type_kind_i8,
type_kind_last_basic = type_kind_char,
type_kind_last_basic = type_kind_void,
};
typedef struct type_t type_t;
@@ -101,6 +102,7 @@ gb_read_only type_t type__isize = {type_kind_isize, s8_const_lit("isize"), sizeo
gb_read_only type_t type__usize = {type_kind_usize, s8_const_lit("usize"), sizeof(usize)};
gb_read_only type_t type__int = {type_kind_int, s8_const_lit("int"), sizeof(int)};
gb_read_only type_t type__char = {type_kind_char, s8_const_lit("char"), sizeof(char)};
gb_read_only type_t type__void = {type_kind_void, s8_const_lit("void")};
gb_read_only type_t type__s8_t = { type_kind_struct, s8_const_lit("s8_t"), sizeof(s8_t), .count = 2,
.members = (type_member_t[]){
@@ -146,7 +148,8 @@ gb_read_only type_t type__sb8_t = { type_kind_struct, s8_const_lit("sb8_t"), siz
{s8_const_lit("arena"), &POINTER(ma_arena_t), .offset = offsetof(sb8_t, arena)},
{s8_const_lit("first"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, first)},
{s8_const_lit("last"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, last)},
{s8_const_lit("indent"), &type__i32, .offset = offsetof(sb8_t, first)},
{s8_const_lit("indent"), &type__i32, .offset = offsetof(sb8_t, indent)},
{s8_const_lit("user_data"), &POINTER(void), .offset = offsetof(sb8_t, user_data)},
}
};
@@ -353,26 +356,3 @@ gb_read_only type_member_t members__r1i64_t[] = {
{s8_const_lit("x1"), &type__i64, .offset = offsetof(r1i64_t, x1)},
};
gb_read_only DEFINE_STRUCT(r1i64_t);
gb_read_only type_member_t members__lex_kind_t[] = {
#define X(KIND, STR, SIMPLE) {.name = s8_const_lit("lex_kind_" #KIND), .value = KIND},
LEX_KIND_XLIST
#undef X
};
DEFINE_ENUM(lex_kind_t);
gb_read_only type_member_t members__lex_suffix_t[] = {
#define X(KIND) {.name = s8_const_lit(#KIND), .value = KIND},
LEX_SUFFIX_XLIST
#undef X
};
DEFINE_ENUM(lex_suffix_t);
gb_read_only type_member_t members__log_level_t[] = {
{.name = s8_const_lit("log_level_debug"), .value = log_level_debug},
{.name = s8_const_lit("log_level_info"), .value = log_level_info},
{.name = s8_const_lit("log_level_warning"), .value = log_level_warning},
{.name = s8_const_lit("log_level_error"), .value = log_level_error},
{.name = s8_const_lit("log_level_fatal"), .value = log_level_fatal},
};
DEFINE_ENUM(log_level_t);

View File

@@ -16,6 +16,7 @@ typedef enum {
X(ast_flag_type_array) \
X(ast_flag_dont_serialize) \
X(ast_flag_flag_enum) \
X(ast_flag_row) \
#define X(NAME) NAME,
@@ -38,7 +39,7 @@ struct ast_t {
i64 integer;
};
fn s8_t s8_serial_ast_flag_t(ma_arena_t *arena, ast_flag_t flag) {
fn s8_t mt_serial_ast_flag(ma_arena_t *arena, ast_flag_t flag) {
ma_temp_t scratch = ma_begin_scratch1(arena);
sb8_t *sb = sb8_serial_begin(scratch.arena);
#define X(NAME) if (flag & set_bit(NAME)) sb8_printf(sb, #NAME);
@@ -162,35 +163,12 @@ fn i64 mt_eval_const_expr(ast_t *expr) {
}
} else {
ma_temp_t scratch = ma_begin_scratch();
parser_panicf(expr->pos, "unhandled ast in const expression evaluation: %S", s8_serial_ast_flag_t(scratch.arena, expr->flags));
parser_panicf(expr->pos, "unhandled ast in const expression evaluation: %S", mt_serial_ast_flag(scratch.arena, expr->flags));
ma_end_scratch(scratch);
}
return 0;
}
#define test_expr(x) do {\
lex_array_t tokens = lex_tokens(scratch.arena, "parser_test", s8_lit(#x));\
parser_t *par = parser_make(scratch.arena, tokens.data);\
ast_t *expr = mt_parse_expr(par);\
assert(expr != NULL);\
i64 value = mt_eval_const_expr(expr);\
assert(value == x);\
} while (0)
fn void run_parser_test() {
ma_temp_t scratch = ma_begin_scratch();
test_expr(32 + 2 + 5 + 5);
test_expr(32 - 2 + 5 - 5);
test_expr(2 * 2 / 4 * 5 + 2 + 3);
test_expr(2 * 5 * 5 / 2 + 2 - 1 - 1);
test_expr(2 * (5 * 5) / 2 + (2 - 1 - 1));
test_expr((2 * (5 * 5) / (2)) + (2 - 1 - 1));
test_expr(10 % 3);
test_expr(10 % 3 + 4 || 2);
test_expr(10 % 3 + 4 || 2 && (4 && 2) || 3 && 1 || 0);
ma_end_scratch(scratch);
}
fn ast_t *mt_parse_struct_mem(parser_t *par, s8_t *name) {
lex_t *type_name = parser_expect(par, lex_kind_ident);
ast_t *type = mt_create_ast(par->arena, type_name, set_bit(ast_flag_type_name) | set_bit(ast_flag_string));

View File

@@ -26,73 +26,67 @@ fn void mtt__parse_row(parser_t *par, ast_t *parent) {
}
}
/*
** DATA:
** { windows linux macos }
** { win32 unix unix }
** { msvc gcc clang }
**
** AST (represented in key value format):
** table {
** row {
** windows { win32 }
** linux { unix }
** macos { unix }
** }
** row {
** windows { msvc }
** linux { gcc }
** macos { clang }
** }
** }
*/
fn ast_t *mtt_parse(ma_arena_t *arena, char *file, s8_t code) {
lex_array_t tokens = lex_tokens(arena, file, code);
parser_t *par = parser_make(arena, tokens.data);
ast_t *table = mt_create_ast(arena, par->at, 0);
mtt__parse_row(par, table);
ast_t *name_row = mt_create_ast(arena, par->at, set_bit(ast_flag_row));
mtt__parse_row(par, name_row);
while (par->at->kind != lex_kind_eof) {
mtt__parse_row(par, table->first);
ast_t *row = mt_create_ast(arena, par->at, set_bit(ast_flag_row));
mt_ast_append(table, row);
for (ast_t *it = name_row->first; it; it = it->next) {
ast_t *name_copy = mt_create_ast(arena, par->at, it->flags);
mt_ast_append(row, name_copy);
name_copy->string = it->string;
name_copy->real = it->real;
name_copy->integer = it->integer;
}
mtt__parse_row(par, row->first);
}
return table;
}
fn ast_t *mtt_find_row(ast_t *table, char *name) {
s8_t name_string = s8_from_char(name);
for (ast_t *it = table->first; it; it = it->next) {
if (s8_are_equal(it->string, name_string)) return it;
fn ast_t *mtt_get(ast_t *row, s8_t name_string) {
for (ast_t *it = row->first; it; it = it->next) {
if (s8_are_equal(it->string, name_string)) return it->first;
}
return NULL;
}
typedef struct mtt_iter_t mtt_iter_t;
struct mtt_iter_t {
ma_arena_t *arena;
ast_t **first_row;
ast_t **it;
i32 len;
};
fn mtt_iter_t mtt_iterate(ma_arena_t *arena, ast_t *table) {
mtt_iter_t iter = {arena};
iter.len = table->len;
iter.first_row = ma_push_array(arena, ast_t *, iter.len);
iter.it = ma_push_array(arena, ast_t *, iter.len);
i32 i = 0;
for (ast_t *it = table->first; it; it = it->next) {
iter.it[i] = it->first;
iter.first_row[i] = it;
i += 1;
}
return iter;
fn s8_t mtt_gets(ast_t *row, s8_t name_string) {
ast_t *n = mtt_get(row, name_string);
return n->string;
}
fn s8_t mttsi(mtt_iter_t iter, i32 idx) {
assert(idx >= 0 && idx < iter.len);
return iter.it[idx]->string;
}
fn ast_t *mtt(mtt_iter_t iter, char *name) {
fn ast_t *mtt(ast_t *row, char *name) {
s8_t name_string = s8_from_char(name);
for (i32 i = 0; i < iter.len; i += 1) {
if (s8_are_equal(iter.first_row[i]->string, name_string)) return iter.it[i];
}
return NULL;
return mtt_get(row, name_string);
}
fn s8_t mtts(mtt_iter_t iter, char *name) {
return mtt(iter, name)->string;
}
fn void mtt_advance(mtt_iter_t *iter) {
for (i32 i = 0; i < iter->len; i += 1) {
iter->it[i] = iter->it[i]->next;
}
}
fn b32 mtt_is_valid(mtt_iter_t iter) {
b32 result = iter.it[0] != NULL;
return result;
fn s8_t mtts(ast_t *row, char *name) {
ast_t *v = mtt(row, name);
return v->string;
}
fn void mtt_serialb(sb8_t *c, sb8_t *h, ast_t *table, s8_t decl) {
@@ -101,7 +95,7 @@ fn void mtt_serialb(sb8_t *c, sb8_t *h, ast_t *table, s8_t decl) {
///////////////////////////////
// enum typedef
sb8_printf(h, "typedef enum {\n");
for (mtt_iter_t it = mtt_iterate(c->arena, table); mtt_is_valid(it); mtt_advance(&it)) {
for (ast_t *it = table->first; it; it = it->next) {
sb8_printf(h, "%S_%S", decl, mtts(it, "name"));
sb8_printf(h, ",\n");
}
@@ -116,15 +110,16 @@ fn void mtt_serialb(sb8_t *c, sb8_t *h, ast_t *table, s8_t decl) {
sb8_stmtf(c, ".members = (type_member_t[]){");
c->indent += 1;
{
for (mtt_iter_t it = mtt_iterate(c->arena, table); mtt_is_valid(it); mtt_advance(&it)) {
for (ast_t *it = table->first; it; it = it->next) {
sb8_stmtf(c, "{.name = s8_const_lit(\"%S_%S\"), .value = %S_%S},", decl, mtts(it, "name"), decl, mtts(it, "name"));
}
}
c->indent -= 1;
sb8_stmtf(c, "},");
sb8_stmtf(c, ".count = %d,", mtt_find_row(table, "name")->len);
sb8_stmtf(c, ".count = %d,", table->len);
}
c->indent -= 1;
sb8_stmtf(c, "};");
}

View File

@@ -1,5 +1,70 @@
void mt_test_replace(ma_arena_t *arena) {
ast_t *keys = mtt_parse(arena, __FILE__, S8_CODE(
fn ast_t *mt_ast_string(ma_arena_t *arena, s8_t string) {
ast_t *n = mt_create_ast(arena, &lex_null, set_bit(ast_flag_string));
n->string = string;
return n;
}
fn ast_t *mt_kv(ma_arena_t *arena, s8_t key, s8_t value) {
ast_t *n = mt_ast_string(arena, key);
mt_ast_append(n, mt_ast_string(arena, value));
return n;
}
fn s8_t mt_templatize_string(ma_arena_t *arena, s8_t string, lex_array_t tokens, ast_t *n) {
ma_temp_t scratch = ma_begin_scratch1(arena);
sb8_t *sb = sb8_serial_begin(scratch.arena);
parser_t *par = parser_make(arena, tokens.data);
for (i64 i = 0; i < string.len;) {
if (par->at->str != string.str + i) {
sb8_append(sb, s8(string.str + i, 1));
i += 1;
continue;
}
lex_t *token = parser_next(par); i += token->len;
if (token->kind == lex_kind_tag && char_is_alphanumeric(string.str[i])) {
lex_t *ident = parser_expect(par, lex_kind_ident); i += ident->len;
sb8_append(sb, mtt_gets(n, ident->string));
} else {
sb8_append(sb, token->string);
}
}
s8_t result = sb8_serial_end(arena, sb);
ma_end_scratch(scratch);
return result;
}
fn s8_t mt_print(ma_arena_t *arena, ast_t *n, s8_t string) {
ma_temp_t scratch = ma_begin_scratch1(arena);
lex_array_t tokens = lex_tokens(scratch.arena, "mt_print", string);
string = mt_templatize_string(arena, string, tokens, n);
ma_end_scratch(scratch);
return string;
}
fn s8_t mt_printf(ma_arena_t *arena, ast_t *n, char *str, ...) {
ma_temp_t scratch = ma_begin_scratch1(arena);
S8_FMT(scratch.arena, str, string);
s8_t result = mt_print(arena, n, string);
ma_end_scratch(scratch);
return result;
}
fn s8_t mt_sbprintf(sb8_t *sb, char *str, ...) {
assert(sb->user_data);
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
S8_FMT(scratch.arena, str, string);
s8_t result = mt_print(sb->arena, (ast_t *)sb->user_data, string);
sb8_append(sb, result);
ma_end_scratch(scratch);
return result;
}
fn void mt_test_replace(ma_arena_t *arena) {
ast_t *table = mtt_parse(arena, __FILE__, S8_CODE(
// javascript filter out
{ name js1 js2 jf windows1 windows2 }
{ null XXX XXX 1 XXX XXX }
@@ -72,7 +137,12 @@ void mt_test_replace(ma_arena_t *arena) {
{ page_up PageUp XXX 1 VK_INSERT XXX }
{ page_down PageDown XXX 1 VK_PRIOR XXX }
));
sb8_t *sb = sb8_serial_begin(arena);
for (ast_t *it = table->first; it; it = it->next) {
sb->user_data = it;
mt_sbprintf(sb, "@name = @windows1 @windows2\n");
}
debugf("%S", sb8_serial_end(arena, sb));
}
void mt_ui(ma_arena_t *arena) {
@@ -169,7 +239,7 @@ void mt_ui(ma_arena_t *arena) {
///
variables_t vars = serial_vars_from_struct(it, type(mt_ui_stacks_t));
sb8_tmplf(h, "typedef struct node_type node_type; struct node_type { value_type value; node_type *next; };", vars);
sb8_tmplf(h, "typedef struct $node_type $node_type; struct $node_type { value_type value; $node_type *next; };", vars);
////

View File

@@ -30,6 +30,7 @@
[x] remove dates and time from core
[ ] meta
[ ] prototype something like templates, readable string generation
[ ] mt_tag syntax // f32 value; mt_tag(min = 0, min = 10) // mt_tag(something)
[x] search for python snippets and execute meta.py script on that file
[x] simplify logging!!!!
[x] somehow index properly the meta files and ignore generated files