Files
raddebugger/src/eval2/eval2.c
T

5554 lines
190 KiB
C

// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Generated Code
#include "generated/eval2.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("<unknown-class>"));
}
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(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(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(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(arena, &oplist, RDI_EvalOp_RegRead, regread_param);
e_oplist_push(arena, &oplist, RDI_EvalOp_ConstU16, loc_reg_u16.offset);
e_oplist_push(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(arena, &oplist, RDI_EvalOp_RegRead, regread_param);
e_oplist_push(arena, &oplist, RDI_EvalOp_ConstU16, loc_reg_u16.offset);
e_oplist_push(arena, &oplist, RDI_EvalOp_Add, 0);
e_oplist_push(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(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 => invalid
case E_TokenKind_StringLiteral:
{
e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "String literals are not supported.");
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);
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(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(arena, list, RDI_EvalOp_ConstU8, x); }
else if(x <= 0xFFFF) { e_oplist_push(arena, list, RDI_EvalOp_ConstU16, x); }
else if(x <= 0xFFFFFFFF) { e_oplist_push(arena, list, RDI_EvalOp_ConstU32, x); }
else { e_oplist_push(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(arena, list, RDI_EvalOp_ConstU8, (U64)x);
e_oplist_push(arena, list, RDI_EvalOp_TruncSigned, 8);
}
else if(-0x8000 <= x && x <= 0x7FFF)
{
e_oplist_push(arena, list, RDI_EvalOp_ConstU16, (U64)x);
e_oplist_push(arena, list, RDI_EvalOp_TruncSigned, 16);
}
else if(-0x80000000ll <= x && x <= 0x7FFFFFFFll)
{
e_oplist_push(arena, list, RDI_EvalOp_ConstU32, (U64)x);
e_oplist_push(arena, list, RDI_EvalOp_TruncSigned, 32);
}
else
{
e_oplist_push(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_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:
{
e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "(internal) Undefined expression kind (%u).", kind);
}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 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. <prt_cond> , Op_Cond (sizeof(2))
// 2. <prt_right>, Op_Skip (sizeof(3))
// 3. <ptr_left>
// rjf: modify prt_right in place to create step 2
e_oplist_push(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(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(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];
}
else if(result.code == E_InterpretationCode_Good)
{
result.code = E_InterpretationCode_MalformedBytecode;
}
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:
if(e_state->ctx->memory_read != 0)
{
E_TypeKey type_key = eval.type_key;
E_TypeKind type_kind = e_type_kind_from_key(type_key);
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<<idx);
}
eval.value.u64 = eval.value.u64 >> 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;
}