mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 09:18:09 +00:00
eval2 checkpoint: type operations, constructed types, checkpoint before splitting back to frontend / compiler split - we need to do things with the parse tree that we can't with an ir tree
This commit is contained in:
+32
-6
@@ -9,6 +9,13 @@ target:
|
||||
debug_subprocesses: 0
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/raddbg.exe"
|
||||
working_directory: "../raddebugger"
|
||||
arguments: "--user:test123"
|
||||
debug_subprocesses: 0
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/mule_main.exe"
|
||||
working_directory: build
|
||||
@@ -18,6 +25,7 @@ target:
|
||||
{
|
||||
executable: "build/torture.exe"
|
||||
working_directory: build
|
||||
arguments: "raddbg/*"
|
||||
}
|
||||
target:
|
||||
{
|
||||
@@ -31,14 +39,32 @@ target:
|
||||
arguments: "--rdi raddbg"
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/release_version/raddbg.exe"
|
||||
working_directory: "build/release_version"
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/radbin.exe"
|
||||
working_directory: build
|
||||
arguments: "--rdi fat.so --capture"
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/radbin.exe"
|
||||
working_directory: build
|
||||
arguments: "--rdi fat.debug --capture"
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/radbin.exe"
|
||||
working_directory: build
|
||||
arguments: "--rdi raddbg"
|
||||
}
|
||||
watch_pin: expression: tag_hash_slots
|
||||
target:
|
||||
{
|
||||
executable: "build/ryan_scratch.exe"
|
||||
working_directory: build
|
||||
enabled: 1
|
||||
}
|
||||
target:
|
||||
{
|
||||
executable: "build/raddbg.exe"
|
||||
working_directory: build
|
||||
arguments: "--bin --dump test123.rdi"
|
||||
}
|
||||
|
||||
+607
-8
@@ -163,6 +163,153 @@ e2_dbgi_from_num(U32 num)
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Constructed Types
|
||||
|
||||
internal E2_ConsTypeMap *
|
||||
e2_cons_type_map_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
E2_ConsTypeMap *map = push_array(arena, E2_ConsTypeMap, 1);
|
||||
map->arena = arena;
|
||||
map->table_start_arena_pos = arena_pos(arena);
|
||||
return map;
|
||||
}
|
||||
|
||||
internal void
|
||||
e2_select_cons_type_map(E2_ConsTypeMap *map)
|
||||
{
|
||||
arena_pop_to(map->arena, map->table_start_arena_pos);
|
||||
map->slots_count = 256;
|
||||
map->content_slots = push_array(map->arena, E2_ConsTypeSlot, map->slots_count);
|
||||
map->id_slots = push_array(map->arena, E2_ConsTypeSlot, map->slots_count);
|
||||
e2_cons_type_map = map;
|
||||
}
|
||||
|
||||
internal B32
|
||||
e2_cons_type_params_match(E2_ConsTypeParams *a, E2_ConsTypeParams *b)
|
||||
{
|
||||
B32 result = (a->arch == b->arch &&
|
||||
a->kind == b->kind &&
|
||||
str8_match(a->name, b->name, 0) &&
|
||||
e2_type_key_match(a->direct, b->direct) &&
|
||||
a->count == b->count &&
|
||||
a->depth == b->depth &&
|
||||
a->args == 0 && b->args == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal E2_ConsTypeNode *
|
||||
e2_cons_type_node_from_params(E2_ConsTypeParams *params)
|
||||
{
|
||||
E2_ConsTypeMap *map = e2_cons_type_map;
|
||||
|
||||
// rjf: params -> hash
|
||||
U64 hash = 0;
|
||||
{
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(¶ms->arch));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(¶ms->kind));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(¶ms->name));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(¶ms->direct));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(¶ms->count));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(¶ms->depth));
|
||||
}
|
||||
|
||||
// rjf: hash -> content slot
|
||||
U64 content_slot_idx = hash%map->slots_count;
|
||||
E2_ConsTypeSlot *content_slot = &map->content_slots[content_slot_idx];
|
||||
|
||||
// rjf: parameters -> existing node
|
||||
E2_ConsTypeNode *node = 0;
|
||||
for(E2_ConsTypeNode *n = content_slot->first; n != 0; n = n->content_next)
|
||||
{
|
||||
if(e2_cons_type_params_match(&n->params, params))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if node wasn't found -> push into the map
|
||||
if(node == 0)
|
||||
{
|
||||
// rjf: form node ID
|
||||
map->id_gen += 1;
|
||||
U64 id = map->id_gen;
|
||||
|
||||
// rjf: build the node
|
||||
node = push_array(map->arena, E2_ConsTypeNode, 1);
|
||||
SLLQueuePush_N(content_slot->first, content_slot->last, node, content_next);
|
||||
node->id = id;
|
||||
MemoryCopyStruct(&node->params, params);
|
||||
node->params.name = str8_copy(map->arena, node->params.name);
|
||||
// TODO(rjf): double check once we're doing type expression
|
||||
// arguments that we don't need a deep copy of the args here.
|
||||
switch(node->params.kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
node->byte_size = e2_byte_size_from_type_key(node->params.direct);
|
||||
}break;
|
||||
case E2_TypeKind_Ptr:
|
||||
case E2_TypeKind_Function:
|
||||
case E2_TypeKind_Method:
|
||||
case E2_TypeKind_MemberPtr:
|
||||
case E2_TypeKind_RRef:
|
||||
case E2_TypeKind_LRef:
|
||||
{
|
||||
node->byte_size = byte_size_from_arch(node->params.arch);
|
||||
}break;
|
||||
case E2_TypeKind_Array:
|
||||
{
|
||||
node->byte_size = node->params.count * e2_byte_size_from_type_key(node->params.direct);
|
||||
}break;
|
||||
}
|
||||
|
||||
// rjf: insert node into the ID slots
|
||||
{
|
||||
U64 id_hash = u64_hash_from_str8(str8_struct(&id));
|
||||
U64 id_slot_idx = id_hash%map->slots_count;
|
||||
E2_ConsTypeSlot *id_slot = &map->id_slots[id_slot_idx];
|
||||
SLLQueuePush_N(id_slot->first, id_slot->last, node, id_next);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
internal E2_ConsTypeNode *
|
||||
e2_cons_type_node_from_id(U64 id)
|
||||
{
|
||||
E2_ConsTypeMap *map = e2_cons_type_map;
|
||||
U64 id_hash = u64_hash_from_str8(str8_struct(&id));
|
||||
U64 id_slot_idx = id_hash%map->slots_count;
|
||||
E2_ConsTypeSlot *id_slot = &map->id_slots[id_slot_idx];
|
||||
E2_ConsTypeNode *node = &e2_cons_type_node_nil;
|
||||
for(E2_ConsTypeNode *n = id_slot->first; n != 0; n = n->id_next)
|
||||
{
|
||||
if(n->id == id)
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
internal E2_TypeKey
|
||||
e2_type_key_from_cons_type_node(E2_ConsTypeNode *node)
|
||||
{
|
||||
E2_TypeKey key =
|
||||
{
|
||||
.kind = E2_TypeKeyKind_Cons,
|
||||
.u32[0] = node->params.kind,
|
||||
.u32[1] = (U32)((node->id&0xffffffff00000000ull) >> 32),
|
||||
.u32[2] = node->id&0xffffffffull,
|
||||
};
|
||||
return key;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Keys
|
||||
|
||||
@@ -371,8 +518,8 @@ e2_type_key_reg(Arch arch, ARCH_RegCode reg_code)
|
||||
internal E2_TypeKey
|
||||
e2_type_key_cons_(E2_ConsTypeParams *params)
|
||||
{
|
||||
E2_TypeKey result = {E2_TypeKeyKind_Null};
|
||||
// TODO(rjf)
|
||||
E2_ConsTypeNode *node = e2_cons_type_node_from_params(params);
|
||||
E2_TypeKey result = e2_type_key_from_cons_type_node(node);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -428,7 +575,9 @@ e2_byte_size_from_type_key(E2_TypeKey k)
|
||||
}break;
|
||||
case E2_TypeKeyKind_Cons:
|
||||
{
|
||||
// TODO(rjf)
|
||||
U64 id = e2_cons_type_id_from_key(k);
|
||||
E2_ConsTypeNode *node = e2_cons_type_node_from_id(id);
|
||||
result = node->byte_size;
|
||||
}break;
|
||||
case E2_TypeKeyKind_Reg:
|
||||
{
|
||||
@@ -475,6 +624,17 @@ e2_dbgi_type_idx_from_key(E2_TypeKey k)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
e2_cons_type_id_from_key(E2_TypeKey k)
|
||||
{
|
||||
U64 result = 0;
|
||||
if(k.kind == E2_TypeKeyKind_Cons)
|
||||
{
|
||||
result = ((U64)k.u32[1] << 32) | k.u32[2];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
e2_shift_from_type_key(E2_TypeKey k)
|
||||
{
|
||||
@@ -540,7 +700,9 @@ e2_arch_from_type_key(E2_TypeKey k)
|
||||
}break;
|
||||
case E2_TypeKeyKind_Cons:
|
||||
{
|
||||
// TODO(rjf)
|
||||
U64 id = e2_cons_type_id_from_key(k);
|
||||
E2_ConsTypeNode *node = e2_cons_type_node_from_id(id);
|
||||
arch = node->params.arch;
|
||||
}break;
|
||||
case E2_TypeKeyKind_Reg:
|
||||
{
|
||||
@@ -558,7 +720,104 @@ e2_type_deep_match(E2_TypeKey l, E2_TypeKey r)
|
||||
B32 result = e2_type_key_match(l, r);
|
||||
if(!result)
|
||||
{
|
||||
// TODO(rjf)
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
E2_TypeKey k;
|
||||
U64 member_num;
|
||||
};
|
||||
Task *free_task = 0;
|
||||
Task l_start_task = {0, l};
|
||||
Task r_start_task = {0, r};
|
||||
Task *l_top = &l_start_task;
|
||||
Task *r_top = &r_start_task;
|
||||
U64 l_hash = 0;
|
||||
U64 r_hash = 0;
|
||||
result = 1;
|
||||
for(;l_top != 0 || r_top != 0;)
|
||||
{
|
||||
// rjf: mismatched task structures -> immediately mark as a non-match & break
|
||||
if((l_top && !r_top) || (!l_top && r_top))
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: mismatched hashes -> immediately mark as a non-match & break
|
||||
if(l_hash != r_hash)
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: do next step of hash
|
||||
Task **task_tops[] = {&l_top, &r_top};
|
||||
E2_TypeKey keys[] = {l_top->k, r_top->k};
|
||||
U64 *hash_ptrs[] = {&l_hash, &r_hash};
|
||||
for EachElement(key_idx, keys)
|
||||
{
|
||||
Task *top = task_tops[key_idx][0];
|
||||
E2_TypeKey key = keys[key_idx];
|
||||
E2_TypeKind kind = e2_type_kind_from_key(key);
|
||||
|
||||
// rjf: have not advanced to members -> mix in kind / byte size
|
||||
if(top->member_num == 0)
|
||||
{
|
||||
U64 byte_size = e2_byte_size_from_type_key(key);
|
||||
hash_ptrs[key_idx][0] = u64_hash_from_seed_str8(hash_ptrs[key_idx][0], str8_struct(&kind));
|
||||
hash_ptrs[key_idx][0] = u64_hash_from_seed_str8(hash_ptrs[key_idx][0], str8_struct(&byte_size));
|
||||
}
|
||||
|
||||
// rjf: advance to next member
|
||||
B32 has_next_member = 0;
|
||||
if(kind == E2_TypeKind_Struct ||
|
||||
kind == E2_TypeKind_Union ||
|
||||
kind == E2_TypeKind_Class ||
|
||||
kind == E2_TypeKind_Enum)
|
||||
{
|
||||
U32 dbgi_num = e2_dbgi_num_from_type_key(key);
|
||||
U32 type_idx = e2_dbgi_type_idx_from_key(key);
|
||||
E2_DbgInfo *dbgi = e2_dbgi_from_num(dbgi_num);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(dbgi->rdi, TypeNodes, type_idx);
|
||||
String8 name = str8_from_rdi_string_idx(dbgi->rdi, type_node->user_defined.name_string_idx);
|
||||
hash_ptrs[key_idx][0] = u64_hash_from_seed_str8(hash_ptrs[key_idx][0], name);
|
||||
RDI_UDT *udt = rdi_element_from_name_idx(dbgi->rdi, UDTs, type_node->user_defined.udt_idx);
|
||||
U64 next_member_num = top->member_num + 1;
|
||||
if(next_member_num <= udt->member_count)
|
||||
{
|
||||
has_next_member = 1;
|
||||
RDI_Member *member = rdi_element_from_name_idx(dbgi->rdi, Members, next_member_num-1);
|
||||
RDI_TypeNode *member_type_node = rdi_element_from_name_idx(dbgi->rdi, TypeNodes, member->type_idx);
|
||||
String8 member_name = str8_from_rdi_string_idx(dbgi->rdi, member->name_string_idx);
|
||||
hash_ptrs[key_idx][0] = u64_hash_from_seed_str8(hash_ptrs[key_idx][0], str8_struct(&member->off));
|
||||
hash_ptrs[key_idx][0] = u64_hash_from_seed_str8(hash_ptrs[key_idx][0], member_name);
|
||||
Task *member_task = free_task;
|
||||
if(member_task != 0)
|
||||
{
|
||||
SLLStackPop(free_task);
|
||||
}
|
||||
else
|
||||
{
|
||||
member_task = push_array_no_zero(scratch.arena, Task, 1);
|
||||
}
|
||||
MemoryZeroStruct(&member_task);
|
||||
member_task->k = e2_type_key_dbgi(e2_type_kind_from_rdi(member_type_node->kind), dbgi_num, member->type_idx);
|
||||
SLLStackPush(task_tops[key_idx][0], member_task);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if we don't have a subsequent member, pop this task
|
||||
if(!has_next_member)
|
||||
{
|
||||
Task *popped = task_tops[key_idx][0];
|
||||
SLLStackPop(task_tops[key_idx][0]);
|
||||
SLLStackPush(free_task, popped);
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -596,7 +855,9 @@ e2_type_key_direct(E2_TypeKey k)
|
||||
}break;
|
||||
case E2_TypeKeyKind_Cons:
|
||||
{
|
||||
// TODO(rjf)
|
||||
U64 id = e2_cons_type_id_from_key(k);
|
||||
E2_ConsTypeNode *node = e2_cons_type_node_from_id(id);
|
||||
result = node->params.direct;
|
||||
}break;
|
||||
case E2_TypeKeyKind_Reg:{}break;
|
||||
}
|
||||
@@ -955,6 +1216,235 @@ e2_expr_push_child(Arena *arena, E2_Expr *parent, E2_Expr *expr)
|
||||
e2_expr_push_child_node(parent, n);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Expression Constructors
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode(Arena *arena)
|
||||
{
|
||||
E2_IRNode *expr = push_array(arena, E2_IRNode, 1);
|
||||
MemoryCopyStruct(expr, &e2_irnode_nil);
|
||||
return expr;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_const_u64_or_smaller(Arena *arena, U64 u)
|
||||
{
|
||||
E2_IRNode *e = e2_irnode(arena);
|
||||
{
|
||||
e->mode = E2_Mode_Value;
|
||||
e->val.u64 = u;
|
||||
if(u <= 0x7fffffff)
|
||||
{
|
||||
e->op = RDI_EvalOp_ConstU32;
|
||||
e->type_key = e2_type_key_basic(E2_TypeKind_S32);
|
||||
}
|
||||
else if(u <= 0xffffffff)
|
||||
{
|
||||
e->op = RDI_EvalOp_ConstU32;
|
||||
e->type_key = e2_type_key_basic(E2_TypeKind_U32);
|
||||
}
|
||||
else if(u <= 0x7fffffffffffffffull)
|
||||
{
|
||||
e->op = RDI_EvalOp_ConstU64;
|
||||
e->type_key = e2_type_key_basic(E2_TypeKind_S64);
|
||||
}
|
||||
else if(u <= 0xffffffffffffffffull)
|
||||
{
|
||||
e->op = RDI_EvalOp_ConstU64;
|
||||
e->type_key = e2_type_key_basic(E2_TypeKind_U64);
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_const_f32(Arena *arena, F32 f32)
|
||||
{
|
||||
E2_IRNode *e = e2_irnode(arena);
|
||||
e->mode = E2_Mode_Value;
|
||||
e->val.f32 = f32;
|
||||
e->op = RDI_EvalOp_ConstU32;
|
||||
e->type_key = e2_type_key_basic(E2_TypeKind_F32);
|
||||
return e;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_const_f64(Arena *arena, F64 f64)
|
||||
{
|
||||
E2_IRNode *e = e2_irnode(arena);
|
||||
e->mode = E2_Mode_Value;
|
||||
e->val.f64 = f64;
|
||||
e->op = RDI_EvalOp_ConstU64;
|
||||
e->type_key = e2_type_key_basic(E2_TypeKind_F64);
|
||||
return e;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *operand)
|
||||
{
|
||||
E2_IRNode *e = e2_irnode(arena);
|
||||
e->type_key = type_key;
|
||||
e->op = op;
|
||||
e->mode = E2_Mode_Value;
|
||||
e->val.u512.u8[0] = e2_type_group_from_kind(e2_type_kind_from_key(type_key));
|
||||
e->val.u512.u8[1] = 8*e2_byte_size_from_type_key(type_key);
|
||||
e2_irnode_push_child(arena, e, operand);
|
||||
return e;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *lhs, E2_IRNode *rhs)
|
||||
{
|
||||
E2_IRNode *e = e2_irnode(arena);
|
||||
E2_TypeKey arith_type_key = type_key;
|
||||
if(RDI_EvalOp_FirstLogical <= op && op <= RDI_EvalOp_LastLogical)
|
||||
{
|
||||
arith_type_key = lhs->type_key;
|
||||
}
|
||||
e->type_key = type_key;
|
||||
e->op = op;
|
||||
e->mode = E2_Mode_Value;
|
||||
e->val.u512.u8[0] = e2_type_group_from_kind(e2_type_kind_from_key(arith_type_key));
|
||||
e->val.u512.u8[1] = 8*e2_byte_size_from_type_key(arith_type_key);
|
||||
e2_irnode_push_child(arena, e, lhs);
|
||||
e2_irnode_push_child(arena, e, rhs);
|
||||
return e;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_resolve_to_value(Arena *arena, E2_IRNode *expr)
|
||||
{
|
||||
E2_IRNode *result = expr;
|
||||
|
||||
// rjf: address evaluations of arrays -> create value of pointer to first element
|
||||
if(expr->mode == E2_Mode_Address && e2_type_kind_from_key(e2_type_key_undecorate(expr->type_key)) == E2_TypeKind_Array)
|
||||
{
|
||||
result = e2_irnode(arena);
|
||||
result->type_key = e2_type_key_direct(e2_type_key_undecorate(expr->type_key));
|
||||
result->mode = E2_Mode_Value;
|
||||
e2_irnode_push_child(arena, result, expr);
|
||||
}
|
||||
|
||||
// rjf: address evaluations -> read value from space
|
||||
else if(expr->mode == E2_Mode_Address)
|
||||
{
|
||||
U64 memread_byte_size = e2_byte_size_from_type_key(expr->type_key);
|
||||
memread_byte_size = Min(64, memread_byte_size);
|
||||
E2_IRNode *memread_expr = e2_irnode(arena);
|
||||
memread_expr->op = RDI_EvalOp_MemRead;
|
||||
memread_expr->mode = E2_Mode_Value;
|
||||
memread_expr->type_key = expr->type_key;
|
||||
memread_expr->val.u64 = memread_byte_size;
|
||||
e2_irnode_push_child(arena, memread_expr, expr);
|
||||
result = memread_expr;
|
||||
}
|
||||
|
||||
// rjf: bitfields -> shift & mask
|
||||
E2_TypeKey core_type_key = e2_type_key_undecorate(expr->type_key);
|
||||
if(e2_type_kind_from_key(core_type_key) == E2_TypeKind_Bitfield)
|
||||
{
|
||||
// rjf: unpack bitfield params
|
||||
U64 shift = e2_shift_from_type_key(result->type_key);
|
||||
U64 mask_count = e2_mask_count_from_type_key(result->type_key);
|
||||
U64 valid_bits_mask = 0;
|
||||
for EachIndex(idx, mask_count)
|
||||
{
|
||||
valid_bits_mask |= (1ull<<idx);
|
||||
}
|
||||
|
||||
// rjf: mask(shift(expr, count), bitmask)
|
||||
E2_IRNode *shift_expr = e2_irnode_binary_op(arena, e2_type_key_basic(E2_TypeKind_U64), RDI_EvalOp_RShift, result, e2_irnode_const_u64_or_smaller(arena, shift));
|
||||
E2_IRNode *mask_expr = e2_irnode_binary_op(arena, e2_type_key_direct(core_type_key), RDI_EvalOp_BitAnd, shift_expr, e2_irnode_const_u64_or_smaller(arena, valid_bits_mask));
|
||||
result = mask_expr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_truncate(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key)
|
||||
{
|
||||
E2_IRNode *result = expr;
|
||||
E2_TypeKind dst_type_kind = e2_type_kind_from_key(dst_type_key);
|
||||
U64 dst_type_byte_size = e2_byte_size_from_type_key(dst_type_key);
|
||||
B32 dst_type_is_signed = e2_type_kind_is_signed(dst_type_kind);
|
||||
if(dst_type_byte_size < 64)
|
||||
{
|
||||
result = e2_irnode(arena);
|
||||
result->type_key = dst_type_key;
|
||||
result->op = dst_type_is_signed ? RDI_EvalOp_TruncSigned : RDI_EvalOp_Trunc;
|
||||
result->val.u64 = dst_type_byte_size*8;
|
||||
e2_irnode_push_child(arena, result, expr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_convert_if_possible(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key)
|
||||
{
|
||||
E2_IRNode *result = expr;
|
||||
{
|
||||
// rjf: unpack src / dst types
|
||||
E2_TypeKey src_type_key = expr->type_key;
|
||||
E2_TypeKind src_type_kind = e2_type_kind_from_key(src_type_key);
|
||||
E2_TypeKind dst_type_kind = e2_type_kind_from_key(dst_type_key);
|
||||
RDI_EvalTypeGroup src_type_group = e2_type_group_from_kind(src_type_kind);
|
||||
RDI_EvalTypeGroup dst_type_group = e2_type_group_from_kind(dst_type_kind);
|
||||
U64 src_byte_size = e2_byte_size_from_type_key(src_type_key);
|
||||
U64 dst_byte_size = e2_byte_size_from_type_key(dst_type_key);
|
||||
|
||||
// rjf: convert from src -> dst
|
||||
RDI_EvalConversionKind conversion_kind = rdi_eval_conversion_kind_from_typegroups(src_type_group, dst_type_group);
|
||||
if(conversion_kind == RDI_EvalConversionKind_Legal)
|
||||
{
|
||||
result = e2_irnode(arena);
|
||||
result->mode = E2_Mode_Value;
|
||||
result->type_key = dst_type_key;
|
||||
result->op = RDI_EvalOp_Convert;
|
||||
result->val.u64 = src_type_group | (dst_type_group << 8);
|
||||
e2_irnode_push_child(arena, result, expr);
|
||||
}
|
||||
|
||||
// rjf: no-op from src -> dst
|
||||
if(conversion_kind == RDI_EvalConversionKind_Noop)
|
||||
{
|
||||
result->type_key = dst_type_key;
|
||||
}
|
||||
|
||||
// rjf: if shrinking integer sizes, truncate
|
||||
if(dst_byte_size < src_byte_size && e2_type_kind_is_integer(dst_type_kind))
|
||||
{
|
||||
result = e2_irnode_truncate(arena, expr, dst_type_key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal E2_IRNode *
|
||||
e2_irnode_type(Arena *arena, E2_TypeKey type_key)
|
||||
{
|
||||
E2_IRNode *expr = e2_irnode(arena);
|
||||
expr->type_key = type_key;
|
||||
expr->mode = E2_Mode_Type;
|
||||
return expr;
|
||||
}
|
||||
|
||||
internal void
|
||||
e2_irnode_push_child_node(E2_IRNode *parent, E2_IRNodePtrNode *node)
|
||||
{
|
||||
SLLQueuePush(parent->first_child, parent->last_child, node);
|
||||
parent->child_count += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
e2_irnode_push_child(Arena *arena, E2_IRNode *parent, E2_IRNode *expr)
|
||||
{
|
||||
E2_IRNodePtrNode *n = push_array(arena, E2_IRNodePtrNode, 1);
|
||||
n->v = expr;
|
||||
e2_irnode_push_child_node(parent, n);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String -> Expression
|
||||
|
||||
@@ -1319,9 +1809,29 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E
|
||||
{
|
||||
String8 identifier = str8_substr(string, token.range);
|
||||
B32 identifier_mapped = 0;
|
||||
B32 definitions_are_allowed = (state->top_task == 0 || state->top_task->op_kind != E2_OpKind_Macro);
|
||||
|
||||
// rjf: if we're currently parsing a macro definition, then we first want to try
|
||||
// resolving identifiers as macro arguments
|
||||
if(!identifier_mapped && state->top_task != 0 && state->top_task->op_kind == E2_OpKind_Macro)
|
||||
{
|
||||
U64 arg_num = 1;
|
||||
for(String8Node *n = state->top_task->macro_arg_names.first; n != 0; n = n->next, arg_num += 1)
|
||||
{
|
||||
if(str8_match(n->string, identifier, 0))
|
||||
{
|
||||
identifier_mapped = 1;
|
||||
expr = e2_expr(arena);
|
||||
expr->op = E2_EvalOp_LeafMacroArgument;
|
||||
expr->val.u64 = arg_num;
|
||||
expr->mode = E2_Mode_Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: first try to resolve as a definition
|
||||
if(!identifier_mapped && e2_try_token(string, E2_TokenKind_Symbol, s("="), &off, 0))
|
||||
if(definitions_are_allowed && !identifier_mapped && e2_try_token(string, E2_TokenKind_Symbol, s("="), &off, 0))
|
||||
{
|
||||
identifier_mapped = 1;
|
||||
E2_ParseTask *task = state->free_task;
|
||||
@@ -1342,6 +1852,74 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E
|
||||
SLLStackPush(state->top_task, task);
|
||||
}
|
||||
|
||||
// rjf: try to resolve it as a macro definition
|
||||
if(definitions_are_allowed && !identifier_mapped)
|
||||
{
|
||||
U64 macro_off = off;
|
||||
if(e2_try_token(string, E2_TokenKind_Symbol, s("("), ¯o_off, 0))
|
||||
{
|
||||
U64 post_macro_paren_off = macro_off;
|
||||
B32 looks_like_macro_def = 1;
|
||||
U64 macro_arg_count = 0;
|
||||
for(;macro_off < string.size;)
|
||||
{
|
||||
if(!e2_try_token(string, E2_TokenKind_Identifier, s(""), ¯o_off, 0))
|
||||
{
|
||||
looks_like_macro_def = 0;
|
||||
break;
|
||||
}
|
||||
macro_arg_count += 1;
|
||||
e2_try_token(string, E2_TokenKind_Symbol, s(","), ¯o_off, 0);
|
||||
if(e2_try_token(string, E2_TokenKind_Symbol, s(")"), ¯o_off, 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(looks_like_macro_def && e2_try_token(string, E2_TokenKind_Symbol, s("="), ¯o_off, 0))
|
||||
{
|
||||
// rjf: push task to fill macro definition
|
||||
identifier_mapped = 1;
|
||||
E2_ParseTask *task = state->free_task;
|
||||
if(task != 0)
|
||||
{
|
||||
SLLStackPop(state->free_task);
|
||||
}
|
||||
else
|
||||
{
|
||||
task = push_array_no_zero(arena, E2_ParseTask, 1);
|
||||
}
|
||||
MemoryZeroStruct(task);
|
||||
task->src_range = token.range;
|
||||
task->child_count_target = 1;
|
||||
task->op_kind = E2_OpKind_Macro;
|
||||
task->max_precedence = max_S64;
|
||||
task->identifier = identifier;
|
||||
SLLStackPush(state->top_task, task);
|
||||
|
||||
// rjf: gather argument names
|
||||
macro_off = post_macro_paren_off;
|
||||
for(;macro_off < string.size;)
|
||||
{
|
||||
E2_Token next_token = {0};
|
||||
if(!e2_try_token(string, E2_TokenKind_Identifier, s(""), ¯o_off, &next_token))
|
||||
{
|
||||
break;
|
||||
}
|
||||
str8_list_push(arena, &task->macro_arg_names, str8_substr(string, next_token.range));
|
||||
e2_try_token(string, E2_TokenKind_Symbol, s(","), ¯o_off, 0);
|
||||
if(e2_try_token(string, E2_TokenKind_Symbol, s(")"), ¯o_off, 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
e2_try_token(string, E2_TokenKind_Symbol, s("="), ¯o_off, 0);
|
||||
|
||||
// rjf: advance offset to past '='
|
||||
off = macro_off;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: first try to resolve as an operator name
|
||||
if(!identifier_mapped)
|
||||
{
|
||||
@@ -2102,6 +2680,23 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: macros
|
||||
case E2_OpKind_Macro:
|
||||
{
|
||||
if(completed_with_caller_info)
|
||||
{
|
||||
finished_root = &e2_expr_nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
done = 1;
|
||||
parse.status = E2_ParseStatus_NewIdentifierDefinition;
|
||||
parse.expr = lhs;
|
||||
parse.identifier = completed_task->identifier;
|
||||
state->caller_info_completes_task = 1;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: conditionals
|
||||
case E2_OpKind_Cond:
|
||||
{
|
||||
@@ -2459,7 +3054,11 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_
|
||||
U64 ctx_base_addr = 0;
|
||||
switch(op)
|
||||
{
|
||||
default:{}break;
|
||||
default:
|
||||
{
|
||||
good = 0;
|
||||
interp.status = E2_InterpStatus_UnsupportedOp;
|
||||
}break;
|
||||
|
||||
case E2_EvalOp_SetCtxID:
|
||||
{
|
||||
|
||||
+97
-5
@@ -39,6 +39,7 @@ struct E2_OpInfo
|
||||
enum
|
||||
{
|
||||
E2_EvalOp_SetCtxID = RDI_EvalOp_COUNT,
|
||||
E2_EvalOp_LeafMacroArgument,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -67,6 +68,32 @@ E2_ParseStatus;
|
||||
#define e2_parse_status_is_terminal(s) (E2_ParseStatus_FirstTerminal <= (s) && (s) <= E2_ParseStatus_LastTerminal)
|
||||
#define e2_parse_status_is_caller_request(s) (E2_ParseStatus_FirstCallerRequest <= (s) && (s) <= E2_ParseStatus_LastCallerRequest)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Compiler Statuses
|
||||
|
||||
typedef enum E2_CompileStatus
|
||||
{
|
||||
//- rjf: terminals
|
||||
E2_CompileStatus_Good,
|
||||
E2_CompileStatus_Error,
|
||||
E2_CompileStatus_FirstTerminal = E2_CompileStatus_Good,
|
||||
E2_CompileStatus_LastTerminal = E2_CompileStatus_Error,
|
||||
|
||||
//- rjf: caller-provided info
|
||||
E2_CompileStatus_MissedIdentifierResolution,
|
||||
E2_CompileStatus_NewIdentifierDefinition,
|
||||
E2_CompileStatus_MemberAccess,
|
||||
E2_CompileStatus_IndexAccess,
|
||||
E2_CompileStatus_Call,
|
||||
E2_CompileStatus_CompileTimeEval,
|
||||
E2_CompileStatus_FirstCallerRequest = E2_CompileStatus_MissedIdentifierResolution,
|
||||
E2_CompileStatus_LastCallerRequest = E2_CompileStatus_CompileTimeEval,
|
||||
}
|
||||
E2_CompileStatus;
|
||||
|
||||
#define e2_compile_status_is_terminal(s) (E2_CompileStatus_FirstTerminal <= (s) && (s) <= E2_CompileStatus_LastTerminal)
|
||||
#define e2_compile_status_is_caller_request(s) (E2_CompileStatus_FirstCallerRequest <= (s) && (s) <= E2_CompileStatus_LastCallerRequest)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Interpretation Statuses
|
||||
|
||||
@@ -152,9 +179,9 @@ struct E2_ConsTypeParams
|
||||
typedef struct E2_ConsTypeNode E2_ConsTypeNode;
|
||||
struct E2_ConsTypeNode
|
||||
{
|
||||
E2_ConsTypeNode *key_next;
|
||||
E2_ConsTypeNode *id_next;
|
||||
E2_ConsTypeNode *content_next;
|
||||
E2_TypeKey key;
|
||||
U64 id;
|
||||
E2_ConsTypeParams params;
|
||||
U64 byte_size;
|
||||
};
|
||||
@@ -169,11 +196,12 @@ struct E2_ConsTypeSlot
|
||||
typedef struct E2_ConsTypeMap E2_ConsTypeMap;
|
||||
struct E2_ConsTypeMap
|
||||
{
|
||||
Arena *arena;
|
||||
U64 id_gen;
|
||||
U64 content_slots_count;
|
||||
U64 table_start_arena_pos;
|
||||
U64 slots_count;
|
||||
E2_ConsTypeSlot *content_slots;
|
||||
U64 key_slots_count;
|
||||
E2_ConsTypeSlot *key_slots;
|
||||
E2_ConsTypeSlot *id_slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -340,6 +368,7 @@ struct E2_ParseTask
|
||||
String8 expected_closer;
|
||||
String8 expected_splitter;
|
||||
B32 splitter_is_required;
|
||||
String8List macro_arg_names;
|
||||
};
|
||||
|
||||
typedef struct E2_ParseState E2_ParseState;
|
||||
@@ -381,6 +410,40 @@ struct E2_Parse
|
||||
E2_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IR Tree Building
|
||||
|
||||
typedef struct E2_IRNodePtrNode E2_IRNodePtrNode;
|
||||
struct E2_IRNodePtrNode
|
||||
{
|
||||
E2_IRNodePtrNode *next;
|
||||
struct E2_IRNode *v;
|
||||
};
|
||||
|
||||
typedef struct E2_IRNode E2_IRNode;
|
||||
struct E2_IRNode
|
||||
{
|
||||
E2_IRNodePtrNode *first_child;
|
||||
E2_IRNodePtrNode *last_child;
|
||||
U64 child_count;
|
||||
RDI_EvalOp op;
|
||||
String8 string;
|
||||
E2_TypeKey type_key;
|
||||
E2_Mode mode;
|
||||
E2_Val val;
|
||||
};
|
||||
|
||||
typedef struct E2_Compile E2_Compile;
|
||||
struct E2_Compile
|
||||
{
|
||||
E2_CompileStatus status;
|
||||
String8 identifier;
|
||||
E2_Expr *expr;
|
||||
String8 member_name;
|
||||
E2_Expr *params_expr;
|
||||
E2_MsgList msgs;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Interpretation
|
||||
|
||||
@@ -433,9 +496,11 @@ struct E2_Interp
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static E2_Assets *e2_assets = 0;
|
||||
thread_static E2_ConsTypeMap *e2_cons_type_map = 0;
|
||||
read_only global E2_ConsTypeNode e2_cons_type_node_nil = {&e2_cons_type_node_nil, &e2_cons_type_node_nil};
|
||||
read_only global E2_DbgInfo e2_dbg_info_nil = {{0}, &rdi_parsed_nil};
|
||||
read_only global E2_Expr e2_expr_nil = {0};
|
||||
read_only global E2_IRNode e2_irnode_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Space -> Memory Map Helpers
|
||||
@@ -461,6 +526,16 @@ internal E2_Msg *e2_msgf(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, char
|
||||
internal void e2_select_assets(E2_Assets *assets);
|
||||
internal E2_DbgInfo *e2_dbgi_from_num(U32 num);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Constructed Types
|
||||
|
||||
internal E2_ConsTypeMap *e2_cons_type_map_alloc(void);
|
||||
internal void e2_select_cons_type_map(E2_ConsTypeMap *map);
|
||||
internal B32 e2_cons_type_params_match(E2_ConsTypeParams *a, E2_ConsTypeParams *b);
|
||||
internal E2_ConsTypeNode *e2_cons_type_node_from_params(E2_ConsTypeParams *params);
|
||||
internal E2_ConsTypeNode *e2_cons_type_node_from_id(U64 id);
|
||||
internal E2_TypeKey e2_type_key_from_cons_type_node(E2_ConsTypeNode *node);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Type Keys
|
||||
|
||||
@@ -496,6 +571,7 @@ internal U64 e2_byte_size_from_type_key(E2_TypeKey k);
|
||||
internal U32 e2_dbgi_num_from_type_key(E2_TypeKey k);
|
||||
internal E2_DbgInfo *e2_dbgi_from_type_key(E2_TypeKey k);
|
||||
internal U32 e2_dbgi_type_idx_from_key(E2_TypeKey k);
|
||||
internal U64 e2_cons_type_id_from_key(E2_TypeKey k);
|
||||
internal U64 e2_shift_from_type_key(E2_TypeKey k);
|
||||
internal U64 e2_mask_count_from_type_key(E2_TypeKey k);
|
||||
internal Arch e2_arch_from_type_key(E2_TypeKey k);
|
||||
@@ -543,6 +619,22 @@ internal E2_Expr *e2_expr_type(Arena *arena, E2_TypeKey type_key);
|
||||
internal void e2_expr_push_child_node(E2_Expr *parent, E2_ExprNode *node);
|
||||
internal void e2_expr_push_child(Arena *arena, E2_Expr *parent, E2_Expr *expr);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IR Tree Constructors
|
||||
|
||||
internal E2_IRNode *e2_irnode(Arena *arena);
|
||||
internal E2_IRNode *e2_irnode_const_u64_or_smaller(Arena *arena, U64 u);
|
||||
internal E2_IRNode *e2_irnode_const_f32(Arena *arena, F32 f32);
|
||||
internal E2_IRNode *e2_irnode_const_f64(Arena *arena, F64 f64);
|
||||
internal E2_IRNode *e2_irnode_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *operand);
|
||||
internal E2_IRNode *e2_irnode_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *lhs, E2_IRNode *rhs);
|
||||
internal E2_IRNode *e2_irnode_resolve_to_value(Arena *arena, E2_IRNode *expr);
|
||||
internal E2_IRNode *e2_irnode_truncate(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key);
|
||||
internal E2_IRNode *e2_irnode_convert_if_possible(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key);
|
||||
internal E2_IRNode *e2_irnode_type(Arena *arena, E2_TypeKey type_key);
|
||||
internal void e2_irnode_push_child_node(E2_IRNode *parent, E2_IRNodePtrNode *node);
|
||||
internal void e2_irnode_push_child(Arena *arena, E2_IRNode *parent, E2_IRNode *expr);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String -> Expression
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ E2_OpTable:
|
||||
{LogAnd Binary 11 "" "&&" "" "" }
|
||||
{LogOr Binary 12 "" "||" "" "" }
|
||||
{Define Null 13 "" "=" "" "" }
|
||||
{Macro Null 14 "" "" "" "" }
|
||||
{Cond Ternary 14 "" "?" "" ":"}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
E2_OpInfo e2_op_kind_info_table[34] =
|
||||
E2_OpInfo e2_op_kind_info_table[35] =
|
||||
{
|
||||
{0},
|
||||
{E2_OpParseKind_Binary, 1, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("")},
|
||||
@@ -38,7 +38,8 @@ E2_OpInfo e2_op_kind_info_table[34] =
|
||||
{E2_OpParseKind_Binary, 10, str8_lit_comp(""), str8_lit_comp("|"), str8_lit_comp(""), str8_lit_comp("")},
|
||||
{E2_OpParseKind_Binary, 11, str8_lit_comp(""), str8_lit_comp("&&"), str8_lit_comp(""), str8_lit_comp("")},
|
||||
{E2_OpParseKind_Binary, 12, str8_lit_comp(""), str8_lit_comp("||"), str8_lit_comp(""), str8_lit_comp("")},
|
||||
{E2_OpParseKind_Binary, 13, str8_lit_comp(""), str8_lit_comp("="), str8_lit_comp(""), str8_lit_comp("")},
|
||||
{E2_OpParseKind_Null, 13, str8_lit_comp(""), str8_lit_comp("="), str8_lit_comp(""), str8_lit_comp("")},
|
||||
{E2_OpParseKind_Null, 14, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")},
|
||||
{E2_OpParseKind_Ternary, 14, str8_lit_comp(""), str8_lit_comp("?"), str8_lit_comp(""), str8_lit_comp(":")},
|
||||
};
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ E2_OpKind_BitOr,
|
||||
E2_OpKind_LogAnd,
|
||||
E2_OpKind_LogOr,
|
||||
E2_OpKind_Define,
|
||||
E2_OpKind_Macro,
|
||||
E2_OpKind_Cond,
|
||||
E2_OpKind_COUNT,
|
||||
} E2_OpKind;
|
||||
@@ -124,7 +125,7 @@ E2_TypeKind_LastMeta = E2_TypeKind_MetaDescription,
|
||||
} E2_TypeKind;
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
extern E2_OpInfo e2_op_kind_info_table[34];
|
||||
extern E2_OpInfo e2_op_kind_info_table[35];
|
||||
extern U8 e2_type_kind_basic_byte_size_table[61];
|
||||
extern String8 e2_type_kind_basic_string_table[61];
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
internal void
|
||||
entry_point(CmdLine *cmdline)
|
||||
{
|
||||
E2_ConsTypeMap *cons_types = e2_cons_type_map_alloc();
|
||||
e2_select_cons_type_map(cons_types);
|
||||
String8 strings[] =
|
||||
{
|
||||
// (A)B
|
||||
@@ -44,6 +46,7 @@ entry_point(CmdLine *cmdline)
|
||||
s("123, 456"),
|
||||
s("int32 == int32"),
|
||||
s("foo = 123"),
|
||||
s("bar(a, b) = a + b"),
|
||||
s("1 > 2"),
|
||||
s("1 ? \"Test\" : 888"),
|
||||
s("'a'"),
|
||||
|
||||
Reference in New Issue
Block a user