From 4d1d2a7581d52aca8f0b339625434bcddb2b9482 Mon Sep 17 00:00:00 2001 From: lightovernight Date: Tue, 8 Jul 2025 15:23:45 +0800 Subject: [PATCH] simplify the workdir process and minor optimizations --- include/pocketpy/debugger/core.h | 8 ++- src/debugger/core.c | 94 ++++++++++++++++++++++++-------- src/debugger/dap.c | 36 +++++++++++- src2/main.c | 6 +- 4 files changed, 116 insertions(+), 28 deletions(-) diff --git a/include/pocketpy/debugger/core.h b/include/pocketpy/debugger/core.h index aaa82339..0508dff4 100644 --- a/include/pocketpy/debugger/core.h +++ b/include/pocketpy/debugger/core.h @@ -5,11 +5,13 @@ #include "pocketpy/common/vector.h" #include "pocketpy/pocketpy.h" -enum C11_STEP_MODE { C11_STEP_IN, C11_STEP_OVER, C11_STEP_OUT, C11_STEP_CONTINUE }; +typedef enum { C11_STEP_IN, C11_STEP_OVER, C11_STEP_OUT, C11_STEP_CONTINUE } C11_STEP_MODE; + +typedef enum { C11_DEBUGGER_SUCCESS, C11_DEBUGGER_UNKNOW_ERROR, C11_DEBUGGER_FILEPATH_ERROR } C11_DEBUGGER_FAIL_REASON; void c11_debugger_init(void); -void c11_debugger_set_step_mode(enum C11_STEP_MODE mode); -void c11_debugger_on_trace(py_Frame* frame, enum py_TraceEvent event); +void c11_debugger_set_step_mode(C11_STEP_MODE mode); +C11_DEBUGGER_FAIL_REASON c11_debugger_on_trace(py_Frame* frame, enum py_TraceEvent event); void c11_debugger_frames(c11_sbuf* buffer); void c11_debugger_scopes(int frameid, c11_sbuf* buffer); bool c11_debugger_unfold_var(int var_id, c11_sbuf* buffer); diff --git a/src/debugger/core.c b/src/debugger/core.c index bdd97896..addbf963 100644 --- a/src/debugger/core.c +++ b/src/debugger/core.c @@ -34,14 +34,18 @@ static struct c11_debugger { int current_line; int pause_allowed_depth; int step_line; - enum C11_STEP_MODE step_mode; + C11_STEP_MODE step_mode; bool keep_suspend; c11_vector breakpoints; c11_vector py_frames; c11_smallmap_d2index scopes_query_cache; +<<<<<<< HEAD #define python_vars py_r7() +======= +#define python_vars py_r7() +>>>>>>> 429f2e78 (simplify the workdir process) } debugger; @@ -65,6 +69,21 @@ inline static py_Ref get_variable(int var_ref) { return py_list_getitem(python_vars, var_ref); } + +static inline const char* format_filepath(const char* path) { + if (strstr(path, "..")) { + return NULL; + } + if (strstr(path + 1, "./") || strstr(path + 1, ".\\")) { + return NULL; + } + if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) { + return path + 2; + } + return path; +} + + void c11_debugger_init() { debugger.curr_stack_depth = 0; debugger.current_line = -1; @@ -75,16 +94,22 @@ void c11_debugger_init() { init_structures(); } -void c11_debugger_on_trace(py_Frame* frame, enum py_TraceEvent event) { +C11_DEBUGGER_FAIL_REASON c11_debugger_on_trace(py_Frame* frame, enum py_TraceEvent event) { debugger.current_frame = frame; debugger.current_event = event; - debugger.current_filename = py_Frame_sourceloc(debugger.current_frame, &debugger.current_line); + const char* source_name = py_Frame_sourceloc(debugger.current_frame, &debugger.current_line); + debugger.current_filename = format_filepath(source_name); + if(debugger.current_filename == NULL) { return C11_DEBUGGER_FILEPATH_ERROR; } clear_structures(); - if(event == TRACE_EVENT_LINE) return; - event == TRACE_EVENT_PUSH ? debugger.curr_stack_depth++ : debugger.curr_stack_depth--; + switch(event) { + case TRACE_EVENT_PUSH: debugger.curr_stack_depth++; break; + case TRACE_EVENT_POP: debugger.curr_stack_depth--; break; + default: break; + } + return C11_DEBUGGER_SUCCESS; } -void c11_debugger_set_step_mode(enum C11_STEP_MODE mode) { +void c11_debugger_set_step_mode(C11_STEP_MODE mode) { switch(mode) { case C11_STEP_IN: debugger.pause_allowed_depth = INT32_MAX; break; case C11_STEP_OVER: @@ -98,7 +123,10 @@ void c11_debugger_set_step_mode(enum C11_STEP_MODE mode) { debugger.keep_suspend = false; } +<<<<<<< HEAD +======= +>>>>>>> 429f2e78 (simplify the workdir process) int c11_debugger_setbreakpoint(const char* filename, int lineno) { c11_debugger_breakpoint breakpoint = {.sourcename = c11_strdup(filename), .lineno = lineno}; c11_vector__push(c11_debugger_breakpoint, &debugger.breakpoints, breakpoint); @@ -156,7 +184,10 @@ int c11_debugger_should_pause() { int c11_debugger_should_keep_pause(void) { return debugger.keep_suspend; } +<<<<<<< HEAD +======= +>>>>>>> 429f2e78 (simplify the workdir process) inline static c11_sv sv_from_cstr(const char* str) { c11_sv sv = {.data = str, .size = strlen(str)}; return sv; @@ -164,7 +195,7 @@ inline static c11_sv sv_from_cstr(const char* str) { const inline static char* get_basename(const char* path) { const char* last_slash = strrchr(path, '/'); -#ifdef _WIN32 +#if defined(_WIN32) || defined(_WIN64) const char* last_backslash = strrchr(path, '\\'); if(!last_slash || (last_backslash && last_backslash > last_slash)) { last_slash = last_backslash; @@ -254,31 +285,46 @@ bool c11_debugger_unfold_var(int var_id, c11_sbuf* buffer) { py_Ref base_var_ref = py_pushtmp(); py_newint(base_var_ref, base_index); - // 3. construct DAP JSON - const char* dap_code = - "{'variables': [" - " {" - " 'name': kv[0]," - " 'value': repr(kv[1])," - " 'variablesReference': (_1 + i) if (isinstance(kv[1], (dict, list, tuple)) or kv[1].__dict__ is not None) else 0," - " 'type': type(kv[1]).__name__" - " }" - " for i, kv in enumerate(_0)" - "]}"; - if(!py_smarteval(dap_code, NULL, kv_list, base_var_ref)) { - py_printexc(); - return false; - } + // 3. construct DAP JSON and extend python_vars py_Ref dap_obj = py_pushtmp(); +<<<<<<< HEAD py_assign(dap_obj, py_retval()); // 4. extend python_vars if(!py_smartexec("_0.extend([kv[1] for kv in _1])", NULL, python_vars, kv_list)) { +======= + py_newdict(dap_obj); // 先创建字典 + const char* dap_code = + "_2['variables'] = []\n" + "var_ref = _1\n" + "for k, v in _0:\n" + " has_children = isinstance(v, (dict, list, tuple)) or v.__dict__ is not None\n" + " _2['variables'].append({\n" + " 'name': k if type(k) == str else str(k),\n" + " 'value': repr(v) if type(v) == str else str(v),\n" + " 'variablesReference': var_ref if has_children else 0,\n" + " 'type': type(v).__name__\n" + " })\n" + " if has_children: var_ref += 1\n"; + if(!py_smartexec(dap_code, NULL, kv_list, base_var_ref, dap_obj)) { +>>>>>>> 429f2e78 (simplify the workdir process) py_printexc(); return false; } + + // 4. extend python_vars + if(!py_smartexec( + "_0.extend([v for k, v in _1 if isinstance(v, (dict, list, tuple)) or v.__dict__ is not None])", + NULL, + python_vars, + kv_list)) { + py_printexc(); + return false; + } + // 5. dump & write if(!py_json_dumps(dap_obj, 0)) { + printf("dap_obj: %s\n", py_tpname(py_typeof(dap_obj))); py_printexc(); return false; } @@ -291,4 +337,8 @@ bool c11_debugger_unfold_var(int var_id, c11_sbuf* buffer) { py_pop(); // kv_list return true; } +<<<<<<< HEAD +======= + +>>>>>>> 429f2e78 (simplify the workdir process) #undef python_vars diff --git a/src/debugger/dap.c b/src/debugger/dap.c index a2fa919b..272dac2e 100644 --- a/src/debugger/dap.c +++ b/src/debugger/dap.c @@ -54,10 +54,14 @@ void c11_dap_handle_initialize(py_Ref arguments, c11_sbuf* buffer) { c11_sbuf__write_char(buffer, ','); } +<<<<<<< HEAD void c11_dap_handle_attach(py_Ref arguments, c11_sbuf* buffer) { server.isatttach = true; } +======= +void c11_dap_handle_attach(py_Ref arguments, c11_sbuf* buffer) { server.isatttach = true; } +>>>>>>> 429f2e78 (simplify the workdir process) void c11_dap_handle_next(py_Ref arguments, c11_sbuf* buffer) { c11_debugger_set_step_mode(C11_STEP_OVER); @@ -230,9 +234,24 @@ void c11_dap_send_event(const char* event_name, const char* body_json) { void c11_dap_send_stop_event() { c11_dap_send_event("stopped", - "{\"reason\":\"breakpoint\",\"threadId\":1,\"allThreadsStopped\":true}"); + "{\"threadId\":1,\"allThreadsStopped\":true}"); } +<<<<<<< HEAD +======= +void c11_dap_send_exited_event(int exitCode) { + char body[64]; + snprintf(body, sizeof(body), "{\"exitCode\":%d}", exitCode); + c11_dap_send_event("exited", body); +} + +void c11_dap_send_fatal_event(const char* message) { + char body[128]; + snprintf(body, sizeof(body), "{\"message\":\"%s\"}", message); + c11_dap_send_event("pkpy/fatalError", body); +} + +>>>>>>> 429f2e78 (simplify the workdir process) void c11_dap_send_initialized_event() { c11_dap_send_event("initialized", "{}"); } int c11_dap_read_content_length(const char* buffer, int* header_length) { @@ -346,7 +365,20 @@ void c11_dap_configure_debugger() { void c11_dap_tracefunc(py_Frame* frame, enum py_TraceEvent event) { py_sys_settrace(NULL, false); - c11_debugger_on_trace(frame, event); + C11_DEBUGGER_FAIL_REASON result = c11_debugger_on_trace(frame, event); + if(result != C11_DEBUGGER_SUCCESS) { + const char* message = NULL; + switch(result) { + case C11_DEBUGGER_FILEPATH_ERROR: + message = "Invalid py_file path: '..' forbidden, './' only allowed at start."; + break; + case C11_DEBUGGER_UNKNOW_ERROR: + default: message = "Unknown debugger failure."; break; + } + if(message) { c11_dap_send_fatal_event(message); } + c11_dap_send_exited_event(1); + exit(1); + } c11_dap_handle_message(); if(!c11_debugger_should_pause()) { py_sys_settrace(c11_dap_tracefunc, false); diff --git a/src2/main.c b/src2/main.c index 5ebe61e7..b6b9a0b8 100644 --- a/src2/main.c +++ b/src2/main.c @@ -4,7 +4,7 @@ #include #include "pocketpy.h" - +#include "pocketpy/debugger/dap.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -90,9 +90,13 @@ int main(int argc, char** argv) { } } } else { +<<<<<<< HEAD if(profile) py_profiler_begin(); if(debug) py_debugger_waitforattach("127.0.0.1", 6110); +======= + wait_for_debugger("127.0.0.1", 3939); +>>>>>>> 429f2e78 (simplify the workdir process) char* source = read_file(filename); if(source) { if(!py_exec(source, filename, EXEC_MODE, NULL))