From 0eff5aca06c0bcb499552db0f00d632142e04aae Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 13 Aug 2024 13:04:05 -0700 Subject: [PATCH] extend constructed types in eval system to support procedural construction of structs/unions/enums; can be used for synthetic evals in debugger frontend & ctrl layer --- src/df/gfx/df_view_rules.c | 4 +- src/eval/eval_bundles.c | 4 +- src/eval/eval_ir.c | 6 +- src/eval/eval_parse.c | 22 ++--- src/eval/eval_parse.h | 2 +- src/eval/eval_types.c | 166 ++++++++++++++++++++++++++++++------- src/eval/eval_types.h | 33 ++++++-- 7 files changed, 182 insertions(+), 55 deletions(-) diff --git a/src/df/gfx/df_view_rules.c b/src/df/gfx/df_view_rules.c index 9d865daf..6e545670 100644 --- a/src/df/gfx/df_view_rules.c +++ b/src/df/gfx/df_view_rules.c @@ -31,8 +31,8 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array) // rjf: apply array size to type E_TypeKey pointee = e_type_ptee_from_key(type_key); - E_TypeKey array_type = e_type_key_cons(E_TypeKind_Array, pointee, array_size); - eval.type_key = e_type_key_cons(E_TypeKind_Ptr, array_type, 0); + E_TypeKey array_type = e_type_key_cons_array(pointee, array_size); + eval.type_key = e_type_key_cons_ptr(array_type); } } scratch_end(scratch); diff --git a/src/eval/eval_bundles.c b/src/eval/eval_bundles.c index 987b9d56..8113d394 100644 --- a/src/eval/eval_bundles.c +++ b/src/eval/eval_bundles.c @@ -53,7 +53,7 @@ e_autoresolved_eval_from_eval(E_Eval eval) if(string_idx == 0) { string_idx = gvar->name_string_idx; } if(string_idx != 0) { - eval.type_key = e_type_key_cons(E_TypeKind_Ptr, e_type_key_basic(E_TypeKind_Void), 0); + eval.type_key = e_type_key_cons_ptr(e_type_key_basic(E_TypeKind_Void)); } } return eval; @@ -117,7 +117,7 @@ e_dynamically_typed_eval_from_eval(E_Eval eval) RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, global_var->container_idx); RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); E_TypeKey derived_type_key = e_type_key_ext(e_type_kind_from_rdi(type->kind), udt->self_type_idx, rdi_idx); - E_TypeKey ptr_to_derived_type_key = e_type_key_cons(E_TypeKind_Ptr, derived_type_key, 0); + E_TypeKey ptr_to_derived_type_key = e_type_key_cons_ptr(derived_type_key); eval.type_key = ptr_to_derived_type_key; } } diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 9a9ecea4..c11f5328 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -631,7 +631,7 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) // rjf: generate result.root = r_tree.root; - result.type_key = e_type_key_cons(E_TypeKind_Ptr, r_type_unwrapped, 0); + result.type_key = e_type_key_cons_ptr(r_type_unwrapped); result.mode = E_Mode_Value; }break; @@ -928,7 +928,7 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) E_TypeKey ptr_type = ptr_tree->type_key; if(ptr_is_decay) { - ptr_type = e_type_key_cons(E_TypeKind_Ptr, direct_type, 0); + ptr_type = e_type_key_cons_ptr(direct_type); } E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_root, int_root); result.root = new_root; @@ -1039,7 +1039,7 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) case E_ExprKind_LeafStringLiteral: { String8 string = expr->string; - E_TypeKey type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_UChar8), string.size); + E_TypeKey type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_UChar8), string.size); E_IRNode *new_tree = e_irtree_string_literal(arena, string); result.root = new_tree; result.type_key = type_key; diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 0e8bea61..f93b5fde 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -57,9 +57,9 @@ global read_only S64 e_max_precedence = 15; //~ rjf: Basic Helper Functions internal U64 -e_hash_from_string(String8 string) +e_hash_from_string(U64 seed, String8 string) { - U64 result = 5381; + U64 result = seed; for(U64 i = 0; i < string.size; i += 1) { result = ((result << 5) + result) + string.str[i]; @@ -84,7 +84,7 @@ e_string2num_map_make(Arena *arena, U64 slot_count) internal void e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num) { - U64 hash = e_hash_from_string(string); + U64 hash = e_hash_from_string(5381, string); U64 slot_idx = hash%map->slots_count; E_String2NumMapNode *existing_node = 0; for(E_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) @@ -112,7 +112,7 @@ e_num_from_string(E_String2NumMap *map, String8 string) U64 num = 0; if(map->slots_count != 0) { - U64 hash = e_hash_from_string(string); + U64 hash = e_hash_from_string(5381, string); U64 slot_idx = hash%map->slots_count; E_String2NumMapNode *existing_node = 0; for(E_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) @@ -180,7 +180,7 @@ e_string2expr_map_make(Arena *arena, U64 slot_count) internal void e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr) { - U64 hash = e_hash_from_string(string); + U64 hash = e_hash_from_string(5381, string); U64 slot_idx = hash%map->slots_count; E_String2ExprMapNode *existing_node = 0; for(E_String2ExprMapNode *node = map->slots[slot_idx].first; @@ -206,7 +206,7 @@ e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_ internal void e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string) { - U64 hash = e_hash_from_string(string); + U64 hash = e_hash_from_string(5381, string); U64 slot_idx = hash%map->slots_count; for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; @@ -223,7 +223,7 @@ e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string) internal void e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string) { - U64 hash = e_hash_from_string(string); + U64 hash = e_hash_from_string(5381, string); U64 slot_idx = hash%map->slots_count; for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; @@ -243,7 +243,7 @@ e_expr_from_string(E_String2ExprMap *map, String8 string) E_Expr *expr = &e_expr_nil; if(map->slots_count != 0) { - U64 hash = e_hash_from_string(string); + U64 hash = e_hash_from_string(5381, string); U64 slot_idx = hash%map->slots_count; E_String2ExprMapNode *existing_node = 0; for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) @@ -844,13 +844,13 @@ e_type_from_expr(E_Expr *expr) case E_ExprKind_Ptr: { E_TypeKey direct_type_key = e_type_from_expr(expr->first); - result = e_type_key_cons(E_TypeKind_Ptr, direct_type_key, 0); + result = e_type_key_cons_ptr(direct_type_key); }break; case E_ExprKind_Array: { E_Expr *child_expr = expr->first; E_TypeKey direct_type_key = e_type_from_expr(child_expr); - result = e_type_key_cons(E_TypeKind_Array, direct_type_key, expr->u64); + result = e_type_key_cons_array(direct_type_key, expr->u64); }break; } return result; @@ -1131,7 +1131,7 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to // rjf: build cast-to-U64*, and dereference operators E_Expr *type = e_push_expr(arena, E_ExprKind_TypeIdent, token_string.str); - type->type_key = e_type_key_cons(E_TypeKind_Ptr, e_type_key_basic(E_TypeKind_U64), 0); + type->type_key = e_type_key_cons_ptr(e_type_key_basic(E_TypeKind_U64)); E_Expr *casted = atom; E_Expr *cast = e_push_expr(arena, E_ExprKind_Cast, token_string.str); e_expr_push_child(cast, type); diff --git a/src/eval/eval_parse.h b/src/eval/eval_parse.h index 65cf5fe1..55692f7e 100644 --- a/src/eval/eval_parse.h +++ b/src/eval/eval_parse.h @@ -231,7 +231,7 @@ thread_static E_ParseCtx *e_parse_ctx = 0; //////////////////////////////// //~ rjf: Basic Helper Functions -internal U64 e_hash_from_string(String8 string); +internal U64 e_hash_from_string(U64 seed, String8 string); //////////////////////////////// //~ rjf: Basic Map Functions diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 7b993dca..d0503390 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -237,28 +237,72 @@ e_type_key_reg_alias(Architecture arch, REGS_AliasCode code) return key; } -internal E_TypeKey -e_type_key_cons(E_TypeKind kind, E_TypeKey direct_key, U64 u64) +//- rjf: constructed type construction + +internal U64 +e_hash_from_cons_type_params(E_ConsTypeParams *params) { U32 buffer[] = { - (U32)kind, - (U32)direct_key.kind, - (U32)direct_key.u32[0], - (U32)direct_key.u32[1], - (U32)direct_key.u32[2], - (U32)((u64 & 0x00000000ffffffffull)>> 0), - (U32)((u64 & 0xffffffff00000000ull)>> 32), + (U32)params->kind, + (U32)params->direct_key.kind, + params->direct_key.u32[0], + params->direct_key.u32[1], + params->direct_key.u32[2], + (U32)((params->count & 0x00000000ffffffffull)>> 0), + (U32)((params->count & 0xffffffff00000000ull)>> 32), }; - U64 content_hash = e_hash_from_string(str8((U8 *)buffer, sizeof(buffer))); + U64 hash = e_hash_from_string(5381, str8((U8 *)buffer, sizeof(buffer))); + hash = e_hash_from_string(hash, params->name); + return hash; +} + +internal B32 +e_cons_type_params_match(E_ConsTypeParams *l, E_ConsTypeParams *r) +{ + B32 result = (l->kind == r->kind && + str8_match(l->name, r->name, 0) && + e_type_key_match(l->direct_key, r->direct_key) && + l->count == r->count); + if(result && l->members != 0 && r->members != 0) + { + for(U64 idx = 0; idx < l->count; idx += 1) + { + if(l->members[idx].kind != r->members[idx].kind || + !e_type_key_match(l->members[idx].type_key, r->members[idx].type_key) || + !str8_match(l->members[idx].name, r->members[idx].name, 0) || + l->members[idx].off != r->members[idx].off) + { + result = 0; + break; + } + } + } + if(result && l->enum_vals != 0 && r->enum_vals != 0) + { + for(U64 idx = 0; idx < l->count; idx += 1) + { + if(l->enum_vals[idx].val != r->enum_vals[idx].val || + !str8_match(l->enum_vals[idx].name, r->enum_vals[idx].name, 0)) + { + result = 0; + break; + } + } + } + return result; +} + +internal E_TypeKey +e_type_key_cons_(E_ConsTypeParams *params) +{ + U64 content_hash = e_hash_from_cons_type_params(params); U64 content_slot_idx = content_hash%e_type_state->cons_content_slots_count; E_ConsTypeSlot *content_slot = &e_type_state->cons_content_slots[content_slot_idx]; E_ConsTypeNode *node = 0; for(E_ConsTypeNode *n = content_slot->first; n != 0; n = n->content_next) { - if(e_type_kind_from_key(n->key) == kind && - e_type_key_match(n->direct_key, direct_key) && - n->u64 == u64) + if(e_cons_type_params_match(params, &n->params)) { node = n; break; @@ -268,18 +312,37 @@ e_type_key_cons(E_TypeKind kind, E_TypeKey direct_key, U64 u64) if(node == 0) { E_TypeKey key = {E_TypeKeyKind_Cons}; - key.u32[0] = (U32)kind; + key.u32[0] = (U32)params->kind; key.u32[1] = (U32)e_type_state->cons_id_gen; e_type_state->cons_id_gen += 1; - U64 key_hash = e_hash_from_string(str8_struct(&key)); + U64 key_hash = e_hash_from_string(5381, str8_struct(&key)); U64 key_slot_idx = key_hash%e_type_state->cons_key_slots_count; E_ConsTypeSlot *key_slot = &e_type_state->cons_key_slots[key_slot_idx]; E_ConsTypeNode *node = push_array(e_type_state->arena, E_ConsTypeNode, 1); SLLQueuePush_N(content_slot->first, content_slot->last, node, content_next); SLLQueuePush_N(key_slot->first, key_slot->last, node, key_next); node->key = key; - node->direct_key = direct_key; - node->u64 = u64; + MemoryCopyStruct(&node->params, params); + node->params.name = push_str8_copy(e_type_state->arena, params->name); + if(params->members != 0) + { + node->params.members = push_array(e_type_state->arena, E_Member, params->count); + MemoryCopy(node->params.members, params->members, sizeof(E_Member)*params->count); + for(U64 idx = 0; idx < node->params.count; idx += 1) + { + node->params.members[idx].name = push_str8_copy(e_type_state->arena, node->params.members[idx].name); + node->params.members[idx].inheritance_key_chain = e_type_key_list_copy(e_type_state->arena, &node->params.members[idx].inheritance_key_chain); + } + } + else if(params->enum_vals != 0) + { + node->params.enum_vals = push_array(e_type_state->arena, E_EnumVal, params->count); + MemoryCopy(node->params.enum_vals, params->enum_vals, sizeof(E_EnumVal)*params->count); + for(U64 idx = 0; idx < node->params.count; idx += 1) + { + node->params.enum_vals[idx].name = push_str8_copy(e_type_state->arena, node->params.enum_vals[idx].name); + } + } result = key; } else @@ -289,6 +352,22 @@ e_type_key_cons(E_TypeKind kind, E_TypeKey direct_key, U64 u64) return result; } +//- rjf: constructed type helpers + +internal E_TypeKey +e_type_key_cons_array(E_TypeKey element_type_key, U64 count) +{ + E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_Array, .direct_key = element_type_key, .count = count); + return key; +} + +internal E_TypeKey +e_type_key_cons_ptr(E_TypeKey element_type_key) +{ + E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_Ptr, .direct_key = element_type_key); + return key; +} + //- rjf: basic type key functions internal B32 @@ -342,7 +421,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) //- rjf: constructed type keys case E_TypeKeyKind_Cons: { - U64 key_hash = e_hash_from_string(str8_struct(&key)); + U64 key_hash = e_hash_from_string(5381, str8_struct(&key)); U64 key_slot_idx = key_hash%e_type_state->cons_key_slots_count; E_ConsTypeSlot *key_slot = &e_type_state->cons_key_slots[key_slot_idx]; for(E_ConsTypeNode *node = key_slot->first; @@ -353,19 +432,48 @@ e_type_from_key(Arena *arena, E_TypeKey key) { type = push_array(arena, E_Type, 1); type->kind = e_type_kind_from_key(node->key); - type->direct_type_key = node->direct_key; - type->count = node->u64; + type->name = push_str8_copy(arena, node->params.name); + type->direct_type_key = node->params.direct_key; + type->count = node->params.count; switch(type->kind) { default: + { + type->byte_size = e_type_byte_size_from_key(type->direct_type_key); + }break; + case E_TypeKind_Ptr: { type->byte_size = bit_size_from_arch(e_type_state->ctx->arch)/8; }break; case E_TypeKind_Array: { - U64 ptee_size = e_type_byte_size_from_key(node->direct_key); + U64 ptee_size = e_type_byte_size_from_key(node->params.direct_key); type->byte_size = ptee_size * type->count; }break; + case E_TypeKind_Struct: + { + type->members = push_array(arena, E_Member, type->count); + MemoryCopy(type->members, node->params.members, sizeof(E_Member)*type->count); + for(U64 idx = 0; idx < type->count; idx += 1) + { + type->byte_size += e_type_byte_size_from_key(type->members[idx].type_key); + } + }break; + case E_TypeKind_Union: + { + type->members = push_array(arena, E_Member, type->count); + MemoryCopy(type->members, node->params.members, sizeof(E_Member)*type->count); + for(U64 idx = 0; idx < type->count; idx += 1) + { + U64 member_size = e_type_byte_size_from_key(type->members[idx].type_key); + type->byte_size = Max(type->byte_size, member_size); + } + }break; + case E_TypeKind_Enum: + { + type->enum_vals = push_array(arena, E_EnumVal, type->count); + MemoryCopy(type->enum_vals, node->params.enum_vals, sizeof(E_EnumVal)*type->count); + }break; } } } @@ -768,7 +876,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u128s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_U128), reg_byte_count/16); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U128), reg_byte_count/16); } if(type->byte_size > 8 && type->byte_size%8 == 0) { @@ -778,7 +886,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u64s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_U64), reg_byte_count/8); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U64), reg_byte_count/8); } if(type->byte_size > 4 && type->byte_size%4 == 0) { @@ -788,7 +896,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u32s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_U32), reg_byte_count/4); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U32), reg_byte_count/4); } if(type->byte_size > 2 && type->byte_size%2 == 0) { @@ -798,7 +906,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u16s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_U16), reg_byte_count/2); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U16), reg_byte_count/2); } if(type->byte_size > 1) { @@ -808,7 +916,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u8s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_U8), reg_byte_count); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), reg_byte_count); } if(type->byte_size > 4 && type->byte_size%4 == 0) { @@ -818,7 +926,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("f32s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_F32), reg_byte_count/4); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_F32), reg_byte_count/4); } if(type->byte_size > 8 && type->byte_size%8 == 0) { @@ -828,7 +936,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("f64s"); - mem->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_F64), reg_byte_count/8); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_F64), reg_byte_count/8); } } } @@ -1267,7 +1375,7 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) E_Member *padding_member = &new_members.v[n->prev_member_idx+padding_idx+1]; MemoryZeroStruct(padding_member); padding_member->kind = E_MemberKind_Padding; - padding_member->type_key = e_type_key_cons(E_TypeKind_Array, e_type_key_basic(E_TypeKind_U8), n->size); + padding_member->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), n->size); padding_member->off = n->off; padding_member->name = str8_lit("padding"); padding_idx += 1; diff --git a/src/eval/eval_types.h b/src/eval/eval_types.h index 445dd8ca..c7e2f231 100644 --- a/src/eval/eval_types.h +++ b/src/eval/eval_types.h @@ -24,8 +24,8 @@ struct E_TypeKey E_TypeKeyKind kind; U32 u32[3]; // [0] -> E_TypeKind (Basic, Cons, Ext); Architecture (Reg, RegAlias) - // [1] -> Type Index In RDI (Cons, Ext); Code (Reg, RegAlias) - // [2] -> RDI Index (Cons, Ext) + // [1] -> Type Index In RDI (Ext); Code (Reg, RegAlias); Type Index In Constructed (Cons) + // [2] -> RDI Index (Ext) }; typedef struct E_TypeKeyNode E_TypeKeyNode; @@ -135,14 +135,24 @@ struct E_Type //////////////////////////////// //~ rjf: Evaluation Context -typedef struct E_ConsTypeNode E_ConsTypeNode; +typedef struct E_ConsTypeParams E_ConsTypeParams; +struct E_ConsTypeParams +{ + E_TypeKind kind; + String8 name; + E_TypeKey direct_key; + U64 count; + E_Member *members; + E_EnumVal *enum_vals; +}; + +typedef struct E_ConsTypeNode E_ConsTypeNode; struct E_ConsTypeNode { E_ConsTypeNode *key_next; E_ConsTypeNode *content_next; E_TypeKey key; - E_TypeKey direct_key; - U64 u64; + E_ConsTypeParams params; }; typedef struct E_ConsTypeSlot E_ConsTypeSlot; @@ -211,13 +221,22 @@ internal void e_select_type_ctx(E_TypeCtx *ctx); //////////////////////////////// //~ rjf: Type Operation Functions -//- rjf: key constructors +//- rjf: basic key constructors internal E_TypeKey e_type_key_zero(void); internal E_TypeKey e_type_key_basic(E_TypeKind kind); internal E_TypeKey e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_idx); internal E_TypeKey e_type_key_reg(Architecture arch, REGS_RegCode code); internal E_TypeKey e_type_key_reg_alias(Architecture arch, REGS_AliasCode code); -internal E_TypeKey e_type_key_cons(E_TypeKind kind, E_TypeKey direct_key, U64 u64); + +//- rjf: constructed type construction +internal U64 e_hash_from_cons_type_params(E_ConsTypeParams *params); +internal B32 e_cons_type_params_match(E_ConsTypeParams *l, E_ConsTypeParams *r); +internal E_TypeKey e_type_key_cons_(E_ConsTypeParams *params); +#define e_type_key_cons(...) e_type_key_cons_(&(E_ConsTypeParams){.kind = E_TypeKind_Null, __VA_ARGS__}) + +//- rjf: constructed type construction helpers +internal E_TypeKey e_type_key_cons_array(E_TypeKey element_type_key, U64 count); +internal E_TypeKey e_type_key_cons_ptr(E_TypeKey element_type_key); //- rjf: basic type key functions internal B32 e_type_key_match(E_TypeKey l, E_TypeKey r);