diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 955b2a10..117208ad 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -68,6 +68,8 @@ typedef struct py_Callbacks { char* (*importfile)(const char*); /// Used by `print` to output a string. void (*print)(const char*); + /// Flush the output buffer of `print`. + void (*flush)(); /// Used by `input` to get a character. int (*getchar)(); } py_Callbacks; diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index a14e2816..667086f2 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -29,6 +29,8 @@ static char* pk_default_importfile(const char* path) { static void pk_default_print(const char* data) { printf("%s", data); } +static void pk_default_flush() { fflush(stdout); } + static void py_TypeInfo__ctor(py_TypeInfo* self, py_Name name, py_Type index, @@ -67,6 +69,7 @@ void VM__ctor(VM* self) { self->callbacks.importfile = pk_default_importfile; self->callbacks.print = pk_default_print; + self->callbacks.flush = pk_default_flush; self->callbacks.getchar = getchar; self->last_retval = *py_NIL(); diff --git a/src/modules/pkpy.c b/src/modules/pkpy.c index 79cac762..8b68dafe 100644 --- a/src/modules/pkpy.c +++ b/src/modules/pkpy.c @@ -65,6 +65,14 @@ static bool pkpy_is_user_defined_type(int argc, py_Ref argv) { return true; } +static bool pkpy_enable_full_buffering_mode(int argc, py_Ref argv) { + PY_CHECK_ARGC(0); + static char buf[1024 * 1024 * 1]; + setvbuf(stdout, buf, _IOFBF, sizeof(buf)); + py_newnone(py_retval()); + return true; +} + static bool pkpy_currentvm(int argc, py_Ref argv) { PY_CHECK_ARGC(0); py_newint(py_retval(), py_currentvm()); @@ -411,7 +419,9 @@ static void pk_ComputeThread__register(py_Ref mod) { py_bindmethod(type, "submit_exec", ComputeThread_submit_exec); py_bindmethod(type, "submit_eval", ComputeThread_submit_eval); - py_bind(py_tpobject(type), "submit_call(self, eval_src, *args, **kwargs)", ComputeThread_submit_call); + py_bind(py_tpobject(type), + "submit_call(self, eval_src, *args, **kwargs)", + ComputeThread_submit_call); py_bindmethod(type, "exec", ComputeThread_exec); py_bindmethod(type, "eval", ComputeThread_eval); @@ -453,6 +463,7 @@ void pk__add_module_pkpy() { py_bindfunc(mod, "memory_usage", pkpy_memory_usage); py_bindfunc(mod, "is_user_defined_type", pkpy_is_user_defined_type); + py_bindfunc(mod, "enable_full_buffering_mode", pkpy_enable_full_buffering_mode); py_bindfunc(mod, "currentvm", pkpy_currentvm); diff --git a/src/public/modules.c b/src/public/modules.c index b4af2af9..b6c5c694 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -200,12 +200,12 @@ static bool builtins_input(int argc, py_Ref argv) { if(!py_checkstr(argv)) return false; prompt = py_tostr(argv); } - pk_current_vm->callbacks.print(prompt); + py_callbacks()->print(prompt); c11_sbuf buf; c11_sbuf__ctor(&buf); while(true) { - int c = pk_current_vm->callbacks.getchar(); + int c = py_callbacks()->getchar(); if(c == '\n' || c == '\r') break; if(c == EOF) break; c11_sbuf__write_char(&buf, c); @@ -323,11 +323,15 @@ static bool builtins_round(int argc, py_Ref argv) { } static bool builtins_print(int argc, py_Ref argv) { - // print(*args, sep=' ', end='\n') + // print(*args, sep=' ', end='\n', flush=False) py_TValue* args = py_tuple_data(argv); int length = py_tuple_len(argv); + PY_CHECK_ARG_TYPE(1, tp_str); + PY_CHECK_ARG_TYPE(2, tp_str); + PY_CHECK_ARG_TYPE(3, tp_bool); c11_sv sep = py_tosv(py_arg(1)); c11_sv end = py_tosv(py_arg(2)); + bool flush = py_tobool(py_arg(3)); c11_sbuf buf; c11_sbuf__ctor(&buf); for(int i = 0; i < length; i++) { @@ -340,7 +344,8 @@ static bool builtins_print(int argc, py_Ref argv) { } c11_sbuf__write_sv(&buf, end); c11_string* res = c11_sbuf__submit(&buf); - pk_current_vm->callbacks.print(res->data); + py_callbacks()->print(res->data); + if(flush) py_callbacks()->flush(); c11_string__delete(res); py_newnone(py_retval()); return true; @@ -722,7 +727,7 @@ py_TValue pk_builtins__register() { py_bindfunc(builtins, "divmod", builtins_divmod); py_bindfunc(builtins, "round", builtins_round); - py_bind(builtins, "print(*args, sep=' ', end='\\n')", builtins_print); + py_bind(builtins, "print(*args, sep=' ', end='\\n', flush=False)", builtins_print); py_bindfunc(builtins, "isinstance", builtins_isinstance); py_bindfunc(builtins, "issubclass", builtins_issubclass);