com shim for launching raddbg in cli mode, for proper console subsystem style usage of packaged bin utilities; checkpoint on eval2

This commit is contained in:
Ryan Fleury
2026-06-19 20:12:20 -07:00
parent 3fd7b40f4d
commit fe2aa4d14c
18 changed files with 638 additions and 152 deletions
+8 -2
View File
@@ -36,8 +36,8 @@ if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode] if "%release%"=="1" set debug=0 && echo [release mode]
if "%msvc%"=="1" set clang=0 && echo [msvc compile] if "%msvc%"=="1" set clang=0 && echo [msvc compile]
if "%clang%"=="1" set msvc=0 && echo [clang compile] if "%clang%"=="1" set msvc=0 && echo [clang compile]
if "%~1"=="" 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 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 ------------------------------------ :: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags= set auto_compile_flags=
@@ -141,6 +141,7 @@ popd
pushd build 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%"=="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 "%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 "%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 "%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 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 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 ------------------------------------------------------ :: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" ( 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`. 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`.
+1 -1
View File
@@ -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", .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 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", .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] //- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+1 -1
View File
@@ -7,7 +7,6 @@ target:
working_directory: "../raddebugger" working_directory: "../raddebugger"
arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user" arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user"
debug_subprocesses: 0 debug_subprocesses: 0
enabled: 1
} }
target: target:
{ {
@@ -35,4 +34,5 @@ target:
{ {
executable: "build/ryan_scratch.exe" executable: "build/ryan_scratch.exe"
working_directory: build working_directory: build
enabled: 1
} }
+1 -1
View File
@@ -70,7 +70,7 @@ internal Process launch_cmd_linef(char *fmt, ...);
//////////////////////////////// ////////////////////////////////
//~ rjf: @per_os_impl Aborting //~ 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 //~ rjf: @per_os_impl Process Info
+64
View File
@@ -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);
}
+2
View File
@@ -693,6 +693,7 @@ di_async_tick(void)
B32 og_is_downloading = 0; B32 og_is_downloading = 0;
if(og_path.size != 0) if(og_path.size != 0)
{ {
#if defined(SYMBOL_SERVER_H)
B32 file_is_present = (properties_from_file_path(og_path).modified != 0); B32 file_is_present = (properties_from_file_path(og_path).modified != 0);
if(!file_is_present) if(!file_is_present)
{ {
@@ -715,6 +716,7 @@ di_async_tick(void)
} }
} }
} }
#endif
} }
//- rjf: analyze O.G. debug info //- rjf: analyze O.G. debug info
+386 -71
View File
@@ -95,20 +95,23 @@ internal E2_Expr *
e2_expr_from_name(E2_ExprMap *map, String8 name) e2_expr_from_name(E2_ExprMap *map, String8 name)
{ {
E2_Expr *expr = &e2_expr_nil; E2_Expr *expr = &e2_expr_nil;
U64 hash = u64_hash_from_str8(name); if(map->slots_count != 0)
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(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; if(str8_match(n->name, name, 0))
break; {
node = n;
break;
}
}
if(node != 0)
{
expr = node->expr;
} }
}
if(node != 0)
{
expr = node->expr;
} }
return 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->type_key = type_key;
e->op = op; e->op = op;
e->mode = E2_Mode_Value; 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); e2_expr_push_child(e, operand);
return e; return e;
} }
@@ -1125,21 +1130,40 @@ e2_try_token(String8 string, E2_TokenKind kind, String8 expected_string, U64 *of
} }
internal E2_Parse 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; 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 //- rjf: parse & attach to top parsing task - if we don't have a top task
// then it is just the result // then it is just the result
E2_Expr *expr = &e2_expr_nil; E2_Expr *expr = &e2_expr_nil;
for(B32 done = 0; !done;) for(B32 done = 0; !done;)
{ {
U64 start_off = off;
S64 max_precedence = state->top_task ? state->top_task->max_precedence : max_S64; 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}; 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 //- 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; E2_ParseTask *task = state->free_task;
if(task != 0) 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); SLLStackPush(state->top_task, task);
} }
//- rjf: prefix unaries //- rjf: symbols (possible prefix unaries, *or* unexpected)
else if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Symbol, s(""), &off, &token)) else if(need_new_expr && e2_try_token(string, E2_TokenKind_Symbol, s(""), &off, &token))
{ {
// rjf: string -> operator kind // rjf: string -> operator kind
E2_OpKind op_kind = E2_OpKind_Null; E2_OpKind op_kind = E2_OpKind_Null;
String8 closer = {0};
{ {
String8 token_string = str8_substr(string, token.range); String8 token_string = str8_substr(string, token.range);
for EachNonZeroEnumVal(E2_OpKind, k) 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)) str8_match(token_string, e2_op_kind_info_table[k].pre, 0))
{ {
op_kind = k; op_kind = k;
closer = e2_op_kind_info_table[k].post;
break; 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->child_count_target = 1;
task->op_kind = op_kind; task->op_kind = op_kind;
task->max_precedence = e2_op_kind_info_table[op_kind].precedence; task->max_precedence = e2_op_kind_info_table[op_kind].precedence;
task->expected_closer = closer;
SLLStackPush(state->top_task, task); 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 //- rjf: identifiers with an active dot op kind -> member access
else if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Identifier, s(""), &off, &token)) 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); // rjf: if we have a caller-provided access result, use that as our new expression
expr = e2_expr_from_name(expr_map, identifier); if(next_access_result != &e2_expr_nil)
if(expr == &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; 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; parse.missed_identifier = identifier;
off = start_off;
} }
} }
//- rjf: leaf numerics //- 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; U64 u64_val = 0;
String8 numeric_string = str8_substr(string, token.range); 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 //- rjf: extend parsed expression tree with trailing operators
if(expr != &e2_expr_nil) if(!state->caller_info_completes_task && expr != &e2_expr_nil)
{ {
U64 trailing_symbol_off = off; U64 trailing_symbol_off = off;
if(e2_try_token(string, E2_TokenKind_Symbol, s(""), &trailing_symbol_off, &token)) if(e2_try_token(string, E2_TokenKind_Symbol, s(""), &trailing_symbol_off, &token))
{ {
// rjf: token string -> operator kind // rjf: token string -> operator kind
E2_OpKind op_kind = E2_OpKind_Null; 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); String8 token_string = str8_substr(string, token.range);
for EachNonZeroEnumVal(E2_OpKind, k) for EachNonZeroEnumVal(E2_OpKind, k)
{ {
if(e2_op_kind_info_table[k].parse_kind == E2_OpParseKind_Binary && E2_OpInfo *op_info = &e2_op_kind_info_table[k];
e2_op_kind_info_table[k].precedence <= max_precedence && if(op_info->precedence <= max_precedence && str8_match(token_string, op_info->sep, 0))
str8_match(token_string, e2_op_kind_info_table[k].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; op_kind = k;
break; break;
} }
@@ -1298,9 +1417,12 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S
MemoryZeroStruct(task); MemoryZeroStruct(task);
task->src_range = token.range; task->src_range = token.range;
task->child_count = 0; task->child_count = 0;
task->child_count_target = 2; task->child_count_target = child_count_target;
task->op_kind = op_kind; task->op_kind = op_kind;
task->max_precedence = e2_op_kind_info_table[op_kind].precedence; 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); SLLStackPush(state->top_task, task);
off = trailing_symbol_off; 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. //- 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 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 //- 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 //- rjf: gather finished expression to current task; increase task child count
E2_ExprNode *n = push_array(arena, E2_ExprNode, 1); if(!state->caller_info_completes_task)
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)
{ {
//- 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; 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 //- rjf: produced finished expression tree, given all children
E2_Expr *finished_root = &e2_expr_nil; E2_Expr *finished_root = &e2_expr_nil;
E2_Expr *lhs = completed_task->first_child ? completed_task->first_child->v : &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 *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; RDI_EvalOp op = RDI_EvalOp_Stop;
E2_TypeKey dst_type_key = {E2_TypeKeyKind_Null}; 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; }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_Deref:
case E2_OpKind_DerefAsm:
{ {
// rjf: unpack operand // rjf: unpack operand
E2_TypeKey rhs_type_key = e2_type_key_unwrap(rhs->type_key, E2_TypeUnwrapFlag_AllDecorative & ~E2_TypeUnwrapFlag_Enums); 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; malformed = 1;
e2_msgf(arena, &parse.msgs, completed_task->src_range, "Cannot dereference arrays of zero-sized types."); 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; malformed = 1;
e2_msgf(arena, &parse.msgs, completed_task->src_range, "Cannot dereference this type."); 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 // rjf: not malformed -> equip info
if(!malformed) 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) //- 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; case E2_OpKind_Define:{}break;
//- rjf: conditionals
case E2_OpKind_Cond:
{
// TODO(rjf)
}break;
} }
} }
//- rjf: consume expected closers //- rjf: report missing closers
if(completed_task->expected_closer.size != 0) 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 //- rjf: work on the parent of the finished expression next
expr = finished_root; 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. //- 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) if(state->top_task == 0 && off >= string.size)
{ {
parse.expr = expr; 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; break;
} }
} }
//- rjf: we're always done if there's nothing left to parse
if(off >= string.size)
{
done = 1;
}
} }
//- rjf: advance offset if successful //- rjf: asking caller for info? -> if we already did this at this offset,
if(parse.status == E2_Status_Good || parse.status == E2_Status_Error) // 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; state->string_off = off;
} }
return parse; return parse;
} }
@@ -1724,12 +2012,14 @@ e2_bytecode_from_expr(Arena *arena, E2_Expr *expr)
internal E2_Interp internal E2_Interp
e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_map, String8 bytecode) 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 = state->bytecode_off;
U64 off_opl = bytecode.size; U64 off_opl = bytecode.size;
B32 done = 0; B32 done = 0;
B32 good = 1; B32 good = 1;
//- rjf: execute bytecode
for(;off < off_opl && !done && good;) for(;off < off_opl && !done && good;)
{ {
Temp scratch = scratch_begin(&arena, 1); 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: case E2_EvalOp_SetCtxID:
{ {
interp.status = E2_Status_NewCtxID; interp.status = E2_InterpStatus_NewCtxID;
interp.ctx_id = decode_val.u64; interp.ctx_id = decode_val.u64;
}break; }break;
@@ -1818,7 +2108,7 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_
if(read_size != size) if(read_size != size)
{ {
good = 0; good = 0;
interp.status = E2_Status_MissedSpaceRead; interp.status = E2_InterpStatus_MissedSpaceRead;
interp.missed_read_space_addr_range = space_addr_range; interp.missed_read_space_addr_range = space_addr_range;
} }
}break; }break;
@@ -1840,14 +2130,14 @@ e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_
if(read_size != size) if(read_size != size)
{ {
good = 0; good = 0;
interp.status = E2_Status_MissedSpaceRead; interp.status = E2_InterpStatus_MissedSpaceRead;
interp.missed_read_space_addr_range = space_addr_range; interp.missed_read_space_addr_range = space_addr_range;
} }
} }
else else
{ {
good = 0; good = 0;
interp.status = E2_Status_BadRegCode; interp.status = E2_InterpStatus_BadRegCode;
} }
}break; }break;
case RDI_EvalOp_FrameOff: {ctx_flags = E2_CtxFlag_HasFrameBase; ctx_base_addr = state->selected_ctx.frame_base_addr;}goto optional_base_off; 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 else
{ {
good = 0; good = 0;
interp.status = E2_Status_MissingCtxFlag; interp.status = E2_InterpStatus_MissingCtxFlag;
interp.missing_ctx_flags |= ctx_flags; interp.missing_ctx_flags |= ctx_flags;
} }
}break; }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 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 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 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_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_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_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_InterpStatus_DivideByZero; good = 0;} }while(0)
#define ArithTypeCasesInt(symbol)\ #define ArithTypeCasesInt(symbol)\
SizedBinOp(S, 8, s8, s8, symbol);\ SizedBinOp(S, 8, s8, s8, symbol);\
SizedBinOp(S, 16, s16, s16, symbol);\ SizedBinOp(S, 16, s16, s16, symbol);\
@@ -1955,7 +2245,7 @@ ArithTypeCasesIntDiv(symbol)
#define ArithTypeCasesIntAllU64(symbol)\ #define ArithTypeCasesIntAllU64(symbol)\
BinOp(S, u64, u64, symbol);\ BinOp(S, u64, u64, symbol);\
BinOp(U, 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(Add, ArithTypeCases(+));
Case(Sub, ArithTypeCases(-)); Case(Sub, ArithTypeCases(-));
Case(Mul, ArithTypeCases(*)); Case(Mul, ArithTypeCases(*));
@@ -2049,7 +2339,7 @@ BinOp(U, u64, u64, symbol);
{ {
switch(in + out*RDI_EvalTypeGroup_COUNT) 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 #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, F32, f32);
Case(U, u64, U64, F64, f64); Case(U, u64, U64, F64, f64);
@@ -2083,7 +2373,7 @@ BinOp(U, u64, u64, symbol);
if(!found) if(!found)
{ {
good = 0; good = 0;
interp.status = E2_Status_InsufficientStackSpace; interp.status = E2_InterpStatus_InsufficientStackSpace;
} }
}break; }break;
@@ -2106,7 +2396,7 @@ BinOp(U, u64, u64, symbol);
else else
{ {
good = 0; good = 0;
interp.status = E2_Status_BadOffset; interp.status = E2_InterpStatus_BadOffset;
} }
}break; }break;
@@ -2118,7 +2408,7 @@ BinOp(U, u64, u64, symbol);
default: default:
{ {
good = 0; good = 0;
interp.status = E2_Status_UnsupportedOp; interp.status = E2_InterpStatus_UnsupportedOp;
}break; }break;
case 2:{push_vals[0].u16 = bswap_u16(popped_vals[0].u16);}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; 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 // skip past the embedded sub-bytecode in the outer stream so the
// bytes are not interpreted as outer ops on resume. // bytes are not interpreted as outer ops on resume.
good = 0; good = 0;
interp.status = E2_Status_UnsupportedOp; interp.status = E2_InterpStatus_UnsupportedOp;
}break; }break;
case RDI_EvalOp_PartialValue: 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 // value already on the stack is the result. for multi-piece, only
// the first piece is returned (stack[0] is the final result). // the first piece is returned (stack[0] is the final result).
good = 0; good = 0;
interp.status = E2_Status_UnsupportedOp; interp.status = E2_InterpStatus_UnsupportedOp;
}break; }break;
case RDI_EvalOp_PartialValueBit: case RDI_EvalOp_PartialValueBit:
{ {
// DW_OP_bit_piece marker. same caveat as PartialValue. // DW_OP_bit_piece marker. same caveat as PartialValue.
good = 0; good = 0;
interp.status = E2_Status_UnsupportedOp; interp.status = E2_InterpStatus_UnsupportedOp;
}break; }break;
} }
@@ -2200,9 +2490,34 @@ BinOp(U, u64, u64, symbol);
break; 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) if(off == off_opl && good)
{ {
interp.status = E2_Status_Good; interp.status = E2_InterpStatus_Good;
if(state->top_val != 0) if(state->top_val != 0)
{ {
interp.val = state->top_val->val; interp.val = state->top_val->val;
+63 -26
View File
@@ -12,7 +12,8 @@ typedef enum E2_OpParseKind
E2_OpParseKind_Null, E2_OpParseKind_Null,
E2_OpParseKind_UnaryPrefix, E2_OpParseKind_UnaryPrefix,
E2_OpParseKind_Binary, E2_OpParseKind_Binary,
E2_OpParseKind_UnaryPostfix, E2_OpParseKind_Ternary,
E2_OpParseKind_Call,
} }
E2_OpParseKind; 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 //- rjf: caller-provided info
E2_Status_MissedSpaceRead, E2_ParseStatus_MissedIdentifierResolution,
E2_Status_MissedIdentifierResolution, E2_ParseStatus_MemberAccess,
E2_Status_Access, E2_ParseStatus_IndexAccess,
E2_Status_NewCtxID, E2_ParseStatus_Call,
E2_ParseStatus_FirstCallerRequest = E2_ParseStatus_MissedIdentifierResolution,
//- rjf: unrecoverable errors E2_ParseStatus_LastCallerRequest = E2_ParseStatus_Call,
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,
} }
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 //~ rjf: Type Keys
@@ -330,6 +357,8 @@ struct E2_ParseTask
S64 max_precedence; S64 max_precedence;
E2_OpKind op_kind; E2_OpKind op_kind;
String8 expected_closer; String8 expected_closer;
String8 expected_splitter;
B32 splitter_is_required;
}; };
typedef struct E2_ParseState E2_ParseState; typedef struct E2_ParseState E2_ParseState;
@@ -338,6 +367,10 @@ struct E2_ParseState
U64 string_off; U64 string_off;
E2_ParseTask *top_task; E2_ParseTask *top_task;
E2_ParseTask *free_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; typedef struct E2_Msg E2_Msg;
@@ -359,10 +392,11 @@ struct E2_MsgList
typedef struct E2_Parse E2_Parse; typedef struct E2_Parse E2_Parse;
struct E2_Parse struct E2_Parse
{ {
E2_Status status; E2_ParseStatus status;
String8 missed_identifier; String8 missed_identifier;
E2_Expr *expr; E2_Expr *expr;
E2_Expr *access_expr; String8 member_name;
E2_Expr *params_expr;
E2_MsgList msgs; E2_MsgList msgs;
}; };
@@ -398,17 +432,20 @@ struct E2_InterpState
E2_Ctx selected_ctx; E2_Ctx selected_ctx;
E2_InterpStackValNode *top_val; E2_InterpStackValNode *top_val;
E2_InterpStackValNode *free_val; E2_InterpStackValNode *free_val;
U64 last_caller_request_bytecode_off;
U64 caller_request_count;
}; };
typedef struct E2_Interp E2_Interp; typedef struct E2_Interp E2_Interp;
struct E2_Interp struct E2_Interp
{ {
E2_Status status; E2_InterpStatus status;
E2_SpaceID space_id; E2_SpaceID space_id;
Rng1U64 missed_read_space_addr_range; Rng1U64 missed_read_space_addr_range;
E2_CtxID ctx_id; E2_CtxID ctx_id;
E2_CtxFlags missing_ctx_flags; E2_CtxFlags missing_ctx_flags;
E2_Val val; 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 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 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 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 //~ rjf: Expression -> Bytecode
+31 -25
View File
@@ -4,31 +4,37 @@
@table(name parse_kind precedence pre sep pos chain) @table(name parse_kind precedence pre sep pos chain)
E2_OpTable: E2_OpTable:
{ {
{Deref UnaryPrefix 2 "*" "" "" ""} {Dot Binary 1 "" "." "" "" }
{Address UnaryPrefix 2 "&" "" "" ""} {Index Binary 1 "" "[" "]" "" }
{Pos UnaryPrefix 2 "+" "" "" ""} {Call Call 1 "" "(" ")" ","}
{Neg UnaryPrefix 2 "-" "" "" ""} {DerefAsm UnaryPrefix 1 "[" "" "]" "" }
{LogNot UnaryPrefix 2 "!" "" "" ""} {SizeOf UnaryPrefix 1 "sizeof " "" "" "" }
{BitNot UnaryPrefix 2 "~" "" "" ""} {Deref UnaryPrefix 2 "*" "" "" "" }
{Mul Binary 3 "" "*" "" ""} {Address UnaryPrefix 2 "&" "" "" "" }
{Div Binary 3 "" "/" "" ""} {Pos UnaryPrefix 2 "+" "" "" "" }
{Mod Binary 3 "" "%" "" ""} {Neg UnaryPrefix 2 "-" "" "" "" }
{Add Binary 4 "" "+" "" ""} {LogNot UnaryPrefix 2 "!" "" "" "" }
{Sub Binary 4 "" "-" "" ""} {BitNot UnaryPrefix 2 "~" "" "" "" }
{LShift Binary 5 "" "<<" "" ""} {Mul Binary 3 "" "*" "" "" }
{RShift Binary 5 "" ">>" "" ""} {Div Binary 3 "" "/" "" "" }
{Less Binary 6 "" "<" "" ""} {Mod Binary 3 "" "%" "" "" }
{LtEq Binary 6 "" "<=" "" ""} {Add Binary 4 "" "+" "" "" }
{Grtr Binary 6 "" ">" "" ""} {Sub Binary 4 "" "-" "" "" }
{GrEq Binary 6 "" ">=" "" ""} {LShift Binary 5 "" "<<" "" "" }
{EqEq Binary 7 "" "==" "" ""} {RShift Binary 5 "" ">>" "" "" }
{NtEq Binary 7 "" "!=" "" ""} {Less Binary 6 "" "<" "" "" }
{BitAnd Binary 8 "" "&" "" ""} {LtEq Binary 6 "" "<=" "" "" }
{BitXor Binary 9 "" "^" "" ""} {Grtr Binary 6 "" ">" "" "" }
{BitOr Binary 10 "" "|" "" ""} {GrEq Binary 6 "" ">=" "" "" }
{LogAnd Binary 11 "" "&&" "" ""} {EqEq Binary 7 "" "==" "" "" }
{LogOr Binary 12 "" "||" "" ""} {NtEq Binary 7 "" "!=" "" "" }
{Define Binary 13 "" "=" "" ""} {BitAnd Binary 8 "" "&" "" "" }
{BitXor Binary 9 "" "^" "" "" }
{BitOr Binary 10 "" "|" "" "" }
{LogAnd Binary 11 "" "&&" "" "" }
{LogOr Binary 12 "" "||" "" "" }
{Define Binary 13 "" "=" "" "" }
{Cond Ternary 14 "" "?" "" ":"}
} }
@enum E2_OpKind: @enum E2_OpKind:
+7 -1
View File
@@ -4,9 +4,14 @@
//- GENERATED CODE //- GENERATED CODE
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
E2_OpInfo e2_op_kind_info_table[26] = E2_OpInfo e2_op_kind_info_table[32] =
{ {
{0}, {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("")}, {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, 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, 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_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] = U8 e2_type_kind_basic_byte_size_table[61] =
+7 -1
View File
@@ -9,6 +9,11 @@
typedef enum E2_OpKind typedef enum E2_OpKind
{ {
E2_OpKind_Null, E2_OpKind_Null,
E2_OpKind_Dot,
E2_OpKind_Index,
E2_OpKind_Call,
E2_OpKind_DerefAsm,
E2_OpKind_SizeOf,
E2_OpKind_Deref, E2_OpKind_Deref,
E2_OpKind_Address, E2_OpKind_Address,
E2_OpKind_Pos, E2_OpKind_Pos,
@@ -34,6 +39,7 @@ E2_OpKind_BitOr,
E2_OpKind_LogAnd, E2_OpKind_LogAnd,
E2_OpKind_LogOr, E2_OpKind_LogOr,
E2_OpKind_Define, E2_OpKind_Define,
E2_OpKind_Cond,
E2_OpKind_COUNT, E2_OpKind_COUNT,
} E2_OpKind; } E2_OpKind;
@@ -116,7 +122,7 @@ E2_TypeKind_LastMeta = E2_TypeKind_MetaDescription,
} E2_TypeKind; } E2_TypeKind;
C_LINKAGE_BEGIN 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 U8 e2_type_kind_basic_byte_size_table[61];
extern String8 e2_type_kind_basic_string_table[61]; extern String8 e2_type_kind_basic_string_table[61];
+2 -2
View File
@@ -79,8 +79,8 @@ RDI_EVAL_CTRLBITS(16, 0, 1),
RDI_EVAL_CTRLBITS(32, 0, 1), RDI_EVAL_CTRLBITS(32, 0, 1),
RDI_EVAL_CTRLBITS(64, 0, 1), RDI_EVAL_CTRLBITS(64, 0, 1),
RDI_EVAL_CTRLBITS(1, 0, 1), RDI_EVAL_CTRLBITS(1, 0, 1),
RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(2, 1, 1),
RDI_EVAL_CTRLBITS(1, 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), RDI_EVAL_CTRLBITS(2, 2, 1),
RDI_EVAL_CTRLBITS(2, 2, 1), RDI_EVAL_CTRLBITS(2, 2, 1),
+2 -2
View File
@@ -1187,9 +1187,9 @@ make_directory(String8 path)
//~ rjf: @per_os_impl Aborting //~ rjf: @per_os_impl Aborting
internal void internal void
abort_self(S32 exit_code) abort_self(U64 exit_code)
{ {
exit(exit_code); exit((int)exit_code);
} }
//////////////////////////////// ////////////////////////////////
+10
View File
@@ -586,6 +586,16 @@ entry_point(CmdLine *cmd_line)
{ {
Temp scratch = scratch_begin(0, 0); 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 //- rjf: unpack command line arguments
ExecMode exec_mode = ExecMode_Normal; ExecMode exec_mode = ExecMode_Normal;
B32 auto_run = 0; B32 auto_run = 0;
+2 -2
View File
@@ -1214,8 +1214,8 @@ RDI_EvalOpTable:
{ConstU256 16 32 0 1} {ConstU256 16 32 0 1}
{ConstU512 17 64 0 1} {ConstU512 17 64 0 1}
{ConstString 18 1 0 1} {ConstString 18 1 0 1}
{Abs 19 1 1 1} {Abs 19 2 1 1}
{Neg 20 1 1 1} {Neg 20 2 1 1}
{Add 21 2 2 1} {Add 21 2 2 1}
{Sub 22 2 2 1} {Sub 22 2 2 1}
{Mul 23 2 2 1} {Mul 23 2 2 1}
+1 -1
View File
@@ -422,7 +422,7 @@ p2r_convert2(Arena *arena, P2R_ConvertParams *params)
} }
else 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].ranges = unit_ranges[idx];
cv2r_comp_units[idx].sym = all_syms[idx]; cv2r_comp_units[idx].sym = all_syms[idx];
+48 -14
View File
@@ -13,9 +13,7 @@
//- rjf: [h] //- rjf: [h]
#include "base/base_inc.h" #include "base/base_inc.h"
#include "x64/x64.h" #include "x64/x64.h"
#include "http/http_inc.h"
#include "artifact_cache/artifact_cache.h" #include "artifact_cache/artifact_cache.h"
#include "symbol_server/symbol_server_inc.h"
#include "rdi/rdi_local.h" #include "rdi/rdi_local.h"
#include "dbg_info/dbg_info.h" #include "dbg_info/dbg_info.h"
#include "arch/arch_inc.h" #include "arch/arch_inc.h"
@@ -24,9 +22,7 @@
//- rjf: [c] //- rjf: [c]
#include "base/base_inc.c" #include "base/base_inc.c"
#include "x64/x64.c" #include "x64/x64.c"
#include "http/http_inc.c"
#include "artifact_cache/artifact_cache.c" #include "artifact_cache/artifact_cache.c"
#include "symbol_server/symbol_server_inc.c"
#include "rdi/rdi_local.c" #include "rdi/rdi_local.c"
#include "dbg_info/dbg_info.c" #include "dbg_info/dbg_info.c"
#include "arch/arch_inc.c" #include "arch/arch_inc.c"
@@ -40,6 +36,10 @@ entry_point(CmdLine *cmdline)
{ {
String8 strings[] = String8 strings[] =
{ {
s("[123]"),
s("foo"),
s("foo.bar"),
s("123[456]"),
s("123"), s("123"),
s("123 + 456"), s("123 + 456"),
s("!1"), s("!1"),
@@ -50,22 +50,47 @@ entry_point(CmdLine *cmdline)
s("3 * 4 + 2"), s("3 * 4 + 2"),
s("(3 * 4) + 2"), s("(3 * 4) + 2"),
s("2 + (3 * 4)"), 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) for EachElement(idx, strings)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
String8List msgs = {0};
// rjf: string -> expr // rjf: string -> expr
E2_Expr *expr = &e2_expr_nil; E2_Expr *expr = &e2_expr_nil;
{ {
E2_ParseState state = {0}; E2_ParseState state = {0};
E2_ExprMap expr_map = {0}; E2_ExprMap expr_map = {0};
E2_Expr *access_expr = &e2_expr_nil;
for(;;) for(;;)
{ {
E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, strings[idx]); E2_Parse parse = e2_parse_from_string(scratch.arena, &state, &expr_map, access_expr, strings[idx]);
if(parse.status == E2_Status_Good) 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; break;
} }
} }
@@ -82,20 +107,29 @@ entry_point(CmdLine *cmdline)
for(;;) for(;;)
{ {
E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &state, &space_map, bytecode); E2_Interp interp = e2_interp_from_bytecode(scratch.arena, &state, &space_map, bytecode);
if(interp.status == E2_Status_Good) val = interp.val;
{ if(e2_interp_status_is_terminal(interp.status))
val = interp.val;
break;
}
else if(E2_Status_FirstError <= interp.status <= E2_Status_LastError)
{ {
if(interp.status != E2_InterpStatus_Good)
{
str8_list_pushf(scratch.arena, &msgs, "Interpretation error (%i).", interp.status);
}
break; break;
} }
} }
} }
// rjf: message string list -> string
StringJoin join = {.sep = s(" ")};
String8 msgs_string = str8_list_join(scratch.arena, &msgs, &join);
// rjf: log // 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); fflush(stdout);
scratch_end(scratch); scratch_end(scratch);
+2 -2
View File
@@ -1276,9 +1276,9 @@ make_directory(String8 path)
//~ rjf: @per_os_impl Aborting //~ rjf: @per_os_impl Aborting
internal void internal void
abort_self(S32 exit_code) abort_self(U64 exit_code)
{ {
ExitProcess(exit_code); ExitProcess((int)exit_code);
} }
//////////////////////////////// ////////////////////////////////