// Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// //~ rjf: Generated Code #include "generated/eval.meta.c" //////////////////////////////// //~ rjf: Lexing/Parsing Data Tables global read_only String8 e_multichar_symbol_strings[] = { str8_lit_comp("<<"), str8_lit_comp(">>"), str8_lit_comp("->"), str8_lit_comp("<="), str8_lit_comp(">="), str8_lit_comp("=="), str8_lit_comp("!="), str8_lit_comp("&&"), str8_lit_comp("||"), }; global read_only struct {E_ExprKind kind; String8 string; S64 precedence;} e_unary_prefix_op_table[] = { // { E_ExprKind_???, str8_lit_comp("+"), 2 }, { E_ExprKind_Neg, str8_lit_comp("-"), 2 }, { E_ExprKind_LogNot, str8_lit_comp("!"), 2 }, { E_ExprKind_Deref, str8_lit_comp("*"), 2 }, { E_ExprKind_Address,str8_lit_comp("&"), 2 }, { E_ExprKind_Sizeof, str8_lit_comp("sizeof"), 2 }, // { E_ExprKind_Alignof, str8_lit_comp("_Alignof"), 2 }, }; global read_only struct {E_ExprKind kind; String8 string; S64 precedence;} e_binary_op_table[] = { { E_ExprKind_Mul, str8_lit_comp("*"), 3 }, { E_ExprKind_Div, str8_lit_comp("/"), 3 }, { E_ExprKind_Mod, str8_lit_comp("%"), 3 }, { E_ExprKind_Add, str8_lit_comp("+"), 4 }, { E_ExprKind_Sub, str8_lit_comp("-"), 4 }, { E_ExprKind_LShift, str8_lit_comp("<<"), 5 }, { E_ExprKind_RShift, str8_lit_comp(">>"), 5 }, { E_ExprKind_Less, str8_lit_comp("<"), 6 }, { E_ExprKind_LsEq, str8_lit_comp("<="), 6 }, { E_ExprKind_Grtr, str8_lit_comp(">"), 6 }, { E_ExprKind_GrEq, str8_lit_comp(">="), 6 }, { E_ExprKind_EqEq, str8_lit_comp("=="), 7 }, { E_ExprKind_NtEq, str8_lit_comp("!="), 7 }, { E_ExprKind_BitAnd, str8_lit_comp("&"), 8 }, { E_ExprKind_BitXor, str8_lit_comp("^"), 9 }, { E_ExprKind_BitOr, str8_lit_comp("|"), 10 }, { E_ExprKind_LogAnd, str8_lit_comp("&&"), 11 }, { E_ExprKind_LogOr, str8_lit_comp("||"), 12 }, { E_ExprKind_Define, str8_lit_comp("="), 13 }, }; global read_only S64 e_max_precedence = 15; //////////////////////////////// //~ rjf: Basic Helper Functions internal U64 e_hash_from_string(String8 string) { U64 result = 5381; for(U64 i = 0; i < string.size; i += 1) { result = ((result << 5) + result) + string.str[i]; } return result; } //////////////////////////////// //~ rjf: Expr Kind Enum Functions internal RDI_EvalOp e_opcode_from_expr_kind(E_ExprKind kind) { RDI_EvalOp result = RDI_EvalOp_Stop; switch(kind) { case E_ExprKind_Neg: result = RDI_EvalOp_Neg; break; case E_ExprKind_LogNot: result = RDI_EvalOp_LogNot; break; case E_ExprKind_BitNot: result = RDI_EvalOp_BitNot; break; case E_ExprKind_Mul: result = RDI_EvalOp_Mul; break; case E_ExprKind_Div: result = RDI_EvalOp_Div; break; case E_ExprKind_Mod: result = RDI_EvalOp_Mod; break; case E_ExprKind_Add: result = RDI_EvalOp_Add; break; case E_ExprKind_Sub: result = RDI_EvalOp_Sub; break; case E_ExprKind_LShift: result = RDI_EvalOp_LShift; break; case E_ExprKind_RShift: result = RDI_EvalOp_RShift; break; case E_ExprKind_Less: result = RDI_EvalOp_Less; break; case E_ExprKind_LsEq: result = RDI_EvalOp_LsEq; break; case E_ExprKind_Grtr: result = RDI_EvalOp_Grtr; break; case E_ExprKind_GrEq: result = RDI_EvalOp_GrEq; break; case E_ExprKind_EqEq: result = RDI_EvalOp_EqEq; break; case E_ExprKind_NtEq: result = RDI_EvalOp_NtEq; break; case E_ExprKind_BitAnd: result = RDI_EvalOp_BitAnd; break; case E_ExprKind_BitXor: result = RDI_EvalOp_BitXor; break; case E_ExprKind_BitOr: result = RDI_EvalOp_BitOr; break; case E_ExprKind_LogAnd: result = RDI_EvalOp_LogAnd; break; case E_ExprKind_LogOr: result = RDI_EvalOp_LogOr; break; } return result; } internal B32 e_expr_kind_is_comparison(E_ExprKind kind) { B32 result = 0; switch(kind) { default:{}break; case E_ExprKind_EqEq: case E_ExprKind_NtEq: case E_ExprKind_Less: case E_ExprKind_Grtr: case E_ExprKind_LsEq: case E_ExprKind_GrEq: { result = 1; }break; } return result; } //////////////////////////////// //~ rjf: Type Kind Enum Functions internal E_TypeKind e_type_kind_from_rdi(RDI_TypeKind kind) { E_TypeKind result = E_TypeKind_Null; switch(kind) { default:{}break; case RDI_TypeKind_Void: {result = E_TypeKind_Void;}break; case RDI_TypeKind_Handle: {result = E_TypeKind_Handle;}break; case RDI_TypeKind_Char8: {result = E_TypeKind_Char8;}break; case RDI_TypeKind_Char16: {result = E_TypeKind_Char16;}break; case RDI_TypeKind_Char32: {result = E_TypeKind_Char32;}break; case RDI_TypeKind_UChar8: {result = E_TypeKind_UChar8;}break; case RDI_TypeKind_UChar16: {result = E_TypeKind_UChar16;}break; case RDI_TypeKind_UChar32: {result = E_TypeKind_UChar32;}break; case RDI_TypeKind_U8: {result = E_TypeKind_U8;}break; case RDI_TypeKind_U16: {result = E_TypeKind_U16;}break; case RDI_TypeKind_U32: {result = E_TypeKind_U32;}break; case RDI_TypeKind_U64: {result = E_TypeKind_U64;}break; case RDI_TypeKind_U128: {result = E_TypeKind_U128;}break; case RDI_TypeKind_U256: {result = E_TypeKind_U256;}break; case RDI_TypeKind_U512: {result = E_TypeKind_U512;}break; case RDI_TypeKind_S8: {result = E_TypeKind_S8;}break; case RDI_TypeKind_S16: {result = E_TypeKind_S16;}break; case RDI_TypeKind_S32: {result = E_TypeKind_S32;}break; case RDI_TypeKind_S64: {result = E_TypeKind_S64;}break; case RDI_TypeKind_S128: {result = E_TypeKind_S128;}break; case RDI_TypeKind_S256: {result = E_TypeKind_S256;}break; case RDI_TypeKind_S512: {result = E_TypeKind_S512;}break; case RDI_TypeKind_Bool: {result = E_TypeKind_Bool;}break; case RDI_TypeKind_F16: {result = E_TypeKind_F16;}break; case RDI_TypeKind_F32: {result = E_TypeKind_F32;}break; case RDI_TypeKind_F32PP: {result = E_TypeKind_F32PP;}break; case RDI_TypeKind_F48: {result = E_TypeKind_F48;}break; case RDI_TypeKind_F64: {result = E_TypeKind_F64;}break; case RDI_TypeKind_F80: {result = E_TypeKind_F80;}break; case RDI_TypeKind_F128: {result = E_TypeKind_F128;}break; case RDI_TypeKind_ComplexF32: {result = E_TypeKind_ComplexF32;}break; case RDI_TypeKind_ComplexF64: {result = E_TypeKind_ComplexF64;}break; case RDI_TypeKind_ComplexF80: {result = E_TypeKind_ComplexF80;}break; case RDI_TypeKind_ComplexF128: {result = E_TypeKind_ComplexF128;}break; case RDI_TypeKind_Modifier: {result = E_TypeKind_Modifier;}break; case RDI_TypeKind_Ptr: {result = E_TypeKind_Ptr;}break; case RDI_TypeKind_LRef: {result = E_TypeKind_LRef;}break; case RDI_TypeKind_RRef: {result = E_TypeKind_RRef;}break; case RDI_TypeKind_Array: {result = E_TypeKind_Array;}break; case RDI_TypeKind_Function: {result = E_TypeKind_Function;}break; case RDI_TypeKind_Method: {result = E_TypeKind_Method;}break; case RDI_TypeKind_MemberPtr: {result = E_TypeKind_MemberPtr;}break; case RDI_TypeKind_Struct: {result = E_TypeKind_Struct;}break; case RDI_TypeKind_Class: {result = E_TypeKind_Class;}break; case RDI_TypeKind_Union: {result = E_TypeKind_Union;}break; case RDI_TypeKind_Enum: {result = E_TypeKind_Enum;}break; case RDI_TypeKind_Alias: {result = E_TypeKind_Alias;}break; case RDI_TypeKind_IncompleteStruct: {result = E_TypeKind_IncompleteStruct;}break; case RDI_TypeKind_IncompleteUnion: {result = E_TypeKind_IncompleteUnion;}break; case RDI_TypeKind_IncompleteClass: {result = E_TypeKind_IncompleteClass;}break; case RDI_TypeKind_IncompleteEnum: {result = E_TypeKind_IncompleteEnum;}break; case RDI_TypeKind_Bitfield: {result = E_TypeKind_Bitfield;}break; case RDI_TypeKind_Variadic: {result = E_TypeKind_Variadic;}break; } return result; } internal E_MemberKind e_member_kind_from_rdi(RDI_MemberKind kind) { E_MemberKind result = E_MemberKind_Null; switch(kind) { default:{}break; case RDI_MemberKind_DataField: {result = E_MemberKind_DataField;}break; case RDI_MemberKind_StaticData: {result = E_MemberKind_StaticData;}break; case RDI_MemberKind_Method: {result = E_MemberKind_Method;}break; case RDI_MemberKind_StaticMethod: {result = E_MemberKind_StaticMethod;}break; case RDI_MemberKind_VirtualMethod: {result = E_MemberKind_VirtualMethod;}break; case RDI_MemberKind_VTablePtr: {result = E_MemberKind_VTablePtr;}break; case RDI_MemberKind_Base: {result = E_MemberKind_Base;}break; case RDI_MemberKind_VirtualBase: {result = E_MemberKind_VirtualBase;}break; case RDI_MemberKind_NestedType: {result = E_MemberKind_NestedType;}break; } return result; } internal RDI_EvalTypeGroup e_type_group_from_kind(E_TypeKind kind) { RDI_EvalTypeGroup result = 0; switch(kind) { default:{}break; case E_TypeKind_Null: case E_TypeKind_Void: case E_TypeKind_F16: case E_TypeKind_F32PP: case E_TypeKind_F48: case E_TypeKind_F80: case E_TypeKind_F128: case E_TypeKind_ComplexF32: case E_TypeKind_ComplexF64: case E_TypeKind_ComplexF80: case E_TypeKind_ComplexF128: case E_TypeKind_Modifier: case E_TypeKind_Array: case E_TypeKind_Struct: case E_TypeKind_Class: case E_TypeKind_Union: case E_TypeKind_Enum: case E_TypeKind_Alias: case E_TypeKind_IncompleteStruct: case E_TypeKind_IncompleteClass: case E_TypeKind_IncompleteUnion: case E_TypeKind_IncompleteEnum: case E_TypeKind_Bitfield: case E_TypeKind_Variadic: {result = RDI_EvalTypeGroup_Other;}break; case E_TypeKind_Handle: case E_TypeKind_UChar8: case E_TypeKind_UChar16: case E_TypeKind_UChar32: case E_TypeKind_U8: case E_TypeKind_U16: case E_TypeKind_U32: case E_TypeKind_U64: case E_TypeKind_U128: case E_TypeKind_U256: case E_TypeKind_U512: case E_TypeKind_Ptr: case E_TypeKind_LRef: case E_TypeKind_RRef: case E_TypeKind_Function: case E_TypeKind_Method: case E_TypeKind_MemberPtr: {result = RDI_EvalTypeGroup_U;}break; case E_TypeKind_Char8: case E_TypeKind_Char16: case E_TypeKind_Char32: case E_TypeKind_S8: case E_TypeKind_S16: case E_TypeKind_S32: case E_TypeKind_S64: case E_TypeKind_S128: case E_TypeKind_S256: case E_TypeKind_S512: case E_TypeKind_Bool: {result = RDI_EvalTypeGroup_S;}break; case E_TypeKind_F32:{result = RDI_EvalTypeGroup_F32;}break; case E_TypeKind_F64:{result = RDI_EvalTypeGroup_F64;}break; } return result; } internal B32 e_type_kind_is_integer(E_TypeKind kind) { B32 result = (E_TypeKind_FirstInteger <= kind && kind <= E_TypeKind_LastInteger); return result; } internal B32 e_type_kind_is_signed(E_TypeKind kind) { B32 result = ((E_TypeKind_FirstSigned1 <= kind && kind <= E_TypeKind_LastSigned1) || (E_TypeKind_FirstSigned2 <= kind && kind <= E_TypeKind_LastSigned2)); return result; } internal B32 e_type_kind_is_basic_or_enum(E_TypeKind kind) { B32 result = ((E_TypeKind_FirstBasic <= kind && kind <= E_TypeKind_LastBasic) || kind == E_TypeKind_Enum); return result; } //////////////////////////////// //~ rjf: Message Functions internal void e_msg(Arena *arena, E_MsgList *msgs, E_MsgKind kind, void *location, String8 text) { E_Msg *msg = push_array(arena, E_Msg, 1); SLLQueuePush(msgs->first, msgs->last, msg); msgs->count += 1; msgs->max_kind = Max(kind, msgs->max_kind); msg->kind = kind; msg->location = location; msg->text = text; } internal void e_msgf(Arena *arena, E_MsgList *msgs, E_MsgKind kind, void *location, char *fmt, ...) { va_list args; va_start(args, fmt); String8 text = push_str8fv(arena, fmt, args); va_end(args); e_msg(arena, msgs, kind, location, text); } internal void e_msg_list_concat_in_place(E_MsgList *dst, E_MsgList *to_push) { if(dst->last != 0 && to_push->first != 0) { dst->last->next = to_push->first; dst->last = to_push->last; dst->count += to_push->count; dst->max_kind = Max(dst->max_kind, to_push->max_kind); } else if(to_push->first != 0) { MemoryCopyStruct(dst, to_push); } MemoryZeroStruct(to_push); } //////////////////////////////// //~ rjf: Basic Map Functions //- rjf: string -> num internal E_String2NumMap e_string2num_map_make(Arena *arena, U64 slot_count) { E_String2NumMap map = {0}; map.slots_count = slot_count; map.slots = push_array(arena, E_String2NumMapSlot, map.slots_count); return map; } internal void e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num) { U64 hash = e_hash_from_string(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) { if(str8_match(node->string, string, 0) && node->num == num) { existing_node = node; break; } } if(existing_node == 0) { E_String2NumMapNode *node = push_array(arena, E_String2NumMapNode, 1); SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); SLLQueuePush_N(map->first, map->last, node, order_next); node->string = push_str8_copy(arena, string); node->num = num; map->node_count += 1; } } internal U64 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 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) { if(str8_match(node->string, string, 0)) { existing_node = node; break; } } if(existing_node != 0) { num = existing_node->num; } } return num; } internal E_String2NumMapNodeArray e_string2num_map_node_array_from_map(Arena *arena, E_String2NumMap *map) { E_String2NumMapNodeArray result = {0}; result.count = map->node_count; result.v = push_array(arena, E_String2NumMapNode *, result.count); U64 idx = 0; for(E_String2NumMapNode *n = map->first; n != 0; n = n->order_next, idx += 1) { result.v[idx] = n; } return result; } internal int e_string2num_map_node_qsort_compare__num_ascending(E_String2NumMapNode **a, E_String2NumMapNode **b) { int result = 0; if(a[0]->num < b[0]->num) { result = -1; } else if(a[0]->num > b[0]->num) { result = +1; } return result; } internal void e_string2num_map_node_array_sort__in_place(E_String2NumMapNodeArray *array) { quick_sort(array->v, array->count, sizeof(array->v[0]), e_string2num_map_node_qsort_compare__num_ascending); } //- rjf: string -> expr internal E_String2ExprMap e_string2expr_map_make(Arena *arena, U64 slot_count) { E_String2ExprMap map = {0}; map.slots_count = slot_count; map.slots = push_array(arena, E_String2ExprMapSlot, map.slots_count); return map; } internal void e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr) { U64 hash = e_hash_from_string(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) { if(str8_match(node->string, string, 0)) { existing_node = node; break; } } if(existing_node == 0) { E_String2ExprMapNode *node = push_array(arena, E_String2ExprMapNode, 1); SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); node->string = push_str8_copy(arena, string); existing_node = node; } existing_node->expr = expr; } internal void e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string) { U64 hash = e_hash_from_string(string); U64 slot_idx = hash%map->slots_count; for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) { if(str8_match(node->string, string, 0)) { node->poison_count += 1; break; } } } internal void e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string) { U64 hash = e_hash_from_string(string); U64 slot_idx = hash%map->slots_count; for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) { if(str8_match(node->string, string, 0) && node->poison_count > 0) { node->poison_count -= 1; break; } } } internal E_Expr * 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 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) { if(str8_match(node->string, string, 0) && node->poison_count == 0) { existing_node = node; break; } } if(existing_node != 0) { expr = existing_node->expr; } } return expr; } //////////////////////////////// //~ rjf: Debug-Info-Driven Map Building Functions internal E_String2NumMap * e_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) { Temp scratch = scratch_begin(&arena, 1); //- rjf: gather scopes to walk typedef struct Task Task; struct Task { Task *next; RDI_Scope *scope; }; Task *first_task = 0; Task *last_task = 0; //- rjf: voff -> tightest scope RDI_Scope *tightest_scope = 0; { U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); Task *task = push_array(scratch.arena, Task, 1); task->scope = scope; SLLQueuePush(first_task, last_task, task); tightest_scope = scope; } //- rjf: voff-1 -> scope if(voff > 0) { U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff-1); RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); if(scope != tightest_scope) { Task *task = push_array(scratch.arena, Task, 1); task->scope = scope; SLLQueuePush(first_task, last_task, task); } } //- rjf: tightest scope -> walk up the tree & build tasks for each parent scope if(tightest_scope != 0) { RDI_Scope *nil_scope = rdi_element_from_name_idx(rdi, Scopes, 0); for(RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, tightest_scope->parent_scope_idx); scope != 0 && scope != nil_scope; scope = rdi_element_from_name_idx(rdi, Scopes, scope->parent_scope_idx)) { Task *task = push_array(scratch.arena, Task, 1); task->scope = scope; SLLQueuePush(first_task, last_task, task); } } //- rjf: build blank map E_String2NumMap *map = push_array(arena, E_String2NumMap, 1); *map = e_string2num_map_make(arena, 1024); //- rjf: accumulate locals for all tasks for(Task *task = first_task; task != 0; task = task->next) { RDI_Scope *scope = task->scope; if(scope != 0) { U32 local_opl_idx = scope->local_first + scope->local_count; for(U32 local_idx = scope->local_first; local_idx < local_opl_idx; local_idx += 1) { RDI_Local *local_var = rdi_element_from_name_idx(rdi, Locals, local_idx); U64 local_name_size = 0; U8 *local_name_str = rdi_string_from_idx(rdi, local_var->name_string_idx, &local_name_size); String8 name = push_str8_copy(arena, str8(local_name_str, local_name_size)); e_string2num_map_insert(arena, map, name, (U64)local_idx+1); } } } scratch_end(scratch); return map; } internal E_String2NumMap * e_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) { //- rjf: voff -> tightest scope U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); RDI_Scope *tightest_scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); //- rjf: tightest scope -> procedure U32 proc_idx = tightest_scope->proc_idx; RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); //- rjf: procedure -> udt U32 udt_idx = procedure->container_idx; RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, udt_idx); //- rjf: build blank map E_String2NumMap *map = push_array(arena, E_String2NumMap, 1); *map = e_string2num_map_make(arena, 64); //- rjf: udt -> fill member map if(!(udt->flags & RDI_UDTFlag_EnumMembers)) { U64 data_member_num = 1; for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { RDI_Member *m = rdi_element_from_name_idx(rdi, Members, member_idx); if(m->kind == RDI_MemberKind_DataField) { String8 name = {0}; name.str = rdi_string_from_idx(rdi, m->name_string_idx, &name.size); e_string2num_map_insert(arena, map, name, data_member_num); data_member_num += 1; } } } return map; } //////////////////////////////// //~ rjf: Tokenization Functions internal E_Token e_token_zero(void) { E_Token t = zero_struct; return t; } internal void e_token_chunk_list_push(Arena *arena, E_TokenChunkList *list, U64 chunk_size, E_Token *token) { E_TokenChunkNode *node = list->last; if(node == 0 || node->count >= node->cap) { node = push_array(arena, E_TokenChunkNode, 1); SLLQueuePush(list->first, list->last, node); node->cap = chunk_size; node->v = push_array_no_zero(arena, E_Token, node->cap); list->node_count += 1; } MemoryCopyStruct(&node->v[node->count], token); node->count += 1; list->total_count += 1; } internal E_TokenArray e_token_array_from_chunk_list(Arena *arena, E_TokenChunkList *list) { E_TokenArray array = {0}; array.count = list->total_count; array.v = push_array_no_zero(arena, E_Token, array.count); U64 idx = 0; for(E_TokenChunkNode *node = list->first; node != 0; node = node->next) { MemoryCopy(array.v+idx, node->v, sizeof(E_Token)*node->count); } return array; } internal E_TokenArray e_token_array_from_text(Arena *arena, String8 text) { Temp scratch = scratch_begin(&arena, 1); //- rjf: lex loop E_TokenChunkList tokens = {0}; U64 active_token_start_idx = 0; E_TokenKind active_token_kind = E_TokenKind_Null; B32 active_token_kind_started_with_tick = 0; B32 escaped = 0; for(U64 idx = 0, advance = 0; idx <= text.size; idx += advance) { U8 byte = (idx+0 < text.size) ? text.str[idx+0] : 0; U8 byte_next = (idx+1 < text.size) ? text.str[idx+1] : 0; U8 byte_next2= (idx+2 < text.size) ? text.str[idx+2] : 0; advance = 1; B32 token_formed = 0; U64 token_end_idx_pad = 0; switch(active_token_kind) { //- rjf: no active token -> seek token starter default: { if(char_is_alpha(byte) || byte == '_' || byte == '`' || byte == '$') { active_token_kind = E_TokenKind_Identifier; active_token_start_idx = idx; active_token_kind_started_with_tick = (byte == '`'); } else if(char_is_digit(byte, 10) || (byte == '.' && char_is_digit(byte_next, 10))) { active_token_kind = E_TokenKind_Numeric; active_token_start_idx = idx; } else if(byte == '"') { active_token_kind = E_TokenKind_StringLiteral; active_token_start_idx = idx; } else if(byte == '\'') { active_token_kind = E_TokenKind_CharLiteral; active_token_start_idx = idx; } else if(byte == '~' || byte == '!' || byte == '%' || byte == '^' || byte == '&' || byte == '*' || byte == '(' || byte == ')' || byte == '-' || byte == '=' || byte == '+' || byte == '[' || byte == ']' || byte == '{' || byte == '}' || byte == ':' || byte == ';' || byte == ',' || byte == '.' || byte == '<' || byte == '>' || byte == '/' || byte == '?' || byte == '|') { active_token_kind = E_TokenKind_Symbol; active_token_start_idx = idx; } }break; //- rjf: active tokens -> seek enders case E_TokenKind_Identifier: { if(byte == ':' && byte_next == ':' && (char_is_alpha(byte_next2) || byte_next2 == '_' || byte_next2 == '<')) { // NOTE(rjf): encountering C++-style namespaces - skip over scope resolution symbol // & keep going. advance = 2; } else if((byte == '\'' || byte == '`') && active_token_kind_started_with_tick) { // NOTE(rjf): encountering ` -> ' or ` -> ` style identifier escapes active_token_kind_started_with_tick = 0; advance = 1; } else if(byte == '<') { // NOTE(rjf): encountering C++-style templates - try to find ender. if no ender found, // assume this is an operator & just consume the identifier part. S64 nest = 1; for(U64 idx2 = idx+1; idx2 <= text.size; idx2 += 1) { if(idx2 < text.size && text.str[idx2] == '<') { nest += 1; } else if(idx2 < text.size && text.str[idx2] == '>') { nest -= 1; if(nest == 0) { advance = (idx2+1-idx); break; } } else if(idx2 == text.size && nest != 0) { token_formed = 1; advance = 0; break; } } } else if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && !active_token_kind_started_with_tick && byte != '@' && byte != '$') { advance = 0; token_formed = 1; } }break; case E_TokenKind_Numeric: { if(!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '.') { advance = 0; token_formed = 1; } }break; case E_TokenKind_StringLiteral: { if(escaped == 0 && byte == '\\') { escaped = 1; } else if(escaped) { escaped = 0; } else if(escaped == 0 && byte == '"') { advance = 1; token_formed = 1; token_end_idx_pad = 1; } }break; case E_TokenKind_CharLiteral: { if(escaped == 0 && byte == '\\') { escaped = 1; } else if(escaped) { escaped = 0; } else if(escaped == 0 && byte == '\'') { advance = 1; token_formed = 1; token_end_idx_pad = 1; } }break; case E_TokenKind_Symbol: { if(byte != '~' && byte != '!' && byte != '%' && byte != '^' && byte != '&' && byte != '*' && byte != '(' && byte != ')' && byte != '-' && byte != '=' && byte != '+' && byte != '[' && byte != ']' && byte != '{' && byte != '}' && byte != ':' && byte != ';' && byte != ',' && byte != '.' && byte != '<' && byte != '>' && byte != '/' && byte != '?' && byte != '|') { advance = 0; token_formed = 1; } }break; } //- rjf: token formed -> push new formed token(s) if(token_formed) { // rjf: non-symbols *or* symbols of only 1-length can be immediately // pushed as a token if(active_token_kind != E_TokenKind_Symbol || idx==active_token_start_idx+1) { E_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+token_end_idx_pad)}; e_token_chunk_list_push(scratch.arena, &tokens, 256, &token); } // rjf: symbolic strings matching `--` mean the remainder of the string // is reserved for external usage. the rest of the stream should not // be tokenized. else if(idx == active_token_start_idx+2 && text.str[active_token_start_idx] == '-' && text.str[active_token_start_idx+1] == '-') { break; } // rjf: if we got a symbol string of N>1 characters, then we need to // apply the maximum-munch rule, and produce M<=N tokens, where each // formed token is the maximum size possible, given the legal // >1-length symbol strings. else { U64 advance2 = 0; for(U64 idx2 = active_token_start_idx; idx2 < idx; idx2 += advance2) { advance2 = 1; for(U64 multichar_symbol_idx = 0; multichar_symbol_idx < ArrayCount(e_multichar_symbol_strings); multichar_symbol_idx += 1) { String8 multichar_symbol_string = e_multichar_symbol_strings[multichar_symbol_idx]; String8 part_of_token = str8_substr(text, r1u64(idx2, idx2+multichar_symbol_string.size)); if(str8_match(part_of_token, multichar_symbol_string, 0)) { advance2 = multichar_symbol_string.size; break; } } E_Token token = {active_token_kind, r1u64(idx2, idx2+advance2)}; e_token_chunk_list_push(scratch.arena, &tokens, 256, &token); } } // rjf: reset for subsequent tokens. active_token_kind = E_TokenKind_Null; } } //- rjf: chunk list -> array & return E_TokenArray array = e_token_array_from_chunk_list(arena, &tokens); scratch_end(scratch); return array; } internal E_TokenArray e_token_array_make_first_opl(E_Token *first, E_Token *opl) { E_TokenArray array = {first, (U64)(opl-first)}; return array; } //////////////////////////////// //~ rjf: Expression Tree Building Functions internal E_Expr * e_push_expr(Arena *arena, E_ExprKind kind, void *location) { E_Expr *e = push_array(arena, E_Expr, 1); e->first = e->last = e->next = &e_expr_nil; e->location = location; e->kind = kind; return e; } internal void e_expr_push_child(E_Expr *parent, E_Expr *child) { SLLQueuePush_NZ(&e_expr_nil, parent->first, parent->last, child, next); } //////////////////////////////// //~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) internal E_Ctx * e_ctx(void) { return e_state->ctx; } internal void e_select_ctx(E_Ctx *ctx) { if(e_state == 0) { Arena *arena = arena_alloc(); e_state = push_array(arena, E_State, 1); e_state->arena = arena; e_state->arena_eval_start_pos = arena_pos(e_state->arena); } arena_pop_to(e_state->arena, e_state->arena_eval_start_pos); e_state->ctx = ctx; e_state->cons_content_slots_count = 256; e_state->cons_key_slots_count = 256; e_state->cons_content_slots = push_array(e_state->arena, E_ConsTypeSlot, e_state->cons_content_slots_count); e_state->cons_key_slots = push_array(e_state->arena, E_ConsTypeSlot, e_state->cons_key_slots_count); } internal U32 e_idx_from_rdi(RDI_Parsed *rdi) { U32 result = 0; for(U64 idx = 0; idx < e_state->ctx->rdis_count; idx += 1) { if(e_state->ctx->rdis[idx] == rdi) { result = (U32)idx; break; } } return result; } //////////////////////////////// //~ rjf: Type Operation Functions //- rjf: key constructors internal E_TypeKey e_type_key_zero(void) { E_TypeKey k = zero_struct; return k; } internal E_TypeKey e_type_key_basic(E_TypeKind kind) { E_TypeKey key = {E_TypeKeyKind_Basic}; key.u32[0] = (U32)kind; return key; } internal E_TypeKey e_type_key_ext(E_TypeKind kind, U32 type_idx, U32 rdi_idx) { E_TypeKey key = {E_TypeKeyKind_Ext}; key.u32[0] = (U32)kind; if(E_TypeKind_FirstBasic <= kind && kind <= E_TypeKind_LastBasic) { key.kind = E_TypeKeyKind_Basic; } else { key.u32[1] = type_idx; key.u32[2] = rdi_idx; } return key; } internal E_TypeKey e_type_key_reg(Architecture arch, REGS_RegCode code) { E_TypeKey key = {E_TypeKeyKind_Reg}; key.u32[0] = (U32)arch; key.u32[1] = (U32)code; return key; } internal E_TypeKey e_type_key_reg_alias(Architecture arch, REGS_AliasCode code) { E_TypeKey key = {E_TypeKeyKind_RegAlias}; key.u32[0] = (U32)arch; key.u32[1] = (U32)code; return key; } internal E_TypeKey e_type_key_cons(E_TypeKind kind, E_TypeKey direct_key, U64 u64) { 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), }; U64 content_hash = e_hash_from_string(str8((U8 *)buffer, sizeof(buffer))); U64 content_slot_idx = content_hash%e_state->cons_content_slots_count; E_ConsTypeSlot *content_slot = &e_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) { node = n; break; } } E_TypeKey result = zero_struct; if(node == 0) { E_TypeKey key = {E_TypeKeyKind_Cons}; key.u32[0] = (U32)kind; key.u32[1] = (U32)e_state->cons_id_gen; e_state->cons_id_gen += 1; U64 key_hash = e_hash_from_string(str8_struct(&key)); U64 key_slot_idx = key_hash%e_state->cons_key_slots_count; E_ConsTypeSlot *key_slot = &e_state->cons_key_slots[key_slot_idx]; E_ConsTypeNode *node = push_array(e_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; result = key; } else { result = node->key; } return result; } //- rjf: basic type key functions internal B32 e_type_key_match(E_TypeKey l, E_TypeKey r) { B32 result = MemoryMatchStruct(&l, &r); return result; } //- rjf: key -> info extraction internal E_TypeKind e_type_kind_from_key(E_TypeKey key) { E_TypeKind kind = E_TypeKind_Null; switch(key.kind) { default:{}break; case E_TypeKeyKind_Basic: {kind = (E_TypeKind)key.u32[0];}break; case E_TypeKeyKind_Ext: {kind = (E_TypeKind)key.u32[0];}break; case E_TypeKeyKind_Cons: {kind = (E_TypeKind)key.u32[0];}break; case E_TypeKeyKind_Reg: {kind = E_TypeKind_Union;}break; case E_TypeKeyKind_RegAlias:{kind = E_TypeKind_Union;}break; } return kind; } internal E_Type * e_type_from_key(Arena *arena, E_TypeKey key) { E_Type *type = &e_type_nil; U64 reg_byte_count = 0; { switch(key.kind) { default:{}break; //- rjf: basic type keys case E_TypeKeyKind_Basic: { E_TypeKind kind = (E_TypeKind)key.u32[0]; if(E_TypeKind_FirstBasic <= kind && kind <= E_TypeKind_LastBasic) { type = push_array(arena, E_Type, 1); type->kind = kind; type->name = e_kind_basic_string_table[kind]; type->byte_size = e_kind_basic_byte_size_table[kind]; } }break; //- rjf: constructed type keys case E_TypeKeyKind_Cons: { U64 key_hash = e_hash_from_string(str8_struct(&key)); U64 key_slot_idx = key_hash%e_state->cons_key_slots_count; E_ConsTypeSlot *key_slot = &e_state->cons_key_slots[key_slot_idx]; for(E_ConsTypeNode *node = key_slot->first; node != 0; node = node->key_next) { if(e_type_key_match(node->key, 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; switch(type->kind) { default: { type->byte_size = bit_size_from_arch(e_state->ctx->arch)/8; }break; case E_TypeKind_Array: { U64 ptee_size = e_type_byte_size_from_key(node->direct_key); type->byte_size = ptee_size * type->count; }break; } } } }break; //- rjf: external (rdi) type keys case E_TypeKeyKind_Ext: { U64 type_node_idx = key.u32[1]; U32 rdi_idx = key.u32[2]; RDI_Parsed *rdi = e_state->ctx->rdis[rdi_idx]; RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx); if(rdi_type->kind != RDI_TypeKind_NULL) { E_TypeKind kind = e_type_kind_from_rdi(rdi_type->kind); //- rjf: record types => unpack name * members & produce if(RDI_TypeKind_FirstRecord <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastRecord) { // rjf: unpack name String8 name = {0}; name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: unpack UDT info RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, rdi_type->user_defined.udt_idx); // rjf: unpack members E_Member *members = 0; U32 members_count = 0; { members_count = udt->member_count; members = push_array(arena, E_Member, members_count); if(members_count != 0) { for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { RDI_Member *src = rdi_element_from_name_idx(rdi, Members, member_idx); E_TypeKind member_type_kind = E_TypeKind_Null; RDI_TypeNode *member_type = rdi_element_from_name_idx(rdi, TypeNodes, src->type_idx); member_type_kind = e_type_kind_from_rdi(member_type->kind); E_Member *dst = &members[member_idx-udt->member_first]; dst->kind = e_member_kind_from_rdi(src->kind); dst->type_key = e_type_key_ext(member_type_kind, src->type_idx, rdi_idx); dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); dst->off = (U64)src->off; } } } // rjf: produce type = push_array(arena, E_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); type->byte_size = (U64)rdi_type->byte_size; type->count = members_count; type->members = members; } //- rjf: enum types => unpack name * values & produce else if(rdi_type->kind == RDI_TypeKind_Enum) { // rjf: unpack name String8 name = {0}; name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: unpack direct type E_TypeKey direct_type_key = zero_struct; if(rdi_type->user_defined.direct_type_idx < type_node_idx) { RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->user_defined.direct_type_idx); E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->user_defined.direct_type_idx, rdi_idx); } // rjf: unpack members E_EnumVal *enum_vals = 0; U32 enum_vals_count = 0; { U32 udt_idx = rdi_type->user_defined.udt_idx; RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, udt_idx); enum_vals_count = udt->member_count; enum_vals = push_array(arena, E_EnumVal, enum_vals_count); for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { RDI_EnumMember *src = rdi_element_from_name_idx(rdi, EnumMembers, member_idx); E_EnumVal *dst = &enum_vals[member_idx-udt->member_first]; dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); dst->val = src->val; } } // rjf: produce type = push_array(arena, E_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); type->byte_size = (U64)rdi_type->byte_size; type->count = enum_vals_count; type->enum_vals = enum_vals; type->direct_type_key = direct_type_key; } //- rjf: constructed types else if(RDI_TypeKind_FirstConstructed <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastConstructed) { // rjf: unpack direct type B32 direct_type_is_good = 0; E_TypeKey direct_type_key = zero_struct; U64 direct_type_byte_size = 0; if(rdi_type->constructed.direct_type_idx < type_node_idx) { RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->constructed.direct_type_idx); E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->constructed.direct_type_idx, rdi_idx); direct_type_is_good = 1; direct_type_byte_size = (U64)direct_type_node->byte_size; } // rjf: construct based on kind switch(rdi_type->kind) { case RDI_TypeKind_Modifier: { E_TypeFlags flags = 0; if(rdi_type->flags & RDI_TypeModifierFlag_Const) { flags |= E_TypeFlag_Const; } if(rdi_type->flags & RDI_TypeModifierFlag_Volatile) { flags |= E_TypeFlag_Volatile; } type = push_array(arena, E_Type, 1); type->kind = kind; type->direct_type_key = direct_type_key; type->byte_size = direct_type_byte_size; type->flags = flags; }break; case RDI_TypeKind_Ptr: case RDI_TypeKind_LRef: case RDI_TypeKind_RRef: { type = push_array(arena, E_Type, 1); type->kind = kind; type->direct_type_key = direct_type_key; type->byte_size = bit_size_from_arch(e_state->ctx->arch)/8; }break; case RDI_TypeKind_Array: { type = push_array(arena, E_Type, 1); type->kind = kind; type->direct_type_key = direct_type_key; type->count = rdi_type->constructed.count; type->byte_size = direct_type_byte_size * type->count; }break; case RDI_TypeKind_Function: { U32 count = rdi_type->constructed.count; U32 idx_run_first = rdi_type->constructed.param_idx_run_first; U32 check_count = 0; U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); if(check_count == count) { type = push_array(arena, E_Type, 1); type->kind = kind; type->byte_size = bit_size_from_arch(e_state->ctx->arch)/8; type->direct_type_key = direct_type_key; type->count = count; type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count); for(U32 idx = 0; idx < type->count; idx += 1) { U32 param_type_idx = idx_run[idx]; if(param_type_idx < type_node_idx) { RDI_TypeNode *param_type_node = rdi_element_from_name_idx(rdi, TypeNodes, param_type_idx); E_TypeKind param_kind = e_type_kind_from_rdi(param_type_node->kind); type->param_type_keys[idx] = e_type_key_ext(param_kind, param_type_idx, rdi_idx); } else { break; } } } }break; case RDI_TypeKind_Method: { // NOTE(rjf): for methods, the `direct` type points at the owner type. // the return type, instead of being encoded via the `direct` type, is // encoded via the first parameter. U32 count = rdi_type->constructed.count; U32 idx_run_first = rdi_type->constructed.param_idx_run_first; U32 check_count = 0; U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); if(check_count == count) { type = push_array(arena, E_Type, 1); type->kind = kind; type->byte_size = bit_size_from_arch(e_state->ctx->arch)/8; type->owner_type_key = direct_type_key; type->count = count; type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count); for(U32 idx = 0; idx < type->count; idx += 1) { U32 param_type_idx = idx_run[idx]; if(param_type_idx < type_node_idx) { RDI_TypeNode *param_type_node = rdi_element_from_name_idx(rdi, TypeNodes, param_type_idx); E_TypeKind param_kind = e_type_kind_from_rdi(param_type_node->kind); type->param_type_keys[idx] = e_type_key_ext(param_kind, param_type_idx, rdi_idx); } else { break; } } if(type->count > 0) { type->direct_type_key = type->param_type_keys[0]; type->count -= 1; type->param_type_keys += 1; } } }break; case RDI_TypeKind_MemberPtr: { // rjf: unpack owner type E_TypeKey owner_type_key = zero_struct; if(rdi_type->constructed.owner_type_idx < type_node_idx) { RDI_TypeNode *owner_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->constructed.owner_type_idx); E_TypeKind owner_type_kind = e_type_kind_from_rdi(owner_type_node->kind); owner_type_key = e_type_key_ext(owner_type_kind, rdi_type->constructed.owner_type_idx, rdi_idx); } type = push_array(arena, E_Type, 1); type->kind = kind; type->byte_size = bit_size_from_arch(e_state->ctx->arch)/8; type->owner_type_key = owner_type_key; type->direct_type_key = direct_type_key; }break; } } //- rjf: alias types else if(rdi_type->kind == RDI_TypeKind_Alias) { // rjf: unpack name String8 name = {0}; name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: unpack direct type E_TypeKey direct_type_key = zero_struct; U64 direct_type_byte_size = 0; if(rdi_type->user_defined.direct_type_idx < type_node_idx) { RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->user_defined.direct_type_idx); E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->user_defined.direct_type_idx, rdi_idx); direct_type_byte_size = direct_type_node->byte_size; } // rjf: produce type = push_array(arena, E_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); type->byte_size = direct_type_byte_size; type->direct_type_key = direct_type_key; } //- rjf: bitfields else if(RDI_TypeKind_Bitfield == rdi_type->kind) { // rjf: unpack direct type E_TypeKey direct_type_key = zero_struct; U64 direct_type_byte_size = 0; if(rdi_type->bitfield.direct_type_idx < type_node_idx) { RDI_TypeNode *direct_type_node = rdi_element_from_name_idx(rdi, TypeNodes, rdi_type->bitfield.direct_type_idx); E_TypeKind direct_type_kind = e_type_kind_from_rdi(direct_type_node->kind); direct_type_key = e_type_key_ext(direct_type_kind, rdi_type->bitfield.direct_type_idx, rdi_idx); direct_type_byte_size = direct_type_node->byte_size; } // rjf: produce type = push_array(arena, E_Type, 1); type->kind = kind; type->byte_size = direct_type_byte_size; type->direct_type_key = direct_type_key; type->off = (U32)rdi_type->bitfield.off; type->count = (U64)rdi_type->bitfield.size; } //- rjf: incomplete types else if(RDI_TypeKind_FirstIncomplete <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastIncomplete) { // rjf: unpack name String8 name = {0}; name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: produce type = push_array(arena, E_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); } } }break; //- rjf: reg type keys case E_TypeKeyKind_Reg: { Architecture arch = (Architecture)key.u32[0]; REGS_RegCode code = (REGS_RegCode)key.u32[1]; REGS_Rng rng = regs_reg_code_rng_table_from_architecture(arch)[code]; reg_byte_count = (U64)rng.byte_size; }goto build_reg_type; case E_TypeKeyKind_RegAlias: { Architecture arch = (Architecture)key.u32[0]; REGS_AliasCode code = (REGS_AliasCode)key.u32[1]; REGS_Slice slice = regs_alias_code_slice_table_from_architecture(arch)[code]; reg_byte_count = (U64)slice.byte_size; }goto build_reg_type; build_reg_type: { Temp scratch = scratch_begin(&arena, 1); type = push_array(arena, E_Type, 1); type->kind = E_TypeKind_Union; type->name = push_str8f(arena, "reg_%I64u_bit", reg_byte_count*8); type->byte_size = (U64)reg_byte_count; // rjf: build register type members E_MemberList members = {0}; { // rjf: build exact-sized members { if(type->byte_size == 16) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u128"); mem->type_key = e_type_key_basic(E_TypeKind_U128); } if(type->byte_size == 8) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u64"); mem->type_key = e_type_key_basic(E_TypeKind_U64); } if(type->byte_size == 4) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u32"); mem->type_key = e_type_key_basic(E_TypeKind_U32); } if(type->byte_size == 2) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u16"); mem->type_key = e_type_key_basic(E_TypeKind_U16); } if(type->byte_size == 1) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u8"); mem->type_key = e_type_key_basic(E_TypeKind_U8); } } // rjf: build arrays for subdivisions { if(type->byte_size > 16 && type->byte_size%16 == 0) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } if(type->byte_size > 8 && type->byte_size%8 == 0) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } if(type->byte_size > 4 && type->byte_size%4 == 0) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } if(type->byte_size > 2 && type->byte_size%2 == 0) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } if(type->byte_size > 1) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } if(type->byte_size > 4 && type->byte_size%4 == 0) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } if(type->byte_size > 8 && type->byte_size%8 == 0) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); SLLQueuePush(members.first, members.last, n); members.count += 1; 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); } } } // rjf: commit members type->count = members.count; type->members = push_array_no_zero(arena, E_Member, members.count); U64 idx = 0; for(E_MemberNode *n = members.first; n != 0; n = n->next, idx += 1) { MemoryCopyStruct(&type->members[idx], &n->v); } scratch_end(scratch); }break; } } return type; } internal U64 e_type_byte_size_from_key(E_TypeKey key) { U64 result = 0; switch(key.kind) { default:{}break; case E_TypeKeyKind_Basic: { E_TypeKind kind = (E_TypeKind)key.u32[0]; result = e_kind_basic_byte_size_table[kind]; }break; case E_TypeKeyKind_Ext: case E_TypeKeyKind_Cons: { Temp scratch = scratch_begin(0, 0); E_Type *type = e_type_from_key(scratch.arena, key); result = type->byte_size; scratch_end(scratch); }break; } return result; } internal E_TypeKey e_type_direct_from_key(E_TypeKey key) { E_TypeKey result = zero_struct; switch(key.kind) { default:{}break; case E_TypeKeyKind_Ext: case E_TypeKeyKind_Cons: { Temp scratch = scratch_begin(0, 0); E_Type *type = e_type_from_key(scratch.arena, key); result = type->direct_type_key; scratch_end(scratch); }break; } return result; } internal E_TypeKey e_type_owner_from_key(E_TypeKey key) { E_TypeKey result = zero_struct; switch(key.kind) { default:{}break; case E_TypeKeyKind_Ext: case E_TypeKeyKind_Cons: { Temp scratch = scratch_begin(0, 0); E_Type *type = e_type_from_key(scratch.arena, key); result = type->owner_type_key; scratch_end(scratch); }break; } return result; } internal E_TypeKey e_type_ptee_from_key(E_TypeKey key) { E_TypeKey result = key; B32 passed_ptr = 0; for(;;) { E_TypeKind kind = e_type_kind_from_key(result); result = e_type_direct_from_key(result); if(kind == E_TypeKind_Ptr || kind == E_TypeKind_LRef || kind == E_TypeKind_RRef) { passed_ptr = 1; } E_TypeKind next_kind = e_type_kind_from_key(result); if(passed_ptr && next_kind != E_TypeKind_IncompleteStruct && next_kind != E_TypeKind_IncompleteUnion && next_kind != E_TypeKind_IncompleteEnum && next_kind != E_TypeKind_IncompleteClass && next_kind != E_TypeKind_Alias && next_kind != E_TypeKind_Modifier) { break; } if(kind == E_TypeKind_Null) { break; } } return result; } internal E_TypeKey e_type_unwrap_enum(E_TypeKey key) { E_TypeKey result = key; for(B32 good = 1; good;) { E_TypeKind kind = e_type_kind_from_key(result); if(kind == E_TypeKind_Enum) { result = e_type_direct_from_key(result); } else { good = 0; } } return result; } internal E_TypeKey e_type_unwrap(E_TypeKey key) { E_TypeKey result = key; for(B32 good = 1; good;) { E_TypeKind kind = e_type_kind_from_key(result); if((E_TypeKind_FirstIncomplete <= kind && kind <= E_TypeKind_LastIncomplete) || kind == E_TypeKind_Modifier || kind == E_TypeKind_Alias) { result = e_type_direct_from_key(result); } else { good = 0; } } return result; } internal E_TypeKey e_type_promote(E_TypeKey key) { E_TypeKey result = key; E_TypeKind kind = e_type_kind_from_key(key); if(kind == E_TypeKind_Bool || kind == E_TypeKind_S8 || kind == E_TypeKind_S16 || kind == E_TypeKind_U8 || kind == E_TypeKind_U16) { result = e_type_key_basic(E_TypeKind_S32); } return result; } internal B32 e_type_match(E_TypeKey l, E_TypeKey r) { // rjf: unpack parameters E_TypeKey lu = e_type_unwrap(l); E_TypeKey ru = e_type_unwrap(r); // rjf: exact key matches -> match B32 result = e_type_key_match(lu, ru); // rjf: if keys don't match, type *contents* could still match, // so we need to unpack the type info & compare if(!result) { E_TypeKind luk = e_type_kind_from_key(lu); E_TypeKind ruk = e_type_kind_from_key(ru); if(luk == ruk) { switch(luk) { default: { result = 1; }break; case E_TypeKind_Ptr: case E_TypeKind_LRef: case E_TypeKind_RRef: { E_TypeKey lud = e_type_direct_from_key(lu); E_TypeKey rud = e_type_direct_from_key(ru); result = e_type_match(lud, rud); }break; case E_TypeKind_MemberPtr: { E_TypeKey lud = e_type_direct_from_key(lu); E_TypeKey rud = e_type_direct_from_key(ru); E_TypeKey luo = e_type_owner_from_key(lu); E_TypeKey ruo = e_type_owner_from_key(ru); result = (e_type_match(lud, rud) && e_type_match(luo, ruo)); }break; case E_TypeKind_Array: { Temp scratch = scratch_begin(0, 0); E_Type *lt = e_type_from_key(scratch.arena, l); E_Type *rt = e_type_from_key(scratch.arena, r); if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key)) { result = 1; } scratch_end(scratch); }break; case E_TypeKind_Function: { Temp scratch = scratch_begin(0, 0); E_Type *lt = e_type_from_key(scratch.arena, l); E_Type *rt = e_type_from_key(scratch.arena, r); if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key)) { B32 params_match = 1; E_TypeKey *lp = lt->param_type_keys; E_TypeKey *rp = rt->param_type_keys; U64 count = lt->count; for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) { if(!e_type_match(*lp, *rp)) { params_match = 0; break; } } result = params_match; } scratch_end(scratch); }break; case E_TypeKind_Method: { Temp scratch = scratch_begin(0, 0); E_Type *lt = e_type_from_key(scratch.arena, l); E_Type *rt = e_type_from_key(scratch.arena, r); if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key) && e_type_match(lt->owner_type_key, rt->owner_type_key)) { B32 params_match = 1; E_TypeKey *lp = lt->param_type_keys; E_TypeKey *rp = rt->param_type_keys; U64 count = lt->count; for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) { if(!e_type_match(*lp, *rp)) { params_match = 0; break; } } result = params_match; } scratch_end(scratch); }break; } } } return result; } internal E_Member * e_type_member_copy(Arena *arena, E_Member *src) { E_Member *dst = push_array(arena, E_Member, 1); MemoryCopyStruct(dst, src); dst->name = push_str8_copy(arena, src->name); dst->inheritance_key_chain = e_type_key_list_copy(arena, &src->inheritance_key_chain); return dst; } internal int e_type_qsort_compare_members_offset(E_Member *a, E_Member *b) { int result = 0; if(a->off < b->off) { result = -1; } else if(a->off > b->off) { result = +1; } return result; } internal E_MemberArray e_type_data_members_from_key(Arena *arena, E_TypeKey key) { Temp scratch = scratch_begin(&arena, 1); E_TypeKind root_type_kind = e_type_kind_from_key(key); //- rjf: walk type tree; gather members list E_MemberList members_list = {0}; B32 members_need_offset_sort = 0; { E_Type *root_type = e_type_from_key(scratch.arena, key); typedef struct Task Task; struct Task { Task *next; U64 base_off; E_TypeKeyList inheritance_chain; E_TypeKey type_key; E_Type *type; }; Task start_task = {0, 0, {0}, key, root_type}; Task *first_task = &start_task; Task *last_task = &start_task; for(Task *task = first_task; task != 0; task = task->next) { E_Type *type = task->type; if(type->members != 0) { U64 last_member_off = 0; for(U64 member_idx = 0; member_idx < type->count; member_idx += 1) { if(type->members[member_idx].kind == E_MemberKind_DataField) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); MemoryCopyStruct(&n->v, &type->members[member_idx]); n->v.off += task->base_off; n->v.inheritance_key_chain = task->inheritance_chain; SLLQueuePush(members_list.first, members_list.last, n); members_list.count += 1; members_need_offset_sort = members_need_offset_sort || (n->v.off < last_member_off); last_member_off = n->v.off; } else if(type->members[member_idx].kind == E_MemberKind_Base) { Task *t = push_array(scratch.arena, Task, 1); t->base_off = type->members[member_idx].off + task->base_off; t->inheritance_chain = e_type_key_list_copy(scratch.arena, &task->inheritance_chain); e_type_key_list_push(scratch.arena, &t->inheritance_chain, type->members[member_idx].type_key); t->type_key = type->members[member_idx].type_key; t->type = e_type_from_key(scratch.arena, type->members[member_idx].type_key); SLLQueuePush(first_task, last_task, t); members_need_offset_sort = 1; } } } } } //- rjf: convert to array E_MemberArray members = {0}; { members.count = members_list.count; members.v = push_array(arena, E_Member, members.count); U64 idx = 0; for(E_MemberNode *n = members_list.first; n != 0; n = n->next) { MemoryCopyStruct(&members.v[idx], &n->v); members.v[idx].name = push_str8_copy(arena, members.v[idx].name); members.v[idx].inheritance_key_chain = e_type_key_list_copy(arena, &members.v[idx].inheritance_key_chain); idx += 1; } } //- rjf: sort array by offset if needed if(members_need_offset_sort) { quick_sort(members.v, members.count, sizeof(E_Member), e_type_qsort_compare_members_offset); } //- rjf: find all padding instances typedef struct PaddingNode PaddingNode; struct PaddingNode { PaddingNode *next; U64 off; U64 size; U64 prev_member_idx; }; PaddingNode *first_padding = 0; PaddingNode *last_padding = 0; U64 padding_count = 0; if(root_type_kind == E_TypeKind_Struct || root_type_kind == E_TypeKind_Class) { for(U64 idx = 0; idx < members.count; idx += 1) { E_Member *member = &members.v[idx]; if(idx+1 < members.count) { U64 member_byte_size = e_type_byte_size_from_key(member->type_key); Rng1U64 member_byte_range = r1u64(member->off, member->off + member_byte_size); if(member[1].off > member_byte_range.max) { PaddingNode *n = push_array(scratch.arena, PaddingNode, 1); SLLQueuePush(first_padding, last_padding, n); n->off = member_byte_range.max; n->size = member[1].off - member_byte_range.max; n->prev_member_idx = idx; padding_count += 1; } } } } //- rjf: produce new members array, if we have any padding if(padding_count != 0) { E_MemberArray new_members = {0}; new_members.count = members.count + padding_count; new_members.v = push_array(arena, E_Member, new_members.count); MemoryCopy(new_members.v, members.v, sizeof(E_Member)*members.count); U64 padding_idx = 0; for(PaddingNode *n = first_padding; n != 0; n = n->next) { if(members.count+padding_idx > n->prev_member_idx+1) { MemoryCopy(new_members.v + n->prev_member_idx + padding_idx + 2, new_members.v + n->prev_member_idx + padding_idx + 1, sizeof(E_Member) * (members.count + padding_idx - (n->prev_member_idx + padding_idx + 1))); } 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->off = n->off; padding_member->name = str8_lit("padding"); padding_idx += 1; } members = new_members; } scratch_end(scratch); return members; } internal void e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 prec, B32 skip_return) { String8 keyword = {0}; E_TypeKind kind = e_type_kind_from_key(key); switch(kind) { default: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); str8_list_push(arena, out, push_str8_copy(arena, type->name)); str8_list_push(arena, out, str8_lit(" ")); scratch_end(scratch); }break; case E_TypeKind_Bitfield: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); e_type_lhs_string_from_key(arena, type->direct_type_key, out, prec, skip_return); str8_list_pushf(arena, out, ": %I64u", type->count); scratch_end(scratch); }break; case E_TypeKind_Modifier: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); E_TypeKey direct = type->direct_type_key; e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); if(type->flags & E_TypeFlag_Const) { str8_list_push(arena, out, str8_lit("const ")); } if(type->flags & E_TypeFlag_Volatile) { str8_list_push(arena, out, str8_lit("volatile ")); } scratch_end(scratch); }break; case E_TypeKind_Variadic: { str8_list_push(arena, out, str8_lit("...")); }break; case E_TypeKind_Struct: case E_TypeKind_Union: case E_TypeKind_Enum: case E_TypeKind_Class: case E_TypeKind_Alias: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); str8_list_push(arena, out, push_str8_copy(arena, type->name)); str8_list_push(arena, out, str8_lit(" ")); scratch_end(scratch); }break; case E_TypeKind_IncompleteStruct: keyword = str8_lit("struct"); goto fwd_udt; case E_TypeKind_IncompleteUnion: keyword = str8_lit("union"); goto fwd_udt; case E_TypeKind_IncompleteEnum: keyword = str8_lit("enum"); goto fwd_udt; case E_TypeKind_IncompleteClass: keyword = str8_lit("class"); goto fwd_udt; fwd_udt:; { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); str8_list_push(arena, out, keyword); str8_list_push(arena, out, str8_lit(" ")); str8_list_push(arena, out, push_str8_copy(arena, type->name)); str8_list_push(arena, out, str8_lit(" ")); scratch_end(scratch); }break; case E_TypeKind_Array: { E_TypeKey direct = e_type_direct_from_key(key); e_type_lhs_string_from_key(arena, direct, out, 2, skip_return); if(prec == 1) { str8_list_push(arena, out, str8_lit("(")); } }break; case E_TypeKind_Function: { if(!skip_return) { E_TypeKey direct = e_type_direct_from_key(key); e_type_lhs_string_from_key(arena, direct, out, 2, 0); } if(prec == 1) { str8_list_push(arena, out, str8_lit("(")); } }break; case E_TypeKind_Ptr: { E_TypeKey direct = e_type_direct_from_key(key); e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("*")); }break; case E_TypeKind_LRef: { E_TypeKey direct = e_type_direct_from_key(key); e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("&")); }break; case E_TypeKind_RRef: { E_TypeKey direct = e_type_direct_from_key(key); e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("&&")); }break; case E_TypeKind_MemberPtr: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); E_TypeKey direct = type->direct_type_key; e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); E_Type *container = e_type_from_key(scratch.arena, type->owner_type_key); if(container->kind != E_TypeKind_Null) { str8_list_push(arena, out, push_str8_copy(arena, container->name)); } else { str8_list_push(arena, out, str8_lit("")); } str8_list_push(arena, out, str8_lit("::*")); scratch_end(scratch); }break; } } internal void e_type_rhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 prec) { E_TypeKind kind = e_type_kind_from_key(key); switch(kind) { default:{}break; case E_TypeKind_Bitfield: { E_TypeKey direct = e_type_direct_from_key(key); e_type_rhs_string_from_key(arena, direct, out, prec); }break; case E_TypeKind_Modifier: case E_TypeKind_Ptr: case E_TypeKind_LRef: case E_TypeKind_RRef: case E_TypeKind_MemberPtr: { E_TypeKey direct = e_type_direct_from_key(key); e_type_rhs_string_from_key(arena, direct, out, 1); }break; case E_TypeKind_Array: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); if(prec == 1) { str8_list_push(arena, out, str8_lit(")")); } String8 count_str = str8_from_u64(arena, type->count, 10, 0, 0); str8_list_push(arena, out, str8_lit("[")); str8_list_push(arena, out, count_str); str8_list_push(arena, out, str8_lit("]")); E_TypeKey direct = e_type_direct_from_key(key); e_type_rhs_string_from_key(arena, direct, out, 2); scratch_end(scratch); }break; case E_TypeKind_Function: { Temp scratch = scratch_begin(&arena, 1); E_Type *type = e_type_from_key(scratch.arena, key); if(prec == 1) { str8_list_push(arena, out, str8_lit(")")); } if(type->count == 0) { str8_list_push(arena, out, str8_lit("(void)")); } else { str8_list_push(arena, out, str8_lit("(")); U64 param_count = type->count; E_TypeKey *param_type_keys = type->param_type_keys; for(U64 param_idx = 0; param_idx < param_count; param_idx += 1) { E_TypeKey param_type_key = param_type_keys[param_idx]; String8 param_str = e_type_string_from_key(arena, param_type_key); String8 param_str_trimmed = str8_skip_chop_whitespace(param_str); str8_list_push(arena, out, param_str_trimmed); if(param_idx+1 < param_count) { str8_list_push(arena, out, str8_lit(", ")); } } str8_list_push(arena, out, str8_lit(")")); } E_TypeKey direct = e_type_direct_from_key(key); e_type_rhs_string_from_key(arena, direct, out, 2); scratch_end(scratch); }break; } } internal String8 e_type_string_from_key(Arena *arena, E_TypeKey key) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; e_type_lhs_string_from_key(scratch.arena, key, &list, 0, 0); e_type_rhs_string_from_key(scratch.arena, key, &list, 0); String8 result = str8_list_join(arena, &list, 0); scratch_end(scratch); return result; } //- rjf: type key data structures internal void e_type_key_list_push(Arena *arena, E_TypeKeyList *list, E_TypeKey key) { E_TypeKeyNode *n = push_array(arena, E_TypeKeyNode, 1); n->v = key; SLLQueuePush(list->first, list->last, n); list->count += 1; } internal E_TypeKeyList e_type_key_list_copy(Arena *arena, E_TypeKeyList *src) { E_TypeKeyList dst = {0}; for(E_TypeKeyNode *n = src->first; n != 0; n = n->next) { e_type_key_list_push(arena, &dst, n->v); } return dst; } //////////////////////////////// //~ rjf: Parsing Functions internal E_TypeKey e_leaf_type_from_name(String8 name) { E_TypeKey key = zero_struct; B32 found = 0; for(U64 rdi_idx = 0; rdi_idx < e_state->ctx->rdis_count; rdi_idx += 1) { RDI_Parsed *rdi = e_state->ctx->rdis[rdi_idx]; RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Types); RDI_ParsedNameMap parsed_name_map = {0}; rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); if(node != 0) { U32 match_count = 0; U32 *matches = rdi_matches_from_map_node(rdi, node, &match_count); if(match_count != 0) { RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, matches[0]); found = type_node->kind != RDI_TypeKind_NULL; key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), matches[0], rdi_idx); break; } } } if(!found) { #define Case(str) (str8_match(name, str8_lit(str), 0)) if(Case("u8") || Case("uint8") || Case("uint8_t") || Case("uchar8") || Case("U8")) { key = e_type_key_basic(E_TypeKind_U8); } else if(Case("u16") || Case("uint16") || Case("uint16_t") || Case("uchar16") || Case("U16")) { key = e_type_key_basic(E_TypeKind_U16); } else if(Case("u32") || Case("uint32") || Case("uint32_t") || Case("uchar32") || Case("U32") || Case("uint")) { key = e_type_key_basic(E_TypeKind_U32); } else if(Case("u64") || Case("uint64") || Case("uint64_t") || Case("U64")) { key = e_type_key_basic(E_TypeKind_U64); } else if(Case("s8") || Case("b8") || Case("B8") || Case("i8") || Case("int8") || Case("int8_t") || Case("char8") || Case("S8")) { key = e_type_key_basic(E_TypeKind_S8); } else if(Case("s16") ||Case("b16") || Case("B16") || Case("i16") || Case("int16") || Case("int16_t") || Case("char16") || Case("S16")) { key = e_type_key_basic(E_TypeKind_S16); } else if(Case("s32") || Case("b32") || Case("B32") || Case("i32") || Case("int32") || Case("int32_t") || Case("char32") || Case("S32") || Case("int")) { key = e_type_key_basic(E_TypeKind_S32); } else if(Case("s64") || Case("b64") || Case("B64") || Case("i64") || Case("int64") || Case("int64_t") || Case("S64")) { key = e_type_key_basic(E_TypeKind_S64); } else if(Case("void")) { key = e_type_key_basic(E_TypeKind_Void); } else if(Case("bool")) { key = e_type_key_basic(E_TypeKind_Bool); } else if(Case("float") || Case("f32") || Case("F32") || Case("r32") || Case("R32")) { key = e_type_key_basic(E_TypeKind_F32); } else if(Case("double") || Case("f64") || Case("F64") || Case("r64") || Case("R64")) { key = e_type_key_basic(E_TypeKind_F64); } #undef Case } return key; } internal E_TypeKey e_type_from_expr(E_Expr *expr) { E_TypeKey result = zero_struct; E_ExprKind kind = expr->kind; switch(kind) { // TODO(rjf): do we support E_ExprKind_Func here? default:{}break; case E_ExprKind_TypeIdent: { result = expr->type_key; }break; 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); }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); }break; } return result; } internal void e_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, E_String2ExprMap *map, E_Expr *expr) { switch(expr->kind) { default: { for(E_Expr *child = expr->first; child != &e_expr_nil; child = child->next) { e_push_leaf_ident_exprs_from_expr__in_place(arena, map, child); } }break; case E_ExprKind_Define: { E_Expr *exprl = expr->first; E_Expr *exprr = exprl->next; if(exprl->kind == E_ExprKind_LeafIdent) { e_string2expr_map_insert(arena, map, exprl->string, exprr); } }break; } } internal E_Parse e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) { E_Parse parse = {0, &e_expr_nil}; E_Token *token_it = tokens->v; //- rjf: parse unsigned marker B32 unsigned_marker = 0; { E_Token token = e_token_at_it(token_it, tokens); if(token.kind == E_TokenKind_Identifier) { String8 token_string = str8_substr(text, token.range); if(str8_match(token_string, str8_lit("unsigned"), 0)) { token_it += 1; unsigned_marker = 1; } } } //- rjf: parse base type { E_Token token = e_token_at_it(token_it, tokens); if(token.kind == E_TokenKind_Identifier) { String8 token_string = str8_substr(text, token.range); E_TypeKey type_key = e_leaf_type_from_name(token_string); if(!e_type_key_match(e_type_key_zero(), type_key)) { token_it += 1; // rjf: apply unsigned marker to base type if(unsigned_marker) switch(e_type_kind_from_key(type_key)) { default:{}break; case E_TypeKind_Char8: {type_key = e_type_key_basic(E_TypeKind_UChar8);}break; case E_TypeKind_Char16:{type_key = e_type_key_basic(E_TypeKind_UChar16);}break; case E_TypeKind_Char32:{type_key = e_type_key_basic(E_TypeKind_UChar32);}break; case E_TypeKind_S8: {type_key = e_type_key_basic(E_TypeKind_U8);}break; case E_TypeKind_S16: {type_key = e_type_key_basic(E_TypeKind_U16);}break; case E_TypeKind_S32: {type_key = e_type_key_basic(E_TypeKind_U32);}break; case E_TypeKind_S64: {type_key = e_type_key_basic(E_TypeKind_U64);}break; case E_TypeKind_S128:{type_key = e_type_key_basic(E_TypeKind_U128);}break; case E_TypeKind_S256:{type_key = e_type_key_basic(E_TypeKind_U256);}break; case E_TypeKind_S512:{type_key = e_type_key_basic(E_TypeKind_U512);}break; } // rjf: construct leaf type parse.expr = e_push_expr(arena, E_ExprKind_TypeIdent, token_string.str); parse.expr->type_key = type_key; } } } //- rjf: parse extensions if(parse.expr != &e_expr_nil) { for(;;) { E_Token token = e_token_at_it(token_it, tokens); if(token.kind != E_TokenKind_Symbol) { break; } String8 token_string = str8_substr(text, token.range); if(str8_match(token_string, str8_lit("*"), 0)) { token_it += 1; E_Expr *ptee = parse.expr; parse.expr = e_push_expr(arena, E_ExprKind_Ptr, token_string.str); e_expr_push_child(parse.expr, ptee); } else { break; } } } //- rjf: fill parse & end parse.last_token = token_it; return parse; } internal E_Parse e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *tokens, S64 max_precedence) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); E_Token *it = tokens->v; E_Token *it_opl = tokens->v + tokens->count; E_Parse result = {0, &e_expr_nil}; //- rjf: parse prefix unaries typedef struct PrefixUnaryNode PrefixUnaryNode; struct PrefixUnaryNode { PrefixUnaryNode *next; E_ExprKind kind; E_Expr *cast_expr; void *location; }; PrefixUnaryNode *first_prefix_unary = 0; PrefixUnaryNode *last_prefix_unary = 0; { for(;it < it_opl;) { E_Token *start_it = it; E_Token token = e_token_at_it(it, tokens); String8 token_string = str8_substr(text, token.range); S64 prefix_unary_precedence = 0; E_ExprKind prefix_unary_kind = 0; E_Expr *cast_expr = &e_expr_nil; void *location = 0; // rjf: try op table for(U64 idx = 0; idx < ArrayCount(e_unary_prefix_op_table); idx += 1) { if(str8_match(token_string, e_unary_prefix_op_table[idx].string, 0)) { prefix_unary_precedence = e_unary_prefix_op_table[idx].precedence; prefix_unary_kind = e_unary_prefix_op_table[idx].kind; break; } } // rjf: consume valid op if(prefix_unary_precedence != 0) { location = token_string.str; it += 1; } // rjf: try casting expression if(prefix_unary_precedence == 0 && str8_match(token_string, str8_lit("("), 0)) { E_Token some_type_identifier_maybe = e_token_at_it(it+1, tokens); String8 some_type_identifier_maybe_string = str8_substr(text, some_type_identifier_maybe.range); if(some_type_identifier_maybe.kind == E_TokenKind_Identifier) { E_TypeKey type_key = e_leaf_type_from_name(some_type_identifier_maybe_string); if(!e_type_key_match(type_key, e_type_key_zero()) || str8_match(some_type_identifier_maybe_string, str8_lit("unsigned"), 0)) { // rjf: move past open paren it += 1; // rjf: parse type expr E_TokenArray type_parse_tokens = e_token_array_make_first_opl(it, it_opl); E_Parse type_parse = e_parse_type_from_text_tokens(arena, text, &type_parse_tokens); E_Expr *type = type_parse.expr; e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); it = type_parse.last_token; location = token_string.str; // rjf: expect ) E_Token close_paren_maybe = e_token_at_it(it, tokens); String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing )."); } // rjf: consume ) else { it += 1; } // rjf: fill prefix_unary_precedence = 2; prefix_unary_kind = E_ExprKind_Cast; cast_expr = type; } } } // rjf: break if we got no operators if(prefix_unary_precedence == 0) { break; } // rjf: break if the token node iterator has not changed if(it == start_it) { break; } // rjf: push prefix unary if we got one { PrefixUnaryNode *op_n = push_array(scratch.arena, PrefixUnaryNode, 1); op_n->kind = prefix_unary_kind; op_n->cast_expr = cast_expr; op_n->location = location; SLLQueuePushFront(first_prefix_unary, last_prefix_unary, op_n); } } } //- rjf: parse atom E_Expr *atom = &e_expr_nil; String8 atom_implicit_member_name = {0}; if(it < it_opl) { E_Token token = e_token_at_it(it, tokens); String8 token_string = str8_substr(text, token.range); //- rjf: descent to nested expression if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("("), 0)) { // rjf: skip ( it += 1; // rjf: parse () contents E_TokenArray nested_parse_tokens = e_token_array_make_first_opl(it, it_opl); E_Parse nested_parse = e_parse_expr_from_text_tokens__prec(arena, text, &nested_parse_tokens, e_max_precedence); e_msg_list_concat_in_place(&result.msgs, &nested_parse.msgs); atom = nested_parse.expr; it = nested_parse.last_token; // rjf: expect ) E_Token close_paren_maybe = e_token_at_it(it, tokens); String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing )."); } // rjf: consume ) else { it += 1; } } //- rjf: descent to assembly-style dereference sub-expression else if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("["), 0)) { // rjf: skip [ it += 1; // rjf: parse [] contents E_TokenArray nested_parse_tokens = e_token_array_make_first_opl(it, it_opl); E_Parse nested_parse = e_parse_expr_from_text_tokens__prec(arena, text, &nested_parse_tokens, e_max_precedence); e_msg_list_concat_in_place(&result.msgs, &nested_parse.msgs); atom = nested_parse.expr; it = nested_parse.last_token; // 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); E_Expr *casted = atom; E_Expr *cast = e_push_expr(arena, E_ExprKind_Cast, token_string.str); e_expr_push_child(cast, type); e_expr_push_child(cast, casted); atom = e_push_expr(arena, E_ExprKind_Deref, token_string.str); e_expr_push_child(atom, cast); // rjf: expect ] E_Token close_paren_maybe = e_token_at_it(it, tokens); String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit("]"), 0)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing ]."); } // rjf: consume ) else { it += 1; } } //- rjf: leaf (identifier, literal) else if(token.kind != E_TokenKind_Symbol) { switch(token.kind) { //- rjf: identifier => name resolution default: case E_TokenKind_Identifier: { B32 mapped_identifier = 0; B32 identifier_type_is_possibly_dynamically_overridden = 0; B32 identifier_looks_like_type_expr = 0; RDI_LocationKind loc_kind = RDI_LocationKind_NULL; RDI_LocationReg loc_reg = {0}; RDI_LocationRegPlusU16 loc_reg_u16 = {0}; String8 loc_bytecode = {0}; REGS_RegCode reg_code = 0; REGS_AliasCode alias_code = 0; E_TypeKey type_key = zero_struct; String8 local_lookup_string = token_string; //- rjf: form namespaceified fallback versions of this lookup string String8List namespaceified_token_strings = {0}; { U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(e_state->ctx->rdis[0], RDI_SectionKind_ScopeVMap, e_state->ctx->ip_voff); RDI_Scope *scope = rdi_element_from_name_idx(e_state->ctx->rdis[0], Scopes, scope_idx); U64 proc_idx = scope->proc_idx; RDI_Procedure *procedure = rdi_element_from_name_idx(e_state->ctx->rdis[0], Procedures, proc_idx); U64 name_size = 0; U8 *name_ptr = rdi_string_from_idx(e_state->ctx->rdis[0], procedure->name_string_idx, &name_size); String8 containing_procedure_name = str8(name_ptr, name_size); U64 last_past_scope_resolution_pos = 0; for(;;) { U64 past_next_dbl_colon_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("::"), 0)+2; U64 past_next_dot_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("."), 0)+1; U64 past_next_scope_resolution_pos = Min(past_next_dbl_colon_pos, past_next_dot_pos); if(past_next_scope_resolution_pos >= containing_procedure_name.size) { break; } String8 new_namespace_prefix_possibility = str8_prefix(containing_procedure_name, past_next_scope_resolution_pos); String8 namespaceified_token_string = push_str8f(scratch.arena, "%S%S", new_namespace_prefix_possibility, token_string); str8_list_push_front(scratch.arena, &namespaceified_token_strings, namespaceified_token_string); last_past_scope_resolution_pos = past_next_scope_resolution_pos; } } //- rjf: try members if(mapped_identifier == 0) { U64 data_member_num = e_num_from_string(e_state->ctx->member_map, token_string); if(data_member_num != 0) { atom_implicit_member_name = token_string; local_lookup_string = str8_lit("this"); } } //- rjf: try locals if(mapped_identifier == 0) { U64 local_num = e_num_from_string(e_state->ctx->locals_map, local_lookup_string); if(local_num != 0) { mapped_identifier = 1; identifier_type_is_possibly_dynamically_overridden = 1; RDI_Local *local_var = rdi_element_from_name_idx(e_state->ctx->rdis[0], Locals, local_num-1); RDI_TypeNode *type_node = rdi_element_from_name_idx(e_state->ctx->rdis[0], TypeNodes, local_var->type_idx); type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local_var->type_idx, 0); // rjf: grab location info for(U32 loc_block_idx = local_var->location_first; loc_block_idx < local_var->location_opl; loc_block_idx += 1) { RDI_LocationBlock *block = rdi_element_from_name_idx(e_state->ctx->rdis[0], LocationBlocks, loc_block_idx); if(block->scope_off_first <= e_state->ctx->ip_voff && e_state->ctx->ip_voff < block->scope_off_opl) { U64 all_location_data_size = 0; U8 *all_location_data = rdi_table_from_name(e_state->ctx->rdis[0], LocationData, &all_location_data_size); loc_kind = *((RDI_LocationKind *)(all_location_data + block->location_data_off)); switch(loc_kind) { default:{mapped_identifier = 0;}break; case RDI_LocationKind_AddrBytecodeStream: case RDI_LocationKind_ValBytecodeStream: { U8 *bytecode_base = all_location_data + block->location_data_off + sizeof(RDI_LocationKind); U64 bytecode_size = 0; for(U64 idx = 0; idx < all_location_data_size; idx += 1) { U8 op = bytecode_base[idx]; if(op == 0) { break; } U8 ctrlbits = rdi_eval_op_ctrlbits_table[op]; U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); bytecode_size += 1+p_size; } loc_bytecode = str8(bytecode_base, bytecode_size); }break; case RDI_LocationKind_AddrRegPlusU16: case RDI_LocationKind_AddrAddrRegPlusU16: { MemoryCopy(&loc_reg_u16, (all_location_data + block->location_data_off), sizeof(loc_reg_u16)); }break; case RDI_LocationKind_ValReg: { MemoryCopy(&loc_reg, (all_location_data + block->location_data_off), sizeof(loc_reg)); }break; } } } } } //- rjf: try registers if(mapped_identifier == 0) { U64 reg_num = e_num_from_string(e_state->ctx->regs_map, token_string); if(reg_num != 0) { reg_code = reg_num; mapped_identifier = 1; type_key = e_type_key_reg(e_state->ctx->arch, reg_code); } } //- rjf: try register aliases if(mapped_identifier == 0) { U64 alias_num = e_num_from_string(e_state->ctx->reg_alias_map, token_string); if(alias_num != 0) { alias_code = (REGS_AliasCode)alias_num; type_key = e_type_key_reg_alias(e_state->ctx->arch, alias_code); mapped_identifier = 1; } } //- rjf: try global variables if(mapped_identifier == 0) { for(U64 rdi_idx = 0; rdi_idx < e_state->ctx->rdis_count; rdi_idx += 1) { RDI_Parsed *rdi = e_state->ctx->rdis[rdi_idx]; RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables); RDI_ParsedNameMap parsed_name_map = {0}; rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, token_string.str, token_string.size); U32 matches_count = 0; U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); for(String8Node *n = namespaceified_token_strings.first; n != 0 && matches_count == 0; n = n->next) { node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); matches_count = 0; matches = rdi_matches_from_map_node(rdi, node, &matches_count); } if(matches_count != 0) { // NOTE(rjf): apparently, PDBs can be produced such that they // also keep stale *GLOBAL VARIABLE SYMBOLS* around too. I // don't know of a magic hash table fixup path in PDBs, so // in this case, I'm going to prefer the latest-added global. U32 match_idx = matches[matches_count-1]; RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, match_idx); E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_ModuleOff, global_var->voff); loc_kind = RDI_LocationKind_AddrBytecodeStream; loc_bytecode = e_bytecode_from_oplist(arena, &oplist); U32 type_idx = global_var->type_idx; RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)rdi_idx); mapped_identifier = 1; break; } } } //- rjf: try thread variables if(mapped_identifier == 0) { for(U64 rdi_idx = 0; rdi_idx < e_state->ctx->rdis_count; rdi_idx += 1) { RDI_Parsed *rdi = e_state->ctx->rdis[rdi_idx]; RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_ThreadVariables); RDI_ParsedNameMap parsed_name_map = {0}; rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, token_string.str, token_string.size); U32 matches_count = 0; U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); for(String8Node *n = namespaceified_token_strings.first; n != 0 && matches_count == 0; n = n->next) { node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); matches_count = 0; matches = rdi_matches_from_map_node(rdi, node, &matches_count); } if(matches_count != 0) { U32 match_idx = matches[0]; RDI_ThreadVariable *thread_var = rdi_element_from_name_idx(rdi, ThreadVariables, match_idx); E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, thread_var->tls_off); loc_kind = RDI_LocationKind_AddrBytecodeStream; loc_bytecode = e_bytecode_from_oplist(arena, &oplist); U32 type_idx = thread_var->type_idx; RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)rdi_idx); mapped_identifier = 1; break; } } } //- rjf: try procedures if(mapped_identifier == 0) { for(U64 rdi_idx = 0; rdi_idx < e_state->ctx->rdis_count; rdi_idx += 1) { RDI_Parsed *rdi = e_state->ctx->rdis[rdi_idx]; RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); RDI_ParsedNameMap parsed_name_map = {0}; rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, token_string.str, token_string.size); U32 matches_count = 0; U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); for(String8Node *n = namespaceified_token_strings.first; n != 0 && matches_count == 0; n = n->next) { node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); matches_count = 0; matches = rdi_matches_from_map_node(rdi, node, &matches_count); } if(matches_count != 0) { U32 match_idx = matches[0]; RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match_idx); RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx); U64 voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first); E_OpList oplist = {0}; e_oplist_push_op(arena, &oplist, RDI_EvalOp_ModuleOff, voff); loc_kind = RDI_LocationKind_ValBytecodeStream; loc_bytecode = e_bytecode_from_oplist(arena, &oplist); U32 type_idx = procedure->type_idx; RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)rdi_idx); mapped_identifier = 1; break; } } } //- rjf: try types if(mapped_identifier == 0) { type_key = e_leaf_type_from_name(token_string); if(!e_type_key_match(e_type_key_zero(), type_key)) { mapped_identifier = 1; identifier_looks_like_type_expr = 1; } } //- rjf: attach on map if(mapped_identifier != 0) { it += 1; // rjf: build atom switch(loc_kind) { default: { if(identifier_looks_like_type_expr) { E_TokenArray type_parse_tokens = e_token_array_make_first_opl(it-1, it_opl); E_Parse type_parse = e_parse_type_from_text_tokens(arena, text, &type_parse_tokens); E_Expr *type = type_parse.expr; e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); it = type_parse.last_token; atom = type; } else if(reg_code != 0) { REGS_Rng reg_rng = regs_reg_code_rng_table_from_architecture(e_state->ctx->arch)[reg_code]; E_OpList oplist = {0}; e_oplist_push_uconst(arena, &oplist, reg_rng.byte_off); atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Reg; atom->type_key = type_key; atom->string = e_bytecode_from_oplist(arena, &oplist); } else if(alias_code != 0) { REGS_Slice alias_slice = regs_alias_code_slice_table_from_architecture(e_state->ctx->arch)[alias_code]; REGS_Rng alias_reg_rng = regs_reg_code_rng_table_from_architecture(e_state->ctx->arch)[alias_slice.code]; E_OpList oplist = {0}; e_oplist_push_uconst(arena, &oplist, alias_reg_rng.byte_off + alias_slice.byte_off); atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Reg; atom->type_key = type_key; atom->string = e_bytecode_from_oplist(arena, &oplist); } else { e_msgf(arena, &result.msgs, E_MsgKind_MissingInfo, token_string.str, "Missing location information for \"%S\".", token_string); } }break; case RDI_LocationKind_AddrBytecodeStream: { atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Addr; atom->type_key = type_key; atom->string = loc_bytecode; }break; case RDI_LocationKind_ValBytecodeStream: { atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Value; atom->type_key = type_key; atom->string = loc_bytecode; }break; case RDI_LocationKind_AddrRegPlusU16: { E_OpList oplist = {0}; U64 byte_size = bit_size_from_arch(e_state->ctx->arch)/8; U64 regread_param = RDI_EncodeRegReadParam(loc_reg_u16.reg_code, byte_size, 0); e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, regread_param); e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, loc_reg_u16.offset); e_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, 0); atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Addr; atom->type_key = type_key; atom->string = e_bytecode_from_oplist(arena, &oplist); }break; case RDI_LocationKind_AddrAddrRegPlusU16: { E_OpList oplist = {0}; U64 byte_size = bit_size_from_arch(e_state->ctx->arch)/8; U64 regread_param = RDI_EncodeRegReadParam(loc_reg_u16.reg_code, byte_size, 0); e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, regread_param); e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, loc_reg_u16.offset); e_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, 0); e_oplist_push_op(arena, &oplist, RDI_EvalOp_MemRead, bit_size_from_arch(e_state->ctx->arch)/8); atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Addr; atom->type_key = type_key; atom->string = e_bytecode_from_oplist(arena, &oplist); }break; case RDI_LocationKind_ValReg: { REGS_RegCode regs_reg_code = regs_reg_code_from_arch_rdi_code(e_state->ctx->arch, loc_reg.reg_code); REGS_Rng reg_rng = regs_reg_code_rng_table_from_architecture(e_state->ctx->arch)[regs_reg_code]; E_OpList oplist = {0}; U64 byte_size = (U64)reg_rng.byte_size; U64 byte_pos = 0; U64 regread_param = RDI_EncodeRegReadParam(loc_reg.reg_code, byte_size, byte_pos); e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, regread_param); atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); atom->mode = E_Mode_Value; atom->type_key = type_key; atom->string = e_bytecode_from_oplist(arena, &oplist); }break; } // rjf: implicit local lookup -> attach member access node if(atom_implicit_member_name.size != 0) { E_Expr *member_container = atom; E_Expr *member_expr = e_push_expr(arena, E_ExprKind_LeafMember, atom_implicit_member_name.str); member_expr->string = atom_implicit_member_name; atom = e_push_expr(arena, E_ExprKind_MemberAccess, atom_implicit_member_name.str); e_expr_push_child(atom, member_container); e_expr_push_child(atom, member_expr); } } //- rjf: map failure -> attach as leaf identifier, to be resolved later if(!mapped_identifier) { atom = e_push_expr(arena, E_ExprKind_LeafIdent, token_string.str); atom->string = token_string; it += 1; } }break; //- rjf: numeric => directly extract value case E_TokenKind_Numeric: { U64 dot_pos = str8_find_needle(token_string, 0, str8_lit("."), 0); it += 1; // rjf: no . => integral if(dot_pos == token_string.size) { U64 val = 0; try_u64_from_str8_c_rules(token_string, &val); atom = e_push_expr(arena, E_ExprKind_LeafU64, token_string.str); atom->u64 = val; break; } // rjf: presence of . => double or float if(dot_pos < token_string.size) { F64 val = f64_from_str8(token_string); U64 f_pos = str8_find_needle(token_string, 0, str8_lit("f"), StringMatchFlag_CaseInsensitive); // rjf: presence of f after . => f32 if(f_pos < token_string.size) { atom = e_push_expr(arena, E_ExprKind_LeafF32, token_string.str); atom->f32 = (F32)val; } // rjf: no f => f64 else { atom = e_push_expr(arena, E_ExprKind_LeafF64, token_string.str); atom->f64 = val; } } }break; //- rjf: char => extract char value case E_TokenKind_CharLiteral: { it += 1; if(token_string.size > 1 && token_string.str[0] == '\'' && token_string.str[1] != '\'') { U8 char_val = token_string.str[1]; atom = e_push_expr(arena, E_ExprKind_LeafU64, token_string.str); atom->u64 = (U64)char_val; } else { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Malformed character literal."); } }break; // rjf: string => leaf string literal case E_TokenKind_StringLiteral: { String8 string_value_escaped = str8_chop(str8_skip(token_string, 1), 1); atom = e_push_expr(arena, E_ExprKind_LeafStringLiteral, token_string.str); atom->string = string_value_escaped; it += 1; }break; } } } //- rjf: upgrade atom w/ postfix unaries if(atom != &e_expr_nil) for(;it < it_opl;) { E_Token token = e_token_at_it(it, tokens); String8 token_string = str8_substr(text, token.range); B32 is_postfix_unary = 0; // rjf: dot/arrow operator if(token.kind == E_TokenKind_Symbol && (str8_match(token_string, str8_lit("."), 0) || str8_match(token_string, str8_lit("->"), 0))) { is_postfix_unary = 1; // rjf: advance past operator it += 1; // rjf: expect member name String8 member_name = {0}; B32 good_member_name = 0; { E_Token member_name_maybe = e_token_at_it(it, tokens); String8 member_name_maybe_string = str8_substr(text, member_name_maybe.range); if(member_name_maybe.kind != E_TokenKind_Identifier) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected member name after %S.", token_string); } else { member_name = member_name_maybe_string; good_member_name = 1; } } // rjf: produce lookup member expr if(good_member_name) { E_Expr *member_container = atom; E_Expr *member_expr = e_push_expr(arena, E_ExprKind_LeafMember, member_name.str); member_expr->string = member_name; atom = e_push_expr(arena, E_ExprKind_MemberAccess, token_string.str); e_expr_push_child(atom, member_container); e_expr_push_child(atom, member_expr); } // rjf: increment past good member names if(good_member_name) { it += 1; } } // rjf: array index if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("["), 0)) { is_postfix_unary = 1; // rjf: advance past [ it += 1; // rjf: parse indexing expression E_TokenArray idx_expr_parse_tokens = e_token_array_make_first_opl(it, it_opl); E_Parse idx_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &idx_expr_parse_tokens, e_max_precedence); e_msg_list_concat_in_place(&result.msgs, &idx_expr_parse.msgs); it = idx_expr_parse.last_token; // rjf: valid indexing expression => produce index expr if(idx_expr_parse.expr != &e_expr_nil) { E_Expr *array_expr = atom; E_Expr *index_expr = idx_expr_parse.expr; atom = e_push_expr(arena, E_ExprKind_ArrayIndex, token_string.str); e_expr_push_child(atom, array_expr); e_expr_push_child(atom, index_expr); } // rjf: expect ] { E_Token close_brace_maybe = e_token_at_it(it, tokens); String8 close_brace_maybe_string = str8_substr(text, close_brace_maybe.range); if(close_brace_maybe.kind != E_TokenKind_Symbol || !str8_match(close_brace_maybe_string, str8_lit("]"), 0)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Unclosed [."); } else { it += 1; } } } // rjf: quit if this doesn't look like any patterns of postfix unary we know if(!is_postfix_unary) { break; } } //- rjf: upgrade atom w/ previously parsed prefix unaries if(atom == &e_expr_nil && first_prefix_unary != 0 && first_prefix_unary->cast_expr != 0) { atom = first_prefix_unary->cast_expr; for(PrefixUnaryNode *prefix_unary = first_prefix_unary->next; prefix_unary != 0; prefix_unary = prefix_unary->next) { E_Expr *rhs = atom; atom = e_push_expr(arena, prefix_unary->kind, prefix_unary->location); if(prefix_unary->cast_expr != &e_expr_nil) { e_expr_push_child(atom, prefix_unary->cast_expr); } e_expr_push_child(atom, rhs); } } else if(atom == 0 && first_prefix_unary != 0) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, last_prefix_unary->location, "Missing expression."); } else { for(PrefixUnaryNode *prefix_unary = first_prefix_unary; prefix_unary != 0; prefix_unary = prefix_unary->next) { E_Expr *rhs = atom; atom = e_push_expr(arena, prefix_unary->kind, prefix_unary->location); if(prefix_unary->cast_expr != &e_expr_nil) { e_expr_push_child(atom, prefix_unary->cast_expr); } e_expr_push_child(atom, rhs); } } //- rjf: parse complex operators if(atom != &e_expr_nil) for(;it < it_opl;) { E_Token *start_it = it; E_Token token = e_token_at_it(it, tokens); String8 token_string = str8_substr(text, token.range); //- rjf: parse binaries { // rjf: first try to find a matching binary operator S64 binary_precedence = 0; E_ExprKind binary_kind = 0; for(U64 idx = 0; idx < ArrayCount(e_binary_op_table); idx += 1) { if(str8_match(token_string, e_binary_op_table[idx].string, 0)) { binary_precedence = e_binary_op_table[idx].precedence; binary_kind = e_binary_op_table[idx].kind; break; } } // rjf: if we got a valid binary precedence, and it's not to be handled by // a caller, then we need to parse the right-hand-side with a tighter // precedence if(binary_precedence != 0 && binary_precedence <= max_precedence) { E_TokenArray rhs_expr_parse_tokens = e_token_array_make_first_opl(it+1, it_opl); E_Parse rhs_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &rhs_expr_parse_tokens, binary_precedence-1); e_msg_list_concat_in_place(&result.msgs, &rhs_expr_parse.msgs); E_Expr *rhs = rhs_expr_parse.expr; it = rhs_expr_parse.last_token; if(rhs == &e_expr_nil) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing right-hand-side of %S.", token_string); } else { E_Expr *lhs = atom; atom = e_push_expr(arena, binary_kind, token_string.str); e_expr_push_child(atom, lhs); e_expr_push_child(atom, rhs); } } } //- rjf: parse ternaries { if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("?"), 0) && 13 <= max_precedence) { // rjf: parse middle expression E_TokenArray middle_expr_tokens = e_token_array_make_first_opl(it, it_opl); E_Parse middle_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &middle_expr_tokens, e_max_precedence); it = middle_expr_parse.last_token; E_Expr *middle_expr = middle_expr_parse.expr; e_msg_list_concat_in_place(&result.msgs, &middle_expr_parse.msgs); if(middle_expr_parse.expr == &e_expr_nil) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected expression after ?."); } // rjf: expect : B32 got_colon = 0; E_Token colon_token = zero_struct; String8 colon_token_string = {0}; { E_Token colon_token_maybe = e_token_at_it(it, tokens); String8 colon_token_maybe_string = str8_substr(text, colon_token_maybe.range); if(colon_token_maybe.kind != E_TokenKind_Symbol || !str8_match(colon_token_maybe_string, str8_lit(":"), 0)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected : after ?."); } else { got_colon = 1; colon_token = colon_token_maybe; colon_token_string = colon_token_maybe_string; it += 1; } } // rjf: parse rhs E_TokenArray rhs_expr_parse_tokens = e_token_array_make_first_opl(it, it_opl); E_Parse rhs_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &rhs_expr_parse_tokens, e_max_precedence); if(got_colon) { it = rhs_expr_parse.last_token; e_msg_list_concat_in_place(&result.msgs, &rhs_expr_parse.msgs); if(rhs_expr_parse.expr == &e_expr_nil) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, colon_token_string.str, "Expected expression after :."); } } // rjf: build ternary { E_Expr *lhs = atom; E_Expr *mhs = middle_expr_parse.expr; E_Expr *rhs = rhs_expr_parse.expr; atom = e_push_expr(arena, E_ExprKind_Ternary, token_string.str); e_expr_push_child(atom, lhs); e_expr_push_child(atom, mhs); e_expr_push_child(atom, rhs); } } } // rjf: if we parsed nothing successfully, we're done if(it == start_it) { break; } } //- rjf: fill result & return result.last_token = it; result.expr = atom; scratch_end(scratch); ProfEnd(); return result; } internal E_Parse e_parse_expr_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) { E_Parse parse = e_parse_expr_from_text_tokens__prec(arena, text, tokens, e_max_precedence); return parse; } //////////////////////////////// //~ rjf: IR-ization Functions //- rjf: op list functions internal void e_oplist_push_op(Arena *arena, E_OpList *list, RDI_EvalOp opcode, U64 p) { U8 ctrlbits = rdi_eval_op_ctrlbits_table[opcode]; U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); E_Op *node = push_array_no_zero(arena, E_Op, 1); node->opcode = opcode; node->p = p; SLLQueuePush(list->first, list->last, node); list->op_count += 1; list->encoded_size += 1 + p_size; } internal void e_oplist_push_uconst(Arena *arena, E_OpList *list, U64 x) { if(0){} else if(x <= 0xFF) { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU8, x); } else if(x <= 0xFFFF) { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU16, x); } else if(x <= 0xFFFFFFFF) { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU32, x); } else { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU64, x); } } internal void e_oplist_push_sconst(Arena *arena, E_OpList *list, S64 x) { if(-0x80 <= x && x <= 0x7F) { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU8, (U64)x); e_oplist_push_op(arena, list, RDI_EvalOp_TruncSigned, 8); } else if(-0x8000 <= x && x <= 0x7FFF) { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU16, (U64)x); e_oplist_push_op(arena, list, RDI_EvalOp_TruncSigned, 16); } else if(-0x80000000ll <= x && x <= 0x7FFFFFFFll) { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU32, (U64)x); e_oplist_push_op(arena, list, RDI_EvalOp_TruncSigned, 32); } else { e_oplist_push_op(arena, list, RDI_EvalOp_ConstU64, (U64)x); } } internal void e_oplist_push_bytecode(Arena *arena, E_OpList *list, String8 bytecode) { E_Op *node = push_array_no_zero(arena, E_Op, 1); node->opcode = E_IRExtKind_Bytecode; node->bytecode = bytecode; SLLQueuePush(list->first, list->last, node); list->op_count += 1; list->encoded_size += bytecode.size; } internal void e_oplist_concat_in_place(E_OpList *dst, E_OpList *to_push) { if(to_push->first && dst->first) { to_push->last->next = dst->first; to_push->last = dst->last; to_push->op_count += to_push->op_count; to_push->encoded_size += to_push->encoded_size; } else if(dst->first) { MemoryCopyStruct(dst, to_push); } MemoryZeroStruct(to_push); } //- rjf: ir tree core building helpers internal E_IRNode * e_push_irnode(Arena *arena, RDI_EvalOp op) { E_IRNode *n = push_array(arena, E_IRNode, 1); n->first = n->last = n->next = &e_irnode_nil; n->op = op; return n; } internal void e_irnode_push_child(E_IRNode *parent, E_IRNode *child) { SLLQueuePush_NZ(&e_irnode_nil, parent->first, parent->last, child, next); } //- rjf: ir subtree building helpers internal E_IRNode * e_irtree_const_u(Arena *arena, U64 v) { // rjf: choose op RDI_EvalOp op = RDI_EvalOp_ConstU64; if (v < 0x100) { op = RDI_EvalOp_ConstU8; } else if(v < 0x10000) { op = RDI_EvalOp_ConstU16; } else if(v < 0x100000000) { op = RDI_EvalOp_ConstU32; } // rjf: build E_IRNode *n = e_push_irnode(arena, op); n->u64 = v; return n; } internal E_IRNode * e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *c) { E_IRNode *n = e_push_irnode(arena, op); n->u64 = group; e_irnode_push_child(n, c); return n; } internal E_IRNode * e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *l, E_IRNode *r) { E_IRNode *n = e_push_irnode(arena, op); n->u64 = group; e_irnode_push_child(n, l); e_irnode_push_child(n, r); return n; } internal E_IRNode * e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, E_IRNode *l, E_IRNode *r) { E_IRNode *n = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, l, r); return n; } internal E_IRNode * e_irtree_conditional(Arena *arena, E_IRNode *c, E_IRNode *l, E_IRNode *r) { E_IRNode *n = e_push_irnode(arena, RDI_EvalOp_Cond); e_irnode_push_child(n, c); e_irnode_push_child(n, l); e_irnode_push_child(n, r); return n; } internal E_IRNode * e_irtree_bytecode_no_copy(Arena *arena, String8 bytecode) { E_IRNode *n = e_push_irnode(arena, E_IRExtKind_Bytecode); n->bytecode = bytecode; return n; } internal E_IRNode * e_irtree_string_literal(Arena *arena, String8 string) { E_IRNode *root = &e_irnode_nil; for(U64 idx = 0, advance = 0; idx < string.size; idx += advance) { U64 bytes_left = string.size-idx; U64 bytes_to_encode = 0; RDI_EvalOp opcode = 0; switch(bytes_left%8) { default: case 1:{opcode = RDI_EvalOp_ConstU8; bytes_to_encode = 1;}break; case 2:{opcode = RDI_EvalOp_ConstU16; bytes_to_encode = 2;}break; case 3: case 4:{opcode = RDI_EvalOp_ConstU32; bytes_to_encode = 4;}break; case 5: case 6: case 7: case 8:{opcode = RDI_EvalOp_ConstU64; bytes_to_encode = 8;}break; } U64 value = 0; MemoryCopy(&value, string.str+idx, bytes_to_encode); E_IRNode *old_root = root; root = e_push_irnode(arena, opcode); root->u64 = value; if(old_root != &e_irnode_nil) { e_irnode_push_child(root, old_root); } advance = bytes_to_encode; } return root; } internal E_IRNode * e_irtree_mem_read_type(Arena *arena, E_IRNode *c, E_TypeKey type_key) { U64 byte_size = e_type_byte_size_from_key(type_key); E_IRNode *result = &e_irnode_nil; if(0 < byte_size && byte_size <= 8) { // rjf: build the read node E_IRNode *read_node = e_push_irnode(arena, RDI_EvalOp_MemRead); read_node->u64 = byte_size; e_irnode_push_child(read_node, c); // rjf: build a signed trunc node if needed U64 bit_size = byte_size << 3; E_IRNode *with_trunc = read_node; E_TypeKind kind = e_type_kind_from_key(type_key); if(bit_size < 64 && e_type_kind_is_signed(kind)) { with_trunc = e_push_irnode(arena, RDI_EvalOp_TruncSigned); with_trunc->u64 = bit_size; e_irnode_push_child(with_trunc, read_node); } // rjf: fill result = with_trunc; } else { // TODO(rjf): unexpected path } return result; } internal E_IRNode * e_irtree_convert_lo(Arena *arena, E_IRNode *c, RDI_EvalTypeGroup out, RDI_EvalTypeGroup in) { E_IRNode *n = e_push_irnode(arena, RDI_EvalOp_Convert); n->u64 = in | (out << 8); e_irnode_push_child(n, c); return n; } internal E_IRNode * e_irtree_trunc(Arena *arena, E_IRNode *c, E_TypeKey type_key) { E_IRNode *result = c; U64 byte_size = e_type_byte_size_from_key(type_key); if(byte_size < 64) { RDI_EvalOp op = RDI_EvalOp_Trunc; E_TypeKind kind = e_type_kind_from_key(type_key); if(e_type_kind_is_signed(kind)) { op = RDI_EvalOp_TruncSigned; } U64 bit_size = byte_size << 3; result = e_push_irnode(arena, op); result->u64 = bit_size; e_irnode_push_child(result, c); } return result; } internal E_IRNode * e_irtree_convert_hi(Arena *arena, E_IRNode *c, E_TypeKey out, E_TypeKey in) { E_IRNode *result = c; E_TypeKind in_kind = e_type_kind_from_key(in); E_TypeKind out_kind = e_type_kind_from_key(out); U8 in_group = e_type_group_from_kind(in_kind); U8 out_group = e_type_group_from_kind(out_kind); U32 conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group); if(conversion_rule == RDI_EvalConversionKind_Legal) { result = e_irtree_convert_lo(arena, result, out_group, in_group); } U64 in_byte_size = e_type_byte_size_from_key(in); U64 out_byte_size = e_type_byte_size_from_key(out); if(out_byte_size < in_byte_size && e_type_kind_is_integer(out_kind)) { result = e_irtree_trunc(arena, result, out); } return result; } internal E_IRNode * e_irtree_resolve_to_value(Arena *arena, E_Mode from_mode, E_IRNode *tree, E_TypeKey type_key) { E_IRNode *result = tree; switch(from_mode) { default:{}break; case E_Mode_Addr: { result = e_irtree_mem_read_type(arena, tree, type_key); }break; case E_Mode_Reg: { result = e_irtree_unary_op(arena, RDI_EvalOp_RegReadDyn, RDI_EvalTypeGroup_U, tree); }break; } return result; } //- rjf: top-level irtree/type extraction internal E_IRTreeAndType e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) { E_IRTreeAndType result = {&e_irnode_nil}; E_ExprKind kind = expr->kind; switch(kind) { default: { }break; //- rjf: array indices case E_ExprKind_ArrayIndex: { // rjf: unpack left/right expressions E_Expr *exprl = expr->first; E_Expr *exprr = exprl->next; E_IRTreeAndType l = e_irtree_and_type_from_expr(arena, exprl); E_IRTreeAndType r = e_irtree_and_type_from_expr(arena, exprr); E_TypeKey l_restype = e_type_unwrap(l.type_key); E_TypeKey r_restype = e_type_unwrap(r.type_key); E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); E_TypeKind r_restype_kind = e_type_kind_from_key(r_restype); if(e_type_kind_is_basic_or_enum(r_restype_kind)) { r_restype = e_type_unwrap_enum(r_restype); r_restype_kind = e_type_kind_from_key(r_restype); } E_TypeKey direct_type = e_type_unwrap(l_restype); direct_type = e_type_direct_from_key(direct_type); direct_type = e_type_unwrap(direct_type); U64 direct_type_size = e_type_byte_size_from_key(direct_type); e_msg_list_concat_in_place(&result.msgs, &l.msgs); e_msg_list_concat_in_place(&result.msgs, &r.msgs); // rjf: bad conditions? -> error if applicable, exit if(l.root->op == 0 || r.root->op == 0) { break; } else if(l_restype_kind != E_TypeKind_Ptr && l_restype_kind != E_TypeKind_Array) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot index into this type."); break; } else if(!e_type_kind_is_integer(r_restype_kind)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index with this type."); break; } else if(l_restype_kind == E_TypeKind_Ptr && direct_type_size == 0) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index into pointers of zero-sized types."); break; } else if(l_restype_kind == E_TypeKind_Array && direct_type_size == 0) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index into arrays of zero-sized types."); break; } // rjf: generate { // rjf: ops to compute the index E_IRNode *index_tree = e_irtree_resolve_to_value(arena, r.mode, r.root, r_restype); if(direct_type_size > 1) { E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); index_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, index_tree, const_tree); } // rjf: ops to compute the base address (resolve to value if addr-of-pointer) E_IRNode *base_tree = l.root; if(l_restype_kind == E_TypeKind_Ptr && l.mode != E_Mode_Value) { base_tree = e_irtree_resolve_to_value(arena, l.mode, base_tree, l_restype); } // rjf: ops to compute the final address E_IRNode *new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, index_tree, base_tree); // rjf: fill result.root = new_tree; result.type_key = direct_type; result.mode = E_Mode_Addr; } }break; //- rjf: member accesses case E_ExprKind_MemberAccess: { // rjf: unpack left/right expressions E_Expr *exprl = expr->first; E_Expr *exprr = exprl->next; E_IRTreeAndType l = e_irtree_and_type_from_expr(arena, exprl); E_TypeKey l_restype = e_type_unwrap(l.type_key); E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); E_TypeKey check_type_key = l_restype; E_TypeKind check_type_kind = l_restype_kind; if(l_restype_kind == E_TypeKind_Ptr || l_restype_kind == E_TypeKind_LRef || l_restype_kind == E_TypeKind_RRef) { check_type_key = e_type_unwrap(l_restype); check_type_kind = e_type_kind_from_key(check_type_key); } e_msg_list_concat_in_place(&result.msgs, &l.msgs); // rjf: look up member B32 r_found = 0; E_TypeKey r_type = zero_struct; U32 r_off = 0; { Temp scratch = scratch_begin(&arena, 1); E_MemberArray check_type_members = e_type_data_members_from_key(scratch.arena, check_type_key); E_Member *match = 0; for(U64 member_idx = 0; member_idx < check_type_members.count; member_idx += 1) { E_Member *member = &check_type_members.v[member_idx]; if(str8_match(member->name, exprr->string, 0)) { match = member; break; } else if(str8_match(member->name, exprr->string, StringMatchFlag_CaseInsensitive)) { match = member; } } if(match != 0) { r_found = 1; r_type = match->type_key; r_off = match->off; } scratch_end(scratch); } // rjf: bad conditions? -> error if applicable, exit if(l.root->op == 0) { break; } else if(e_type_key_match(e_type_key_zero(), check_type_key)) { break; } else if(exprr->kind != E_ExprKind_LeafMember) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Expected member name."); break; } else if(!r_found) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Could not find a member named '%S'.", exprr->string); break; } else if(check_type_kind != E_TypeKind_Struct && check_type_kind != E_TypeKind_Class && check_type_kind != E_TypeKind_Union) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot perform member access on this type."); break; } else if(l.mode != E_Mode_Addr && l.mode != E_Mode_Reg) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot access member without a base address or register location."); break; } // rjf: generate { // rjf: build tree E_IRNode *new_tree = l.root; E_Mode mode = l.mode; if(l_restype_kind == E_TypeKind_Ptr || l_restype_kind == E_TypeKind_LRef || l_restype_kind == E_TypeKind_RRef) { new_tree = e_irtree_resolve_to_value(arena, l.mode, new_tree, l_restype); mode = E_Mode_Addr; } if(r_off != 0) { E_IRNode *const_tree = e_irtree_const_u(arena, r_off); new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, new_tree, const_tree); } // rjf: fill result.root = new_tree; result.type_key = r_type; result.mode = mode; } }break; //- rjf: dereference case E_ExprKind_Deref: { // rjf: unpack operand E_Expr *r_expr = expr->first; E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); E_TypeKey r_type = e_type_unwrap(r_tree.type_key); E_TypeKind r_type_kind = e_type_kind_from_key(r_type); E_TypeKey r_type_direct = e_type_direct_from_key(r_type); U64 r_type_direct_size = e_type_byte_size_from_key(r_type_direct); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); // rjf: bad conditions? -> error if applicable, exit if(r_tree.root->op == 0) { break; } else if(r_type_direct_size == 0 && (r_type_kind == E_TypeKind_Ptr || r_type_kind == E_TypeKind_LRef || r_type_kind == E_TypeKind_RRef)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference pointers of zero-sized types."); break; } else if(r_type_direct_size == 0 && r_type_kind == E_TypeKind_Array) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference arrays of zero-sized types."); break; } else if(r_type_kind == E_TypeKind_Array && r_tree.mode != E_Mode_Addr) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference arrays without base address."); break; } else if(r_type_kind != E_TypeKind_Array && r_type_kind != E_TypeKind_Ptr && r_type_kind != E_TypeKind_LRef && r_type_kind != E_TypeKind_RRef) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference this type."); break; } // rjf: generate { E_IRNode *new_tree = r_tree.root; if(r_tree.mode != E_Mode_Value && (r_type_kind == E_TypeKind_Ptr || r_type_kind == E_TypeKind_LRef || r_type_kind == E_TypeKind_RRef)) { new_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); } result.root = new_tree; result.type_key = r_type_direct; result.mode = E_Mode_Addr; } }break; //- rjf: address-of case E_ExprKind_Address: { // rjf: unpack operand E_Expr *r_expr = expr->first; E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); E_TypeKey r_type = r_tree.type_key; E_TypeKey r_type_unwrapped = e_type_unwrap(r_type); E_TypeKind r_type_unwrapped_kind = e_type_kind_from_key(r_type_unwrapped); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); // rjf: bad conditions? -> error if applicable, exit if(r_tree.root->op == 0) { break; } else if(e_type_key_match(e_type_key_zero(), r_type_unwrapped)) { break; } else if(r_tree.mode != E_Mode_Addr) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot take address of non-memory."); break; } // rjf: generate result.root = r_tree.root; result.type_key = e_type_key_cons(E_TypeKind_Ptr, r_type_unwrapped, 0); result.mode = E_Mode_Value; }break; //- rjf: cast case E_ExprKind_Cast: { // rjf: unpack operands E_Expr *cast_type_expr = expr->first; E_Expr *casted_expr = cast_type_expr->next; E_TypeKey cast_type = e_type_from_expr(cast_type_expr); E_TypeKind cast_type_kind = e_type_kind_from_key(cast_type); U64 cast_type_byte_size = e_type_byte_size_from_key(cast_type); E_IRTreeAndType casted_tree = e_irtree_and_type_from_expr(arena, casted_expr); e_msg_list_concat_in_place(&result.msgs, &casted_tree.msgs); E_TypeKey casted_type = e_type_unwrap(casted_tree.type_key); E_TypeKind casted_type_kind = e_type_kind_from_key(casted_type); U64 casted_type_byte_size = e_type_byte_size_from_key(casted_type); U8 in_group = e_type_group_from_kind(casted_type_kind); U8 out_group = e_type_group_from_kind(cast_type_kind); RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group); // rjf: bad conditions? -> error if applicable, exit if(casted_tree.root->op == 0) { break; } else if(cast_type_kind == E_TypeKind_Null) { break; } else if(conversion_rule != RDI_EvalConversionKind_Noop && conversion_rule != RDI_EvalConversionKind_Legal) { String8 text = str8_lit("Unknown cast conversion rule."); if(conversion_rule < RDI_EvalConversionKind_COUNT) { text.str = rdi_explanation_string_from_eval_conversion_kind(conversion_rule, &text.size); } e_msg(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, text); break; } // rjf: generate { E_IRNode *in_tree = e_irtree_resolve_to_value(arena, casted_tree.mode, casted_tree.root, casted_type); E_IRNode *new_tree = in_tree; if(conversion_rule == RDI_EvalConversionKind_Legal) { new_tree = e_irtree_convert_lo(arena, in_tree, out_group, in_group); } if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_kind)) { new_tree = e_irtree_trunc(arena, in_tree, cast_type); } result.root = new_tree; result.type_key = cast_type; result.mode = E_Mode_Value; } }break; //- rjf: sizeof case E_ExprKind_Sizeof: { // rjf: unpack operand E_Expr *r_expr = expr->first; E_TypeKey r_type = zero_struct; switch(r_expr->kind) { case E_ExprKind_TypeIdent: case E_ExprKind_Ptr: case E_ExprKind_Array: case E_ExprKind_Func: { r_type = e_type_from_expr(r_expr); }break; default: { E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); r_type = r_tree.type_key; }break; } // rjf: bad conditions? -> error if applicable, exit if(e_type_key_match(r_type, e_type_key_zero())) { break; } else if(e_type_kind_from_key(r_type) == E_TypeKind_Null) { break; } // rjf: generate { U64 r_type_byte_size = e_type_byte_size_from_key(r_type); result.root = e_irtree_const_u(arena, r_type_byte_size); result.type_key = e_type_key_basic(E_TypeKind_U64); result.mode = E_Mode_Value; } }break; //- rjf: unary operations case E_ExprKind_Neg: case E_ExprKind_LogNot: case E_ExprKind_BitNot: { // rjf: unpack operand E_Expr *r_expr = expr->first; E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); E_TypeKey r_type = e_type_unwrap(r_tree.type_key); E_TypeKind r_type_kind = e_type_kind_from_key(r_type); RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); E_TypeKey r_type_promoted = e_type_promote(r_type); RDI_EvalOp op = e_opcode_from_expr_kind(kind); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); // rjf: bad conditions? -> error if applicable, exit if(r_tree.root->op == 0) { break; } else if(!rdi_eval_op_typegroup_are_compatible(op, r_type_group)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Cannot use this operator on this type."); break; } // rjf: generate { E_IRNode *in_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); in_tree = e_irtree_convert_hi(arena, in_tree, r_type_promoted, r_type); E_IRNode *new_tree = e_irtree_unary_op(arena, op, r_type_group, in_tree); result.root = new_tree; result.type_key = r_type_promoted; result.mode = E_Mode_Value; } }break; //- rjf: binary operations case E_ExprKind_Mul: case E_ExprKind_Div: case E_ExprKind_Mod: case E_ExprKind_Add: case E_ExprKind_Sub: case E_ExprKind_LShift: case E_ExprKind_RShift: case E_ExprKind_Less: case E_ExprKind_LsEq: case E_ExprKind_Grtr: case E_ExprKind_GrEq: case E_ExprKind_EqEq: case E_ExprKind_NtEq: case E_ExprKind_BitAnd: case E_ExprKind_BitXor: case E_ExprKind_BitOr: case E_ExprKind_LogAnd: case E_ExprKind_LogOr: { // rjf: unpack operands RDI_EvalOp op = e_opcode_from_expr_kind(kind); B32 is_comparison = e_expr_kind_is_comparison(kind); E_Expr *l_expr = expr->first; E_Expr *r_expr = l_expr->next; E_IRTreeAndType l_tree = e_irtree_and_type_from_expr(arena, l_expr); E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); e_msg_list_concat_in_place(&result.msgs, &l_tree.msgs); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); E_TypeKey l_type = e_type_unwrap(l_tree.type_key); E_TypeKey r_type = e_type_unwrap(r_tree.type_key); E_TypeKind l_type_kind = e_type_kind_from_key(l_type); E_TypeKind r_type_kind = e_type_kind_from_key(r_type); if(l_type.kind == E_TypeKeyKind_Reg) { l_type_kind = E_TypeKind_U64; l_type = e_type_key_basic(l_type_kind); } if(r_type.kind == E_TypeKeyKind_Reg) { r_type_kind = E_TypeKind_U64; r_type = e_type_key_basic(r_type_kind); } B32 l_is_pointer = (l_type_kind == E_TypeKind_Ptr); B32 l_is_decay = (l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Addr); B32 l_is_pointer_like = (l_is_pointer || l_is_decay); B32 r_is_pointer = (r_type_kind == E_TypeKind_Ptr); B32 r_is_decay = (r_type_kind == E_TypeKind_Array && r_tree.mode == E_Mode_Addr); B32 r_is_pointer_like = (r_is_pointer || r_is_decay); RDI_EvalTypeGroup l_type_group = e_type_group_from_kind(l_type_kind); RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); // rjf: bad conditions? -> error if applicable, exit if(l_tree.root->op == 0 || r_tree.root->op == 0) { break; } // rjf: determine arithmetic path #define E_ArithPath_Normal 0 #define E_ArithPath_PtrAdd 1 #define E_ArithPath_PtrSub 2 B32 ptr_arithmetic_mul_rptr = 0; U32 arith_path = E_ArithPath_Normal; if(kind == E_ExprKind_Add) { if(l_is_pointer_like && e_type_kind_is_integer(r_type_kind)) { arith_path = E_ArithPath_PtrAdd; } if(l_is_pointer_like && e_type_kind_is_integer(l_type_kind)) { arith_path = E_ArithPath_PtrAdd; ptr_arithmetic_mul_rptr = 1; } } else if(kind == E_ExprKind_Sub) { if(l_is_pointer_like && e_type_kind_is_integer(r_type_kind)) { arith_path = E_ArithPath_PtrAdd; } if(l_is_pointer_like && r_is_pointer_like) { E_TypeKey l_type_direct = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(l_type))); E_TypeKey r_type_direct = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(r_type))); U64 l_type_direct_byte_size = e_type_byte_size_from_key(l_type_direct); U64 r_type_direct_byte_size = e_type_byte_size_from_key(r_type_direct); if(l_type_direct_byte_size == r_type_direct_byte_size) { arith_path = E_ArithPath_PtrSub; } } } // rjf: generate according to arithmetic path switch(arith_path) { //- rjf: normal arithmetic case E_ArithPath_Normal: { // rjf: bad conditions? -> error if applicable, exit if(!rdi_eval_op_typegroup_are_compatible(op, l_type_group) || !rdi_eval_op_typegroup_are_compatible(op, r_type_group)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Cannot use this operator on this type."); break; } // rjf: generate { E_TypeKey final_type_key = is_comparison ? e_type_key_basic(E_TypeKind_Bool) : l_type; E_IRNode *l_value_tree = e_irtree_resolve_to_value(arena, l_tree.mode, l_tree.root, l_type); E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); l_value_tree = e_irtree_convert_hi(arena, l_value_tree, l_type, l_type); r_value_tree = e_irtree_convert_hi(arena, r_value_tree, l_type, r_type); E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, l_value_tree, r_value_tree); result.root = new_tree; result.type_key = final_type_key; result.mode = E_Mode_Value; } }break; //- rjf: pointer addition case E_ArithPath_PtrAdd: { // rjf: map l/r to ptr/int E_IRTreeAndType *ptr_tree = &l_tree; E_IRTreeAndType *int_tree = &r_tree; B32 ptr_is_decay = l_is_decay; if(ptr_arithmetic_mul_rptr) { ptr_tree = &r_tree; int_tree = &l_tree; ptr_is_decay = r_is_decay; } // rjf: unpack type E_TypeKey direct_type = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(ptr_tree->type_key))); U64 direct_type_size = e_type_byte_size_from_key(direct_type); // rjf: generate { E_IRNode *ptr_root = ptr_tree->root; if(!ptr_is_decay) { ptr_root = e_irtree_resolve_to_value(arena, ptr_tree->mode, ptr_root, ptr_tree->type_key); } E_IRNode *int_root = int_tree->root; if(direct_type_size > 1) { E_IRNode *const_root = e_irtree_const_u(arena, direct_type_size); int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, int_root, const_root); } E_TypeKey ptr_type = ptr_tree->type_key; if(ptr_is_decay) { ptr_type = e_type_key_cons(E_TypeKind_Ptr, direct_type, 0); } E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_root, int_root); result.root = new_root; result.type_key = ptr_type; result.mode = E_Mode_Value; } }break; //- rjf: pointer subtraction case E_ArithPath_PtrSub: { // rjf: unpack type E_TypeKey direct_type = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(l_type))); U64 direct_type_size = e_type_byte_size_from_key(direct_type); // rjf: generate E_IRNode *l_root = l_tree.root; E_IRNode *r_root = r_tree.root; if(!l_is_decay) { l_root = e_irtree_resolve_to_value(arena, l_tree.mode, l_root, l_type); } if(!r_is_decay) { r_root = e_irtree_resolve_to_value(arena, r_tree.mode, r_root, r_type); } E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_root, r_root); E_IRNode *new_tree = op_tree; if(direct_type_size > 1) { E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, new_tree, const_tree); } result.root = new_tree; result.type_key = e_type_key_basic(E_TypeKind_U64); result.mode = E_Mode_Value; }break; } }break; //- rjf: ternary operators case E_ExprKind_Ternary: { // rjf: unpack operands E_Expr *c_expr = expr->first; E_Expr *l_expr = c_expr->next; E_Expr *r_expr = l_expr->next; E_IRTreeAndType c_tree = e_irtree_and_type_from_expr(arena, c_expr); E_IRTreeAndType l_tree = e_irtree_and_type_from_expr(arena, l_expr); E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); e_msg_list_concat_in_place(&result.msgs, &c_tree.msgs); e_msg_list_concat_in_place(&result.msgs, &l_tree.msgs); e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); E_TypeKey c_type = e_type_unwrap(c_tree.type_key); E_TypeKey l_type = e_type_unwrap(l_tree.type_key); E_TypeKey r_type = e_type_unwrap(r_tree.type_key); E_TypeKind c_type_kind = e_type_kind_from_key(c_type); E_TypeKind l_type_kind = e_type_kind_from_key(l_type); E_TypeKind r_type_kind = e_type_kind_from_key(r_type); E_TypeKey result_type = l_type; // rjf: bad conditions? -> error if applicable, exit if(c_tree.root->op == 0 || l_tree.root->op == 0 || r_tree.root->op == 0) { break; } else if(!e_type_kind_is_integer(c_type_kind) && c_type_kind != E_TypeKind_Bool) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Conditional term must be an integer or boolean type."); } else if(!e_type_match(l_type, r_type)) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Left and right terms must have matching types."); } // rjf: generate { E_IRNode *c_value_tree = e_irtree_resolve_to_value(arena, c_tree.mode, c_tree.root, c_type); E_IRNode *l_value_tree = e_irtree_resolve_to_value(arena, l_tree.mode, l_tree.root, l_type); E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); l_value_tree = e_irtree_convert_hi(arena, l_value_tree, result_type, l_type); r_value_tree = e_irtree_convert_hi(arena, r_value_tree, result_type, r_type); E_IRNode *new_tree = e_irtree_conditional(arena, c_value_tree, l_value_tree, r_value_tree); result.root = new_tree; result.type_key = result_type; result.mode = E_Mode_Value; } }break; //- rjf: leaf bytecode case E_ExprKind_LeafBytecode: { E_IRNode *new_tree = e_irtree_bytecode_no_copy(arena, expr->string); E_TypeKey final_type_key = expr->type_key; E_Mode mode = expr->mode; result.root = new_tree; result.type_key = final_type_key; result.mode = mode; }break; //- rjf: (unexpected) leaf member case E_ExprKind_LeafMember: { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "(internal) Leaf member not expected here."); }break; //- rjf: leaf string literal 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_IRNode *new_tree = e_irtree_string_literal(arena, string); result.root = new_tree; result.type_key = type_key; result.mode = E_Mode_Value; }break; //- rjf: leaf U64s case E_ExprKind_LeafU64: { U64 val = expr->u64; E_IRNode *new_tree = e_irtree_const_u(arena, val); E_TypeKey type_key = zero_struct; if(0){} else if(val <= max_S32){type_key = e_type_key_basic(E_TypeKind_S32);} else if(val <= max_S64){type_key = e_type_key_basic(E_TypeKind_S64);} else {type_key = e_type_key_basic(E_TypeKind_U64);} result.root = new_tree; result.type_key = type_key; result.mode = E_Mode_Value; }break; //- rjf: leaf F64s case E_ExprKind_LeafF64: { U64 val = expr->u64; E_IRNode *new_tree = e_irtree_const_u(arena, val); result.root = new_tree; result.type_key = e_type_key_basic(E_TypeKind_F64); result.mode = E_Mode_Value; }break; //- rjf: leaf F32s case E_ExprKind_LeafF32: { U32 val = expr->u32; E_IRNode *new_tree = e_irtree_const_u(arena, val); result.root = new_tree; result.type_key = e_type_key_basic(E_TypeKind_F32); result.mode = E_Mode_Value; }break; //- rjf: types case E_ExprKind_TypeIdent: { result.root = &e_irnode_nil; result.type_key = expr->type_key; result.mode = E_Mode_Null; }break; //- rjf: (unexpected) type expressions case E_ExprKind_Ptr: case E_ExprKind_Array: case E_ExprKind_Func: { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Type expression not expected."); }break; //- rjf: definitions case E_ExprKind_Define: { E_Expr *lhs = expr->first; E_Expr *rhs = lhs->next; result = e_irtree_and_type_from_expr(arena, rhs); if(lhs->kind != E_ExprKind_LeafIdent) { e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Left side of assignment must be an identifier."); } }break; //- rjf: leaf identifiers case E_ExprKind_LeafIdent: { E_Expr *macro_expr = e_expr_from_string(e_state->ctx->macro_map, expr->string); if(macro_expr == &e_expr_nil) { e_msgf(arena, &result.msgs, E_MsgKind_ResolutionFailure, expr->location, "\"%S\" could not be found.", expr->string); } else { e_string2expr_map_inc_poison(e_state->ctx->macro_map, expr->string); result = e_irtree_and_type_from_expr(arena, macro_expr); e_string2expr_map_dec_poison(e_state->ctx->macro_map, expr->string); } }break; } return result; } //- rjf: irtree -> linear ops/bytecode internal void e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_OpList *out) { U32 op = root->op; switch(op) { case RDI_EvalOp_Stop: case RDI_EvalOp_Skip: { // TODO: error - invalid ir-tree op }break; case E_IRExtKind_Bytecode: { e_oplist_push_bytecode(arena, out, root->bytecode); }break; case RDI_EvalOp_Cond: { // rjf: generate oplists for each child E_OpList prt_cond = e_oplist_from_irtree(arena, root->first); E_OpList prt_left = e_oplist_from_irtree(arena, root->first->next); E_OpList prt_right = e_oplist_from_irtree(arena, root->first->next->next); // rjf: put together like so: // 1. , Op_Cond (sizeof(2)) // 2. , Op_Skip (sizeof(3)) // 3. // rjf: modify prt_right in place to create step 2 e_oplist_push_op(arena, &prt_right, RDI_EvalOp_Skip, prt_left.encoded_size); // rjf: merge 1 into out e_oplist_concat_in_place(out, &prt_cond); e_oplist_push_op(arena, out, RDI_EvalOp_Cond, prt_right.encoded_size); // rjf: merge 2 into out e_oplist_concat_in_place(out, &prt_right); // rjf: merge 3 into out e_oplist_concat_in_place(out, &prt_left); }break; default: { if(op >= RDI_EvalOp_COUNT) { // TODO: error - invalid ir-tree op } else { // rjf: append ops for all children U8 ctrlbits = rdi_eval_op_ctrlbits_table[op]; U64 child_count = RDI_POPN_FROM_CTRLBITS(ctrlbits); U64 idx = 0; for(E_IRNode *child = root->first; child != &e_irnode_nil && idx < child_count; child = child->next, idx += 1) { e_append_oplist_from_irtree(arena, child, out); } // rjf: emit op to compute this node e_oplist_push_op(arena, out, (RDI_EvalOp)root->op, root->u64); } }break; } } internal E_OpList e_oplist_from_irtree(Arena *arena, E_IRNode *root) { E_OpList ops = {0}; e_append_oplist_from_irtree(arena, root, &ops); return ops; } internal String8 e_bytecode_from_oplist(Arena *arena, E_OpList *oplist) { // rjf: allocate buffer U64 size = oplist->encoded_size; U8 *str = push_array_no_zero(arena, U8, size); // rjf: iterate loose op nodes; fill buffer U8 *ptr = str; U8 *opl = str + size; for(E_Op *op = oplist->first; op != 0; op = op->next) { U32 opcode = op->opcode; switch(opcode) { default: { // rjf: compute bytecode advance U8 ctrlbits = rdi_eval_op_ctrlbits_table[opcode]; U64 extra_byte_count = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); U8 *next_ptr = ptr + 1 + extra_byte_count; Assert(next_ptr <= opl); // rjf: fill bytecode ptr[0] = opcode; MemoryCopy(ptr + 1, &op->p, extra_byte_count); // rjf: advance ptr = next_ptr; }break; case E_IRExtKind_Bytecode: { // rjf: compute bytecode advance U64 size = op->bytecode.size; U8 *next_ptr = ptr + size; Assert(next_ptr <= opl); // rjf: fill bytecode MemoryCopy(ptr, op->bytecode.str, size); // rjf: advance ptr = next_ptr; }break; } } // rjf: fill result String8 result = {0}; result.size = size; result.str = str; return result; } //////////////////////////////// //~ rjf: Interpretation Functions internal E_Interpretation e_interpret(String8 bytecode) { E_Interpretation result = {0}; Temp scratch = scratch_begin(0, 0); //- rjf: allocate stack U64 stack_cap = 128; // TODO(rjf): scan bytecode; determine maximum stack depth E_Value *stack = push_array_no_zero(scratch.arena, E_Value, stack_cap); U64 stack_count = 0; //- rjf: iterate bytecode & perform ops U8 *ptr = bytecode.str; U8 *opl = bytecode.str + bytecode.size; for(;ptr < opl;) { // rjf: consume next opcode RDI_EvalOp op = (RDI_EvalOp)*ptr; if(op >= RDI_EvalOp_COUNT) { result.code = E_InterpretationCode_BadOp; goto done; } U8 ctrlbits = rdi_eval_op_ctrlbits_table[op]; ptr += 1; // rjf: decode U64 imm = 0; { U32 decode_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); U8 *next_ptr = ptr + decode_size; if(next_ptr > opl) { result.code = E_InterpretationCode_BadOp; goto done; } // TODO(rjf): guarantee 8 bytes padding after the end of serialized // bytecode; read 8 bytes and mask switch(decode_size) { case 1:{imm = *ptr;}break; case 2:{imm = *(U16*)ptr;}break; case 4:{imm = *(U32*)ptr;}break; case 8:{imm = *(U64*)ptr;}break; } ptr = next_ptr; } // rjf: pop E_Value *svals = 0; { U32 pop_count = RDI_POPN_FROM_CTRLBITS(ctrlbits); if(pop_count > stack_count) { result.code = E_InterpretationCode_BadOp; goto done; } if(pop_count <= stack_count) { stack_count -= pop_count; svals = stack + stack_count; } } // rjf: interpret op, given decodes/pops E_Value nval = {0}; switch(op) { case RDI_EvalOp_Stop: { goto done; }break; case RDI_EvalOp_Noop: { // do nothing }break; case RDI_EvalOp_Cond: if(svals[0].u64) { ptr += imm; }break; case RDI_EvalOp_Skip: { ptr += imm; }break; case RDI_EvalOp_MemRead: { U64 addr = svals[0].u64; U64 size = imm; B32 good_read = 0; if(e_state->ctx->memory_read != 0 && e_state->ctx->memory_read(e_state->ctx->memory_read_user_data, &nval, r1u64(addr, addr+size))) { good_read = 1; } if(!good_read) { result.code = E_InterpretationCode_BadMemRead; goto done; } }break; case RDI_EvalOp_RegRead: { U8 rdi_reg_code = (imm&0x0000FF)>>0; U8 byte_size = (imm&0x00FF00)>>8; U8 byte_off = (imm&0xFF0000)>>16; REGS_RegCode base_reg_code = regs_reg_code_from_arch_rdi_code(e_state->ctx->arch, rdi_reg_code); REGS_Rng rng = regs_reg_code_rng_table_from_architecture(e_state->ctx->arch)[base_reg_code]; U64 off = (U64)rng.byte_off + byte_off; U64 size = (U64)byte_size; if(off + size <= e_state->ctx->reg_size) { MemoryCopy(&nval, (U8*)e_state->ctx->reg_data + off, size); } else { result.code = E_InterpretationCode_BadRegRead; goto done; } }break; case RDI_EvalOp_RegReadDyn: { U64 off = svals[0].u64; U64 size = bit_size_from_arch(e_state->ctx->arch)/8; if(off + size <= e_state->ctx->reg_size) { MemoryCopy(&nval, (U8*)e_state->ctx->reg_data + off, size); } else { result.code = E_InterpretationCode_BadRegRead; goto done; } }break; case RDI_EvalOp_FrameOff: { if(e_state->ctx->frame_base != 0) { nval.u64 = *e_state->ctx->frame_base + imm; } else { result.code = E_InterpretationCode_BadFrameBase; goto done; } }break; case RDI_EvalOp_ModuleOff: { if(e_state->ctx->module_base != 0) { nval.u64 = *e_state->ctx->module_base + imm; } else { result.code = E_InterpretationCode_BadModuleBase; goto done; } }break; case RDI_EvalOp_TLSOff: { if(e_state->ctx->tls_base != 0) { nval.u64 = *e_state->ctx->tls_base + imm; } else { result.code = E_InterpretationCode_BadTLSBase; goto done; } }break; case RDI_EvalOp_ConstU8: case RDI_EvalOp_ConstU16: case RDI_EvalOp_ConstU32: case RDI_EvalOp_ConstU64: { nval.u64 = imm; }break; case RDI_EvalOp_Abs: { if(imm == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32; if(svals[0].f32 < 0) { nval.f32 = -svals[0].f32; } } else if(imm == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64; if(svals[0].f64 < 0) { nval.f64 = -svals[0].f64; } } else { nval.s64 = svals[0].s64; if(svals[0].s64 < 0) { nval.s64 = -svals[0].s64; } } }break; case RDI_EvalOp_Neg: { if(imm == RDI_EvalTypeGroup_F32) { nval.f32 = -svals[0].f32; } else if(imm == RDI_EvalTypeGroup_F64) { nval.f64 = -svals[0].f64; } else { nval.u64 = (~svals[0].u64) + 1; } }break; case RDI_EvalOp_Add: { if(imm == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32 + svals[1].f32; } else if(imm == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64 + svals[1].f64; } else { nval.u64 = svals[0].u64 + svals[1].u64; } }break; case RDI_EvalOp_Sub: { if(imm == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32 - svals[1].f32; } else if(imm == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64 - svals[1].f64; } else { nval.u64 = svals[0].u64 - svals[1].u64; } }break; case RDI_EvalOp_Mul: { if(imm == RDI_EvalTypeGroup_F32) { nval.f32 = svals[0].f32*svals[1].f32; } else if(imm == RDI_EvalTypeGroup_F64) { nval.f64 = svals[0].f64*svals[1].f64; } else { nval.u64 = svals[0].u64*svals[1].u64; } }break; case RDI_EvalOp_Div: { if(imm == RDI_EvalTypeGroup_F32) { if(svals[1].f32 != 0.f) { nval.f32 = svals[0].f32/svals[1].f32; } else { result.code = E_InterpretationCode_DivideByZero; goto done; } } else if(imm == RDI_EvalTypeGroup_F64) { if(svals[1].f64 != 0.) { nval.f64 = svals[0].f64/svals[1].f64; } else { result.code = E_InterpretationCode_DivideByZero; goto done; } } else if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { if(svals[1].u64 != 0) { nval.u64 = svals[0].u64/svals[1].u64; } else { result.code = E_InterpretationCode_DivideByZero; goto done; } } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_Mod: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { if(svals[1].u64 != 0) { nval.u64 = svals[0].u64%svals[1].u64; } } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_LShift: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64 << svals[1].u64; } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_RShift: { if(imm == RDI_EvalTypeGroup_U) { nval.u64 = svals[0].u64 >> svals[1].u64; } else if(imm == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].s64 >> svals[1].u64; } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_BitAnd: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64&svals[1].u64; } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_BitOr: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64|svals[1].u64; } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_BitXor: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = svals[0].u64^svals[1].u64; } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_BitNot: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = ~svals[0].u64; } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_LogAnd: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].u64 && svals[1].u64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_LogOr: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].u64 || svals[1].u64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_LogNot: { if(imm == RDI_EvalTypeGroup_U || imm == RDI_EvalTypeGroup_S) { nval.u64 = (!svals[0].u64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_EqEq: { nval.u64 = (svals[0].u64 == svals[1].u64); }break; case RDI_EvalOp_NtEq: { nval.u64 = (svals[0].u64 != svals[1].u64); }break; case RDI_EvalOp_LsEq: { if(imm == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 <= svals[1].f32); } else if(imm == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 <= svals[1].f64); } else if(imm == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 <= svals[1].u64); } else if(imm == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 <= svals[1].s64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_GrEq: { if(imm == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 >= svals[1].f32); } else if(imm == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 >= svals[1].f64); } else if(imm == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 >= svals[1].u64); } else if(imm == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 >= svals[1].s64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_Less: { if(imm == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 < svals[1].f32); } else if(imm == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 < svals[1].f64); } else if(imm == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 < svals[1].u64); } else if(imm == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 < svals[1].s64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_Grtr: { if(imm == RDI_EvalTypeGroup_F32) { nval.u64 = (svals[0].f32 > svals[1].f32); } else if(imm == RDI_EvalTypeGroup_F64) { nval.u64 = (svals[0].f64 > svals[1].f64); } else if(imm == RDI_EvalTypeGroup_U) { nval.u64 = (svals[0].u64 > svals[1].u64); } else if(imm == RDI_EvalTypeGroup_S) { nval.u64 = (svals[0].s64 > svals[1].s64); } else { result.code = E_InterpretationCode_BadOpTypes; goto done; } }break; case RDI_EvalOp_Trunc: { if(0 < imm) { U64 mask = 0; if(imm < 64) { mask = max_U64 >> (64 - imm); } nval.u64 = svals[0].u64&mask; } }break; case RDI_EvalOp_TruncSigned: { if(0 < imm) { U64 mask = 0; if(imm < 64) { mask = max_U64 >> (64 - imm); } U64 high = 0; if(svals[0].u64 & (1 << (imm - 1))) { high = ~mask; } nval.u64 = high|(svals[0].u64&mask); } }break; case RDI_EvalOp_Convert: { U32 in = imm&0xFF; U32 out = (imm >> 8)&0xFF; if(in != out) { switch(in + out*RDI_EvalTypeGroup_COUNT) { case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f32; }break; case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f64; }break; case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f32; }break; case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f64; }break; case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].u64; }break; case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].s64; }break; case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].f64; }break; case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].u64; }break; case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].s64; }break; case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].f32; }break; } } }break; case RDI_EvalOp_Pick: { if(stack_count > imm) { nval = stack[stack_count - imm - 1]; } else { result.code = E_InterpretationCode_BadOp; goto done; } }break; case RDI_EvalOp_Pop: { // do nothing - the pop is handled by the control bits }break; case RDI_EvalOp_Insert: { if(stack_count > imm) { if(imm > 0) { E_Value tval = stack[stack_count - 1]; E_Value *dst = stack + stack_count - 1 - imm; E_Value *shift = dst + 1; MemoryCopy(shift, dst, imm*sizeof(E_Value)); *dst = tval; } } else { result.code = E_InterpretationCode_BadOp; goto done; } }break; } // rjf: push { U64 push_count = RDI_PUSHN_FROM_CTRLBITS(ctrlbits); if(push_count == 1) { if(stack_count < stack_cap) { stack[stack_count] = nval; stack_count += 1; } else { result.code = E_InterpretationCode_InsufficientStackSpace; goto done; } } } } done:; if(stack_count >= 1) { result.value = stack[0]; } scratch_end(scratch); return result; } //////////////////////////////// //~ rjf: Bundled Evaluation Functions internal E_Eval e_eval_from_string(Arena *arena, String8 string) { E_TokenArray tokens = e_token_array_from_text(arena, string); E_Parse parse = e_parse_expr_from_text_tokens(arena, string, &tokens); E_IRTreeAndType irtree = e_irtree_and_type_from_expr(arena, parse.expr); E_OpList oplist = e_oplist_from_irtree(arena, irtree.root); String8 bytecode = e_bytecode_from_oplist(arena, &oplist); E_Interpretation interp = e_interpret(bytecode); E_Eval eval = { .value = interp.value, .mode = irtree.mode, .type_key = irtree.type_key, .code = interp.code, }; e_msg_list_concat_in_place(&eval.msgs, &parse.msgs); e_msg_list_concat_in_place(&eval.msgs, &irtree.msgs); if(E_InterpretationCode_Good < eval.code && eval.code < E_InterpretationCode_COUNT) { e_msg(arena, &eval.msgs, E_MsgKind_InterpretationError, 0, e_interpretation_code_display_strings[eval.code]); } return eval; } internal E_Eval e_autoresolved_eval_from_eval(E_Eval eval) { if(e_state->ctx->rdis_count > 0 && e_state->ctx->module_base != 0 && (eval.mode == E_Mode_Value || eval.mode == E_Mode_Reg) && (e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_S64)) || e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_U64)) || e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_S32)) || e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_U32)))) { U64 vaddr = eval.value.u64; U64 voff = vaddr - e_state->ctx->module_base[0]; RDI_Parsed *rdi = e_state->ctx->rdis[0]; RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); U32 string_idx = 0; if(string_idx == 0) { string_idx = procedure->name_string_idx; } 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); } } return eval; } internal E_Eval e_dynamically_typed_eval_from_eval(E_Eval eval) { E_TypeKey type_key = eval.type_key; E_TypeKind type_kind = e_type_kind_from_key(type_key); if(e_state->ctx->memory_read != 0 && e_state->ctx->module_base != 0 && type_kind == E_TypeKind_Ptr) { Temp scratch = scratch_begin(0, 0); E_TypeKey ptee_type_key = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(type_key))); E_TypeKind ptee_type_kind = e_type_kind_from_key(ptee_type_key); if(ptee_type_kind == E_TypeKind_Struct || ptee_type_kind == E_TypeKind_Class) { E_Type *ptee_type = e_type_from_key(scratch.arena, ptee_type_key); B32 has_vtable = 0; for(U64 idx = 0; idx < ptee_type->count; idx += 1) { if(ptee_type->members[idx].kind == E_MemberKind_VirtualMethod) { has_vtable = 1; break; } } if(has_vtable) { U64 ptr_vaddr = eval.value.u64; U64 addr_size = bit_size_from_arch(e_state->ctx->arch)/8; U64 class_base_vaddr = 0; U64 vtable_vaddr = 0; if(e_state->ctx->memory_read(e_state->ctx->memory_read_user_data, &class_base_vaddr, r1u64(ptr_vaddr, ptr_vaddr+addr_size)) && e_state->ctx->memory_read(e_state->ctx->memory_read_user_data, &vtable_vaddr, r1u64(class_base_vaddr, class_base_vaddr+addr_size))) { U32 rdi_idx = 0; RDI_Parsed *rdi = 0; U64 module_base = 0; for(U64 idx = 0; idx < e_state->ctx->rdis_count; idx += 1) { if(contains_1u64(e_state->ctx->rdis_vaddr_ranges[idx], vtable_vaddr)) { rdi_idx = (U32)idx; rdi = e_state->ctx->rdis[idx]; module_base = e_state->ctx->rdis_vaddr_ranges[idx].min; break; } } if(rdi != 0) { U64 vtable_voff = vtable_vaddr - module_base; U64 global_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_GlobalVMap, vtable_voff); RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, global_idx); if(global_var->link_flags & RDI_LinkFlag_TypeScoped) { 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); eval.type_key = ptr_to_derived_type_key; } } } } } scratch_end(scratch); } return eval; } internal E_Eval e_value_eval_from_eval(E_Eval eval) { switch(eval.mode) { //- rjf: no work to be done. already in value mode default: case E_Mode_Value:{}break; //- rjf: address => resolve into value, if leaf case E_Mode_Addr: { E_TypeKey type_key = e_type_unwrap(eval.type_key); E_TypeKind type_kind = e_type_kind_from_key(type_key); if(type_kind == E_TypeKind_Array) { eval.mode = E_Mode_Value; } else if(e_state->ctx->memory_read != 0) { U64 type_byte_size = e_type_byte_size_from_key(type_key); Rng1U64 value_vaddr_range = r1u64(eval.value.u64, eval.value.u64 + type_byte_size); MemoryZeroStruct(&eval.value); if(!e_type_key_match(type_key, e_type_key_zero()) && type_byte_size <= sizeof(E_Value) && e_state->ctx->memory_read(e_state->ctx->memory_read_user_data, &eval.value, value_vaddr_range)) { eval.mode = E_Mode_Value; // rjf: mask&shift, for bitfields if(type_kind == E_TypeKind_Bitfield && type_byte_size <= sizeof(U64)) { Temp scratch = scratch_begin(0, 0); E_Type *type = e_type_from_key(scratch.arena, type_key); U64 valid_bits_mask = 0; for(U64 idx = 0; idx < type->count; idx += 1) { valid_bits_mask |= (1<> type->off; eval.value.u64 = eval.value.u64 & valid_bits_mask; eval.type_key = type->direct_type_key; scratch_end(scratch); } // rjf: manually sign-extend switch(type_kind) { default: break; case E_TypeKind_S8: {eval.value.s64 = (S64)*((S8 *)&eval.value.u64);}break; case E_TypeKind_S16: {eval.value.s64 = (S64)*((S16 *)&eval.value.u64);}break; case E_TypeKind_S32: {eval.value.s64 = (S64)*((S32 *)&eval.value.u64);}break; } } } }break; //- rjf: register => resolve into value case E_Mode_Reg: { E_TypeKey type_key = eval.type_key; U64 type_byte_size = e_type_byte_size_from_key(type_key); U64 reg_off = eval.value.u64; MemoryZeroStruct(&eval.value); MemoryCopy(&eval.value.u256, ((U8 *)e_state->ctx->reg_data + reg_off), Min(type_byte_size, sizeof(U64)*4)); eval.mode = E_Mode_Value; }break; } return eval; }