mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-09 15:28:08 +00:00
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:
@@ -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`.
|
||||
|
||||
+1
-1
@@ -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, },
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+368
-53
@@ -95,6 +95,8 @@ internal E2_Expr *
|
||||
e2_expr_from_name(E2_ExprMap *map, String8 name)
|
||||
{
|
||||
E2_Expr *expr = &e2_expr_nil;
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(name);
|
||||
U64 slot_idx = hash%map->slots_count;
|
||||
E2_ExprMapNode *node = 0;
|
||||
@@ -110,6 +112,7 @@ e2_expr_from_name(E2_ExprMap *map, String8 name)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1180,6 +1206,83 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S
|
||||
// rjf: push task for operand
|
||||
if(op_kind != E2_OpKind_Null)
|
||||
{
|
||||
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;
|
||||
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: 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))
|
||||
{
|
||||
// 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_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)
|
||||
{
|
||||
@@ -1198,21 +1301,25 @@ e2_parse_from_string(Arena *arena, E2_ParseState *state, E2_ExprMap *expr_map, S
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: leaf identifiers
|
||||
else if(expr == &e2_expr_nil && e2_try_token(string, E2_TokenKind_Identifier, s(""), &off, &token))
|
||||
// rjf: try to resolve via caller-provided named expressions
|
||||
if(!identifier_mapped)
|
||||
{
|
||||
String8 identifier = str8_substr(string, token.range);
|
||||
expr = e2_expr_from_name(expr_map, identifier);
|
||||
if(expr == &e2_expr_nil)
|
||||
identifier_mapped = (expr != &e2_expr_nil);
|
||||
}
|
||||
|
||||
// rjf: couldn't map -> ask caller to resolve it
|
||||
if(!identifier_mapped)
|
||||
{
|
||||
done = 1;
|
||||
parse.status = E2_Status_MissedIdentifierResolution;
|
||||
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
|
||||
if(!state->caller_info_completes_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: task child count hits limit -> complete this subtree
|
||||
if(state->top_task->child_count >= state->top_task->child_count_target)
|
||||
//- 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)
|
||||
{
|
||||
//- rjf: release task
|
||||
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)
|
||||
{
|
||||
if(!e2_try_token(string, E2_TokenKind_Symbol, completed_task->expected_closer, &off, 0))
|
||||
//- rjf: report missing closers
|
||||
if(!completed_with_caller_info && completed_task->expected_closer.size != 0 && !closer_found)
|
||||
{
|
||||
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;
|
||||
|
||||
+63
-26
@@ -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
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
@table(name parse_kind precedence pre sep pos chain)
|
||||
E2_OpTable:
|
||||
{
|
||||
{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 "+" "" "" "" }
|
||||
@@ -29,6 +34,7 @@ E2_OpTable:
|
||||
{LogAnd Binary 11 "" "&&" "" "" }
|
||||
{LogOr Binary 12 "" "||" "" "" }
|
||||
{Define Binary 13 "" "=" "" "" }
|
||||
{Cond Ternary 14 "" "?" "" ":"}
|
||||
}
|
||||
|
||||
@enum E2_OpKind:
|
||||
|
||||
@@ -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] =
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
+2
-2
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-2
@@ -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}
|
||||
|
||||
@@ -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];
|
||||
|
||||
+47
-13
@@ -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))
|
||||
{
|
||||
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)
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user