mirror of
https://github.com/Ed94/metadesk.git
synced 2026-08-05 23:28:45 +00:00
adjusting repo for removing extra features not part of the original library
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Metagen
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,329 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef METAGEN_H
|
||||
#define METAGEN_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Type
|
||||
|
||||
typedef struct MG_Msg MG_Msg;
|
||||
struct MG_Msg
|
||||
{
|
||||
String8 location;
|
||||
String8 kind;
|
||||
String8 msg;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgNode MG_MsgNode;
|
||||
struct MG_MsgNode
|
||||
{
|
||||
MG_MsgNode *next;
|
||||
MG_Msg v;
|
||||
};
|
||||
|
||||
typedef struct MG_MsgList MG_MsgList;
|
||||
struct MG_MsgList
|
||||
{
|
||||
MG_MsgNode *first;
|
||||
MG_MsgNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Artifact Types
|
||||
|
||||
typedef struct MG_FileParse MG_FileParse;
|
||||
struct MG_FileParse
|
||||
{
|
||||
Node *root;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseNode MG_FileParseNode;
|
||||
struct MG_FileParseNode
|
||||
{
|
||||
MG_FileParseNode *next;
|
||||
MG_FileParse v;
|
||||
};
|
||||
|
||||
typedef struct MG_FileParseList MG_FileParseList;
|
||||
struct MG_FileParseList
|
||||
{
|
||||
MG_FileParseNode *first;
|
||||
MG_FileParseNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Type
|
||||
|
||||
typedef struct MG_MapNode MG_MapNode;
|
||||
struct MG_MapNode
|
||||
{
|
||||
MG_MapNode *next;
|
||||
String8 key;
|
||||
void *val;
|
||||
};
|
||||
|
||||
typedef struct MG_MapSlot MG_MapSlot;
|
||||
struct MG_MapSlot
|
||||
{
|
||||
MG_MapNode *first;
|
||||
MG_MapNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_Map MG_Map;
|
||||
struct MG_Map
|
||||
{
|
||||
MG_MapSlot *slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Types
|
||||
|
||||
typedef enum MG_StrExprOpKind
|
||||
{
|
||||
MG_StrExprOpKind_Null,
|
||||
MG_StrExprOpKind_Prefix,
|
||||
MG_StrExprOpKind_Postfix,
|
||||
MG_StrExprOpKind_Binary,
|
||||
MG_StrExprOpKind_COUNT
|
||||
}
|
||||
MG_StrExprOpKind;
|
||||
|
||||
typedef enum MG_StrExprOp
|
||||
{
|
||||
MG_StrExprOp_Null,
|
||||
|
||||
#define MG_StrExprOp_FirstString MG_StrExprOp_Dot
|
||||
MG_StrExprOp_Dot,
|
||||
MG_StrExprOp_ExpandIfTrue,
|
||||
MG_StrExprOp_Concat,
|
||||
MG_StrExprOp_BumpToColumn,
|
||||
#define MG_StrExprOp_LastString MG_StrExprOp_BumpToColumn
|
||||
|
||||
#define MG_StrExprOp_FirstNumeric MG_StrExprOp_Add
|
||||
MG_StrExprOp_Add,
|
||||
MG_StrExprOp_Subtract,
|
||||
MG_StrExprOp_Multiply,
|
||||
MG_StrExprOp_Divide,
|
||||
MG_StrExprOp_Modulo,
|
||||
MG_StrExprOp_LeftShift,
|
||||
MG_StrExprOp_RightShift,
|
||||
MG_StrExprOp_BitwiseAnd,
|
||||
MG_StrExprOp_BitwiseOr,
|
||||
MG_StrExprOp_BitwiseXor,
|
||||
MG_StrExprOp_BitwiseNegate,
|
||||
MG_StrExprOp_BooleanAnd,
|
||||
MG_StrExprOp_BooleanOr,
|
||||
MG_StrExprOp_BooleanNot,
|
||||
MG_StrExprOp_Equals,
|
||||
MG_StrExprOp_DoesNotEqual,
|
||||
#define MG_StrExprOp_LastNumeric MG_StrExprOp_DoesNotEqual
|
||||
|
||||
MG_StrExprOp_COUNT,
|
||||
}
|
||||
MG_StrExprOp;
|
||||
|
||||
typedef struct MG_StrExpr MG_StrExpr;
|
||||
struct MG_StrExpr
|
||||
{
|
||||
MG_StrExpr *parent;
|
||||
MG_StrExpr *left;
|
||||
MG_StrExpr *right;
|
||||
MG_StrExprOp op;
|
||||
Node *node;
|
||||
};
|
||||
|
||||
typedef struct MG_StrExprParseResult MG_StrExprParseResult;
|
||||
struct MG_StrExprParseResult
|
||||
{
|
||||
MG_StrExpr *root;
|
||||
MsgList msgs;
|
||||
Node *next_node;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Types
|
||||
|
||||
typedef struct MG_NodeArray MG_NodeArray;
|
||||
struct MG_NodeArray
|
||||
{
|
||||
Node **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct MG_NodeGrid MG_NodeGrid;
|
||||
struct MG_NodeGrid
|
||||
{
|
||||
U64 x_stride;
|
||||
U64 y_stride;
|
||||
MG_NodeArray cells;
|
||||
MG_NodeArray row_parents;
|
||||
};
|
||||
|
||||
typedef enum MG_ColumnKind
|
||||
{
|
||||
MG_ColumnKind_DirectCell,
|
||||
MG_ColumnKind_CheckForTag,
|
||||
MG_ColumnKind_TagChild,
|
||||
MG_ColumnKind_COUNT
|
||||
}
|
||||
MG_ColumnKind;
|
||||
|
||||
typedef struct MG_ColumnDesc MG_ColumnDesc;
|
||||
struct MG_ColumnDesc
|
||||
{
|
||||
String8 name;
|
||||
MG_ColumnKind kind;
|
||||
String8 tag_name;
|
||||
};
|
||||
|
||||
typedef struct MG_ColumnDescArray MG_ColumnDescArray;
|
||||
struct MG_ColumnDescArray
|
||||
{
|
||||
U64 count;
|
||||
MG_ColumnDesc *v;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandTask MG_TableExpandTask;
|
||||
struct MG_TableExpandTask
|
||||
{
|
||||
MG_TableExpandTask *next;
|
||||
String8 expansion_label;
|
||||
MG_NodeGrid *grid;
|
||||
MG_ColumnDescArray column_descs;
|
||||
U64 count;
|
||||
U64 idx;
|
||||
};
|
||||
|
||||
typedef struct MG_TableExpandInfo MG_TableExpandInfo;
|
||||
struct MG_TableExpandInfo
|
||||
{
|
||||
MG_TableExpandTask *first_expand_task;
|
||||
String8 missing_value_fallback;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Output Path Types
|
||||
|
||||
typedef struct MG_Layer MG_Layer;
|
||||
struct MG_Layer
|
||||
{
|
||||
String8 key;
|
||||
B32 is_library;
|
||||
String8 gen_folder_name;
|
||||
String8 h_name_override;
|
||||
String8 c_name_override;
|
||||
String8List enums;
|
||||
String8List structs;
|
||||
String8List h_functions;
|
||||
String8List h_tables;
|
||||
String8List h_catchall;
|
||||
String8List h_header;
|
||||
String8List h_footer;
|
||||
String8List c_functions;
|
||||
String8List c_tables;
|
||||
String8List c_catchall;
|
||||
String8List c_header;
|
||||
String8List c_footer;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerNode MG_LayerNode;
|
||||
struct MG_LayerNode
|
||||
{
|
||||
MG_LayerNode *next;
|
||||
MG_Layer v;
|
||||
};
|
||||
|
||||
typedef struct MG_LayerSlot MG_LayerSlot;
|
||||
struct MG_LayerSlot
|
||||
{
|
||||
MG_LayerNode *first;
|
||||
MG_LayerNode *last;
|
||||
};
|
||||
|
||||
typedef struct MG_State MG_State;
|
||||
struct MG_State
|
||||
{
|
||||
U64 slots_count;
|
||||
MG_LayerSlot *slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global Arena *mg_arena = 0;
|
||||
global MG_State *mg_state = 0;
|
||||
read_only global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_nil, &mg_str_expr_nil};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 mg_hash_from_string(String8 string);
|
||||
internal TxtPt mg_txt_pt_from_string_off(String8 string, U64 off);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Message Lists
|
||||
|
||||
internal void mg_msg_list_push(Arena *arena, MG_MsgList *msgs, MG_Msg *msg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Escaping
|
||||
|
||||
internal String8 mg_escaped_from_str8(Arena *arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Wrapping
|
||||
|
||||
internal String8List mg_wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: C-String-Izing
|
||||
|
||||
internal String8 mg_c_string_literal_from_multiline_string(String8 string);
|
||||
internal String8 mg_c_array_literal_contents_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Map Functions
|
||||
|
||||
internal MG_Map mg_push_map(Arena *arena, U64 slot_count);
|
||||
internal void *mg_map_ptr_from_string(MG_Map *map, String8 string);
|
||||
internal void mg_map_insert_ptr(Arena *arena, MG_Map *map, String8 string, void *val);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Expression Parsing
|
||||
|
||||
internal MG_StrExpr *mg_push_str_expr(Arena *arena, MG_StrExprOp op, Node *node);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, Node *first, Node *opl, S8 min_prec);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_first_opl(Arena *arena, Node *first, Node *opl);
|
||||
internal MG_StrExprParseResult mg_str_expr_parse_from_root(Arena *arena, Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Table Generation Functions
|
||||
|
||||
internal MG_NodeArray mg_node_array_make(Arena *arena, U64 count);
|
||||
internal MG_NodeArray mg_child_array_from_node(Arena *arena, Node *node);
|
||||
internal MG_NodeGrid mg_node_grid_make_from_node(Arena *arena, Node *root);
|
||||
internal MG_NodeArray mg_row_from_index(MG_NodeGrid grid, U64 index);
|
||||
internal MG_NodeArray mg_column_from_index(Arena *arena, MG_NodeGrid grid, U64 index);
|
||||
internal Node *mg_node_from_grid_xy(MG_NodeGrid grid, U64 x, U64 y);
|
||||
|
||||
internal MG_ColumnDescArray mg_column_desc_array_make(Arena *arena, U64 count, MG_ColumnDesc *descs);
|
||||
internal MG_ColumnDescArray mg_column_desc_array_from_tag(Arena *arena, Node *tag);
|
||||
internal U64 mg_column_index_from_name(MG_ColumnDescArray descs, String8 name);
|
||||
internal String8 mg_string_from_row_desc_idx(Node *row_parent, MG_ColumnDescArray descs, U64 idx);
|
||||
|
||||
internal S64 mg_eval_table_expand_expr__numeric(MG_StrExpr *expr, MG_TableExpandInfo *info);
|
||||
internal void mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpandInfo *info, String8List *out);
|
||||
internal void mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo *info, MG_TableExpandTask *task, String8List *out);
|
||||
internal String8List mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_column_desc_map, String8 fallback, Node *gen);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Layer Lookup Functions
|
||||
|
||||
internal String8 mg_layer_key_from_path(String8 path);
|
||||
internal MG_Layer *mg_layer_from_key(String8 key);
|
||||
|
||||
#endif //METAGEN_H
|
||||
@@ -0,0 +1,656 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Options
|
||||
|
||||
#define BUILD_CONSOLE_INTERFACE 1
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Includes
|
||||
|
||||
//- rjf: headers
|
||||
#include "metagen/metagen_base/metagen_base_inc.h"
|
||||
#include "metagen/metagen_os/metagen_os_inc.h"
|
||||
#include "mdesk/mdesk.h"
|
||||
#include "metagen.h"
|
||||
|
||||
//- rjf: impls
|
||||
#include "metagen/metagen_base/metagen_base_inc.c"
|
||||
#include "metagen/metagen_os/metagen_os_inc.c"
|
||||
#include "mdesk/mdesk.c"
|
||||
#include "metagen.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entry Point
|
||||
|
||||
internal void
|
||||
entry_point(CmdLine *cmdline)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- rjf: set up state
|
||||
//
|
||||
MG_MsgList msgs = {0};
|
||||
mg_arena = arena_alloc(.reserve_size = GB(64), .commit_size = MB(64));
|
||||
mg_state = push_array(mg_arena, MG_State, 1);
|
||||
mg_state->slots_count = 256;
|
||||
mg_state->slots = push_array(mg_arena, MG_LayerSlot, mg_state->slots_count);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: extract paths
|
||||
//
|
||||
String8 build_dir_path = os_get_process_info()->binary_path;
|
||||
String8 project_dir_path = str8_chop_last_slash(build_dir_path);
|
||||
String8 code_dir_path = push_str8f(mg_arena, "%S/src", project_dir_path);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: search code directories for all files to consider
|
||||
//
|
||||
String8List file_paths = {0};
|
||||
DeferLoop(printf("searching %.*s...", str8_varg(code_dir_path)), printf(" %i files found\n", (int)file_paths.node_count))
|
||||
{
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
String8 path;
|
||||
};
|
||||
Task start_task = {0, code_dir_path};
|
||||
Task* first_task = &start_task;
|
||||
Task* last_task = &start_task;
|
||||
for(Task *task = first_task; task != 0; task = task->next)
|
||||
{
|
||||
OS_FileIter* it = os_file_iter_begin(mg_arena, task->path, 0);
|
||||
for(OS_FileInfo info = {0}; os_file_iter_next(mg_arena, it, &info);)
|
||||
{
|
||||
String8 file_path = push_str8f(mg_arena, "%S/%S", task->path, info.name);
|
||||
if(info.props.flags & FilePropertyFlag_IsFolder)
|
||||
{
|
||||
Task *next_task = push_array(mg_arena, Task, 1);
|
||||
SLLQueuePush(first_task, last_task, next_task);
|
||||
next_task->path = file_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_push(mg_arena, &file_paths, file_path);
|
||||
}
|
||||
}
|
||||
os_file_iter_end(it);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: parse all metadesk files
|
||||
//
|
||||
MG_FileParseList parses = {0};
|
||||
DeferLoop(printf("parsing metadesk..."), printf(" %i metadesk files parsed\n", (int)parses.count))
|
||||
{
|
||||
for(String8Node *n = file_paths.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 file_path = n->string;
|
||||
String8 file_ext = str8_skip_last_dot(file_path);
|
||||
if(str8_match(file_ext, str8_lit("mdesk"), 0))
|
||||
{
|
||||
String8 data = os_data_from_file_path(mg_arena, file_path);
|
||||
TokenizeResult tokenize = tokenize_from_text(mg_arena, data);
|
||||
ParseResult parse = parse_from_text_tokens(mg_arena, file_path, data, tokenize.tokens);
|
||||
for(Msg *m = parse.msgs.first; m != 0; m = m->next)
|
||||
{
|
||||
TxtPt pt = mg_txt_pt_from_string_off(data, m->node->src_offset);
|
||||
String8 msg_kind_string = {0};
|
||||
switch(m->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case MD_MsgKind_Note: {msg_kind_string = str8_lit("note");}break;
|
||||
case MsgKind_Warning: {msg_kind_string = str8_lit("warning");}break;
|
||||
case MsgKind_Error: {msg_kind_string = str8_lit("error");}break;
|
||||
case MD_MsgKind_FatalError: {msg_kind_string = str8_lit("fatal error");}break;
|
||||
}
|
||||
String8 location = push_str8f(mg_arena, "%S:%I64d:%I64d", file_path, pt.line, pt.column);
|
||||
MG_Msg dst_m = {location, msg_kind_string, m->string};
|
||||
mg_msg_list_push(mg_arena, &msgs, &dst_m);
|
||||
}
|
||||
MG_FileParseNode *parse_n = push_array(mg_arena, MG_FileParseNode, 1);
|
||||
SLLQueuePush(parses.first, parses.last, parse_n);
|
||||
parse_n->v.root = parse.root;
|
||||
parses.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather tables
|
||||
//
|
||||
MG_Map table_grid_map = mg_push_map(mg_arena, 1024);
|
||||
MG_Map table_col_map = mg_push_map(mg_arena, 1024);
|
||||
U64 table_count = 0;
|
||||
DeferLoop(printf("gathering tables..."), printf(" %i tables found\n", (int)table_count))
|
||||
{
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
Node *table_tag = tag_from_string(node, str8_lit("table"), 0);
|
||||
if(!node_is_nil(table_tag))
|
||||
{
|
||||
MG_NodeGrid *table = push_array(mg_arena, MG_NodeGrid, 1);
|
||||
MG_ColumnDescArray *col_descs = push_array(mg_arena, MG_ColumnDescArray, 1);
|
||||
*table = mg_node_grid_make_from_node(mg_arena, node);
|
||||
*col_descs = mg_column_desc_array_from_tag(mg_arena, table_tag);
|
||||
mg_map_insert_ptr(mg_arena, &table_grid_map, node->string, table);
|
||||
mg_map_insert_ptr(mg_arena, &table_col_map, node->string, col_descs);
|
||||
table_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather layer options
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
if(node_has_tag(node, str8_lit("option"), 0))
|
||||
{
|
||||
if(str8_match(node->string, str8_lit("library"), 0))
|
||||
{
|
||||
layer->is_library = 1;
|
||||
}
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("gen_folder"), 0))
|
||||
{
|
||||
layer->gen_folder_name = node->string;
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("h_name"), 0))
|
||||
{
|
||||
layer->h_name_override = node->string;
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("c_name"), 0))
|
||||
{
|
||||
layer->c_name_override = node->string;
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("h_header"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->h_header, n->string);
|
||||
str8_list_push(mg_arena, &layer->h_header, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("h_footer"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->h_footer, n->string);
|
||||
str8_list_push(mg_arena, &layer->h_footer, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("c_header"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->c_header, n->string);
|
||||
str8_list_push(mg_arena, &layer->c_header, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("c_footer"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &layer->c_footer, n->string);
|
||||
str8_list_push(mg_arena, &layer->c_footer, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate enums
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
Node *tag = tag_from_string(node, str8_lit("enum"), 0);
|
||||
if(!node_is_nil(tag))
|
||||
{
|
||||
String8 enum_name = node->string;
|
||||
String8 enum_member_prefix = enum_name;
|
||||
if(str8_match(str8_postfix(enum_name, 5), str8_lit("Flags"), 0))
|
||||
{
|
||||
enum_member_prefix = str8_chop(enum_name, 1);
|
||||
}
|
||||
String8 enum_base_type_name = tag->first->string;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
if(enum_base_type_name.size == 0)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", enum_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "typedef %S %S;\n", enum_base_type_name, enum_name);
|
||||
str8_list_pushf(mg_arena, &layer->enums, "typedef enum %SEnum\n{\n", enum_name);
|
||||
}
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 escaped = mg_escaped_from_str8(mg_arena, n->string);
|
||||
str8_list_pushf(mg_arena, &layer->enums, "%S_%S,\n", enum_member_prefix, escaped);
|
||||
}
|
||||
if(enum_base_type_name.size == 0)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "} %S;\n\n", enum_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->enums, "} %SEnum;\n\n", enum_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate xlists
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
Node *tag = tag_from_string(node, str8_lit("xlist"), 0);
|
||||
if(!node_is_nil(tag))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
str8_list_pushf(mg_arena, &layer->enums, "#define %S \\\n", node->string);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 escaped = mg_escaped_from_str8(mg_arena, n->string);
|
||||
str8_list_pushf(mg_arena, &layer->enums, "X(%S)\\\n", escaped);
|
||||
}
|
||||
str8_list_push(mg_arena, &layer->enums, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate structs
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
if(node_has_tag(node, str8_lit("struct"), 0))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
str8_list_pushf(mg_arena, &layer->structs, "typedef struct %S %S;\n", node->string, node->string);
|
||||
str8_list_pushf(mg_arena, &layer->structs, "struct %S\n{\n", node->string);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 escaped = mg_escaped_from_str8(mg_arena, n->string);
|
||||
str8_list_pushf(mg_arena, &layer->structs, "%S;\n", escaped);
|
||||
}
|
||||
str8_list_pushf(mg_arena, &layer->structs, "};\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate data tables
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
Node *tag = tag_from_string(node, str8_lit("data"), 0);
|
||||
if(!node_is_nil(tag))
|
||||
{
|
||||
String8 element_type = tag->first->string;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
if(!node_has_tag(node, str8_lit("c_file"), 0))
|
||||
{
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "extern %S %S[%I64u];\n", element_type, node->string, gen_strings.node_count);
|
||||
}
|
||||
str8_list_pushf(mg_arena, &layer->c_tables, "%S %S[%I64u] =\n{\n", element_type, node->string, gen_strings.node_count);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 escaped = mg_escaped_from_str8(mg_arena, n->string);
|
||||
str8_list_pushf(mg_arena, &layer->c_tables, "%S,\n", escaped);
|
||||
}
|
||||
str8_list_push(mg_arena, &layer->c_tables, str8_lit("};\n\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate enum -> string mapping functions
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
Node *tag = tag_from_string(node, str8_lit("enum2string_switch"), 0);
|
||||
if(!node_is_nil(tag))
|
||||
{
|
||||
String8 enum_type = tag->first->string;
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
str8_list_pushf(mg_arena, &layer->h_functions, "internal String8 %S(%S v);\n", node->string, enum_type);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "internal String8\n%S(%S v)\n{\n", node->string, enum_type);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "String8 result = str8_lit(\"<Unknown %S>\");\n", enum_type);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "switch(v)\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "{\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "default:{}break;\n");
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 escaped = mg_escaped_from_str8(mg_arena, n->string);
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "%S;\n", escaped);
|
||||
}
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "}\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "return result;\n");
|
||||
str8_list_pushf(mg_arena, &layer->c_functions, "}\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate catch-all generations
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
Node *tag = tag_from_string(node, str8_lit("gen"), 0);
|
||||
if(!node_is_nil(tag))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
B32 prefer_c_file = node_has_tag(node, str8_lit("c_file"), 0);
|
||||
String8List *out = prefer_c_file ? &layer->c_catchall : &layer->h_catchall;
|
||||
if(tag->first->string.size == 0){}
|
||||
else if(str8_match(tag->first->string, str8_lit("enums"), 0)) { out = &layer->enums; }
|
||||
else if(str8_match(tag->first->string, str8_lit("structs"), 0)) { out = &layer->structs; }
|
||||
else if(str8_match(tag->first->string, str8_lit("functions"), 0)) { out = prefer_c_file ? &layer->c_functions : &layer->h_functions; }
|
||||
else if(str8_match(tag->first->string, str8_lit("tables"), 0)) { out = prefer_c_file ? &layer->c_tables : &layer->h_tables; }
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 trimmed = str8_skip_chop_whitespace(n->string);
|
||||
String8 escaped = mg_escaped_from_str8(mg_arena, trimmed);
|
||||
str8_list_push(mg_arena, out, escaped);
|
||||
str8_list_push(mg_arena, out, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather & generate all embeds
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
if(node_has_tag(node, str8_lit("embed_string"), 0))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8 embed_string = mg_c_string_literal_from_multiline_string(node->first->string);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "read_only global String8 %S =\nstr8_lit_comp(\n", node->string);
|
||||
str8_list_push (mg_arena, &layer->h_tables, embed_string);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, ");\n\n");
|
||||
}
|
||||
if(node_has_tag(node, str8_lit("embed_file"), 0))
|
||||
{
|
||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||
String8 data = os_data_from_file_path(mg_arena, node->first->string);
|
||||
String8 embed_string = mg_c_array_literal_contents_from_data(data);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "read_only global U8 %S__data[] =\n{\n", node->string);
|
||||
str8_list_push (mg_arena, &layer->h_tables, embed_string);
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "};\n\n");
|
||||
str8_list_pushf(mg_arena, &layer->h_tables, "read_only global String8 %S = {%S__data, sizeof(%S__data)};\n",
|
||||
node->string,
|
||||
node->string,
|
||||
node->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: generate all markdown in build folder
|
||||
//
|
||||
for(MG_FileParseNode *n = parses.first; n != 0; n = n->next)
|
||||
{
|
||||
Node *file = n->v.root;
|
||||
for each_node(node, file->first)
|
||||
{
|
||||
//- rjf: generate markdown page
|
||||
if(node_has_tag(node, str8_lit("markdown"), 0))
|
||||
{
|
||||
String8List md_strs = {0};
|
||||
for(Node *piece = node->first; !node_is_nil(piece); piece = piece->next)
|
||||
{
|
||||
if(node_has_tag(piece, str8_lit("title"), 0))
|
||||
{
|
||||
str8_list_pushf(mg_arena, &md_strs, "# %S\n\n", piece->string);
|
||||
}
|
||||
if(node_has_tag(piece, str8_lit("subtitle"), 0))
|
||||
{
|
||||
str8_list_pushf(mg_arena, &md_strs, "## %S\n\n", piece->string);
|
||||
}
|
||||
if(node_has_tag(piece, str8_lit("p"), 0))
|
||||
{
|
||||
String8 paragraph_text = piece->string;
|
||||
String8List paragraph_lines = mg_wrapped_lines_from_string(mg_arena, paragraph_text, 80, 80, 0);
|
||||
for(String8Node *n = paragraph_lines.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &md_strs, n->string);
|
||||
str8_list_push(mg_arena, &md_strs, str8_lit("\n"));
|
||||
}
|
||||
str8_list_push(mg_arena, &md_strs, str8_lit("\n"));
|
||||
}
|
||||
if(node_has_tag(piece, str8_lit("unordered_list"), 0))
|
||||
{
|
||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), piece);
|
||||
for(String8Node *n = gen_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
str8_list_pushf(mg_arena, &md_strs, " - ");
|
||||
String8 item_text = n->string;
|
||||
String8List item_lines = mg_wrapped_lines_from_string(mg_arena, item_text, 80-3, 80, 3);
|
||||
for(String8Node *line_n = item_lines.first; line_n != 0; line_n = line_n->next)
|
||||
{
|
||||
str8_list_push(mg_arena, &md_strs, line_n->string);
|
||||
str8_list_pushf(mg_arena, &md_strs, "\n");
|
||||
}
|
||||
}
|
||||
str8_list_pushf(mg_arena, &md_strs, "\n");
|
||||
}
|
||||
}
|
||||
String8 output_path = push_str8f(mg_arena, "%S/%S.md", build_dir_path, node->string);
|
||||
FILE *file = fopen((char *)output_path.str, "w");
|
||||
for(String8Node *n = md_strs.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, file);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: write all layer output files
|
||||
//
|
||||
DeferLoop(printf("generating layer code..."), printf("\n"))
|
||||
{
|
||||
for(U64 slot_idx = 0; slot_idx < mg_state->slots_count; slot_idx += 1)
|
||||
{
|
||||
MG_LayerSlot *slot = &mg_state->slots[slot_idx];
|
||||
for(MG_LayerNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
MG_Layer *layer = &n->v;
|
||||
String8 layer_generated_folder = {0};
|
||||
if(layer->gen_folder_name.size != 0)
|
||||
{
|
||||
String8 gen_folder = layer->gen_folder_name;
|
||||
layer_generated_folder = push_str8f(mg_arena, "%S/%S", code_dir_path, gen_folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
String8 gen_folder = str8_lit("generated");
|
||||
layer_generated_folder = push_str8f(mg_arena, "%S/%S/%S", code_dir_path, layer->key, gen_folder);
|
||||
}
|
||||
if(os_make_directory(layer_generated_folder))
|
||||
{
|
||||
String8List layer_key_parts = str8_split_path(mg_arena, layer->key);
|
||||
StringJoin join = {0};
|
||||
join.sep = str8_lit("_");
|
||||
String8 layer_key_filename = str8_list_join(mg_arena, &layer_key_parts, &join);
|
||||
String8 layer_key_filename_upper = upper_from_str8(mg_arena, layer_key_filename);
|
||||
String8 h_path = push_str8f(mg_arena, "%S/%S.meta.h", layer_generated_folder, layer_key_filename);
|
||||
String8 c_path = push_str8f(mg_arena, "%S/%S.meta.c", layer_generated_folder, layer_key_filename);
|
||||
if(layer->h_name_override.size != 0)
|
||||
{
|
||||
h_path = push_str8f(mg_arena, "%S/%S", layer_generated_folder, str8_skip_last_slash(layer->h_name_override));
|
||||
}
|
||||
if(layer->c_name_override.size != 0)
|
||||
{
|
||||
c_path = push_str8f(mg_arena, "%S/%S", layer_generated_folder, str8_skip_last_slash(layer->c_name_override));
|
||||
}
|
||||
{
|
||||
FILE *h = fopen((char *)h_path.str, "w");
|
||||
fprintf(h, "// Copyright (c) 2024 Epic Games Tools\n");
|
||||
fprintf(h, "// Licensed under the MIT license (https://opensource.org/license/mit/)\n\n");
|
||||
if(layer->h_header.first == 0)
|
||||
{
|
||||
fprintf(h, "//- GENERATED CODE\n\n");
|
||||
fprintf(h, "#ifndef %.*s_META_H\n", str8_varg(layer_key_filename_upper));
|
||||
fprintf(h, "#define %.*s_META_H\n\n", str8_varg(layer_key_filename_upper));
|
||||
}
|
||||
else for(String8Node *n = layer->h_header.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->enums.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->structs.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->h_catchall.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
for(String8Node *n = layer->h_functions.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
if(layer->h_tables.first != 0)
|
||||
{
|
||||
if(!layer->is_library)
|
||||
{
|
||||
fprintf(h, "C_LINKAGE_BEGIN\n");
|
||||
}
|
||||
for(String8Node *n = layer->h_tables.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
fprintf(h, "\n");
|
||||
if(!layer->is_library)
|
||||
{
|
||||
fprintf(h, "C_LINKAGE_END\n\n");
|
||||
}
|
||||
}
|
||||
if(layer->h_footer.first == 0)
|
||||
{
|
||||
fprintf(h, "#endif // %.*s_META_H\n", str8_varg(layer_key_filename_upper));
|
||||
}
|
||||
else for(String8Node *n = layer->h_footer.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, h);
|
||||
}
|
||||
fclose(h);
|
||||
}
|
||||
{
|
||||
FILE *c = fopen((char *)c_path.str, "w");
|
||||
fprintf(c, "// Copyright (c) 2024 Epic Games Tools\n");
|
||||
fprintf(c, "// Licensed under the MIT license (https://opensource.org/license/mit/)\n\n");
|
||||
if(layer->c_header.first == 0)
|
||||
{
|
||||
fprintf(c, "//- GENERATED CODE\n\n");
|
||||
}
|
||||
else for(String8Node *n = layer->c_header.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
for(String8Node *n = layer->c_catchall.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
if(layer->c_tables.first != 0)
|
||||
{
|
||||
if(!layer->is_library)
|
||||
{
|
||||
fprintf(c, "C_LINKAGE_BEGIN\n");
|
||||
}
|
||||
for(String8Node *n = layer->c_tables.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
if(!layer->is_library)
|
||||
{
|
||||
fprintf(c, "C_LINKAGE_END\n\n");
|
||||
}
|
||||
}
|
||||
for(String8Node *n = layer->c_functions.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
if(layer->c_footer.first != 0)
|
||||
{
|
||||
for(String8Node *n = layer->c_footer.first; n != 0; n = n->next)
|
||||
{
|
||||
fwrite(n->string.str, n->string.size, 1, c);
|
||||
}
|
||||
}
|
||||
fclose(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: write out all messages to stderr
|
||||
//
|
||||
for(MG_MsgNode *n = msgs.first; n != 0; n = n->next)
|
||||
{
|
||||
MG_Msg *msg = &n->v;
|
||||
fprintf(stderr, "%.*s: %.*s: %.*s\n", str8_varg(msg->location), str8_varg(msg->kind), str8_varg(msg->msg));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user