From fe2aa4d14c8c161b9a09ea72a5d9fe161d797c39 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 18 Jun 2026 22:06:04 -0600 Subject: [PATCH] com shim for launching raddbg in cli mode, for proper console subsystem style usage of packaged bin utilities; checkpoint on eval2 --- build.bat | 10 +- project.4coder | 2 +- project.raddbg | 2 +- src/base/base_processes.h | 2 +- src/com_shim/com_shim_main.c | 64 +++++ src/dbg_info/dbg_info.c | 2 + src/eval2/eval2.c | 457 ++++++++++++++++++++++++++----- src/eval2/eval2.h | 89 ++++-- src/eval2/eval2.mdesk | 56 ++-- src/eval2/generated/eval2.meta.c | 8 +- src/eval2/generated/eval2.meta.h | 8 +- src/lib_rdi/rdi.c | 4 +- src/linux/base/linux_base.c | 4 +- src/raddbg/raddbg_main.c | 10 + src/rdi/rdi.mdesk | 4 +- src/rdi_from_pdb/rdi_from_pdb.c | 2 +- src/scratch/ryan_scratch.c | 62 ++++- src/win32/base/win32_base.c | 4 +- 18 files changed, 638 insertions(+), 152 deletions(-) create mode 100644 src/com_shim/com_shim_main.c diff --git a/build.bat b/build.bat index 5c9c71d4..bc8b1c38 100644 --- a/build.bat +++ b/build.bat @@ -36,8 +36,8 @@ if "%debug%"=="1" set release=0 && echo [debug mode] if "%release%"=="1" set debug=0 && echo [release mode] if "%msvc%"=="1" set clang=0 && echo [msvc compile] if "%clang%"=="1" set msvc=0 && echo [clang compile] -if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1 -if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1 +if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1 +if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1 :: --- Unpack Command Line Build Arguments ------------------------------------ set auto_compile_flags= @@ -141,6 +141,7 @@ popd pushd build if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1 if "%raddbg_non_graphical%"=="1" set didbuild=1 && %compile% -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg_non_graphical.exe || exit /b 1 +if "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.exe || exit /b 1 if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1 if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1 if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1 @@ -166,6 +167,11 @@ if "%mule_peb_trample%"=="1" ( ) popd +:: --- Set Up Debugger Com Shim ----------------------------------------------- +pushd build +if "%raddbg_com_shim%"=="1" copy /y com_shim.exe raddbg.com +popd + :: --- Warn On No Builds ------------------------------------------------------ if "%didbuild%"=="" ( echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`. diff --git a/project.4coder b/project.4coder index 26b9969f..49daa1cc 100644 --- a/project.4coder +++ b/project.4coder @@ -49,7 +49,7 @@ commands = // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin no_meta", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build ryan_scratch && pushd build && ryan_scratch.exe", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/project.raddbg b/project.raddbg index 27a3760b..1bdae732 100644 --- a/project.raddbg +++ b/project.raddbg @@ -7,7 +7,6 @@ target: working_directory: "../raddebugger" arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user" debug_subprocesses: 0 - enabled: 1 } target: { @@ -35,4 +34,5 @@ target: { executable: "build/ryan_scratch.exe" working_directory: build + enabled: 1 } diff --git a/src/base/base_processes.h b/src/base/base_processes.h index 33d3bb13..ce50a222 100644 --- a/src/base/base_processes.h +++ b/src/base/base_processes.h @@ -70,7 +70,7 @@ internal Process launch_cmd_linef(char *fmt, ...); //////////////////////////////// //~ rjf: @per_os_impl Aborting -internal void abort_self(S32 exit_code); +internal void abort_self(U64 exit_code); //////////////////////////////// //~ rjf: @per_os_impl Process Info diff --git a/src/com_shim/com_shim_main.c b/src/com_shim/com_shim_main.c new file mode 100644 index 00000000..5ccce4c0 --- /dev/null +++ b/src/com_shim/com_shim_main.c @@ -0,0 +1,64 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define NO_ASYNC 1 +#define BUILD_CONSOLE_INTERFACE 1 +#define BUILD_TITLE "The RAD Debugger (Command Line Launcher)" +#include "base/base_inc.h" +#include "base/base_inc.c" + +internal void +entry_point(CmdLine *cmd_line) +{ + Temp scratch = scratch_begin(0, 0); + B32 wait_for_process = cmd_line_has_flag(cmd_line, s("cli")) || cmd_line_has_flag(cmd_line, s("bin")); + String8List command_parts = {0}; + String8 exe_name = str8f(scratch.arena, "%S.exe", str8_chop_last_dot(cmd_line->exe_name)); + if(str8_match(exe_name, cmd_line->exe_name, 0)) + { + fprintf(stderr, + "ERROR: Attempting to launch %.*s recursively.\n" + "\n" + "This executable needs to be used with a .com extension next to the real target\n" + "executable, with the same name, but with a .exe extension. This guarantees that\n" + "cmd.exe will prefer launching this .com file when the executable name is used,\n" + "allowing the same executable to be used in the Windows command-line subsystem\n" + "style when launched from the command line, but used graphically when launched\n" + "via Explorer.\n\n", str8_varg(exe_name)); + fflush(stderr); + } + else + { + // NOTE(rjf): sub-processes must be killed if the parent process + // is killed, if we're waiting for it + if(wait_for_process) + { +#if OS_WINDOWS + HANDLE job_handle = CreateJobObjectA(0, 0); + JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = { .BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE }; + SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info)); + AssignProcessToJobObject(job_handle, GetCurrentProcess()); +#endif + } + str8_list_push(scratch.arena, &command_parts, exe_name); + for EachIndex(idx, cmd_line->argc) + { + String8 arg = str8_cstring(cmd_line->argv[idx]); + str8_list_push(scratch.arena, &command_parts, arg); + } + StringJoin join = {.sep = s(" ")}; + String8 command = str8_list_join(scratch.arena, &command_parts, &join); + Process process = launch_cmd_line(command); + if(wait_for_process) + { + U64 exit_code = 0; + process_join(process, max_U64, &exit_code); + abort_self(exit_code); + } + else + { + process_detach(process); + } + } + scratch_end(scratch); +} diff --git a/src/dbg_info/dbg_info.c b/src/dbg_info/dbg_info.c index 0ec80608..fbbe8f63 100644 --- a/src/dbg_info/dbg_info.c +++ b/src/dbg_info/dbg_info.c @@ -693,6 +693,7 @@ di_async_tick(void) B32 og_is_downloading = 0; if(og_path.size != 0) { +#if defined(SYMBOL_SERVER_H) B32 file_is_present = (properties_from_file_path(og_path).modified != 0); if(!file_is_present) { @@ -715,6 +716,7 @@ di_async_tick(void) } } } +#endif } //- rjf: analyze O.G. debug info diff --git a/src/eval2/eval2.c b/src/eval2/eval2.c index 15fcee7e..4754c20d 100644 --- a/src/eval2/eval2.c +++ b/src/eval2/eval2.c @@ -95,20 +95,23 @@ internal E2_Expr * e2_expr_from_name(E2_ExprMap *map, String8 name) { E2_Expr *expr = &e2_expr_nil; - U64 hash = u64_hash_from_str8(name); - U64 slot_idx = hash%map->slots_count; - E2_ExprMapNode *node = 0; - for(E2_ExprMapNode *n = map->slots[slot_idx]; n != 0; n = n->next) + if(map->slots_count != 0) { - if(str8_match(n->name, name, 0)) + U64 hash = u64_hash_from_str8(name); + U64 slot_idx = hash%map->slots_count; + E2_ExprMapNode *node = 0; + for(E2_ExprMapNode *n = map->slots[slot_idx]; n != 0; n = n->next) { - node = n; - break; + if(str8_match(n->name, name, 0)) + { + node = n; + break; + } + } + if(node != 0) + { + expr = node->expr; } - } - if(node != 0) - { - expr = node->expr; } return expr; } @@ -765,6 +768,8 @@ e2_expr_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_Expr *oper 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_expr_push_child(e, operand); return e; } @@ -1125,21 +1130,40 @@ e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *of } internal E2_Parse -e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, String8 string) +e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, String8 string) { U64 off = state->string_off; - E2_Parse parse = {E2_Status_Error, .expr = &e2_expr_nil, .access_expr = &e2_expr_nil}; + E2_Parse parse = {E2_ParseStatus_Error, .expr = &e2_expr_nil, .params_expr = &e2_expr_nil}; + E2_Expr *next_access_result = access_result; //- rjf: parse & attach to top parsing task - if we don't have a top task // then it is just the result E2_Expr *expr = &e2_expr_nil; for(B32 done = 0; !done;) { + U64 start_off = off; S64 max_precedence = state->top_task ? state->top_task->max_precedence : max_S64; + B32 need_new_expr = (expr == &e2_expr_nil && !state->caller_info_completes_task); E2_Token token = {0}; + //- rjf: skip leading whitespace / comments + for(;;) + { + E2_Token next_token = {0}; + U64 next_off = off + e2_read_token(string, off, &next_token); + if(next_token.kind == E2_TokenKind_Whitespace || + next_token.kind == E2_TokenKind_Comment) + { + off = next_off; + } + else + { + break; + } + } + //- rjf: nested sub-expressions - if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Symbol, s("("), &off, &token)) + if(need_new_expr && e2_try_token(string, E2_TokenKind_Symbol, s("("), &off, &token)) { E2_ParseTask *task = state->free_task; if(task != 0) @@ -1158,11 +1182,12 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S SLLStackPush(state->top_task, task); } - //- rjf: prefix unaries - else if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Symbol, s(""), &off, &token)) + //- rjf: symbols (possible prefix unaries, *or* unexpected) + else if(need_new_expr && e2_try_token(string, E2_TokenKind_Symbol, s(""), &off, &token)) { // rjf: string -> operator kind E2_OpKind op_kind = E2_OpKind_Null; + String8 closer = {0}; { String8 token_string = str8_substr(string, token.range); for EachNonZeroEnumVal(E2_OpKind, k) @@ -1172,6 +1197,7 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S str8_match(token_string, e2_op_kind_info_table[k].pre, 0)) { op_kind = k; + closer = e2_op_kind_info_table[k].post; break; } } @@ -1194,25 +1220,106 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S task->child_count_target = 1; task->op_kind = op_kind; task->max_precedence = e2_op_kind_info_table[op_kind].precedence; + task->expected_closer = closer; SLLStackPush(state->top_task, task); } + + // rjf: report unexpected symbols + if(op_kind == E2_OpKind_Null) + { + String8 token_string = str8_substr(string, token.range); + e2_msgf(arena, &parse.msgs, token.range, "Unexpected `%S`.", token_string); + } } - //- rjf: leaf identifiers - else if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Identifier, s(""), &off, &token)) + //- rjf: identifiers with an active dot op kind -> member access + else if(need_new_expr && state->top_task != 0 && state->top_task->op_kind == E2_OpKind_Dot && e2_try_token(string, E2_TokenKind_Identifier, s(""), &off, &token)) { - String8 identifier = str8_substr(string, token.range); - expr = e2_expr_from_name(expr_map, identifier); - if(expr == &e2_expr_nil) + // rjf: if we have a caller-provided access result, use that as our new expression + if(next_access_result != &e2_expr_nil) + { + expr = next_access_result; + next_access_result = &e2_expr_nil; + } + + // rjf: if we don't, ask for it - reset the offset to before this token + else { done = 1; - parse.status = E2_Status_MissedIdentifierResolution; + parse.status = E2_ParseStatus_MemberAccess; + parse.expr = state->top_task->first_child ? state->top_task->first_child->v : &e2_expr_nil; + parse.member_name = str8_substr(string, token.range); + state->last_requested_member_name = parse.member_name; + off = start_off; + } + } + + //- rjf: standalone identifiers (also could be operator keyword) + else if(need_new_expr && e2_try_token(string, E2_TokenKind_Identifier, s(""), &off, &token)) + { + String8 identifier = str8_substr(string, token.range); + B32 identifier_mapped = 0; + + // rjf: first try to resolve as an operator name + if(!identifier_mapped) + { + // rjf: string -> op kind + E2_OpKind op_kind = E2_OpKind_Null; + { + String8 token_string = str8_substr(string, token.range); + for EachNonZeroEnumVal(E2_OpKind, k) + { + if(e2_op_kind_info_table[k].parse_kind == E2_OpParseKind_UnaryPrefix && + e2_op_kind_info_table[k].precedence <= max_precedence && + str8_match(token_string, str8_skip_chop_whitespace(e2_op_kind_info_table[k].pre), 0)) + { + op_kind = k; + break; + } + } + } + + // rjf: push task for operand + if(op_kind != E2_OpKind_Null) + { + 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 = op_kind; + task->max_precedence = e2_op_kind_info_table[op_kind].precedence; + SLLStackPush(state->top_task, task); + } + } + + // rjf: try to resolve via caller-provided named expressions + if(!identifier_mapped) + { + expr = e2_expr_from_name(expr_map, identifier); + identifier_mapped = (expr != &e2_expr_nil); + } + + // rjf: couldn't map -> ask caller to resolve it + if(!identifier_mapped) + { + done = 1; + parse.status = E2_ParseStatus_MissedIdentifierResolution; parse.missed_identifier = identifier; + off = start_off; } } //- rjf: leaf numerics - else if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Numeric, s(""), &off, &token)) + else if(need_new_expr && e2_try_token(string, E2_TokenKind_Numeric, s(""), &off, &token)) { U64 u64_val = 0; String8 numeric_string = str8_substr(string, token.range); @@ -1261,22 +1368,34 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S } } - //- rjf: extend parsed expression tree with trailing binary operators - if(expr != &e2_expr_nil) + //- rjf: extend parsed expression tree with trailing operators + if(!state->caller_info_completes_task && expr != &e2_expr_nil) { U64 trailing_symbol_off = off; if(e2_try_token(string, E2_TokenKind_Symbol, s(""), &trailing_symbol_off, &token)) { // rjf: token string -> operator kind E2_OpKind op_kind = E2_OpKind_Null; + U64 child_count_target = 2; + String8 splitter = {0}; + String8 closer = {0}; + B32 splitter_is_required = 0; { String8 token_string = str8_substr(string, token.range); for EachNonZeroEnumVal(E2_OpKind, k) { - if(e2_op_kind_info_table[k].parse_kind == E2_OpParseKind_Binary && - e2_op_kind_info_table[k].precedence <= max_precedence && - str8_match(token_string, e2_op_kind_info_table[k].sep, 0)) + E2_OpInfo *op_info = &e2_op_kind_info_table[k]; + if(op_info->precedence <= max_precedence && str8_match(token_string, op_info->sep, 0)) { + switch(op_info->parse_kind) + { + default:{}break; + case E2_OpParseKind_Binary: {child_count_target = 2;}break; + case E2_OpParseKind_Ternary: {child_count_target = 3; splitter_is_required = 1;}break; + case E2_OpParseKind_Call: {child_count_target = max_U64;}break; + } + splitter = op_info->chain; + closer = op_info->post; op_kind = k; break; } @@ -1298,9 +1417,12 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S MemoryZeroStruct(task); task->src_range = token.range; task->child_count = 0; - task->child_count_target = 2; + task->child_count_target = child_count_target; task->op_kind = op_kind; task->max_precedence = e2_op_kind_info_table[op_kind].precedence; + task->expected_splitter = splitter; + task->expected_closer = closer; + task->splitter_is_required = splitter_is_required; SLLStackPush(state->top_task, task); off = trailing_symbol_off; } @@ -1309,29 +1431,52 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S //- rjf: attach formed expressions to parent task exprs; pop tasks when they're done. // if we have no parent task, then we just fill the result, and we're done with the parse. - if(expr != &e2_expr_nil) + if(state->caller_info_completes_task || expr != &e2_expr_nil) { //- rjf: pop finished expressions - for(;state->top_task != 0;) + for(;state->top_task != 0 && !done;) { //- rjf: gather finished expression to current task; increase task child count - E2_ExprNode *n = push_array(arena, E2_ExprNode, 1); - SLLQueuePush(state->top_task->first_child, state->top_task->last_child, n); - n->v = expr; - state->top_task->child_count += 1; - - //- rjf: task child count hits limit -> complete this subtree - if(state->top_task->child_count >= state->top_task->child_count_target) + if(!state->caller_info_completes_task) { - //- rjf: release task + E2_ExprNode *n = push_array(arena, E2_ExprNode, 1); + SLLQueuePush(state->top_task->first_child, state->top_task->last_child, n); + n->v = expr; + state->top_task->child_count += 1; + } + + //- rjf: consume expected splitters + if(!state->caller_info_completes_task && + state->top_task->child_count > 1 && + state->top_task->expected_splitter.size != 0 && + state->top_task->child_count < state->top_task->child_count_target) + { + if(!e2_try_token(string, E2_TokenKind_Symbol, state->top_task->expected_splitter, &off, 0) && state->top_task->splitter_is_required) + { + e2_msgf(arena, &parse.msgs, r1u64(off, off), "Expected `%S`.", state->top_task->expected_splitter); + } + } + + //- rjf: consume expected closers - can terminate a child list early + B32 closer_found = 0; + if(!state->caller_info_completes_task && state->top_task->expected_closer.size != 0) + { + closer_found = e2_try_token(string, E2_TokenKind_Symbol, state->top_task->expected_closer, &off, 0); + } + + //- rjf: caller-provided info completes a task, *or* closer found, + // *or* task child count hits limit -> complete this subtree + if(state->caller_info_completes_task || closer_found || state->top_task->child_count >= state->top_task->child_count_target) + { + B32 completed_with_caller_info = state->caller_info_completes_task; + state->caller_info_completes_task = 0; E2_ParseTask *completed_task = state->top_task; - SLLStackPop(state->top_task); - SLLStackPush(state->free_task, completed_task); //- rjf: produced finished expression tree, given all children E2_Expr *finished_root = &e2_expr_nil; E2_Expr *lhs = completed_task->first_child ? completed_task->first_child->v : &e2_expr_nil; E2_Expr *rhs = completed_task->last_child ? completed_task->last_child->v : &e2_expr_nil; + E2_Expr *mhs = completed_task->child_count == 3 ? lhs->next : &e2_expr_nil; { RDI_EvalOp op = RDI_EvalOp_Stop; E2_TypeKey dst_type_key = {E2_TypeKeyKind_Null}; @@ -1354,8 +1499,77 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S } }break; - //- rjf: dereference + //- rjf: member accesses -> at this point we should have a resolved access + // expression submitted to us by the user (the parser reports it first) + // stored as the second child in the list. we just want to use the + // second expression - the initial child was just the accessed evaluation. + case E2_OpKind_Dot: + { + finished_root = rhs; + }break; + + //- rjf: indexes + case E2_OpKind_Index: + { + E2_TypeKey lhs_type_key = e2_type_key_undecorate(lhs->type_key); + E2_TypeKind lhs_type_kind = e2_type_kind_from_key(lhs_type_key); + + // rjf: array/pointer *address* indexes + if(lhs_type_kind == E2_TypeKind_Ptr || lhs_type_kind == E2_TypeKind_Array) + { + E2_TypeKey element_type_key = e2_type_key_direct(lhs_type_key); + U64 element_byte_size = e2_byte_size_from_type_key(element_type_key); + E2_Expr *base_addr_value_expr = e2_expr_resolve_to_value(arena, lhs); + E2_Expr *index_value_expr = e2_expr_resolve_to_value(arena, rhs); + E2_Expr *offset_value_expr = index_value_expr; + if(element_byte_size != 1) + { + E2_Expr *element_size_value_expr = e2_expr_const_u64_or_smaller(arena, element_byte_size); + offset_value_expr = e2_expr_binary_op(arena, e2_type_key_basic(E2_TypeKind_U64), RDI_EvalOp_Mul, index_value_expr, element_size_value_expr); + } + E2_Expr *element_addr_value_expr = e2_expr_binary_op(arena, e2_type_key_basic(E2_TypeKind_U64), RDI_EvalOp_Add, base_addr_value_expr, offset_value_expr); + element_addr_value_expr->type_key = element_type_key; + element_addr_value_expr->mode = E2_Mode_Address; + finished_root = element_addr_value_expr; + } + + // rjf: fallback case: ask the caller for fancy indexing operations + else + { + if(next_access_result != &e2_expr_nil) + { + finished_root = next_access_result; + next_access_result = &e2_expr_nil; + } + else + { + done = 1; + parse.status = E2_ParseStatus_IndexAccess; + parse.expr = lhs; + parse.params_expr = rhs; + state->caller_info_completes_task = 1; + } + } + }break; + + //- rjf: calls + case E2_OpKind_Call: + { + // TODO(rjf) + }break; + + //- rjf: sizeof + case E2_OpKind_SizeOf: + { + E2_TypeKey rhs_type_key = e2_type_key_unwrap(rhs->type_key, E2_TypeUnwrapFlag_AllDecorative & ~E2_TypeUnwrapFlag_Enums); + U64 rhs_size = e2_byte_size_from_type_key(rhs_type_key); + finished_root = e2_expr_const_u64_or_smaller(arena, rhs_size); + finished_root->type_key = e2_type_key_basic(E2_TypeKind_U64); + }break; + + //- rjf: dereferences case E2_OpKind_Deref: + case E2_OpKind_DerefAsm: { // rjf: unpack operand E2_TypeKey rhs_type_key = e2_type_key_unwrap(rhs->type_key, E2_TypeUnwrapFlag_AllDecorative & ~E2_TypeUnwrapFlag_Enums); @@ -1375,12 +1589,26 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S malformed = 1; e2_msgf(arena, &parse.msgs, completed_task->src_range, "Cannot dereference arrays of zero-sized types."); } - else if(!e2_type_kind_is_ptr_or_ref(rhs_type_kind) && rhs_type_kind != E2_TypeKind_Array) + else if(!e2_type_kind_is_ptr_or_ref(rhs_type_kind) && rhs_type_kind != E2_TypeKind_Array && + completed_task->op_kind != E2_OpKind_DerefAsm) { malformed = 1; e2_msgf(arena, &parse.msgs, completed_task->src_range, "Cannot dereference this type."); } + // rjf: asm-style deref -> go to u64 if the address expression isn't + // an array or pointer + // + // TODO(rjf): probably we should get an absolute-fallback-architecture here, + // which ultimately is sourced by the selected thread, to choose an address-sized + // integer type. + // + if(!e2_type_kind_is_ptr_or_ref(rhs_type_kind) && rhs_type_kind != E2_TypeKind_Array && + completed_task->op_kind == E2_OpKind_DerefAsm) + { + dereferenced_type = e2_type_key_basic(E2_TypeKind_U64); + } + // rjf: not malformed -> equip info if(!malformed) { @@ -1597,20 +1825,30 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S //- rjf: definitions (TODO(rjf): tricky with the 'user resolves expressions' model - let's figure it out once basics are in) case E2_OpKind_Define:{}break; + + //- rjf: conditionals + case E2_OpKind_Cond: + { + // TODO(rjf) + }break; } } - //- rjf: consume expected closers - if(completed_task->expected_closer.size != 0) + //- rjf: report missing closers + if(!completed_with_caller_info && completed_task->expected_closer.size != 0 && !closer_found) { - if(!e2_try_token(string, E2_TokenKind_Symbol, completed_task->expected_closer, &off, 0)) - { - e2_msgf(arena, &parse.msgs, r1u64(off, off), "Expected `%S`.", completed_task->expected_closer); - } + e2_msgf(arena, &parse.msgs, r1u64(off, off), "Expected `%S`.", completed_task->expected_closer); } //- rjf: work on the parent of the finished expression next expr = finished_root; + + //- rjf: release task + if(!done) + { + SLLStackPop(state->top_task); + SLLStackPush(state->free_task, completed_task); + } } //- rjf: if the top task is not done -> break & continue - reset expression, because we need to parse another. @@ -1626,20 +1864,70 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S if(state->top_task == 0 && off >= string.size) { parse.expr = expr; - if(parse.status == E2_Status_Error) + if(parse.status == E2_ParseStatus_Error) { - parse.status = E2_Status_Good; + parse.status = E2_ParseStatus_Good; } break; } } + + //- rjf: we're always done if there's nothing left to parse + if(off >= string.size) + { + done = 1; + } } - //- rjf: advance offset if successful - if(parse.status == E2_Status_Good || parse.status == E2_Status_Error) + //- rjf: asking caller for info? -> if we already did this at this offset, + // the user couldn't provide the info, so we just fail out. + if(e2_parse_status_is_caller_request(parse.status)) + { + if(state->caller_request_count > 0 && state->last_caller_request_string_off == state->string_off) + { + if(parse.status == E2_ParseStatus_MissedIdentifierResolution) + { + e2_msgf(arena, &parse.msgs, r1u64(state->string_off, state->string_off + parse.missed_identifier.size), "`%S` couldn't be resolved.", parse.missed_identifier); + } + parse.status = E2_ParseStatus_Error; + } + state->caller_request_count += 1; + state->last_caller_request_string_off = state->string_off; + } + + //- rjf: report incomplete tasks + if(off >= string.size && !e2_parse_status_is_caller_request(parse.status)) + { + for(E2_ParseTask *t = state->top_task; t != 0; t = t->next) + { + if(t->child_count == 1 && t->child_count_target == 2 && t->op_kind == E2_OpKind_Dot) + { + e2_msgf(arena, &parse.msgs, t->src_range, "Couldn't access member `%S`.", state->last_requested_member_name); + } + else if(t->child_count == 2 && t->child_count_target == 2 && t->op_kind == E2_OpKind_Index) + { + e2_msgf(arena, &parse.msgs, t->src_range, "Couldn't index into this type."); + } + else if(t->child_count == 1 && t->child_count_target == 2 && t->op_kind != E2_OpKind_Null) + { + e2_msgf(arena, &parse.msgs, t->src_range, "Expected expression after binary operator `%S`.", e2_op_kind_info_table[t->op_kind].sep); + } + else if(t->child_count == 0 && t->child_count_target == 1 && t->op_kind != E2_OpKind_Null) + { + e2_msgf(arena, &parse.msgs, t->src_range, "Expected expression after unary operator `%S`.", e2_op_kind_info_table[t->op_kind].pre); + } + else + { + e2_msgf(arena, &parse.msgs, t->src_range, "Expected expression."); + } + } + } + + //- rjf: commit offset { state->string_off = off; } + return parse; } @@ -1724,12 +2012,14 @@ e2_bytecode_from_expr(Arena *arena, E2_Expr *expr) internal E2_Interp e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_map, String8 bytecode) { - E2_Interp interp = {E2_Status_Error}; + E2_Interp interp = {E2_InterpStatus_Error}; { U64 off = state->bytecode_off; U64 off_opl = bytecode.size; B32 done = 0; B32 good = 1; + + //- rjf: execute bytecode for(;off < off_opl && !done && good;) { Temp scratch = scratch_begin(&arena, 1); @@ -1784,7 +2074,7 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_ case E2_EvalOp_SetCtxID: { - interp.status = E2_Status_NewCtxID; + interp.status = E2_InterpStatus_NewCtxID; interp.ctx_id = decode_val.u64; }break; @@ -1818,7 +2108,7 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_ if(read_size != size) { good = 0; - interp.status = E2_Status_MissedSpaceRead; + interp.status = E2_InterpStatus_MissedSpaceRead; interp.missed_read_space_addr_range = space_addr_range; } }break; @@ -1840,14 +2130,14 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_ if(read_size != size) { good = 0; - interp.status = E2_Status_MissedSpaceRead; + interp.status = E2_InterpStatus_MissedSpaceRead; interp.missed_read_space_addr_range = space_addr_range; } } else { good = 0; - interp.status = E2_Status_BadRegCode; + interp.status = E2_InterpStatus_BadRegCode; } }break; case RDI_EvalOp_FrameOff: {ctx_flags = E2_CtxFlag_HasFrameBase; ctx_base_addr = state->selected_ctx.frame_base_addr;}goto optional_base_off; @@ -1863,7 +2153,7 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_ else { good = 0; - interp.status = E2_Status_MissingCtxFlag; + interp.status = E2_InterpStatus_MissingCtxFlag; interp.missing_ctx_flags |= ctx_flags; } }break; @@ -1919,9 +2209,9 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_ #define BinOp(target_type_group, dst_type, src_type, symbol) else if(type_group == (RDI_EvalTypeGroup_##target_type_group)) do{push_vals[0].dst_type = popped_vals[1].src_type symbol popped_vals[0].src_type;}while(0) #define SizedBinOp(target_type_group, size, dst_type, src_type, symbol) else if(type_group == (RDI_EvalTypeGroup_##target_type_group) && op_arithmetic_size == (size)) do{push_vals[0].dst_type = popped_vals[1].src_type symbol popped_vals[0].src_type;}while(0) -#define BinOpDiv(target_type_group, dst_type, src_type, symbol) else if(type_group == (RDI_EvalTypeGroup_##target_type_group)) do{if(popped_vals[0].src_type != 0) { push_vals[0].dst_type = popped_vals[1].src_type symbol popped_vals[0].src_type; } else {interp.status = E2_Status_DivideByZero; good = 0;} }while(0) -#define SizedBinOpDiv(target_type_group, size, dst_type, src_type, symbol) else if(type_group == (RDI_EvalTypeGroup_##target_type_group) && op_arithmetic_size == (size)) do{if(popped_vals[0].src_type != 0) { push_vals[0].dst_type = popped_vals[1].src_type symbol popped_vals[0].src_type; } else {interp.status = E2_Status_DivideByZero; good = 0;} }while(0) -#define BinOpDivFn(target_type_group, dst_type, src_type, fn) else if(type_group == (RDI_EvalTypeGroup_##target_type_group)) do{if(popped_vals[0].src_type != 0) { push_vals[0].dst_type = fn(popped_vals[1].src_type, popped_vals[0].src_type); } else {interp.status = E2_Status_DivideByZero; good = 0;} }while(0) +#define BinOpDiv(target_type_group, dst_type, src_type, symbol) else if(type_group == (RDI_EvalTypeGroup_##target_type_group)) do{if(popped_vals[0].src_type != 0) { push_vals[0].dst_type = popped_vals[1].src_type symbol popped_vals[0].src_type; } else {interp.status = E2_InterpStatus_DivideByZero; good = 0;} }while(0) +#define SizedBinOpDiv(target_type_group, size, dst_type, src_type, symbol) else if(type_group == (RDI_EvalTypeGroup_##target_type_group) && op_arithmetic_size == (size)) do{if(popped_vals[0].src_type != 0) { push_vals[0].dst_type = popped_vals[1].src_type symbol popped_vals[0].src_type; } else {interp.status = E2_InterpStatus_DivideByZero; good = 0;} }while(0) +#define BinOpDivFn(target_type_group, dst_type, src_type, fn) else if(type_group == (RDI_EvalTypeGroup_##target_type_group)) do{if(popped_vals[0].src_type != 0) { push_vals[0].dst_type = fn(popped_vals[1].src_type, popped_vals[0].src_type); } else {interp.status = E2_InterpStatus_DivideByZero; good = 0;} }while(0) #define ArithTypeCasesInt(symbol)\ SizedBinOp(S, 8, s8, s8, symbol);\ SizedBinOp(S, 16, s16, s16, symbol);\ @@ -1955,7 +2245,7 @@ ArithTypeCasesIntDiv(symbol) #define ArithTypeCasesIntAllU64(symbol)\ BinOp(S, u64, u64, symbol);\ BinOp(U, u64, u64, symbol); -#define Case(name, ...) case RDI_EvalOp_##name:{if(0){} __VA_ARGS__ else {interp.status = E2_Status_BadOpTypes; good = 0;}}break +#define Case(name, ...) case RDI_EvalOp_##name:{if(0){} __VA_ARGS__ else {interp.status = E2_InterpStatus_BadOpTypes; good = 0;}}break Case(Add, ArithTypeCases(+)); Case(Sub, ArithTypeCases(-)); Case(Mul, ArithTypeCases(*)); @@ -2049,7 +2339,7 @@ BinOp(U, u64, u64, symbol); { switch(in + out*RDI_EvalTypeGroup_COUNT) { - default:{good = 0; interp.status = E2_Status_BadOpTypes;}break; + default:{good = 0; interp.status = E2_InterpStatus_BadOpTypes;}break; #define Case(dst_tg, dst_slot, dst_type, src_tg, src_slot) case RDI_EvalTypeGroup_##src_tg + RDI_EvalTypeGroup_##dst_tg*RDI_EvalTypeGroup_COUNT:{push_vals[0].dst_slot = (dst_type)popped_vals[0].src_slot;}break Case(U, u64, U64, F32, f32); Case(U, u64, U64, F64, f64); @@ -2083,7 +2373,7 @@ BinOp(U, u64, u64, symbol); if(!found) { good = 0; - interp.status = E2_Status_InsufficientStackSpace; + interp.status = E2_InterpStatus_InsufficientStackSpace; } }break; @@ -2106,7 +2396,7 @@ BinOp(U, u64, u64, symbol); else { good = 0; - interp.status = E2_Status_BadOffset; + interp.status = E2_InterpStatus_BadOffset; } }break; @@ -2118,7 +2408,7 @@ BinOp(U, u64, u64, symbol); default: { good = 0; - interp.status = E2_Status_UnsupportedOp; + interp.status = E2_InterpStatus_UnsupportedOp; }break; case 2:{push_vals[0].u16 = bswap_u16(popped_vals[0].u16);}break; case 4:{push_vals[0].u32 = bswap_u32(popped_vals[0].u32);}break; @@ -2136,7 +2426,7 @@ BinOp(U, u64, u64, symbol); // skip past the embedded sub-bytecode in the outer stream so the // bytes are not interpreted as outer ops on resume. good = 0; - interp.status = E2_Status_UnsupportedOp; + interp.status = E2_InterpStatus_UnsupportedOp; }break; case RDI_EvalOp_PartialValue: @@ -2146,14 +2436,14 @@ BinOp(U, u64, u64, symbol); // value already on the stack is the result. for multi-piece, only // the first piece is returned (stack[0] is the final result). good = 0; - interp.status = E2_Status_UnsupportedOp; + interp.status = E2_InterpStatus_UnsupportedOp; }break; case RDI_EvalOp_PartialValueBit: { // DW_OP_bit_piece marker. same caveat as PartialValue. good = 0; - interp.status = E2_Status_UnsupportedOp; + interp.status = E2_InterpStatus_UnsupportedOp; }break; } @@ -2200,9 +2490,34 @@ BinOp(U, u64, u64, symbol); break; } } + + //- rjf: asking caller for info? -> if we already did this at this offset, + // the user couldn't provide the info, so we just fail out. + if(e2_interp_status_is_caller_request(interp.status)) + { + if(state->caller_request_count > 0 && state->last_caller_request_bytecode_off == state->bytecode_off) + { + switch(interp.status) + { + default:{}break; + case E2_InterpStatus_MissedSpaceRead: + { + e2_msgf(arena, &interp.msgs, r1u64(state->bytecode_off, state->bytecode_off+1), "Couldn't read address range [0x%I64x, 0x%I64x) in space 0x%I64x.", + interp.missed_read_space_addr_range.min, + interp.missed_read_space_addr_range.max, + interp.space_id); + }break; + } + interp.status = E2_InterpStatus_Error; + } + state->caller_request_count += 1; + state->last_caller_request_bytecode_off = state->bytecode_off; + } + + //- rjf: if we're done with the bytecode stream, report success / value if(off == off_opl && good) { - interp.status = E2_Status_Good; + interp.status = E2_InterpStatus_Good; if(state->top_val != 0) { interp.val = state->top_val->val; diff --git a/src/eval2/eval2.h b/src/eval2/eval2.h index a9a7cd45..f920d69e 100644 --- a/src/eval2/eval2.h +++ b/src/eval2/eval2.h @@ -12,7 +12,8 @@ typedef enum E2_OpParseKind E2_OpParseKind_Null, E2_OpParseKind_UnaryPrefix, E2_OpParseKind_Binary, - E2_OpParseKind_UnaryPostfix, + E2_OpParseKind_Ternary, + E2_OpParseKind_Call, } E2_OpParseKind; @@ -41,31 +42,57 @@ enum }; //////////////////////////////// -//~ rjf: Compilation Statuses +//~ rjf: Parse Statuses -typedef enum E2_Status +typedef enum E2_ParseStatus { - E2_Status_Good, + //- rjf: terminals + E2_ParseStatus_Good, + E2_ParseStatus_Error, + E2_ParseStatus_FirstTerminal = E2_ParseStatus_Good, + E2_ParseStatus_LastTerminal = E2_ParseStatus_Error, - //- rjf: need caller-provided info - E2_Status_MissedSpaceRead, - E2_Status_MissedIdentifierResolution, - E2_Status_Access, - E2_Status_NewCtxID, - - //- rjf: unrecoverable errors - E2_Status_BadRegCode, - E2_Status_MissingCtxFlag, - E2_Status_DivideByZero, - E2_Status_InsufficientStackSpace, - E2_Status_BadOpTypes, - E2_Status_UnsupportedOp, - E2_Status_BadOffset, - E2_Status_Error, - E2_Status_FirstError = E2_Status_BadRegCode, - E2_Status_LastError = E2_Status_Error, + //- rjf: caller-provided info + E2_ParseStatus_MissedIdentifierResolution, + E2_ParseStatus_MemberAccess, + E2_ParseStatus_IndexAccess, + E2_ParseStatus_Call, + E2_ParseStatus_FirstCallerRequest = E2_ParseStatus_MissedIdentifierResolution, + E2_ParseStatus_LastCallerRequest = E2_ParseStatus_Call, } -E2_Status; +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: Interpretation Statuses + +typedef enum E2_InterpStatus +{ + //- rjf: terminals + E2_InterpStatus_Good, + E2_InterpStatus_BadRegCode, + E2_InterpStatus_MissingCtxFlag, + E2_InterpStatus_DivideByZero, + E2_InterpStatus_InsufficientStackSpace, + E2_InterpStatus_BadOpTypes, + E2_InterpStatus_UnsupportedOp, + E2_InterpStatus_BadOffset, + E2_InterpStatus_Error, + E2_InterpStatus_FirstTerminal = E2_InterpStatus_Good, + E2_InterpStatus_LastTerminal = E2_InterpStatus_Error, + + //- rjf: caller-provided info + E2_InterpStatus_MissedSpaceRead, + E2_InterpStatus_NewCtxID, + E2_InterpStatus_FirstCallerRequest = E2_InterpStatus_MissedSpaceRead, + E2_InterpStatus_LastCallerRequest = E2_InterpStatus_NewCtxID, +} +E2_InterpStatus; + +#define e2_interp_status_is_terminal(s) (E2_InterpStatus_FirstTerminal <= (s) && (s) <= E2_InterpStatus_LastTerminal) +#define e2_interp_status_is_caller_request(s) (E2_InterpStatus_FirstCallerRequest <= (s) && (s) <= E2_InterpStatus_LastCallerRequest) //////////////////////////////// //~ rjf: Type Keys @@ -330,6 +357,8 @@ struct E2_ParseTask S64 max_precedence; E2_OpKind op_kind; String8 expected_closer; + String8 expected_splitter; + B32 splitter_is_required; }; typedef struct E2_ParseState E2_ParseState; @@ -338,6 +367,10 @@ struct E2_ParseState U64 string_off; E2_ParseTask *top_task; E2_ParseTask *free_task; + U64 last_caller_request_string_off; + U64 caller_request_count; + String8 last_requested_member_name; + B32 caller_info_completes_task; }; typedef struct E2_Msg E2_Msg; @@ -359,10 +392,11 @@ struct E2_MsgList typedef struct E2_Parse E2_Parse; struct E2_Parse { - E2_Status status; + E2_ParseStatus status; String8 missed_identifier; E2_Expr *expr; - E2_Expr *access_expr; + String8 member_name; + E2_Expr *params_expr; E2_MsgList msgs; }; @@ -398,17 +432,20 @@ struct E2_InterpState E2_Ctx selected_ctx; E2_InterpStackValNode *top_val; E2_InterpStackValNode *free_val; + U64 last_caller_request_bytecode_off; + U64 caller_request_count; }; typedef struct E2_Interp E2_Interp; struct E2_Interp { - E2_Status status; + E2_InterpStatus status; E2_SpaceID space_id; Rng1U64 missed_read_space_addr_range; E2_CtxID ctx_id; E2_CtxFlags missing_ctx_flags; E2_Val val; + E2_MsgList msgs; }; //////////////////////////////// @@ -537,7 +574,7 @@ internal void e2_expr_push_child(E2_Expr *parent, E2_Expr *expr); internal E2_Token e2_token_from_string_off(String8 string, U64 start_off); internal U64 e2_read_token(String8 string, U64 off, E2_Token *token_out); internal B32 e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *off_out, E2_Token *token_out); -internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, String8 string); +internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, E2_Expr *access_result, String8 string); //////////////////////////////// //~ rjf: Expression -> Bytecode diff --git a/src/eval2/eval2.mdesk b/src/eval2/eval2.mdesk index e40299a8..2f07c727 100644 --- a/src/eval2/eval2.mdesk +++ b/src/eval2/eval2.mdesk @@ -4,31 +4,37 @@ @table(name parse_kind precedence pre sep pos chain) E2_OpTable: { - {Deref UnaryPrefix 2 "*" "" "" ""} - {Address UnaryPrefix 2 "&" "" "" ""} - {Pos UnaryPrefix 2 "+" "" "" ""} - {Neg UnaryPrefix 2 "-" "" "" ""} - {LogNot UnaryPrefix 2 "!" "" "" ""} - {BitNot UnaryPrefix 2 "~" "" "" ""} - {Mul Binary 3 "" "*" "" ""} - {Div Binary 3 "" "/" "" ""} - {Mod Binary 3 "" "%" "" ""} - {Add Binary 4 "" "+" "" ""} - {Sub Binary 4 "" "-" "" ""} - {LShift Binary 5 "" "<<" "" ""} - {RShift Binary 5 "" ">>" "" ""} - {Less Binary 6 "" "<" "" ""} - {LtEq Binary 6 "" "<=" "" ""} - {Grtr Binary 6 "" ">" "" ""} - {GrEq Binary 6 "" ">=" "" ""} - {EqEq Binary 7 "" "==" "" ""} - {NtEq Binary 7 "" "!=" "" ""} - {BitAnd Binary 8 "" "&" "" ""} - {BitXor Binary 9 "" "^" "" ""} - {BitOr Binary 10 "" "|" "" ""} - {LogAnd Binary 11 "" "&&" "" ""} - {LogOr Binary 12 "" "||" "" ""} - {Define Binary 13 "" "=" "" ""} + {Dot Binary 1 "" "." "" "" } + {Index Binary 1 "" "[" "]" "" } + {Call Call 1 "" "(" ")" ","} + {DerefAsm UnaryPrefix 1 "[" "" "]" "" } + {SizeOf UnaryPrefix 1 "sizeof " "" "" "" } + {Deref UnaryPrefix 2 "*" "" "" "" } + {Address UnaryPrefix 2 "&" "" "" "" } + {Pos UnaryPrefix 2 "+" "" "" "" } + {Neg UnaryPrefix 2 "-" "" "" "" } + {LogNot UnaryPrefix 2 "!" "" "" "" } + {BitNot UnaryPrefix 2 "~" "" "" "" } + {Mul Binary 3 "" "*" "" "" } + {Div Binary 3 "" "/" "" "" } + {Mod Binary 3 "" "%" "" "" } + {Add Binary 4 "" "+" "" "" } + {Sub Binary 4 "" "-" "" "" } + {LShift Binary 5 "" "<<" "" "" } + {RShift Binary 5 "" ">>" "" "" } + {Less Binary 6 "" "<" "" "" } + {LtEq Binary 6 "" "<=" "" "" } + {Grtr Binary 6 "" ">" "" "" } + {GrEq Binary 6 "" ">=" "" "" } + {EqEq Binary 7 "" "==" "" "" } + {NtEq Binary 7 "" "!=" "" "" } + {BitAnd Binary 8 "" "&" "" "" } + {BitXor Binary 9 "" "^" "" "" } + {BitOr Binary 10 "" "|" "" "" } + {LogAnd Binary 11 "" "&&" "" "" } + {LogOr Binary 12 "" "||" "" "" } + {Define Binary 13 "" "=" "" "" } + {Cond Ternary 14 "" "?" "" ":"} } @enum E2_OpKind: diff --git a/src/eval2/generated/eval2.meta.c b/src/eval2/generated/eval2.meta.c index 7bb0448b..0b8b63b1 100644 --- a/src/eval2/generated/eval2.meta.c +++ b/src/eval2/generated/eval2.meta.c @@ -4,9 +4,14 @@ //- GENERATED CODE C_LINKAGE_BEGIN -E2_OpInfo e2_op_kind_info_table[26] = +E2_OpInfo e2_op_kind_info_table[32] = { {0}, +{E2_OpParseKind_Binary, 1, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("")}, +{E2_OpParseKind_Binary, 1, str8_lit_comp(""), str8_lit_comp("["), str8_lit_comp("]"), str8_lit_comp("")}, +{E2_OpParseKind_Call, 1, str8_lit_comp(""), str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(",")}, +{E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("["), str8_lit_comp(""), str8_lit_comp("]"), str8_lit_comp("")}, +{E2_OpParseKind_UnaryPrefix, 1, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, {E2_OpParseKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("")}, @@ -32,6 +37,7 @@ E2_OpInfo e2_op_kind_info_table[26] = {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_Ternary, 14, str8_lit_comp(""), str8_lit_comp("?"), str8_lit_comp(""), str8_lit_comp(":")}, }; U8 e2_type_kind_basic_byte_size_table[61] = diff --git a/src/eval2/generated/eval2.meta.h b/src/eval2/generated/eval2.meta.h index 9262b98c..eedb460f 100644 --- a/src/eval2/generated/eval2.meta.h +++ b/src/eval2/generated/eval2.meta.h @@ -9,6 +9,11 @@ typedef enum E2_OpKind { E2_OpKind_Null, +E2_OpKind_Dot, +E2_OpKind_Index, +E2_OpKind_Call, +E2_OpKind_DerefAsm, +E2_OpKind_SizeOf, E2_OpKind_Deref, E2_OpKind_Address, E2_OpKind_Pos, @@ -34,6 +39,7 @@ E2_OpKind_BitOr, E2_OpKind_LogAnd, E2_OpKind_LogOr, E2_OpKind_Define, +E2_OpKind_Cond, E2_OpKind_COUNT, } E2_OpKind; @@ -116,7 +122,7 @@ E2_TypeKind_LastMeta = E2_TypeKind_MetaDescription, } E2_TypeKind; C_LINKAGE_BEGIN -extern E2_OpInfo e2_op_kind_info_table[26]; +extern E2_OpInfo e2_op_kind_info_table[32]; extern U8 e2_type_kind_basic_byte_size_table[61]; extern String8 e2_type_kind_basic_string_table[61]; diff --git a/src/lib_rdi/rdi.c b/src/lib_rdi/rdi.c index f030ca78..84f35ba9 100644 --- a/src/lib_rdi/rdi.c +++ b/src/lib_rdi/rdi.c @@ -79,8 +79,8 @@ RDI_EVAL_CTRLBITS(16, 0, 1), RDI_EVAL_CTRLBITS(32, 0, 1), RDI_EVAL_CTRLBITS(64, 0, 1), RDI_EVAL_CTRLBITS(1, 0, 1), -RDI_EVAL_CTRLBITS(1, 1, 1), -RDI_EVAL_CTRLBITS(1, 1, 1), +RDI_EVAL_CTRLBITS(2, 1, 1), +RDI_EVAL_CTRLBITS(2, 1, 1), RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1), diff --git a/src/linux/base/linux_base.c b/src/linux/base/linux_base.c index d9675138..44212e92 100644 --- a/src/linux/base/linux_base.c +++ b/src/linux/base/linux_base.c @@ -1187,9 +1187,9 @@ make_directory(String8 path) //~ rjf: @per_os_impl Aborting internal void -abort_self(S32 exit_code) +abort_self(U64 exit_code) { - exit(exit_code); + exit((int)exit_code); } //////////////////////////////// diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 04eab70e..bc34f32a 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -586,6 +586,16 @@ entry_point(CmdLine *cmd_line) { Temp scratch = scratch_begin(0, 0); + //- rjf: re-open stdout handles if cli +#if OS_WINDOWS + if(cmd_line_has_flag(cmd_line, s("bin"))) + { + AttachConsole(ATTACH_PARENT_PROCESS); + freopen("CONOUT$", "wt", stdout); + freopen("CONOUT$", "wt", stderr); + } +#endif + //- rjf: unpack command line arguments ExecMode exec_mode = ExecMode_Normal; B32 auto_run = 0; diff --git a/src/rdi/rdi.mdesk b/src/rdi/rdi.mdesk index 84687215..36509832 100644 --- a/src/rdi/rdi.mdesk +++ b/src/rdi/rdi.mdesk @@ -1214,8 +1214,8 @@ RDI_EvalOpTable: {ConstU256 16 32 0 1} {ConstU512 17 64 0 1} {ConstString 18 1 0 1} - {Abs 19 1 1 1} - {Neg 20 1 1 1} + {Abs 19 2 1 1} + {Neg 20 2 1 1} {Add 21 2 2 1} {Sub 22 2 2 1} {Mul 23 2 2 1} diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index e5bc7465..3ec2ba2c 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -422,7 +422,7 @@ p2r_convert2(Arena *arena, P2R_ConvertParams *params) } else { - cv2r_comp_units[idx].obj_name = s("*global"); + cv2r_comp_units[idx].obj_name = s("*global*"); } cv2r_comp_units[idx].ranges = unit_ranges[idx]; cv2r_comp_units[idx].sym = all_syms[idx]; diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index f8eec594..8c19eaf3 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -13,9 +13,7 @@ //- rjf: [h] #include "base/base_inc.h" #include "x64/x64.h" -#include "http/http_inc.h" #include "artifact_cache/artifact_cache.h" -#include "symbol_server/symbol_server_inc.h" #include "rdi/rdi_local.h" #include "dbg_info/dbg_info.h" #include "arch/arch_inc.h" @@ -24,9 +22,7 @@ //- rjf: [c] #include "base/base_inc.c" #include "x64/x64.c" -#include "http/http_inc.c" #include "artifact_cache/artifact_cache.c" -#include "symbol_server/symbol_server_inc.c" #include "rdi/rdi_local.c" #include "dbg_info/dbg_info.c" #include "arch/arch_inc.c" @@ -40,6 +36,10 @@ entry_point(CmdLine *cmdline) { String8 strings[] = { + s("[123]"), + s("foo"), + s("foo.bar"), + s("123[456]"), s("123"), s("123 + 456"), s("!1"), @@ -50,22 +50,47 @@ entry_point(CmdLine *cmdline) s("3 * 4 + 2"), s("(3 * 4) + 2"), s("2 + (3 * 4)"), + s("123 | 456"), + s("123 + "), + s("-123"), + s("sizeof 123"), + s("1 ? 123 : 456"), + s("123(1, 2, 3)"), }; for EachElement(idx, strings) { Temp scratch = scratch_begin(0, 0); + String8List msgs = {0}; // rjf: string -> expr E2_Expr *expr = &e2_expr_nil; { E2_ParseState state = {0}; E2_ExprMap expr_map = {0}; + E2_Expr *access_expr = &e2_expr_nil; for(;;) { - E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, strings[idx]); - if(parse.status == E2_Status_Good) + E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, access_expr, strings[idx]); + expr = parse.expr; + access_expr = &e2_expr_nil; + for EachNode(n, E2_Msg, parse.msgs.first) + { + str8_list_push(scratch.arena, &msgs, n->string); + } + if(parse.status == E2_ParseStatus_MissedIdentifierResolution) + { + e2_expr_map_push(scratch.arena, &expr_map, parse.missed_identifier, e2_expr_const_u64_or_smaller(scratch.arena, 123)); + } + if(parse.status == E2_ParseStatus_IndexAccess) + { + access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 111); + } + if(parse.status == E2_ParseStatus_MemberAccess) + { + access_expr = e2_expr_const_u64_or_smaller(scratch.arena, 456); + } + if(e2_parse_status_is_terminal(parse.status)) { - expr = parse.expr; break; } } @@ -82,20 +107,29 @@ entry_point(CmdLine *cmdline) for(;;) { E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &state, &space_map, bytecode); - if(interp.status == E2_Status_Good) - { - val = interp.val; - break; - } - else if(E2_Status_FirstError <= interp.status <= E2_Status_LastError) + val = interp.val; + if(e2_interp_status_is_terminal(interp.status)) { + if(interp.status != E2_InterpStatus_Good) + { + str8_list_pushf(scratch.arena, &msgs, "Interpretation error (%i).", interp.status); + } break; } } } + // rjf: message string list -> string + StringJoin join = {.sep = s(" ")}; + String8 msgs_string = str8_list_join(scratch.arena, &msgs, &join); + // rjf: log - printf("%.*s -> %I64u\n", str8_varg(strings[idx]), val.u64); + printf("%.*s -> %I64d *%s* %s%.*s\n", str8_varg(strings[idx]), + val.s64, + expr->mode == E2_Mode_Type ? "type" : + expr->mode == E2_Mode_Value ? "value" : + "address", + msgs_string.size != 0 ? " // " : "", str8_varg(msgs_string)); fflush(stdout); scratch_end(scratch); diff --git a/src/win32/base/win32_base.c b/src/win32/base/win32_base.c index 79945203..f77846c0 100644 --- a/src/win32/base/win32_base.c +++ b/src/win32/base/win32_base.c @@ -1276,9 +1276,9 @@ make_directory(String8 path) //~ rjf: @per_os_impl Aborting internal void -abort_self(S32 exit_code) +abort_self(U64 exit_code) { - ExitProcess(exit_code); + ExitProcess((int)exit_code); } ////////////////////////////////