testing codegen and basic scaffolding
This commit is contained in:
parent
3b76ccbf23
commit
d7d9bc8d92
6
.gitignore
vendored
6
.gitignore
vendored
@ -541,3 +541,9 @@ GitHub.sublime-settings
|
||||
*.cubin
|
||||
*.fatbin
|
||||
|
||||
|
||||
# Custom
|
||||
.ctm
|
||||
build/*
|
||||
data/*
|
||||
*.sublime*
|
||||
|
||||
50
build.bat
Normal file
50
build.bat
Normal 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
4
src/base/base_core.h
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
|
||||
#define function static
|
||||
2
src/base/base_inc.c
Normal file
2
src/base/base_inc.c
Normal file
@ -0,0 +1,2 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
11
src/base/base_inc.h
Normal file
11
src/base/base_inc.h
Normal 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 */
|
||||
8
src/gen_test/generated/test.meta.c
Normal file
8
src/gen_test/generated/test.meta.c
Normal file
@ -0,0 +1,8 @@
|
||||
char * test_value_table[4] =
|
||||
{
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
};
|
||||
|
||||
12
src/gen_test/generated/test.meta.h
Normal file
12
src/gen_test/generated/test.meta.h
Normal 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
29
src/gen_test/test.mdesk
Normal 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
38
src/main.c
Normal 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
148
src/metagen/codegen.c
Normal 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
26
src/metagen/codegen.h
Normal 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
564
src/metagen/codegen_table.c
Normal 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
92
src/metagen/codegen_table.h
Normal file
92
src/metagen/codegen_table.h
Normal 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
|
||||
4410
src/metagen/metadesk_base/md.c
Normal file
4410
src/metagen/metadesk_base/md.c
Normal file
File diff suppressed because it is too large
Load Diff
1248
src/metagen/metadesk_base/md.h
Normal file
1248
src/metagen/metadesk_base/md.h
Normal file
File diff suppressed because it is too large
Load Diff
1905
src/metagen/metadesk_base/md_stb_sprintf.h
Normal file
1905
src/metagen/metadesk_base/md_stb_sprintf.h
Normal file
File diff suppressed because it is too large
Load Diff
2
src/os/os_inc.c
Normal file
2
src/os/os_inc.c
Normal file
@ -0,0 +1,2 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~ os source includes
|
||||
7
src/os/os_inc.h
Normal file
7
src/os/os_inc.h
Normal 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
2
src/render/render_inc.c
Normal file
@ -0,0 +1,2 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
7
src/render/render_inc.h
Normal file
7
src/render/render_inc.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef RENDER_INC_H
|
||||
#define RENDER_INC_H
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//~
|
||||
|
||||
#endif /* RENDER_INC_H */
|
||||
Loading…
Reference in New Issue
Block a user