Commit: 9ebb77f907d30a3516e643a07b64d8c822bb85d2
Parent: 34c5d20511da0480bd83b52eb2d74d26c33d3aa0
Author: Randy Palamar
Date: Mon, 22 Jun 2026 12:01:21 -0600
build: allow Expand inside Table definition
This allows stuff like:
@Enumeration FooBar
{
Nil
@Expand(FooTable) `$(name)`
@Expand(BarTable) `$(name)`
}
or similar for other table entities.
Diffstat:
| M | build.c | | | 1172 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
| M | util.c | | | 7 | ++++--- |
2 files changed, 632 insertions(+), 547 deletions(-)
diff --git a/build.c b/build.c
@@ -2170,6 +2170,392 @@ meta_entity_first_child_of_kind(MetaContext *ctx, MetaEntity *e, MetaEntityKind
}
function void
+meta_expansion_string_split(str8 string, str8 *left, str8 *inner, str8 *remainder, MetaLocation loc)
+{
+ b32 found = 0;
+ for (u8 *s = string.data, *e = s + string.length; (s + 1) != e; s++) {
+ u32 val = (u32)'$' << 8u | (u32)'(';
+ u32 test = (u32)s[0] << 8u | s[1];
+ if (test == val) {
+ if (left) {
+ left->data = string.data;
+ left->length = s - string.data;
+ }
+
+ u8 *start = s + 2;
+ while (s != e && *s != ')') s++;
+ if (s == e) {
+ meta_compiler_error_message(loc, "unterminated expansion in raw string:\n %.*s\n",
+ (i32)string.length, string.data);
+ fprintf(stderr, " %.*s^\n", (i32)(start - string.data), "");
+ meta_error();
+ }
+
+ if (inner) {
+ inner->data = start;
+ inner->length = s - start;
+ }
+
+ if (remainder) {
+ remainder->data = s + 1;
+ remainder->length = string.length - (remainder->data - string.data);
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ if (left) *left = string;
+ if (inner) *inner = (str8){0};
+ if (remainder) *remainder = (str8){0};
+ }
+}
+
+function MetaExpansionPart *
+meta_push_expansion_part(MetaContext *ctx, Arena *arena, MetaExpansionPartList *parts,
+ MetaExpansionPartKind kind, str8 string, MetaEntity *table, MetaLocation loc)
+{
+ MetaExpansionPart *result = da_push(arena, parts);
+
+ result->kind = kind;
+ switch (kind) {
+ case MetaExpansionPartKind_Alignment:
+ case MetaExpansionPartKind_Conditional:
+ {}break;
+
+ case MetaExpansionPartKind_EvalKind:
+ case MetaExpansionPartKind_EvalKindCount:
+ case MetaExpansionPartKind_Reference:
+ {
+ assert(meta_entity_kind_is_table[table->kind]);
+ MetaTable *t = &table->table;
+
+ da_count index = meta_lookup_string_slow(t->fields, t->field_count, s8_from_str8(string));
+ result->strings = t->entries[index];
+ if (index < 0) {
+ /* TODO(rnp): fix this location to point directly at the field in the string */
+ s8 table_name = ctx->entity_names.data[da_index(table, &ctx->entities)];
+ meta_compiler_error(loc, "table \"%.*s\" does not contain member: %.*s\n",
+ (i32)table_name.len, table_name.data, (i32)string.length, string.data);
+ }
+ }break;
+
+ case MetaExpansionPartKind_String:{ result->string = s8_from_str8(string); }break;
+ InvalidDefaultCase;
+ }
+ return result;
+}
+
+#define META_EXPANSION_TOKEN_LIST \
+ X('|', Alignment) \
+ X('%', TypeEval) \
+ X('#', TypeEvalElements) \
+ X('"', Quote) \
+ X('-', Dash) \
+ X('>', GreaterThan) \
+ X('<', LessThan) \
+
+typedef enum {
+ MetaExpansionToken_EOF,
+ MetaExpansionToken_Identifier,
+ MetaExpansionToken_Number,
+ MetaExpansionToken_String,
+ #define X(__1, kind, ...) MetaExpansionToken_## kind,
+ META_EXPANSION_TOKEN_LIST
+ #undef X
+ MetaExpansionToken_Count,
+} MetaExpansionToken;
+
+read_only global s8 meta_expansion_token_strings[] = {
+ s8_comp("EOF"),
+ s8_comp("Indentifier"),
+ s8_comp("Number"),
+ s8_comp("String"),
+ #define X(s, kind, ...) s8_comp(#s),
+ META_EXPANSION_TOKEN_LIST
+ #undef X
+};
+
+typedef struct {
+ str8 s;
+ union {
+ i64 number;
+ str8 string;
+ };
+ str8 save;
+ MetaLocation loc;
+} MetaExpansionParser;
+
+#define meta_expansion_save(v) (v)->save = (v)->s
+#define meta_expansion_restore(v) swap((v)->s, (v)->save)
+#define meta_expansion_commit(v) meta_expansion_restore(v)
+
+#define meta_expansion_expected(loc, e, g) \
+ meta_compiler_error(loc, "invalid expansion string: expected %.*s after %.*s\n", \
+ (i32)meta_expansion_token_strings[e].len, meta_expansion_token_strings[e].data, \
+ (i32)meta_expansion_token_strings[g].len, meta_expansion_token_strings[g].data)
+
+function str8
+meta_expansion_extract_string(MetaExpansionParser *p)
+{
+ str8 result = {.data = p->s.data};
+ for (; result.length < p->s.length; result.length++) {
+ b32 done = 0;
+ switch (p->s.data[result.length]) {
+ #define X(t, ...) case t:
+ META_EXPANSION_TOKEN_LIST
+ #undef X
+ case ' ':
+ {done = 1;}break;
+ default:{}break;
+ }
+ if (done) break;
+ }
+ p->s.data += result.length;
+ p->s.length -= result.length;
+ return result;
+}
+
+function MetaExpansionToken
+meta_expansion_token(MetaExpansionParser *p)
+{
+ MetaExpansionToken result = MetaExpansionToken_EOF;
+ meta_expansion_save(p);
+ if (p->s.length > 0) {
+ b32 chop = 1;
+ switch (p->s.data[0]) {
+ #define X(t, kind, ...) case t:{ result = MetaExpansionToken_## kind; }break;
+ META_EXPANSION_TOKEN_LIST
+ #undef X
+ default:{
+ chop = 0;
+ if (BETWEEN(p->s.data[0], '0', '9')) result = MetaExpansionToken_Number;
+ else result = MetaExpansionToken_Identifier;
+ }break;
+ }
+ if (chop) {
+ str8_chop(&p->s, 1);
+ p->s = str8_trim(p->s);
+ }
+
+ switch (result) {
+ case MetaExpansionToken_Number:{
+ NumberConversion integer = integer_from_str8(p->s);
+ if (integer.result != NumberConversionResult_Success) {
+ /* TODO(rnp): point at start */
+ meta_compiler_error(p->loc, "invalid integer in expansion string\n");
+ }
+ p->number = integer.S64;
+ p->s = integer.unparsed;
+ }break;
+ case MetaExpansionToken_Identifier:{ p->string = meta_expansion_extract_string(p); }break;
+ default:{}break;
+ }
+ p->s = str8_trim(p->s);
+ }
+ return result;
+}
+
+function MetaExpansionPart *
+meta_expansion_start_conditional(MetaContext *ctx, Arena *arena, MetaExpansionPartList *ops,
+ MetaExpansionParser *p, MetaExpansionToken token, b32 negate)
+{
+ MetaExpansionPart *result = meta_push_expansion_part(ctx, arena, ops, MetaExpansionPartKind_Conditional,
+ str8(""), 0, p->loc);
+ switch (token) {
+ case MetaExpansionToken_Number:{
+ result->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Number;
+ result->conditional.lhs.number = negate ? -p->number : p->number;
+ }break;
+ default:{}break;
+ }
+ return result;
+}
+
+function void
+meta_expansion_end_conditional(MetaExpansionPart *ep, MetaExpansionParser *p, MetaExpansionToken token, b32 negate)
+{
+ if (ep->conditional.rhs.kind != MetaExpansionConditionalArgumentKind_Invalid) {
+ meta_compiler_error(p->loc, "invalid expansion conditional: duplicate right hand expression: '%.*s'\n",
+ (i32)p->save.length, p->save.data);
+ }
+ switch (token) {
+ case MetaExpansionToken_Number:{
+ ep->conditional.rhs.kind = MetaExpansionConditionalArgumentKind_Number;
+ ep->conditional.rhs.number = negate ? -p->number : p->number;
+ }break;
+ default:{}break;
+ }
+}
+
+function MetaExpansionPartList
+meta_generate_expansion_set(MetaContext *ctx, Arena *arena, str8 expansion_string, MetaEntity *table, MetaLocation loc)
+{
+ MetaExpansionPartList result = {0};
+ str8 left = {0}, inner, remainder = expansion_string;
+ do {
+ meta_expansion_string_split(remainder, &left, &inner, &remainder, loc);
+ if (left.length) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, left, table, loc);
+ if (inner.length) {
+ MetaExpansionParser p[1] = {{.s = inner, .loc = loc}};
+
+ MetaExpansionPart *test_part = 0;
+ b32 count_test_parts = 0;
+
+ for (MetaExpansionToken token = meta_expansion_token(p);
+ token != MetaExpansionToken_EOF;
+ token = meta_expansion_token(p))
+ {
+ if (count_test_parts) test_part->conditional.instruction_skip++;
+ switch (token) {
+ case MetaExpansionToken_Alignment:{
+ meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Alignment, p->s, table, loc);
+ }break;
+
+ case MetaExpansionToken_Identifier:{
+ meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Reference, p->string, table, loc);
+ }break;
+
+ case MetaExpansionToken_TypeEval:
+ case MetaExpansionToken_TypeEvalElements:
+ {
+ if (meta_expansion_token(p) != MetaExpansionToken_Identifier) {
+ loc.column += (u32)(p->save.data - expansion_string.data);
+ meta_expansion_expected(loc, MetaExpansionToken_Identifier, token);
+ }
+ MetaExpansionPartKind kind = token == MetaExpansionToken_TypeEval ?
+ MetaExpansionPartKind_EvalKind :
+ MetaExpansionPartKind_EvalKindCount;
+ meta_push_expansion_part(ctx, arena, &result, kind, p->string, table, loc);
+ }break;
+
+ case MetaExpansionToken_Quote:{
+ u8 *point = p->s.data;
+ str8 string = meta_expansion_extract_string(p);
+ token = meta_expansion_token(p);
+ if (token != MetaExpansionToken_Quote) {
+ loc.column += (u32)(point - expansion_string.data);
+ /* TODO(rnp): point at start */
+ meta_compiler_error(loc, "unterminated string in expansion\n");
+ }
+ meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, string, table, loc);
+ }break;
+
+ case MetaExpansionToken_Dash:{
+ token = meta_expansion_token(p);
+ switch (token) {
+ case MetaExpansionToken_GreaterThan:{
+ if (!test_part) goto error;
+ if (test_part->conditional.lhs.kind == MetaExpansionConditionalArgumentKind_Invalid ||
+ test_part->conditional.rhs.kind == MetaExpansionConditionalArgumentKind_Invalid)
+ {
+ b32 lhs = test_part->conditional.lhs.kind == MetaExpansionConditionalArgumentKind_Invalid;
+ b32 rhs = test_part->conditional.rhs.kind == MetaExpansionConditionalArgumentKind_Invalid;
+ if (lhs && rhs)
+ meta_compiler_error(loc, "expansion string test terminated without arguments\n");
+ meta_compiler_error(loc, "expansion string test terminated without %s argument\n",
+ lhs? "left" : "right");
+ }
+ count_test_parts = 1;
+ }break;
+ case MetaExpansionToken_Number:{
+ if (test_part) meta_expansion_end_conditional(test_part, p, token, 1);
+ else test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 1);
+ }break;
+ default:{ goto error; }break;
+ }
+ }break;
+
+ case MetaExpansionToken_Number:{
+ if (test_part) meta_expansion_end_conditional(test_part, p, token, 0);
+ else test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 0);
+ }break;
+
+ case MetaExpansionToken_GreaterThan:
+ case MetaExpansionToken_LessThan:
+ {
+ if (test_part && test_part->conditional.op != MetaExpansionOperation_Invalid) goto error;
+ if (!test_part) {
+ if (result.count == 0) {
+ meta_compiler_error(p->loc, "invalid expansion conditional: missing left hand side\n");
+ }
+
+ s8 *strings = result.data[result.count - 1].strings;
+ MetaExpansionPartKind last_kind = result.data[result.count - 1].kind;
+ if (last_kind != MetaExpansionPartKind_EvalKindCount &&
+ last_kind != MetaExpansionPartKind_Reference)
+ {
+ meta_compiler_error(p->loc, "invalid expansion conditional: left hand side not numeric\n");
+ }
+ result.count--;
+ test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 0);
+ if (last_kind == MetaExpansionPartKind_EvalKindCount) {
+ test_part->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Evaluation;
+ } else {
+ test_part->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Reference;
+ }
+ test_part->conditional.lhs.strings = strings;
+ }
+ test_part->conditional.op = token == MetaExpansionToken_LessThan ?
+ MetaExpansionOperation_LessThan :
+ MetaExpansionOperation_GreaterThan;
+ }break;
+
+ error:
+ default:
+ {
+ meta_compiler_error(loc, "invalid nested %.*s in expansion string\n",
+ (i32)meta_expansion_token_strings[token].len,
+ meta_expansion_token_strings[token].data);
+ }break;
+ }
+ }
+ }
+ } while (remainder.length);
+ return result;
+}
+
+function da_count
+meta_expand_table_entity_id(MetaContext *ctx, MetaEntry *e)
+{
+ assert(e->kind == MetaEntryKind_Expand);
+
+ /* TODO(rnp): for now this requires that the @Table came first */
+ meta_entry_argument_expected(e, s8("table_name"));
+ s8 table_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
+
+ da_count result = meta_lookup_string_slow(ctx->entity_names.data, ctx->entity_names.count, table_name);
+
+ if (result < 0) meta_entry_error(e, "undefined table %.*s\n", (i32)table_name.len, table_name.data);
+
+ MetaEntity *table = ctx->entities.data + result;
+ if (!meta_entity_kind_is_table[table->kind]) {
+ s8 old_kind = meta_entity_kind_names[table->kind];
+ s8 wanted_kind = meta_entity_kind_names[MetaEntityKind_Table];
+ meta_entry_error(e, "%.*s previously defined as %.*s but should be %.*s\n",
+ (i32)table_name.len, table_name.data,
+ (i32)old_kind.len, old_kind.data,
+ (i32)wanted_kind.len, wanted_kind.data);
+ }
+
+ return result;
+}
+
+function s8
+meta_expand_parts_to_s8_at_index(MetaContext *ctx, u64 table_index, MetaExpansionPartList parts)
+{
+ Stream sb = arena_stream(*ctx->arena);
+ for EachIndex((u64)parts.count, part) {
+ MetaExpansionPart *p = parts.data + part;
+ u32 index = 0;
+ if (p->kind == MetaExpansionPartKind_Reference) index = table_index;
+ stream_append_s8(&sb, p->strings[index]);
+ }
+ s8 result = arena_stream_commit(ctx->arena, &sb);
+ return result;
+}
+
+function void
meta_pack_table_begin(MetaEntry *e, MetaTable *t)
{
switch (e->kind) {
@@ -2237,568 +2623,290 @@ meta_pack_table_entity(MetaContext *ctx, MetaEntry *e, i64 entry_count, s8 name,
e->kind == MetaEntryKind_Union;
MetaEntryScope scope = meta_entry_extract_scope(e, entry_count);
- if (scope.consumed > 1) {
- for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
- if (row->kind != MetaEntryKind_Array && row->kind != MetaEntryKind_String)
- meta_entry_nesting_error(row, e->kind);
-
- MetaEntryArgument entries = {.count = 1};
- if (row->kind == MetaEntryKind_Array)
- entries.count = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array).count;
-
- if (structure && entries.count != 2 && entries.count != 3) {
- meta_compiler_error(row->location, "incorrect field count for @%s entry got: %zu expected: "
- "[name type (elements)]\n", meta_entry_kind_strings[e->kind],
- (size_t)entries.count);
- } else if (!structure && entries.count != t->field_count) {
- meta_compiler_error_message(row->location, "incorrect field count for @%s entry got: %zu expected: %u\n",
- meta_entry_kind_strings[e->kind], (size_t)entries.count, t->field_count);
- fprintf(stderr, " fields: [");
- for (u64 i = 0; i < t->field_count; i++) {
- if (i != 0) fprintf(stderr, " ");
- fprintf(stderr, "%.*s", (i32)t->fields[i].len, t->fields[i].data);
- }
- fprintf(stderr, "]\n");
- meta_error();
- }
-
- t->entry_count++;
- }
-
- t->entries = push_array(ctx->arena, s8 *, t->field_count);
- for (u32 field = 0; field < t->field_count; field++)
- t->entries[field] = push_array(ctx->arena, s8, t->entry_count);
-
- u32 row_index = 0;
- for (MetaEntry *row = scope.start; row != scope.one_past_last; row++, row_index++) {
- s8 *fs = &row->name;
- if (row->arguments)
- fs = row->arguments->strings;
-
- for (u32 field = 0; field < t->field_count; field++)
- t->entries[field][row_index] = fs[field];
-
- // NOTE(rnp): if we are filling out a struct the array element count is optional
- // and defaults to 1. fill this out here for uniformity elsewhere in the code
- if (structure && row->arguments->count == 2)
- t->entries[2][row_index] = s8("1");
- }
- }
-
- MetaEntity *entity = meta_entity(ctx, entity_id);
- entity->table = table;
-
- switch (e->kind) {
- case MetaEntryKind_Bake:
- case MetaEntryKind_PushConstants:
- case MetaEntryKind_Struct:
- case MetaEntryKind_Union:
- case MetaEntryKind_Enumeration:
- case MetaEntryKind_Table:
- {}break;
-
- InvalidDefaultCase;
- }
-
- return scope.consumed;
-}
-
-function i64
-meta_pack_shader_common(MetaContext *ctx, MetaEntityID shader_id, MetaEntry *e, i64 entry_count, MetaEntityID group_entity_id)
-{
- assert(ctx->entities.data[shader_id.value].kind == MetaEntityKind_Shader);
- i64 result = 0;
-
- switch(e->kind) {
-
- case MetaEntryKind_Bake:{
- e->name = push_s8_from_parts(ctx->arena, s8(""), ctx->entity_names.data[shader_id.value], s8("BakeParameters"));
- result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id);
- }break;
-
- case MetaEntryKind_PushConstants:{
- e->name = push_s8_from_parts(ctx->arena, s8(""), ctx->entity_names.data[shader_id.value], s8("PushConstants"));
- result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id);
- goto reference;
- }break;
-
- case MetaEntryKind_ShaderAlias:{
- MetaEntityID alias_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Shader, group_entity_id,
- e->location, 0);
- meta_entity(ctx, alias_id)->shader.kind = MetaShaderKind_Alias;
- meta_entity(ctx, alias_id)->shader.alias_parent_id = shader_id;
- }break;
-
- case MetaEntryKind_Enumeration:
- case MetaEntryKind_Constant:
- case MetaEntryKind_Struct:
- reference:
- {
- meta_entry_argument_expected(e);
- // TODO(rnp): MetaIDList.data should be of type MetaEntityID
- MetaEntityID ref_id = meta_entity_reference(ctx, e->name, e->location);
- meta_intern_id(ctx, &meta_entity(ctx, shader_id)->shader.entity_reference_ids, ref_id.value);
- }break;
-
- default:{ meta_entry_nesting_error(e, MetaEntryKind_Shader); }break;
- }
-
- return result;
-}
-
-function i64
-meta_pack_render_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id)
-{
- assert(entries[0].kind == MetaEntryKind_RenderShader);
-
- MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader,
- group_entity_id, entries->location, 0);
- meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Render;
-
- meta_entry_argument_expected(entries);
-
- MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
- if (scope.consumed > 1) {
- for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) {
- switch (e->kind) {
-
- case MetaEntryKind_VertexShader:{
- if (meta_entity(ctx, entity_id)->shader.files[0].len)
- meta_entry_error(e, "primitive shader file redefined\n");
- meta_entity(ctx, entity_id)->shader.files[0] = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
- meta_entity(ctx, entity_id)->shader.render.kind = MetaShaderPrimitiveKind_Vertex;
- }break;
-
- case MetaEntryKind_FragmentShader:{
- if (meta_entity(ctx, entity_id)->shader.files[1].len)
- meta_entry_error(e, "fragment shader file redefined\n");
- meta_entity(ctx, entity_id)->shader.files[1] = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
- }break;
-
- default:{
- e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id);
- }break;
- }
- }
- }
- return scope.consumed;
-}
-
-function i64
-meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id)
-{
- assert(entries[0].kind == MetaEntryKind_Shader);
-
- MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader, group_entity_id,
- entries->location, 0);
- meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Compute;
-
- if (entries->argument_count > 1) {
- meta_entry_argument_expected(entries, s8("[file_name]"));
- } else if (entries->argument_count == 1) {
- s8 shader_file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string;
- meta_entity(ctx, entity_id)->shader.files[0] = shader_file;
- }
-
- MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
- if (scope.consumed > 1) {
- for (MetaEntry *e = scope.start; e < scope.one_past_last; e++)
- e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id);
- } else {
- assert(scope.consumed == 1);
- // TODO(rnp): some functions (@Expand) expect no scope and that the next entry
- // is treated as in scope; here we do not want that behaviour.
- scope.consumed = 0;
- }
- return scope.consumed;
-}
-
-function i64
-meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, i64 entry_count)
-{
- assert(entries->kind == MetaEntryKind_ShaderGroup);
-
- MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_ShaderGroup,
- meta_root_entity_id(ctx), entries->location, 0);
-
- MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
- if (scope.consumed > 1) {
- for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) {
- switch (e->kind) {
- case MetaEntryKind_RenderShader:{
- e += meta_pack_render_shader(ctx, e, scope.one_past_last - e, entity_id);
- }break;
- case MetaEntryKind_Shader:{
- e += meta_pack_compute_shader(ctx, e, scope.one_past_last - e, entity_id);
- }break;
- default:{meta_entry_nesting_error(e, MetaEntryKind_ShaderGroup);}break;
- }
- }
- }
- return scope.consumed;
-}
+ if (scope.consumed > 1) {
+ Arena scratch = ctx->scratch;
-function i64
-meta_pack_references(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID parent, s8 scope_name, s8 prefix)
-{
- MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
- for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) {
- switch (e->kind) {
- case MetaEntryKind_Struct:
- case MetaEntryKind_Union:
- {
- meta_entity_reference_reference(ctx, e->name, scope_name, e->location, parent, prefix);
- }break;
- default:{meta_entry_nesting_error(e, entries->kind);}break;
+ // NOTE(rnp): count expands
+ i64 expand_count = 0;
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++)
+ if (row->kind == MetaEntryKind_Expand)
+ expand_count++;
+
+ // NOTE(rnp): extract expand tables
+ da_count *table_ids = 0;
+ i64 table_id_index = 0;
+ if (expand_count > 0) {
+ table_ids = push_array(&ctx->scratch, da_count, expand_count);
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++)
+ if (row->kind == MetaEntryKind_Expand)
+ table_ids[table_id_index++] = meta_expand_table_entity_id(ctx, row);
}
- }
- return scope.consumed;
-}
-function void
-meta_expansion_string_split(str8 string, str8 *left, str8 *inner, str8 *remainder, MetaLocation loc)
-{
- b32 found = 0;
- for (u8 *s = string.data, *e = s + string.length; (s + 1) != e; s++) {
- u32 val = (u32)'$' << 8u | (u32)'(';
- u32 test = (u32)s[0] << 8u | s[1];
- if (test == val) {
- if (left) {
- left->data = string.data;
- left->length = s - string.data;
+ table_id_index = 0;
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
+ if (row->kind != MetaEntryKind_Array &&
+ row->kind != MetaEntryKind_Expand &&
+ row->kind != MetaEntryKind_String)
+ {
+ meta_entry_nesting_error(row, e->kind);
}
- u8 *start = s + 2;
- while (s != e && *s != ')') s++;
- if (s == e) {
- meta_compiler_error_message(loc, "unterminated expansion in raw string:\n %.*s\n",
- (i32)string.length, string.data);
- fprintf(stderr, " %.*s^\n", (i32)(start - string.data), "");
- meta_error();
+ MetaEntryArgument entries = {.count = 1};
+
+ if (row->kind == MetaEntryKind_Expand) {
+ if (row + 1 == scope.one_past_last || (
+ row[1].kind != MetaEntryKind_Array &&
+ row[1].kind != MetaEntryKind_String))
+ {
+ meta_entry_nesting_error(row + 1, row->kind);
+ }
+
+ if (row[1].kind == MetaEntryKind_Array)
+ entries.count = meta_entry_argument_expect(row + 1, 0, MetaEntryArgumentKind_Array).count;
}
- if (inner) {
- inner->data = start;
- inner->length = s - start;
+ if (row->kind == MetaEntryKind_Array)
+ entries.count = meta_entry_argument_expect(row, 0, MetaEntryArgumentKind_Array).count;
+
+ if (structure && entries.count != 2 && entries.count != 3) {
+ meta_compiler_error(row->location, "incorrect field count for @%s entry got: %zu expected: "
+ "[name type (elements)]\n", meta_entry_kind_strings[e->kind],
+ (size_t)entries.count);
+ } else if (!structure && entries.count != t->field_count) {
+ meta_compiler_error_message(row->location, "incorrect field count for @%s entry got: %zu expected: %u\n",
+ meta_entry_kind_strings[e->kind], (size_t)entries.count, t->field_count);
+ fprintf(stderr, " fields: [");
+ for (u64 i = 0; i < t->field_count; i++) {
+ if (i != 0) fprintf(stderr, " ");
+ fprintf(stderr, "%.*s", (i32)t->fields[i].len, t->fields[i].data);
+ }
+ fprintf(stderr, "]\n");
+ meta_error();
}
- if (remainder) {
- remainder->data = s + 1;
- remainder->length = string.length - (remainder->data - string.data);
+ if (row->kind == MetaEntryKind_Expand) {
+ t->entry_count += ctx->entities.data[table_ids[table_id_index++]].table.entry_count;
+ // NOTE(rnp): skip expand argument
+ row++;
+ } else {
+ t->entry_count++;
}
- found = 1;
- break;
}
- }
- if (!found) {
- if (left) *left = string;
- if (inner) *inner = (str8){0};
- if (remainder) *remainder = (str8){0};
- }
-}
-
-function MetaExpansionPart *
-meta_push_expansion_part(MetaContext *ctx, Arena *arena, MetaExpansionPartList *parts,
- MetaExpansionPartKind kind, str8 string, MetaEntity *table, MetaLocation loc)
-{
- MetaExpansionPart *result = da_push(arena, parts);
-
- result->kind = kind;
- switch (kind) {
- case MetaExpansionPartKind_Alignment:
- case MetaExpansionPartKind_Conditional:
- {}break;
- case MetaExpansionPartKind_EvalKind:
- case MetaExpansionPartKind_EvalKindCount:
- case MetaExpansionPartKind_Reference:
- {
- assert(meta_entity_kind_is_table[table->kind]);
- MetaTable *t = &table->table;
+ t->entries = push_array(ctx->arena, s8 *, t->field_count);
+ for (u32 field = 0; field < t->field_count; field++)
+ t->entries[field] = push_array(ctx->arena, s8, t->entry_count);
- da_count index = meta_lookup_string_slow(t->fields, t->field_count, s8_from_str8(string));
- result->strings = t->entries[index];
- if (index < 0) {
- /* TODO(rnp): fix this location to point directly at the field in the string */
- s8 table_name = ctx->entity_names.data[da_index(table, &ctx->entities)];
- meta_compiler_error(loc, "table \"%.*s\" does not contain member: %.*s\n",
- (i32)table_name.len, table_name.data, (i32)string.length, string.data);
- }
- }break;
+ u32 row_index = 0;
+ table_id_index = 0;
+ for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
+ u64 argument_count = row->arguments ? row->arguments->count : 1;
+ if (row->kind == MetaEntryKind_Expand) {
+ row++;
+ argument_count = row->arguments ? row->arguments->count : 1;
- case MetaExpansionPartKind_String:{ result->string = s8_from_str8(string); }break;
- InvalidDefaultCase;
- }
- return result;
-}
+ MetaEntity *table = ctx->entities.data + table_ids[table_id_index++];
-#define META_EXPANSION_TOKEN_LIST \
- X('|', Alignment) \
- X('%', TypeEval) \
- X('#', TypeEvalElements) \
- X('"', Quote) \
- X('-', Dash) \
- X('>', GreaterThan) \
- X('<', LessThan) \
+ u32 working_row_index = row_index;
+ for EachIndex(argument_count, it) {
+ working_row_index = row_index;
+ str8 expand = str8_from_s8(row->arguments ? row->arguments->strings[it] : row->name);
+ MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &ctx->scratch, expand, table, row->location);
+ for EachIndex(table->table.entry_count, entry_index)
+ t->entries[it][working_row_index++] = meta_expand_parts_to_s8_at_index(ctx, entry_index, parts);
+ }
-typedef enum {
- MetaExpansionToken_EOF,
- MetaExpansionToken_Identifier,
- MetaExpansionToken_Number,
- MetaExpansionToken_String,
- #define X(__1, kind, ...) MetaExpansionToken_## kind,
- META_EXPANSION_TOKEN_LIST
- #undef X
- MetaExpansionToken_Count,
-} MetaExpansionToken;
+ for (; row_index < working_row_index; row_index++)
+ if (structure && argument_count == 2)
+ t->entries[2][row_index] = s8("1");
-read_only global s8 meta_expansion_token_strings[] = {
- s8_comp("EOF"),
- s8_comp("Indentifier"),
- s8_comp("Number"),
- s8_comp("String"),
- #define X(s, kind, ...) s8_comp(#s),
- META_EXPANSION_TOKEN_LIST
- #undef X
-};
+ } else {
+ s8 *fs = &row->name;
+ if (row->arguments)
+ fs = row->arguments->strings;
+
+ for (u32 field = 0; field < t->field_count; field++)
+ t->entries[field][row_index] = fs[field];
+
+ // NOTE(rnp): if we are filling out a struct the array element count is optional
+ // and defaults to 1. fill this out here for uniformity elsewhere in the code
+ if (structure && argument_count == 2)
+ t->entries[2][row_index] = s8("1");
+ row_index++;
+ }
+ }
-typedef struct {
- str8 s;
- union {
- i64 number;
- str8 string;
- };
- str8 save;
- MetaLocation loc;
-} MetaExpansionParser;
+ ctx->scratch = scratch;
+ }
-#define meta_expansion_save(v) (v)->save = (v)->s
-#define meta_expansion_restore(v) swap((v)->s, (v)->save)
-#define meta_expansion_commit(v) meta_expansion_restore(v)
+ MetaEntity *entity = meta_entity(ctx, entity_id);
+ entity->table = table;
-#define meta_expansion_expected(loc, e, g) \
- meta_compiler_error(loc, "invalid expansion string: expected %.*s after %.*s\n", \
- (i32)meta_expansion_token_strings[e].len, meta_expansion_token_strings[e].data, \
- (i32)meta_expansion_token_strings[g].len, meta_expansion_token_strings[g].data)
+ switch (e->kind) {
+ case MetaEntryKind_Bake:
+ case MetaEntryKind_PushConstants:
+ case MetaEntryKind_Struct:
+ case MetaEntryKind_Union:
+ case MetaEntryKind_Enumeration:
+ case MetaEntryKind_Table:
+ {}break;
-function str8
-meta_expansion_extract_string(MetaExpansionParser *p)
-{
- str8 result = {.data = p->s.data};
- for (; result.length < p->s.length; result.length++) {
- b32 done = 0;
- switch (p->s.data[result.length]) {
- #define X(t, ...) case t:
- META_EXPANSION_TOKEN_LIST
- #undef X
- case ' ':
- {done = 1;}break;
- default:{}break;
- }
- if (done) break;
+ InvalidDefaultCase;
}
- p->s.data += result.length;
- p->s.length -= result.length;
- return result;
+
+ return scope.consumed;
}
-function MetaExpansionToken
-meta_expansion_token(MetaExpansionParser *p)
+function i64
+meta_pack_shader_common(MetaContext *ctx, MetaEntityID shader_id, MetaEntry *e, i64 entry_count, MetaEntityID group_entity_id)
{
- MetaExpansionToken result = MetaExpansionToken_EOF;
- meta_expansion_save(p);
- if (p->s.length > 0) {
- b32 chop = 1;
- switch (p->s.data[0]) {
- #define X(t, kind, ...) case t:{ result = MetaExpansionToken_## kind; }break;
- META_EXPANSION_TOKEN_LIST
- #undef X
- default:{
- chop = 0;
- if (BETWEEN(p->s.data[0], '0', '9')) result = MetaExpansionToken_Number;
- else result = MetaExpansionToken_Identifier;
- }break;
- }
- if (chop) {
- str8_chop(&p->s, 1);
- p->s = str8_trim(p->s);
- }
+ assert(ctx->entities.data[shader_id.value].kind == MetaEntityKind_Shader);
+ i64 result = 0;
- switch (result) {
- case MetaExpansionToken_Number:{
- NumberConversion integer = integer_from_str8(p->s);
- if (integer.result != NumberConversionResult_Success) {
- /* TODO(rnp): point at start */
- meta_compiler_error(p->loc, "invalid integer in expansion string\n");
- }
- p->number = integer.S64;
- p->s = integer.unparsed;
- }break;
- case MetaExpansionToken_Identifier:{ p->string = meta_expansion_extract_string(p); }break;
- default:{}break;
- }
- p->s = str8_trim(p->s);
- }
- return result;
-}
+ switch(e->kind) {
-function MetaExpansionPart *
-meta_expansion_start_conditional(MetaContext *ctx, Arena *arena, MetaExpansionPartList *ops,
- MetaExpansionParser *p, MetaExpansionToken token, b32 negate)
-{
- MetaExpansionPart *result = meta_push_expansion_part(ctx, arena, ops, MetaExpansionPartKind_Conditional,
- str8(""), 0, p->loc);
- switch (token) {
- case MetaExpansionToken_Number:{
- result->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Number;
- result->conditional.lhs.number = negate ? -p->number : p->number;
+ case MetaEntryKind_Bake:{
+ e->name = push_s8_from_parts(ctx->arena, s8(""), ctx->entity_names.data[shader_id.value], s8("BakeParameters"));
+ result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id);
+ }break;
+
+ case MetaEntryKind_PushConstants:{
+ e->name = push_s8_from_parts(ctx->arena, s8(""), ctx->entity_names.data[shader_id.value], s8("PushConstants"));
+ result = meta_pack_table_entity(ctx, e, entry_count, e->name, shader_id);
+ goto reference;
+ }break;
+
+ case MetaEntryKind_ShaderAlias:{
+ MetaEntityID alias_id = meta_intern_entity(ctx, e->name, MetaEntityKind_Shader, group_entity_id,
+ e->location, 0);
+ meta_entity(ctx, alias_id)->shader.kind = MetaShaderKind_Alias;
+ meta_entity(ctx, alias_id)->shader.alias_parent_id = shader_id;
}break;
- default:{}break;
- }
- return result;
-}
-function void
-meta_expansion_end_conditional(MetaExpansionPart *ep, MetaExpansionParser *p, MetaExpansionToken token, b32 negate)
-{
- if (ep->conditional.rhs.kind != MetaExpansionConditionalArgumentKind_Invalid) {
- meta_compiler_error(p->loc, "invalid expansion conditional: duplicate right hand expression: '%.*s'\n",
- (i32)p->save.length, p->save.data);
- }
- switch (token) {
- case MetaExpansionToken_Number:{
- ep->conditional.rhs.kind = MetaExpansionConditionalArgumentKind_Number;
- ep->conditional.rhs.number = negate ? -p->number : p->number;
+ case MetaEntryKind_Enumeration:
+ case MetaEntryKind_Constant:
+ case MetaEntryKind_Struct:
+ reference:
+ {
+ meta_entry_argument_expected(e);
+ // TODO(rnp): MetaIDList.data should be of type MetaEntityID
+ MetaEntityID ref_id = meta_entity_reference(ctx, e->name, e->location);
+ meta_intern_id(ctx, &meta_entity(ctx, shader_id)->shader.entity_reference_ids, ref_id.value);
}break;
- default:{}break;
+
+ default:{ meta_entry_nesting_error(e, MetaEntryKind_Shader); }break;
}
+
+ return result;
}
-function MetaExpansionPartList
-meta_generate_expansion_set(MetaContext *ctx, Arena *arena, str8 expansion_string, MetaEntity *table, MetaLocation loc)
+function i64
+meta_pack_render_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id)
{
- MetaExpansionPartList result = {0};
- str8 left = {0}, inner, remainder = expansion_string;
- do {
- meta_expansion_string_split(remainder, &left, &inner, &remainder, loc);
- if (left.length) meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, left, table, loc);
- if (inner.length) {
- MetaExpansionParser p[1] = {{.s = inner, .loc = loc}};
+ assert(entries[0].kind == MetaEntryKind_RenderShader);
- MetaExpansionPart *test_part = 0;
- b32 count_test_parts = 0;
+ MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader,
+ group_entity_id, entries->location, 0);
+ meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Render;
- for (MetaExpansionToken token = meta_expansion_token(p);
- token != MetaExpansionToken_EOF;
- token = meta_expansion_token(p))
- {
- if (count_test_parts) test_part->conditional.instruction_skip++;
- switch (token) {
- case MetaExpansionToken_Alignment:{
- meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Alignment, p->s, table, loc);
- }break;
+ meta_entry_argument_expected(entries);
- case MetaExpansionToken_Identifier:{
- meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_Reference, p->string, table, loc);
- }break;
+ MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
+ if (scope.consumed > 1) {
+ for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) {
+ switch (e->kind) {
- case MetaExpansionToken_TypeEval:
- case MetaExpansionToken_TypeEvalElements:
- {
- if (meta_expansion_token(p) != MetaExpansionToken_Identifier) {
- loc.column += (u32)(p->save.data - expansion_string.data);
- meta_expansion_expected(loc, MetaExpansionToken_Identifier, token);
- }
- MetaExpansionPartKind kind = token == MetaExpansionToken_TypeEval ?
- MetaExpansionPartKind_EvalKind :
- MetaExpansionPartKind_EvalKindCount;
- meta_push_expansion_part(ctx, arena, &result, kind, p->string, table, loc);
- }break;
+ case MetaEntryKind_VertexShader:{
+ if (meta_entity(ctx, entity_id)->shader.files[0].len)
+ meta_entry_error(e, "primitive shader file redefined\n");
+ meta_entity(ctx, entity_id)->shader.files[0] = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
+ meta_entity(ctx, entity_id)->shader.render.kind = MetaShaderPrimitiveKind_Vertex;
+ }break;
- case MetaExpansionToken_Quote:{
- u8 *point = p->s.data;
- str8 string = meta_expansion_extract_string(p);
- token = meta_expansion_token(p);
- if (token != MetaExpansionToken_Quote) {
- loc.column += (u32)(point - expansion_string.data);
- /* TODO(rnp): point at start */
- meta_compiler_error(loc, "unterminated string in expansion\n");
- }
- meta_push_expansion_part(ctx, arena, &result, MetaExpansionPartKind_String, string, table, loc);
- }break;
+ case MetaEntryKind_FragmentShader:{
+ if (meta_entity(ctx, entity_id)->shader.files[1].len)
+ meta_entry_error(e, "fragment shader file redefined\n");
+ meta_entity(ctx, entity_id)->shader.files[1] = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
+ }break;
- case MetaExpansionToken_Dash:{
- token = meta_expansion_token(p);
- switch (token) {
- case MetaExpansionToken_GreaterThan:{
- if (!test_part) goto error;
- if (test_part->conditional.lhs.kind == MetaExpansionConditionalArgumentKind_Invalid ||
- test_part->conditional.rhs.kind == MetaExpansionConditionalArgumentKind_Invalid)
- {
- b32 lhs = test_part->conditional.lhs.kind == MetaExpansionConditionalArgumentKind_Invalid;
- b32 rhs = test_part->conditional.rhs.kind == MetaExpansionConditionalArgumentKind_Invalid;
- if (lhs && rhs)
- meta_compiler_error(loc, "expansion string test terminated without arguments\n");
- meta_compiler_error(loc, "expansion string test terminated without %s argument\n",
- lhs? "left" : "right");
- }
- count_test_parts = 1;
- }break;
- case MetaExpansionToken_Number:{
- if (test_part) meta_expansion_end_conditional(test_part, p, token, 1);
- else test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 1);
- }break;
- default:{ goto error; }break;
- }
- }break;
+ default:{
+ e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id);
+ }break;
+ }
+ }
+ }
+ return scope.consumed;
+}
- case MetaExpansionToken_Number:{
- if (test_part) meta_expansion_end_conditional(test_part, p, token, 0);
- else test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 0);
- }break;
+function i64
+meta_pack_compute_shader(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID group_entity_id)
+{
+ assert(entries[0].kind == MetaEntryKind_Shader);
- case MetaExpansionToken_GreaterThan:
- case MetaExpansionToken_LessThan:
- {
- if (test_part && test_part->conditional.op != MetaExpansionOperation_Invalid) goto error;
- if (!test_part) {
- if (result.count == 0) {
- meta_compiler_error(p->loc, "invalid expansion conditional: missing left hand side\n");
- }
+ MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_Shader, group_entity_id,
+ entries->location, 0);
+ meta_entity(ctx, entity_id)->shader.kind = MetaShaderKind_Compute;
- s8 *strings = result.data[result.count - 1].strings;
- MetaExpansionPartKind last_kind = result.data[result.count - 1].kind;
- if (last_kind != MetaExpansionPartKind_EvalKindCount &&
- last_kind != MetaExpansionPartKind_Reference)
- {
- meta_compiler_error(p->loc, "invalid expansion conditional: left hand side not numeric\n");
- }
- result.count--;
- test_part = meta_expansion_start_conditional(ctx, arena, &result, p, token, 0);
- if (last_kind == MetaExpansionPartKind_EvalKindCount) {
- test_part->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Evaluation;
- } else {
- test_part->conditional.lhs.kind = MetaExpansionConditionalArgumentKind_Reference;
- }
- test_part->conditional.lhs.strings = strings;
- }
- test_part->conditional.op = token == MetaExpansionToken_LessThan ?
- MetaExpansionOperation_LessThan :
- MetaExpansionOperation_GreaterThan;
- }break;
+ if (entries->argument_count > 1) {
+ meta_entry_argument_expected(entries, s8("[file_name]"));
+ } else if (entries->argument_count == 1) {
+ s8 shader_file = meta_entry_argument_expect(entries, 0, MetaEntryArgumentKind_String).string;
+ meta_entity(ctx, entity_id)->shader.files[0] = shader_file;
+ }
- error:
- default:
- {
- meta_compiler_error(loc, "invalid nested %.*s in expansion string\n",
- (i32)meta_expansion_token_strings[token].len,
- meta_expansion_token_strings[token].data);
- }break;
- }
+ MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
+ if (scope.consumed > 1) {
+ for (MetaEntry *e = scope.start; e < scope.one_past_last; e++)
+ e += meta_pack_shader_common(ctx, entity_id, e, scope.one_past_last - e, group_entity_id);
+ } else {
+ assert(scope.consumed == 1);
+ // TODO(rnp): some functions (@Expand) expect no scope and that the next entry
+ // is treated as in scope; here we do not want that behaviour.
+ scope.consumed = 0;
+ }
+ return scope.consumed;
+}
+
+function i64
+meta_pack_shader_group(MetaContext *ctx, MetaEntry *entries, i64 entry_count)
+{
+ assert(entries->kind == MetaEntryKind_ShaderGroup);
+
+ MetaEntityID entity_id = meta_intern_entity(ctx, entries->name, MetaEntityKind_ShaderGroup,
+ meta_root_entity_id(ctx), entries->location, 0);
+
+ MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
+ if (scope.consumed > 1) {
+ for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) {
+ switch (e->kind) {
+ case MetaEntryKind_RenderShader:{
+ e += meta_pack_render_shader(ctx, e, scope.one_past_last - e, entity_id);
+ }break;
+ case MetaEntryKind_Shader:{
+ e += meta_pack_compute_shader(ctx, e, scope.one_past_last - e, entity_id);
+ }break;
+ default:{meta_entry_nesting_error(e, MetaEntryKind_ShaderGroup);}break;
}
}
- } while (remainder.length);
- return result;
+ }
+ return scope.consumed;
+}
+
+function i64
+meta_pack_references(MetaContext *ctx, MetaEntry *entries, i64 entry_count, MetaEntityID parent, s8 scope_name, s8 prefix)
+{
+ MetaEntryScope scope = meta_entry_extract_scope(entries, entry_count);
+ for (MetaEntry *e = scope.start; e < scope.one_past_last; e++) {
+ switch (e->kind) {
+ case MetaEntryKind_Struct:
+ case MetaEntryKind_Union:
+ {
+ meta_entity_reference_reference(ctx, e->name, scope_name, e->location, parent, prefix);
+ }break;
+ default:{meta_entry_nesting_error(e, entries->kind);}break;
+ }
+ }
+ return scope.consumed;
}
function s8 *
@@ -2806,16 +2914,8 @@ meta_expand_to_s8_array(MetaContext *ctx, Arena scratch, s8 expand, MetaEntity *
{
MetaExpansionPartList parts = meta_generate_expansion_set(ctx, &scratch, str8_from_s8(expand), table, location);
s8 *result = push_array(ctx->arena, s8, table->table.entry_count);
- for EachIndex(table->table.entry_count, expansion) {
- Stream sb = arena_stream(*ctx->arena);
- for EachIndex((u64)parts.count, part) {
- MetaExpansionPart *p = parts.data + part;
- u32 index = 0;
- if (p->kind == MetaExpansionPartKind_Reference) index = expansion;
- stream_append_s8(&sb, p->strings[index]);
- }
- result[expansion] = arena_stream_commit(ctx->arena, &sb);
- }
+ for EachIndex(table->table.entry_count, expansion)
+ result[expansion] = meta_expand_parts_to_s8_at_index(ctx, expansion, parts);
return result;
}
@@ -2824,24 +2924,8 @@ meta_expand(MetaContext *ctx, Arena scratch, MetaEntry *e, iz entry_count, MetaE
{
assert(e->kind == MetaEntryKind_Expand);
- /* TODO(rnp): for now this requires that the @Table came first */
- meta_entry_argument_expected(e, s8("table_name"));
- s8 table_name = meta_entry_argument_expect(e, 0, MetaEntryArgumentKind_String).string;
-
- MetaEntity *table = ctx->entities.data + meta_lookup_string_slow(ctx->entity_names.data,
- ctx->entity_names.count,
- table_name);
-
- if (table < ctx->entities.data)
- meta_entry_error(e, "undefined table %.*s\n", (i32)table_name.len, table_name.data);
- if (!meta_entity_kind_is_table[table->kind]) {
- s8 old_kind = meta_entity_kind_names[table->kind];
- s8 wanted_kind = meta_entity_kind_names[MetaEntityKind_Table];
- meta_entry_error(e, "%.*s previously defined as %.*s but should be %.*s\n",
- (i32)table_name.len, table_name.data,
- (i32)old_kind.len, old_kind.data,
- (i32)wanted_kind.len, wanted_kind.data);
- }
+ MetaEntity *table = ctx->entities.data + meta_expand_table_entity_id(ctx, e);
+ s8 table_name = ctx->entity_names.data[da_index(table, &ctx->entities)];
MetaEntryScope scope = meta_entry_extract_scope(e, entry_count);
for (MetaEntry *row = scope.start; row != scope.one_past_last; row++) {
diff --git a/util.c b/util.c
@@ -81,10 +81,11 @@ memory_copy_non_temporal(void *restrict dest, void *restrict src, u64 n)
}
function void
-memory_move(u8 *dest, u8 *src, u64 n)
+memory_move(void *dest, void *src, u64 n)
{
- if (dest < src) memory_copy(dest, src, n);
- else while (n) { n--; dest[n] = src[n]; }
+ u8 *d = dest, *s = src;
+ if (d < s) memory_copy(d, s, n);
+ else while (n) { n--; d[n] = s[n]; }
}
function void *