diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 5ec8cffd..2d800c82 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -28,6 +28,7 @@ typedef struct VM { py_TValue last_retval; py_TValue curr_exception; + bool is_signal_interrupted; bool is_curr_exc_handled; // handled by try-except block but not cleared yet py_TValue reg[8]; // users' registers diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index c411a033..d1295ffd 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -87,6 +87,8 @@ PK_API void py_resetvm(); PK_API void* py_getvmctx(); /// Set the current VM context. This is used for user-defined data. PK_API void py_setvmctx(void* ctx); +/// Interrupt the current VM and raise a `KeyboardInterrupt` exception. +PK_API void py_interrupt(); /// Set `sys.argv`. Used for storing command-line arguments. PK_API void py_sys_setargv(int argc, char** argv); /// Setup the callbacks for the current VM. diff --git a/src/common/sstream.c b/src/common/sstream.c index 35ffffd9..70d77ddb 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -253,7 +253,7 @@ int py_replinput(char* buf, int max_size) { while(true) { char c = getchar(); - if(c == EOF) break; + if(c == EOF) return -1; if(c == '\n') { char last = '\0'; diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 92214f10..a610fa32 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -92,6 +92,12 @@ FrameResult VM__run_top_frame(VM* self) { pk_print_stack(self, frame, byte); #endif + if(self->is_signal_interrupted){ + self->is_signal_interrupted = false; + py_exception(tp_KeyboardInterrupt, ""); + goto __ERROR; + } + switch((Opcode)byte.op) { case OP_NO_OP: DISPATCH(); /*****************************************/ diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 2cd5312a..7913e44d 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -69,6 +69,7 @@ void VM__ctor(VM* self) { self->last_retval = *py_NIL(); self->curr_exception = *py_NIL(); + self->is_signal_interrupted = false; self->is_curr_exc_handled = false; self->ctx = NULL; @@ -147,7 +148,6 @@ void VM__ctor(VM* self) { INJECT_BUILTIN_EXC(SystemExit, tp_BaseException); INJECT_BUILTIN_EXC(KeyboardInterrupt, tp_BaseException); - // INJECT_BUILTIN_EXC(StopIteration, tp_Exception); validate(tp_StopIteration, pk_StopIteration__register()); py_setdict(&self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration)); diff --git a/src/public/internal.c b/src/public/internal.c index a339f92a..debd5bcb 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -90,6 +90,8 @@ void* py_getvmctx() { return pk_current_vm->ctx; } void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; } +void py_interrupt() { pk_current_vm->is_signal_interrupted = true; } + void py_sys_setargv(int argc, char** argv) { py_GlobalRef sys = py_getmodule("sys"); py_Ref argv_list = py_getdict(sys, py_name("argv")); diff --git a/src2/main.c b/src2/main.c index 21968a80..35f1368d 100644 --- a/src2/main.c +++ b/src2/main.c @@ -8,6 +8,14 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include +#else + +// set ctrl+c handler +#include +#include + +static void sigint_handler(int sig) { py_interrupt(); } + #endif char* read_file(const char* path) { @@ -31,6 +39,8 @@ int main(int argc, char** argv) { #if _WIN32 SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); +#else + signal(SIGINT, sigint_handler); #endif if(argc > 2) { @@ -53,6 +63,10 @@ int main(int argc, char** argv) { while(true) { int size = py_replinput(buf, sizeof(buf)); + if(size == -1) { // Ctrl-D (i.e. EOF) + printf("\n"); + break; + } assert(size < sizeof(buf)); if(size >= 0) { py_StackRef p0 = py_peek(0);