From a87c03230585854d06e82da39118992271bce8ed Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 25 Sep 2024 13:17:17 -0700 Subject: [PATCH] fix a few details in new eval visualization block tree generation algorithm; fix row generation; start fitting new system into hover eval as a first test --- .../eval_visualization_core.c | 253 ++++++++++++++++-- .../eval_visualization_core.h | 5 + src/raddbg/raddbg_core.c | 31 ++- 3 files changed, 249 insertions(+), 40 deletions(-) diff --git a/src/eval_visualization/eval_visualization_core.c b/src/eval_visualization/eval_visualization_core.c index 1920404b..601bffb6 100644 --- a/src/eval_visualization/eval_visualization_core.c +++ b/src/eval_visualization/eval_visualization_core.c @@ -510,6 +510,8 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex tree.root->expr = expr; tree.root->view_rules = view_rules; tree.root->semantic_row_count = tree.root->visual_row_count = 1; + tree.total_semantic_row_count += 1; + tree.total_visual_row_count += 1; //- rjf: iterate all expansions & generate blocks for each typedef struct Task Task; @@ -517,14 +519,17 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex { Task *next; EV2_Block *parent_block; + E_Expr *expr; + EV_Key key; + EV_ViewRuleList *view_rules; U64 split_relative_idx; }; - Task start_task = {0, tree.root, 1}; + Task start_task = {0, tree.root, expr, tree.root->key, view_rules, 1}; Task *first_task = &start_task; Task *last_task = first_task; for(Task *t = first_task; t != 0; t = t->next) { - EV_ExpandNode *expand_node = ev_expand_node_from_key(view, t->parent_block->key); + EV_ExpandNode *expand_node = ev_expand_node_from_key(view, t->key); // rjf: skip if not expanded if(!expand_node || !expand_node->expanded) @@ -533,9 +538,9 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex } // rjf: get expansion view rule info - EV_ViewRuleInfo *expand_view_rule_info = &ev_nil_view_rule_info; + EV_ViewRuleInfo *expand_view_rule_info = default_expand_view_rule_info; MD_Node *expand_params = &md_nil_node; - for(EV_ViewRuleNode *n = t->parent_block->view_rules->first; n != 0; n = n->next) + for(EV_ViewRuleNode *n = t->view_rules->first; n != 0; n = n->next) { EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string); if(info->expr_expand != 0) @@ -546,17 +551,17 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex } // rjf: get expansion info - EV_ExpandResult expand_result = expand_view_rule_info->expr_expand(arena, t->parent_block->expr, expand_params, r1u64(0, 0)); + EV_ExpandResult expand_result = expand_view_rule_info->expr_expand(arena, t->expr, expand_params, r1u64(0, 0)); // rjf: generate block for expansion EV2_Block *expansion_block = push_array(arena, EV2_Block, 1); MemoryCopyStruct(expansion_block, &ev2_nil_block); - DLLPushBack(t->parent_block->first, t->parent_block->last, expansion_block); + DLLPushBack_NPZ(&ev2_nil_block, t->parent_block->first, t->parent_block->last, expansion_block, next, prev); expansion_block->parent = t->parent_block; - expansion_block->key = t->parent_block->key; + expansion_block->key = t->key; expansion_block->split_relative_idx = t->split_relative_idx; - expansion_block->expr = t->parent_block->expr; - expansion_block->view_rules = t->parent_block->view_rules; + expansion_block->expr = t->expr; + expansion_block->view_rules = t->view_rules; expansion_block->expand_view_rule_info = expand_view_rule_info; expansion_block->expand_view_rule_params = expand_params; expansion_block->semantic_row_count = expand_result.total_semantic_row_count; @@ -564,14 +569,24 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex tree.total_semantic_row_count += expand_result.total_semantic_row_count; tree.total_visual_row_count += expand_result.total_visual_row_count; - // rjf: iterate children expansions, generate children blocks for each + // rjf: iterate children expansions, recurse // TODO(rjf): need to iterate these in index order, rather than "child_num" (which needs to be renamed to "child_id") order for(EV_ExpandNode *child = expand_node->first; child != 0; child = child->next) { - Task *task = push_array(scratch.arena, Task, 1); - SLLQueuePush(first_task, last_task, task); - task->parent_block = expansion_block; - task->split_relative_idx = child->key.child_num - 1; // TODO(rjf): key -> index + U64 split_relative_idx = child->key.child_num - 1; // TODO(rjf): key -> index + EV_ExpandResult child_expand = expand_view_rule_info->expr_expand(arena, t->expr, expand_params, r1u64(split_relative_idx, split_relative_idx+1)); + if(child_expand.row_exprs_count > 0) + { + EV_ViewRuleList *child_view_rules = ev_view_rule_list_from_inheritance(arena, t->view_rules); + // TODO(rjf): need to mix in child's view rules + Task *task = push_array(scratch.arena, Task, 1); + SLLQueuePush(first_task, last_task, task); + task->parent_block = expansion_block; + task->expr = child_expand.row_exprs[0]; + task->key = child->key; + task->view_rules = child_view_rules; + task->split_relative_idx = split_relative_idx; + } } } scratch_end(scratch); @@ -579,6 +594,77 @@ ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *ex return tree; } +internal EV2_BlockTree +ev2_block_tree_from_string(Arena *arena, EV_View *view, String8 string, EV_ViewRuleList *view_rules) +{ + EV2_BlockTree tree = {0}; + Temp scratch = scratch_begin(&arena, 1); + { + // rjf: parse expression + E_TokenArray tokens = e_token_array_from_text(scratch.arena, string); + E_Parse parse = e_parse_expr_from_text_tokens(arena, string, &tokens); + + // rjf: extract view rules, encoded via fastpaths in expression string + String8List fastpath_view_rules = {0}; + { + U64 parse_opl = (parse.last_token >= tokens.v + tokens.count ? string.size : parse.last_token->range.min); + U64 comma_pos = str8_find_needle(string, parse_opl, str8_lit(","), 0); + U64 passthrough_pos = str8_find_needle(string, parse_opl, str8_lit("--"), 0); + if(comma_pos < string.size && comma_pos < passthrough_pos) + { + String8 comma_extension = str8_skip_chop_whitespace(str8_substr(string, r1u64(comma_pos+1, passthrough_pos))); + if(str8_match(comma_extension, str8_lit("x"), StringMatchFlag_CaseInsensitive)) + { + str8_list_pushf(arena, &fastpath_view_rules, "hex"); + } + else if(str8_match(comma_extension, str8_lit("b"), StringMatchFlag_CaseInsensitive)) + { + str8_list_pushf(arena, &fastpath_view_rules, "bin"); + } + else if(str8_match(comma_extension, str8_lit("o"), StringMatchFlag_CaseInsensitive)) + { + str8_list_pushf(arena, &fastpath_view_rules, "oct"); + } + else if(comma_extension.size != 0) + { + str8_list_pushf(arena, &fastpath_view_rules, "array:{%S}", comma_extension); + } + } + if(passthrough_pos < string.size) + { + String8 passthrough_view_rule = str8_skip_chop_whitespace(str8_skip(string, passthrough_pos+2)); + if(passthrough_view_rule.size != 0) + { + str8_list_push(arena, &fastpath_view_rules, passthrough_view_rule); + } + } + } + + // rjf: build full list of view rules + EV_ViewRuleList *all_view_rules = ev_view_rule_list_copy(arena, view_rules); + for(String8Node *n = fastpath_view_rules.first; n != 0; n = n->next) + { + ev_view_rule_list_push_string(arena, all_view_rules, n->string); + } + + // rjf: produce tree + tree = ev2_block_tree_from_expr(arena, view, string, parse.expr, all_view_rules); + } + scratch_end(scratch); + return tree; +} + +internal U64 +ev2_depth_from_block(EV2_Block *block) +{ + U64 depth = 0; + for(EV2_Block *b = block->parent; b != &ev2_nil_block; b = b->parent) + { + depth += 1; + } + return depth; +} + internal EV2_WindowedRowList ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree *block_tree, Rng1U64 visible_range) { @@ -599,7 +685,10 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree { // rjf: get block-relative range, truncated by split position of next child Rng1U64 block_relative_range = t->block_relative_range; - block_relative_range.max = Min(t->next_child->split_relative_idx, block_relative_range.max); + if(t->next_child != &ev2_nil_block) + { + block_relative_range.max = t->next_child->split_relative_idx+1; + } U64 block_num_visual_rows = dim_1u64(block_relative_range); // rjf: get global range of this block @@ -627,27 +716,50 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree // rjf: sum & advance visual_idx_off += block_num_visual_rows; + rows.count_before_visual += num_skipped; // rjf: generate rows before next splitting child if(block_relative_range__windowed.max > block_relative_range__windowed.min) { - EV_ExpandResult expand = t->block->expand_view_rule_info->expr_expand(arena, t->block->expr, t->block->expand_view_rule_params, block_relative_range__windowed); - for EachIndex(idx, expand.row_exprs_count) + // rjf: no expansion operator applied -> push row for block expression; pass through block info + if(t->block->expand_view_rule_info == &ev_nil_view_rule_info) { - U64 row_visual_size = expand.row_exprs_num_visual_rows[idx]; - U64 child_id = block_relative_range.min + idx + 1; // TODO(rjf): index -> key EV2_Row *row = push_array(arena, EV2_Row, 1); SLLQueuePush(rows.first, rows.last, row); + rows.count += 1; row->block = t->block; - row->key = ev_key_make(ev_hash_from_key(row->block->key), child_id); - row->visual_size = row_visual_size; + row->key = t->block->key; + row->visual_size = t->block->visual_row_count; row->visual_size_skipped = 0; // TODO(rjf) row->visual_size_chopped = 0; // TODO(rjf) row->string = t->block->string; - row->expr = expand.row_exprs[idx]; - row->member = expand.row_members[idx]; - row->view_rules = ev_view_rule_list_from_inheritance(arena, t->block->view_rules); - // TODO(rjf): mix in view rules based on row's key, row's type + row->expr = t->block->expr; + row->member = &e_member_nil; + row->view_rules = t->block->view_rules; + } + + // rjf: expansion operator applied -> call, and add rows for all expressions in the viewable range + else + { + EV_ExpandResult expand = t->block->expand_view_rule_info->expr_expand(arena, t->block->expr, t->block->expand_view_rule_params, block_relative_range__windowed); + for EachIndex(idx, expand.row_exprs_count) + { + U64 row_visual_size = expand.row_exprs_num_visual_rows[idx]; + U64 child_id = block_relative_range.min + idx + 1; // TODO(rjf): index -> key + EV2_Row *row = push_array(arena, EV2_Row, 1); + SLLQueuePush(rows.first, rows.last, row); + rows.count += 1; + row->block = t->block; + row->key = ev_key_make(ev_hash_from_key(row->block->key), child_id); + row->visual_size = row_visual_size; + row->visual_size_skipped = 0; // TODO(rjf) + row->visual_size_chopped = 0; // TODO(rjf) + row->string = t->block->string; + row->expr = expand.row_exprs[idx]; + row->member = expand.row_members[idx]; + row->view_rules = ev_view_rule_list_from_inheritance(arena, t->block->view_rules); + // TODO(rjf): mix in view rules based on row's key, row's type + } } } @@ -663,7 +775,7 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree child_task->block_relative_range = r1u64(0, t->next_child->visual_row_count); // rjf: generate task for post-child rows, if any, after children - Rng1U64 remainder_range = r1u64(t->next_child->split_relative_idx, t->block_relative_range.max); + Rng1U64 remainder_range = r1u64(t->next_child->split_relative_idx+1, t->block_relative_range.max); if(remainder_range.max > remainder_range.min) { BlockTask *remainder_task = push_array(scratch.arena, BlockTask, 1); @@ -680,6 +792,95 @@ ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree return rows; } +internal String8 +ev2_expr_string_from_row(Arena *arena, EV2_Row *row, EV_StringFlags flags) +{ + String8 result = row->string; + E_Expr *notable_expr = row->expr; + for(B32 good = 0; !good;) + { + switch(notable_expr->kind) + { + default:{good = 1;}break; + case E_ExprKind_Address: + case E_ExprKind_Deref: + case E_ExprKind_Cast: + { + notable_expr = notable_expr->last; + }break; + case E_ExprKind_Ref: + { + notable_expr = notable_expr->ref; + }break; + } + } + if(result.size == 0) switch(notable_expr->kind) + { + default: + { + result = e_string_from_expr(arena, notable_expr); + }break; + case E_ExprKind_ArrayIndex: + { + result = push_str8f(arena, "[%S]", e_string_from_expr(arena, notable_expr->last)); + }break; + case E_ExprKind_MemberAccess: + { + if(flags & EV_StringFlag_PrettyNames && row->member->pretty_name.size != 0) + { + result = push_str8_copy(arena, row->member->pretty_name); + } + else + { + result = push_str8f(arena, ".%S", e_string_from_expr(arena, notable_expr->last)); + } + }break; + } + return result; +} + +internal B32 +ev2_row_is_expandable(EV2_Row *row) +{ + B32 result = 0; + { + // rjf: determine if view rules force expandability + if(!result) + { + for(EV_ViewRuleNode *n = row->view_rules->first; n != 0; n = n->next) + { + EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string); + if(info->flags & EV_ViewRuleInfoFlag_Expandable) + { + result = 1; + break; + } + } + } + + // rjf: determine if type info force expandability + if(!result) + { + Temp scratch = scratch_begin(0, 0); + E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr); + result = ev_type_key_and_mode_is_expandable(irtree.type_key, irtree.mode); + scratch_end(scratch); + } + } + return result; +} + +internal B32 +ev2_row_is_editable(EV2_Row *row) +{ + B32 result = 0; + Temp scratch = scratch_begin(0, 0); + E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr); + result = ev_type_key_is_editable(irtree.type_key); + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: Block Building diff --git a/src/eval_visualization/eval_visualization_core.h b/src/eval_visualization/eval_visualization_core.h index 647a7522..d71206cd 100644 --- a/src/eval_visualization/eval_visualization_core.h +++ b/src/eval_visualization/eval_visualization_core.h @@ -460,7 +460,12 @@ internal E_Expr *ev_expr_from_expr_view_rules(Arena *arena, E_Expr *expr, EV_Vie //~ rjf: Block Building (v2) internal EV2_BlockTree ev2_block_tree_from_expr(Arena *arena, EV_View *view, String8 string, E_Expr *expr, EV_ViewRuleList *view_rules); +internal EV2_BlockTree ev2_block_tree_from_string(Arena *arena, EV_View *view, String8 string, EV_ViewRuleList *view_rules); +internal U64 ev2_depth_from_block(EV2_Block *block); internal EV2_WindowedRowList ev2_windowed_row_list_from_block_tree(Arena *arena, EV_View *view, EV2_BlockTree *block_tree, Rng1U64 visible_range); +internal String8 ev2_expr_string_from_row(Arena *arena, EV2_Row *row, EV_StringFlags flags); +internal B32 ev2_row_is_expandable(EV2_Row *row); +internal B32 ev2_row_is_editable(EV2_Row *row); //////////////////////////////// //~ rjf: Block Building diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 1bdfab64..25e8b4ec 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -5825,17 +5825,19 @@ rd_window_frame(RD_Window *ws) EV_View *ev_view = rd_ev_view_from_key(d_hash_from_string(ev_view_key_string)); EV_Key parent_key = ev_key_make(5381, 1); EV_Key key = ev_key_make(ev_hash_from_key(parent_key), 1); - EV_BlockList viz_blocks = ev_block_list_from_view_expr_keys(scratch.arena, ev_view, str8_zero(), &top_level_view_rules, expr, parent_key, key, 0); + EV2_BlockTree block_tree = ev2_block_tree_from_string(scratch.arena, ev_view, expr, &top_level_view_rules); + // EV_BlockList viz_blocks = ev_block_list_from_view_expr_keys(scratch.arena, ev_view, str8_zero(), &top_level_view_rules, expr, parent_key, key, 0); CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); U32 default_radix = (entity->kind == CTRL_EntityKind_Thread ? 16 : 10); - EV_WindowedRowList viz_rows = ev_windowed_row_list_from_block_list(scratch.arena, ev_view, r1s64(0, 50), &viz_blocks); + EV2_WindowedRowList rows = ev2_windowed_row_list_from_block_tree(scratch.arena, ev_view, &block_tree, r1u64(0, 50)); + // EV_WindowedRowList viz_rows = ev_windowed_row_list_from_block_list(scratch.arena, ev_view, r1s64(0, 50), &viz_blocks); //- rjf: animate { // rjf: animate height { F32 fish_rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-60.f * rd_state->frame_dt)) : 1.f; - F32 hover_eval_container_height_target = row_height * Min(30, viz_blocks.total_visual_row_count); + F32 hover_eval_container_height_target = row_height * Min(30, block_tree.total_visual_row_count); ws->hover_eval_num_visible_rows_t += (hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) * fish_rate; if(abs_f32(hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) > 0.5f) { @@ -5867,11 +5869,11 @@ rd_window_frame(RD_Window *ws) F32 width_px = 40.f*ui_top_font_size(); F32 expr_column_width_px = 10.f*ui_top_font_size(); F32 value_column_width_px = 30.f*ui_top_font_size(); - if(viz_rows.first != 0) + if(rows.first != 0) { - EV_Row *row = viz_rows.first; + EV2_Row *row = rows.first; E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - String8 row_expr_string = ev_expr_string_from_row(scratch.arena, row, 0); + String8 row_expr_string = ev2_expr_string_from_row(scratch.arena, row, 0); String8 row_display_value = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules); expr_column_width_px = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, 0, row_expr_string).x + ui_top_font_size()*5.f; value_column_width_px = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, 0, row_display_value).x + ui_top_font_size()*5.f; @@ -5915,15 +5917,16 @@ rd_window_frame(RD_Window *ws) UI_Parent(hover_eval_box) UI_PrefHeight(ui_px(row_height, 1.f)) { //- rjf: build rows - for(EV_Row *row = viz_rows.first; row != 0; row = row->next) + for(EV2_Row *row = rows.first; row != 0; row = row->next) { //- rjf: unpack row + U64 row_depth = ev2_depth_from_block(row->block); E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - String8 row_expr_string = ev_expr_string_from_row(scratch.arena, row, 0); + String8 row_expr_string = ev2_expr_string_from_row(scratch.arena, row, 0); String8 row_edit_value = rd_value_string_from_eval(scratch.arena, 0, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules); String8 row_display_value = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules); - B32 row_is_editable = ev_row_is_editable(row); - B32 row_is_expandable = ev_row_is_expandable(row); + B32 row_is_editable = ev2_row_is_editable(row); + B32 row_is_expandable = ev2_row_is_expandable(row); //- rjf: determine if row's data is fresh and/or bad B32 row_is_fresh = 0; @@ -5959,9 +5962,9 @@ rd_window_frame(RD_Window *ws) UI_WidthFill UI_Row { ui_spacer(ui_em(0.75f, 1.f)); - if(row->depth > 0) + if(row_depth > 0) { - for(S32 indent = 0; indent < row->depth; indent += 1) + for(U64 indent = 0; indent < row_depth; indent += 1) { ui_spacer(ui_em(0.75f, 1.f)); UI_Flags(UI_BoxFlag_DrawSideLeft) ui_spacer(ui_em(1.5f, 1.f)); @@ -5973,7 +5976,7 @@ rd_window_frame(RD_Window *ws) UI_PrefWidth(ui_em(1.5f, 1)) if(ui_pressed(ui_expanderf(row_is_expanded, "###%I64x_%I64x_is_expanded", row->key.parent_hash, row->key.child_num))) { - ev_key_set_expansion(ev_view, row->parent_key, row->key, !row_is_expanded); + ev_key_set_expansion(ev_view, row->block->key, row->key, !row_is_expanded); } if(!row_is_expandable) { @@ -6023,7 +6026,7 @@ rd_window_frame(RD_Window *ws) rd_code_label(1.f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), row_display_value); } } - if(row == viz_rows.first) + if(row == rows.first) { UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_em(3.f, 1.f)) UI_CornerRadius00(0)