testing codegen and basic scaffolding

This commit is contained in:
Anton Ljungdahl 2025-05-14 11:12:07 +02:00
parent 3b76ccbf23
commit d7d9bc8d92
20 changed files with 8571 additions and 0 deletions

6
.gitignore vendored
View File

@ -541,3 +541,9 @@ GitHub.sublime-settings
*.cubin
*.fatbin
# Custom
.ctm
build/*
data/*
*.sublime*

50
build.bat Normal file
View File

@ -0,0 +1,50 @@
@echo off
@rem ---------------------------------------------------------------------------------------
@rem Build and run codegen
IF NOT EXIST .\build mkdir .\build
pushd .\build
ctime -begin timeBuild.ctm
cl /Zi /nologo ../src/metagen/codegen.c
set LastError=%ERRORLEVEL%
ctime -end timeBuild.ctm %LastError%
popd
IF NOT %LastError%==0 GOTO :end
pushd src
pushd gen_test
..\..\build\codegen.exe ./
popd
popd
@rem ---------------------------------------------------------------------------------------
@rem Build main program
set CommonCompilerFlags=/nologo /Zi /FC /Od
@rem /WX /W4 /wd4201 /wd4100 /wd4189 /wd4244 /wd4127 /wd4456
@rem
@rem
IF NOT EXIST .\build mkdir .\build
pushd .\build
ctime -begin timeBuild.ctm
cl %CommonCompilerFlags% ../src/main.c /Fe:program.exe
set LastError=%ERRORLEVEL%
ctime -end timeBuild.ctm %LastError%
popd
IF NOT %LastError%==0 GOTO :end
:end

4
src/base/base_core.h Normal file
View File

@ -0,0 +1,4 @@
#define function static

2
src/base/base_inc.c Normal file
View File

@ -0,0 +1,2 @@
//////////////////////////////////////////////////////////////////////////////////////////////
//~

11
src/base/base_inc.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef BASE_INC_H
#define BASE_INC_H
//////////////////////////////////////////////////////////////////////////////////////////////
//~
#include "base_core.h"
// #include "base_arena.h"
// #include "base_math.h"
// #include "base_entry_point.h"
#endif /* BASE_INC_H */

View File

@ -0,0 +1,8 @@
char * test_value_table[4] =
{
"A",
"B",
"C",
"D",
};

View File

@ -0,0 +1,12 @@
typedef enum TestEnum
{
TestEnum_A,
TestEnum_B,
TestEnum_C,
TestEnum_D,
TestEnum_COUNT
}
TestEnum;
extern char * test_value_table[4];

29
src/gen_test/test.mdesk Normal file
View File

@ -0,0 +1,29 @@
@table(key, value)
TestTable:
{
{A, "A"}
{B, "B"}
{C, "C"}
{D, "D"}
}
//////////////////////////////////////////////////////////////////////////////////////////////
//~ Generators
@table_gen_enum TestEnum:
{
@expand(TestTable a)
`TestEnum_$(a.key),`;
`TestEnum_COUNT`;
}
@table_gen_data(`char *`) test_value_table:
{
@expand(TestTable a)
`"$(a.value)",`;
}

38
src/main.c Normal file
View File

@ -0,0 +1,38 @@
#include <stdio.h>
//////////////////////////////////////////////////////////////////////////////////////////////
//~ Header includes
#include "base/base_inc.h"
#include "os/os_inc.h"
#include "render/render_inc.h"
//////////////////////////////////////////////////////////////////////////////////////////////
//~ Source includes
#include "base/base_inc.c"
#include "os/os_inc.c"
#include "render/render_inc.c"
#include "gen_test/generated/test.meta.h"
#include "gen_test/generated/test.meta.c"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~ Main entry
function void
entry_point()
{
}
int main()
{
printf("Accessing generated table gen_table[enum]\n");
for (int i = 0; i < TestEnum_COUNT; i++)
{
printf("table[%i] = %s \n", i, test_value_table[i]);
}
return 0;
}

148
src/metagen/codegen.c Normal file
View File

@ -0,0 +1,148 @@
#include <inttypes.h>
#include "metadesk_base/md.h"
#include "metadesk_base/md.c"
#include "codegen.h"
#include "codegen_table.h"
#include "codegen_table.c"
////////////////////////////////
//~ rjf: Helpers
static CG_FilePair
CG_FilePairFromNode(MD_Node *node)
{
CG_FilePair result = {0};
MD_CodeLoc loc = MD_CodeLocFromNode(node);
MD_String8 filename = loc.filename;
MD_b32 found = 0;
for(int i = 0; i < cg_file_pair_count; i += 1)
{
if(MD_S8Match(filename, cg_file_pairs[i].src_filename, 0))
{
result = cg_file_pairs[i];
found = 1;
break;
}
}
if(found == 0)
{
MD_String8 folder = MD_PathChopLastSlash(filename);
MD_String8 layer_name = MD_PathChopLastPeriod(MD_PathSkipLastSlash(loc.filename));
MD_String8 gen_folder = MD_S8Fmt(cg_arena, "%.*s/generated", MD_S8VArg(folder));
MD_String8 h_filename = MD_S8Fmt(cg_arena, "%.*s/%.*s.meta.h", MD_S8VArg(gen_folder), MD_S8VArg(layer_name));
MD_String8 c_filename = MD_S8Fmt(cg_arena, "%.*s/%.*s.meta.c", MD_S8VArg(gen_folder), MD_S8VArg(layer_name));
result.src_filename = filename;
result.h = fopen((char *)h_filename.str, "w");
result.c = fopen((char *)c_filename.str, "w");
cg_file_pairs[cg_file_pair_count] = result;
cg_file_pair_count += 1;
}
return result;
}
static void
CG_CloseAllFiles(void)
{
for(int i = 0; i < cg_file_pair_count; i += 1)
{
fclose(cg_file_pairs[i].h);
fclose(cg_file_pairs[i].c);
}
}
static MD_String8
CG_EscapedFromString(MD_Arena *arena, MD_String8 string)
{
MD_ArenaTemp scratch = MD_GetScratch(&arena, 1);
MD_String8List strs = {0};
MD_b32 escaped = 0;
MD_u64 start = 0;
for(MD_u64 idx = 0; idx <= string.size; idx += 1)
{
if(idx < string.size && escaped)
{
escaped = 0;
start = idx+1;
MD_u8 replace_char = 0;
switch(string.str[idx])
{
default: break;
case 'a': replace_char = 0x07; break;
case 'b': replace_char = 0x08; break;
case 'e': replace_char = 0x1b; break;
case 'f': replace_char = 0x0c; break;
case 'n': replace_char = 0x0a; break;
case 'r': replace_char = 0x0d; break;
case 't': replace_char = 0x09; break;
case 'v': replace_char = 0x0b; break;
case '\\': replace_char = 0x5c; break;
case '\'': replace_char = 0x27; break;
case '\"': replace_char = 0x22; break;
case '\?': replace_char = 0x3f; break;
}
if(replace_char)
{
MD_String8 string = MD_S8Copy(scratch.arena, MD_S8(&replace_char, 1));
MD_S8ListPush(scratch.arena, &strs, string);
}
}
else if(idx == string.size || string.str[idx] == '\\')
{
escaped = (string.str[idx] == '\\');
MD_String8 part = MD_S8Substring(string, start, idx);
MD_S8ListPush(scratch.arena, &strs, part);
start = idx;
}
}
MD_String8 result = MD_S8ListJoin(arena, strs, 0);
MD_ReleaseScratch(scratch);
return result;
}
////////////////////////////////
//~ rjf: Entry Point
int main(int argument_count, char **arguments)
{
cg_arena = MD_ArenaAlloc();
//- rjf: parse command line
MD_String8List options = MD_StringListFromArgCV(cg_arena, argument_count, arguments);
MD_CmdLine cmdln = MD_MakeCmdLineFromOptions(cg_arena, options);
//- rjf: parse all files
MD_Node *file_list = MD_MakeList(cg_arena);
for(MD_String8Node *n = cmdln.inputs.first; n != 0; n = n->next)
{
MD_String8 code_dir = n->string;
printf("searching %.*s for metacode...\n", MD_S8VArg(code_dir));
MD_FileIter it = {0};
MD_FileIterBegin(&it, code_dir);
for(MD_FileInfo info = {0};;)
{
info = MD_FileIterNext(cg_arena, &it);
if(info.filename.size == 0)
{
break;
}
if(!(info.flags & MD_FileFlag_Directory) &&
MD_S8Match(MD_PathSkipLastPeriod(info.filename), MD_S8Lit("mdesk"), MD_StringMatchFlag_CaseInsensitive))
{
printf("parsing %.*s...\n", MD_S8VArg(info.filename));
MD_String8 path = MD_S8Fmt(cg_arena, "%.*s/%.*s", MD_S8VArg(code_dir), MD_S8VArg(info.filename));
MD_ParseResult parse = MD_ParseWholeFile(cg_arena, path);
MD_PushNewReference(cg_arena, file_list, parse.node);
}
}
MD_FileIterEnd(&it);
}
//- rjf: send all parses to backends
CG_TBL_Generate(file_list);
CG_CloseAllFiles();
return 0;
}

26
src/metagen/codegen.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef METAPROGRAM_H
#define METAPROGRAM_H
typedef struct CG_FilePair CG_FilePair;
struct CG_FilePair
{
MD_String8 src_filename;
FILE *h;
FILE *c;
};
////////////////////////////////
//~ rjf: Helpers
static CG_FilePair CG_FilePairFromNode(MD_Node *node);
static void CG_CloseAllFiles(void);
static MD_String8 CG_EscapedFromString(MD_Arena *arena, MD_String8 string);
////////////////////////////////
//~ rjf: Globals
static MD_Arena *cg_arena = 0;
static int cg_file_pair_count = 0;
static CG_FilePair cg_file_pairs[4096] = {0};
#endif // METAPROGRAM_H

564
src/metagen/codegen_table.c Normal file
View File

@ -0,0 +1,564 @@
static MD_Map cg_tbl_top_level_node_grid_map = {0};
static MD_Map cg_tbl_top_level_table_header_map = {0};
static MD_Map cg_tbl_layer_map_gen = {0};
static MD_Map cg_tbl_layer_map_gen_enum = {0};
static MD_Map cg_tbl_layer_map_gen_data = {0};
static MD_String8 cg_tbl_tag__table = MD_S8LitComp("table");
static MD_String8 cg_tbl_tag__table_gen = MD_S8LitComp("table_gen");
static MD_String8 cg_tbl_tag__table_gen_enum = MD_S8LitComp("table_gen_enum");
static MD_String8 cg_tbl_tag__table_gen_data = MD_S8LitComp("table_gen_data");
static CG_NodeArray
CG_NodeArrayMake(MD_u64 count)
{
CG_NodeArray result = {0};
result.count = count;
result.v = MD_PushArrayZero(cg_arena, MD_Node *, result.count);
for(MD_u64 idx = 0; idx < result.count; idx += 1)
{
result.v[idx] = MD_NilNode();
}
return result;
}
static CG_NodeGrid
CG_GridFromNode(MD_Node *node)
{
CG_NodeGrid grid = {0};
//- rjf: determine dimensions
MD_u64 row_count = 0;
MD_u64 column_count = 0;
{
for(MD_EachNode(row, node->first_child))
{
row_count += 1;
MD_u64 cell_count_this_row = MD_ChildCountFromNode(row);
column_count = MD_Max(cell_count_this_row, column_count);
}
}
//- rjf: allocate cells / row parents
{
grid.cells = CG_NodeArrayMake(row_count * column_count);
grid.row_parents = CG_NodeArrayMake(row_count);
}
//- rjf: fill cells
{
MD_u64 row_idx = 0;
for(MD_EachNode(row, node->first_child))
{
MD_u64 col_idx = 0;
grid.row_parents.v[row_idx] = row;
for(MD_EachNode(cell, row->first_child))
{
grid.cells.v[row_idx * column_count + col_idx] = cell;
col_idx += 1;
}
row_idx += 1;
}
}
return grid;
}
static CG_TableHeader
CG_TableHeaderFromTag(MD_Node *tag)
{
CG_TableHeader result = {0};
result.column_count = MD_ChildCountFromNode(tag);
result.column_descs = MD_PushArrayZero(cg_arena, CG_ColumnDesc, result.column_count);
MD_u64 idx = 0;
for(MD_EachNode(column_node, tag->first_child))
{
result.column_descs[idx].kind = CG_ColumnKind_Default;
result.column_descs[idx].name = column_node->string;
MD_Node *check_for_tag = MD_TagFromString(column_node, MD_S8Lit("check_for_tag"), 0);
if(!MD_NodeIsNil(check_for_tag))
{
result.column_descs[idx].kind = CG_ColumnKind_CheckForTag;
result.column_descs[idx].tag_string = check_for_tag->first_child->string;
}
idx += 1;
}
return result;
}
static MD_u64
CG_RowChildIndexFromColumnName(CG_TableHeader *header, MD_String8 column_name)
{
MD_u64 result = 0;
for(MD_u64 idx = 0; idx < header->column_count; idx += 1)
{
if(MD_S8Match(header->column_descs[idx].name, column_name, 0))
{
break;
}
if(header->column_descs[idx].kind == CG_ColumnKind_Default)
{
result += 1;
}
}
return result;
}
static MD_i64
CG_TableExprEvaluate_Numeric(CG_ExpandInfo *info, MD_Expr *expr)
{
MD_i64 result = 0;
CG_TableOp op = expr->op ? expr->op->op_id : CG_TableOp_Null;
switch(op)
{
case CG_TableOp_Equal:
case CG_TableOp_IsNotEqual:
{
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
MD_String8List left_strs = {0};
MD_String8List right_strs = {0};
CG_TableExprEvaluate_String(info, expr->left, &left_strs);
CG_TableExprEvaluate_String(info, expr->right, &right_strs);
MD_String8 left_str = MD_S8ListJoin(scratch.arena, left_strs, 0);
MD_String8 right_str = MD_S8ListJoin(scratch.arena, right_strs, 0);
result = MD_S8Match(left_str, right_str, 0);
if(op == CG_TableOp_IsNotEqual)
{
result = !result;
}
MD_ReleaseScratch(scratch);
}break;
case CG_TableOp_BooleanAnd:
case CG_TableOp_BooleanOr:
{
MD_i64 left = CG_TableExprEvaluate_Numeric(info, expr->left);
MD_i64 right = CG_TableExprEvaluate_Numeric(info, expr->right);
switch(op)
{
case CG_TableOp_BooleanAnd: result = left && right; break;
case CG_TableOp_BooleanOr: result = left || right; break;
}
}break;
}
return result;
}
static void
CG_TableExprEvaluate_String(CG_ExpandInfo *info, MD_Expr *expr, MD_String8List *out)
{
CG_TableOp op = expr->op ? expr->op->op_id : CG_TableOp_Null;
switch(op)
{
default:
case CG_TableOp_Null:
{
MD_S8ListPush(cg_arena, out, expr->md_node->string);
}break;
case CG_TableOp_Dot:
{
MD_Expr *label_expr = expr->left;
MD_Expr *column_query_expr = expr->right;
MD_Node *label_node = label_expr->md_node;
MD_Node *column_query_node = column_query_expr->md_node;
MD_String8 label = label_node->string;
MD_String8 column_query = column_query_node->string;
MD_b32 column_query_is_by_name = column_query_node->flags & MD_NodeFlag_Identifier;
MD_b32 column_query_is_by_index = column_query_node->flags & MD_NodeFlag_Numeric;
// rjf: find which expansion this label refers to, grab its iterator
CG_ExpandIter *iter = 0;
for(CG_ExpandIter *it = info->first_expand_iter; it != 0; it = it->next)
{
if(MD_S8Match(it->label, label, 0))
{
iter = it;
break;
}
}
// rjf: error on invalid label
if(iter == 0)
{
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(label_node), MD_MessageKind_Error, "Expansion label \"%S\" was not found as referring to a valid @expand tag.", label);
}
// rjf: generate strings from iterator's table
if(iter != 0)
{
CG_NodeGrid *grid = iter->grid;
CG_TableHeader *header = iter->header;
MD_Node *row = grid->row_parents.v[iter->idx];
// rjf: grab the cell string given the row & column_query
MD_String8 cell_string = {0};
{
// NOTE(rjf): by-name index (look into table header)
if(column_query_is_by_name && header != 0)
{
MD_u64 column_idx = 0;
CG_ColumnDesc *column = 0;
for(MD_u64 col_idx = 0; col_idx < header->column_count; col_idx += 1)
{
if(MD_S8Match(header->column_descs[col_idx].name, column_query, 0))
{
column = &header->column_descs[col_idx];
column_idx = col_idx;
break;
}
}
MD_u64 row_child_idx = CG_RowChildIndexFromColumnName(header, column_query);
// rjf: error on invalid column
if(column == 0)
{
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(column_query_node), MD_MessageKind_Error, "Column query \"%S\" did not map to a valid column for expansion label \"%S\".", column_query, label);
}
if(column != 0)
{
switch(column->kind)
{
default:
case CG_ColumnKind_Default:
{
MD_Node *cell_node = MD_ChildFromIndex(row, row_child_idx);
cell_string = cell_node->string;
if(MD_S8Match(cell_node->raw_string, MD_S8Lit("/"), 0))
{
cell_string = MD_S8Lit("");
}
}break;
case CG_ColumnKind_CheckForTag:
{
MD_b32 has_tag = MD_NodeHasTag(row, column->tag_string, 0);
cell_string = has_tag ? MD_S8Lit("1") : MD_S8Lit("0");
}break;
}
}
}
// NOTE(rjf): by-index (grab nth child of row)
else if(column_query_is_by_index)
{
MD_i64 index = MD_CStyleIntFromString(column_query);
cell_string = MD_ChildFromIndex(row, index)->string;
}
}
MD_S8ListPush(cg_arena, out, cell_string);
}
}break;
case CG_TableOp_Bump:
{
MD_u64 dst = MD_CStyleIntFromString(expr->unary_operand->md_node->string);
MD_u64 src = out->total_size;
MD_u64 spaces_to_print = dst - src;
if(dst > src)
{
for(MD_u64 space_idx = 0; space_idx < spaces_to_print; space_idx += 1)
{
MD_S8ListPush(cg_arena, out, MD_S8Lit(" "));
}
}
}break;
case CG_TableOp_CheckIfTrue:
{
MD_i64 check_val = CG_TableExprEvaluate_Numeric(info, expr->left);
if(check_val)
{
CG_TableExprEvaluate_String(info, expr->right, out);
}
}break;
case CG_TableOp_Concat:
{
CG_TableExprEvaluate_String(info, expr->left, out);
CG_TableExprEvaluate_String(info, expr->right, out);
}break;
}
}
static void
CG_LoopExpansionDimension(CG_ExpandIter *it, CG_ExpandInfo *info, MD_String8List *out)
{
if(it->next)
{
for(MD_u64 idx = 0; idx < it->count; idx += 1)
{
it->idx = idx;
CG_LoopExpansionDimension(it->next, info, out);
}
}
else
{
for(MD_u64 idx = 0; idx < it->count; idx += 1)
{
it->idx = idx;
MD_String8List expansion_strs = {0};
MD_u64 start_idx = 0;
for(MD_u64 char_idx = 0; char_idx <= info->strexpr.size; char_idx += 1)
{
MD_b32 is_expr_marker = info->strexpr.str[char_idx] == '$';
// rjf: push regular string contents
if(char_idx == info->strexpr.size || is_expr_marker)
{
MD_String8 normal_string_chunk = MD_S8Substring(info->strexpr, start_idx, char_idx);
MD_String8 escaped = CG_EscapedFromString(cg_arena, normal_string_chunk);
MD_S8ListPush(cg_arena, &expansion_strs, escaped);
}
// rjf: handle expansion
if(is_expr_marker)
{
MD_String8 expr_string = MD_S8Skip(info->strexpr, char_idx+1);
{
MD_i64 paren_nest = 0;
for(MD_u64 expr_str_char_idx = 0; expr_str_char_idx < expr_string.size; expr_str_char_idx += 1)
{
if(expr_string.str[expr_str_char_idx] == '(')
{
paren_nest += 1;
}
else if(expr_string.str[expr_str_char_idx] == ')')
{
paren_nest -= 1;
if(paren_nest == 0)
{
expr_string.size = expr_str_char_idx+1;
break;
}
}
}
}
MD_ParseResult parse = MD_ParseOneNode(cg_arena, expr_string, 0);
MD_Node *node = parse.node;
MD_ExprParseResult expr_parse = MD_ExprParse(cg_arena, &info->expr_op_table, node->first_child, MD_NilNode());
MD_Expr *expr = expr_parse.expr;
CG_TableExprEvaluate_String(info, expr, &expansion_strs);
MD_String8 parsed_string = MD_S8Substring(info->strexpr, char_idx+1, char_idx+1+parse.string_advance);
parsed_string = MD_S8ChopWhitespace(parsed_string);
start_idx = char_idx+1+parsed_string.size;
}
}
// rjf: push expansion string to output list
MD_String8 expansion_str = MD_S8ListJoin(cg_arena, expansion_strs, 0);
MD_S8ListPush(cg_arena, out, expansion_str);
}
}
}
static MD_String8List
CG_GenStringListFromNode(MD_ExprOprTable expr_op_table, MD_Node *gen)
{
MD_String8List result = {0};
MD_ArenaTemp scratch = MD_GetScratch(0, 0);
for(MD_EachNode(strexpr, gen->first_child))
{
//- rjf: build expansion iterator list
CG_ExpandIter *first_iter = 0;
CG_ExpandIter *last_iter = 0;
{
for(MD_EachNode(tag, strexpr->first_tag))
{
if(MD_S8Match(tag->string, MD_S8Lit("expand"), 0))
{
MD_Node *table_name_node = MD_ChildFromIndex(tag, 0);
MD_Node *label_node = MD_ChildFromIndex(tag, 1);
MD_String8 table_name = table_name_node->string;
MD_String8 label = label_node->string;
// rjf: grab the table associated with table_name
CG_NodeGrid *grid = 0;
{
MD_MapSlot *slot = MD_MapLookup(&cg_tbl_top_level_node_grid_map, MD_MapKeyStr(table_name));
if(slot != 0)
{
grid = slot->val;
}
}
// rjf: grab the table header associated with table_name
CG_TableHeader *header = 0;
{
MD_MapSlot *slot = MD_MapLookup(&cg_tbl_top_level_table_header_map, MD_MapKeyStr(table_name));
if(slot != 0)
{
header = slot->val;
}
}
// rjf: make iterator node if we got a grid
if(grid != 0)
{
CG_ExpandIter *iter = MD_PushArrayZero(scratch.arena, CG_ExpandIter, 1);
MD_QueuePush(first_iter, last_iter, iter);
iter->grid = grid;
iter->header = header;
iter->label = label;
iter->count = grid->row_parents.count;
}
// rjf: print out an error if grid is 0
if(grid == 0)
{
MD_PrintMessageFmt(stderr, MD_CodeLocFromNode(tag), MD_MessageKind_Error, "Table \"%S\" was not found.", table_name);
}
}
}
}
//- rjf: generate string list for this strexpr & push to result
if(first_iter != 0)
{
CG_ExpandInfo info = {0};
{
info.strexpr = strexpr->string;
info.first_expand_iter = first_iter;
info.expr_op_table = expr_op_table;
}
CG_LoopExpansionDimension(first_iter, &info, &result);
}
//- rjf: generate non-expansion strings
else
{
MD_String8 escaped = CG_EscapedFromString(cg_arena, strexpr->string);
MD_S8ListPush(cg_arena, &result, escaped);
}
}
MD_ReleaseScratch(scratch);
return result;
}
static void
CG_TBL_Generate(MD_Node *file_list)
{
//- rjf: initialize all maps
cg_tbl_top_level_node_grid_map = MD_MapMake(cg_arena);
cg_tbl_top_level_table_header_map = MD_MapMake(cg_arena);
cg_tbl_layer_map_gen = MD_MapMake(cg_arena);
cg_tbl_layer_map_gen_enum = MD_MapMake(cg_arena);
cg_tbl_layer_map_gen_data = MD_MapMake(cg_arena);
//- rjf: build table expression operator table
MD_ExprOprTable table_expr_op_table = {0};
{
MD_ExprOprList ops_list = {0};
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 10, MD_S8Lit("."), CG_TableOp_Dot, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Prefix, 9, MD_S8Lit("=>"), CG_TableOp_Bump, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 6, MD_S8Lit("??"), CG_TableOp_CheckIfTrue, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 7, MD_S8Lit(".."), CG_TableOp_Concat, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 8, MD_S8Lit("=="), CG_TableOp_Equal, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 8, MD_S8Lit("!="), CG_TableOp_IsNotEqual, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 5, MD_S8Lit("&&"), CG_TableOp_BooleanAnd, 0);
MD_ExprOprPush(cg_arena, &ops_list, MD_ExprOprKind_Binary, 4, MD_S8Lit("||"), CG_TableOp_BooleanOr, 0);
table_expr_op_table = MD_ExprBakeOprTableFromList(cg_arena, &ops_list);
}
//- rjf: gather phase
for(MD_EachNode(file_ref, file_list->first_child))
{
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
MD_String8 layer_name = file->string;
MD_MapKey layer_key = MD_MapKeyStr(layer_name);
for(MD_EachNode(node, file->first_child))
{
MD_Node *table_tag = MD_TagFromString(node, cg_tbl_tag__table, 0);
if(!MD_NodeIsNil(table_tag))
{
CG_NodeGrid *grid = MD_PushArrayZero(cg_arena, CG_NodeGrid, 1);
*grid = CG_GridFromNode(node);
MD_MapOverwrite(cg_arena, &cg_tbl_top_level_node_grid_map, MD_MapKeyStr(node->string), grid);
CG_TableHeader *header = MD_PushArrayZero(cg_arena, CG_TableHeader, 1);
*header = CG_TableHeaderFromTag(table_tag);
MD_MapOverwrite(cg_arena, &cg_tbl_top_level_table_header_map, MD_MapKeyStr(node->string), header);
}
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen, 0))
{
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen, layer_key, node);
}
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen_enum, 0))
{
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen_enum, layer_key, node);
}
if(MD_NodeHasTag(node, cg_tbl_tag__table_gen_data, 0))
{
MD_MapInsert(cg_arena, &cg_tbl_layer_map_gen_data, layer_key, node);
}
}
}
//- rjf: generation phase
for(MD_EachNode(file_ref, file_list->first_child))
{
MD_Node *file = MD_ResolveNodeFromReference(file_ref);
MD_String8 layer_name = file->string;
MD_MapKey layer_key = MD_MapKeyStr(layer_name);
//- rjf: generate all table enums
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen_enum, layer_key);
slot != 0;
slot = MD_MapScan(slot->next, layer_key))
{
MD_Node *gen = (MD_Node *)slot->val;
CG_FilePair f = CG_FilePairFromNode(gen);
fprintf(f.h, "typedef enum %.*s\n{\n", MD_S8VArg(gen->string));
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
fprintf(f.h, "%.*s", MD_S8VArg(gen_string));
fprintf(f.h, "\n}\n%.*s;\n\n", MD_S8VArg(gen->string));
}
//- rjf: generate all data tables
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen_data, layer_key);
slot != 0;
slot = MD_MapScan(slot->next, layer_key))
{
MD_Node *gen = (MD_Node *)slot->val;
MD_Node *tag = MD_TagFromString(gen, cg_tbl_tag__table_gen_data, 0);
MD_Node *data_table_type_node = tag->first_child;
MD_String8 data_table_type = data_table_type_node->string;
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
MD_String8 h_decl_specifier = MD_S8Lit("extern");
CG_FilePair f = CG_FilePairFromNode(gen);
fprintf(f.h, "%.*s %.*s %.*s[%" PRIu64 "];\n\n", MD_S8VArg(h_decl_specifier), MD_S8VArg(data_table_type), MD_S8VArg(gen->string), gen_strings.node_count);
fprintf(f.c, "%.*s %.*s[%" PRIu64 "] =\n{\n", MD_S8VArg(data_table_type), MD_S8VArg(gen->string), gen_strings.node_count);
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
fprintf(f.c, "%.*s", MD_S8VArg(gen_string));
fprintf(f.c, "\n};\n");
fprintf(f.c, "\n");
}
//- rjf: generate all general generations
for(MD_MapSlot *slot = MD_MapLookup(&cg_tbl_layer_map_gen, layer_key);
slot != 0;
slot = MD_MapScan(slot->next, layer_key))
{
MD_Node *gen = (MD_Node *)slot->val;
CG_FilePair f = CG_FilePairFromNode(gen);
FILE *file = MD_NodeHasTag(gen, MD_S8Lit("c"), 0) ? f.c : f.h;
MD_String8List gen_strings = CG_GenStringListFromNode(table_expr_op_table, gen);
MD_StringJoin join = { MD_S8Lit(""), MD_S8Lit("\n"), MD_S8Lit("") };
MD_String8 gen_string = MD_S8ListJoin(cg_arena, gen_strings, &join);
fprintf(file, "%.*s", MD_S8VArg(gen_string));
fprintf(file, "\n\n");
}
}
}

View File

@ -0,0 +1,92 @@
#ifndef METAPROGRAM_TABLE_H
#define METAPROGRAM_TABLE_H
typedef enum CG_TableOp
{
CG_TableOp_Null,
CG_TableOp_BeginStringOps,
CG_TableOp_Dot,
CG_TableOp_Bump,
CG_TableOp_CheckIfTrue,
CG_TableOp_Concat,
CG_TableOp_EndStringOps,
CG_TableOp_BeginNumericOps,
CG_TableOp_Equal,
CG_TableOp_IsNotEqual,
CG_TableOp_BooleanAnd,
CG_TableOp_BooleanOr,
CG_TableOp_EndNumericOps,
CG_TableOp_COUNT
}
CG_TableOp;
typedef struct CG_NodeArray CG_NodeArray;
struct CG_NodeArray
{
MD_u64 count;
MD_Node **v;
};
typedef struct CG_NodeGrid CG_NodeGrid;
struct CG_NodeGrid
{
CG_NodeArray cells;
CG_NodeArray row_parents;
};
typedef enum CG_ColumnKind
{
CG_ColumnKind_Default,
CG_ColumnKind_CheckForTag,
CG_ColumnKind_COUNT
}
CG_ColumnKind;
typedef struct CG_ColumnDesc CG_ColumnDesc;
struct CG_ColumnDesc
{
CG_ColumnKind kind;
MD_String8 name;
MD_String8 tag_string;
};
typedef struct CG_TableHeader CG_TableHeader;
struct CG_TableHeader
{
MD_u64 column_count;
CG_ColumnDesc *column_descs;
};
typedef struct CG_ExpandIter CG_ExpandIter;
struct CG_ExpandIter
{
CG_ExpandIter *next;
CG_NodeGrid *grid;
CG_TableHeader *header;
MD_String8 label;
MD_u64 idx;
MD_u64 count;
};
typedef struct CG_ExpandInfo CG_ExpandInfo;
struct CG_ExpandInfo
{
MD_String8 strexpr;
CG_ExpandIter *first_expand_iter;
MD_ExprOprTable expr_op_table;
};
static CG_NodeArray CG_NodeArrayMake(MD_u64 count);
static CG_NodeGrid CG_GridFromNode(MD_Node *node);
static CG_TableHeader CG_TableHeaderFromTag(MD_Node *tag);
static MD_u64 CG_RowChildIndexFromColumnName(CG_TableHeader *header, MD_String8 column_name);
static MD_i64 CG_TableExprEvaluate_Numeric(CG_ExpandInfo *info, MD_Expr *expr);
static void CG_TableExprEvaluate_String(CG_ExpandInfo *info, MD_Expr *expr, MD_String8List *out);
static void CG_LoopExpansionDimension(CG_ExpandIter *it, CG_ExpandInfo *info, MD_String8List *out);
static MD_String8List CG_GenStringListFromNode(MD_ExprOprTable expr_op_table, MD_Node *gen);
static void CG_TBL_Generate(MD_Node *file_list);
#endif // METAPROGRAM_TABLE_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2
src/os/os_inc.c Normal file
View File

@ -0,0 +1,2 @@
//////////////////////////////////////////////////////////////////////////////////////////////
//~ os source includes

7
src/os/os_inc.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef OS_INC_H
#define OS_INC_H
//////////////////////////////////////////////////////////////////////////////////////////////
//~ OS Header includes
#endif /* OS_INC_H */

2
src/render/render_inc.c Normal file
View File

@ -0,0 +1,2 @@
//////////////////////////////////////////////////////////////////////////////////////////////
//~

7
src/render/render_inc.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef RENDER_INC_H
#define RENDER_INC_H
//////////////////////////////////////////////////////////////////////////////////////////////
//~
#endif /* RENDER_INC_H */