diff --git a/bare-arm/main.c b/bare-arm/main.c index 3c187e5fb0..d9f83b4ebe 100644 --- a/bare-arm/main.c +++ b/bare-arm/main.c @@ -14,6 +14,7 @@ #include "runtime0.h" #include "runtime.h" #include "repl.h" +#include "pfenv.h" void do_str(const char *src) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); @@ -38,7 +39,7 @@ void do_str(const char *src) { if (mp_obj_is_exception_instance(module_fun)) { // compile error - mp_obj_print_exception(module_fun); + mp_obj_print_exception(printf_wrapper, NULL, module_fun); return; } @@ -48,7 +49,7 @@ void do_str(const char *src) { nlr_pop(); } else { // uncaught exception - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); } } diff --git a/py/modsys.c b/py/modsys.c index d9be7d1bc1..06bd4c80e1 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -38,6 +38,8 @@ #include "objstr.h" #include "mpz.h" #include "objint.h" +#include "pfenv.h" +#include "stream.h" #if MICROPY_PY_SYS @@ -78,6 +80,25 @@ STATIC mp_obj_t mp_sys_exit(mp_uint_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit); +STATIC mp_obj_t mp_sys_print_exception(mp_uint_t n_args, const mp_obj_t *args) { + #if MICROPY_PY_IO + mp_obj_t stream_obj = &mp_sys_stdout_obj; + if (n_args > 1) { + stream_obj = args[1]; + } + + pfenv_t pfenv; + pfenv.data = stream_obj; + pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write; + mp_obj_print_exception((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[0]); + #else + mp_obj_print_exception(printf_wrapper, NULL, args[0]); + #endif + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception); + STATIC const mp_map_elem_t mp_module_sys_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) }, @@ -118,6 +139,12 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj }, #endif + + /* + * Extensions to CPython + */ + + { MP_OBJ_NEW_QSTR(MP_QSTR_print_exception), (mp_obj_t)&mp_sys_print_exception_obj }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table); diff --git a/py/obj.c b/py/obj.c index c869a65465..d2801a3968 100644 --- a/py/obj.c +++ b/py/obj.c @@ -85,31 +85,31 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) { } // helper function to print an exception with traceback -void mp_obj_print_exception(mp_obj_t exc) { +void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc) { if (mp_obj_is_exception_instance(exc)) { mp_uint_t n, *values; mp_obj_exception_get_traceback(exc, &n, &values); if (n > 0) { assert(n % 3 == 0); - printf("Traceback (most recent call last):\n"); + print(env, "Traceback (most recent call last):\n"); for (int i = n - 3; i >= 0; i -= 3) { #if MICROPY_ENABLE_SOURCE_LINE - printf(" File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]); + print(env, " File \"%s\", line %d", qstr_str(values[i]), (int)values[i + 1]); #else - printf(" File \"%s\"", qstr_str(values[i])); + print(env, " File \"%s\"", qstr_str(values[i])); #endif // the block name can be NULL if it's unknown qstr block = values[i + 2]; if (block == MP_QSTR_NULL) { - printf("\n"); + print(env, "\n"); } else { - printf(", in %s\n", qstr_str(block)); + print(env, ", in %s\n", qstr_str(block)); } } } } - mp_obj_print(exc, PRINT_EXC); - printf("\n"); + mp_obj_print_helper(print, env, exc, PRINT_EXC); + print(env, "\n"); } bool mp_obj_is_true(mp_obj_t arg) { diff --git a/py/obj.h b/py/obj.h index 3721bea925..6db76405e9 100644 --- a/py/obj.h +++ b/py/obj.h @@ -418,7 +418,7 @@ mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); -void mp_obj_print_exception(mp_obj_t exc); +void mp_obj_print_exception(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t exc); bool mp_obj_is_true(mp_obj_t arg); diff --git a/py/pfenv.h b/py/pfenv.h index fea2c883e9..98c1885f35 100644 --- a/py/pfenv.h +++ b/py/pfenv.h @@ -52,3 +52,6 @@ int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, c //int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args); int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...); + +// Wrapper for system printf +void printf_wrapper(void *env, const char *fmt, ...); diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 449f44d3bc..f183c256fb 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -403,6 +403,7 @@ Q(version_info) #if MICROPY_PY_SYS_MAXSIZE Q(maxsize) #endif +Q(print_exception) #endif #if MICROPY_PY_STRUCT diff --git a/qemu-arm/main.c b/qemu-arm/main.c index 8cbeaaa6ef..11ba2f4028 100644 --- a/qemu-arm/main.c +++ b/qemu-arm/main.c @@ -14,6 +14,7 @@ #include "runtime0.h" #include "runtime.h" #include "repl.h" +#include "pfenv.h" void do_str(const char *src) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); @@ -38,7 +39,7 @@ void do_str(const char *src) { if (mp_obj_is_exception_instance(module_fun)) { // compile error - mp_obj_print_exception(module_fun); + mp_obj_print_exception(printf_wrapper, NULL, module_fun); return; } @@ -48,7 +49,7 @@ void do_str(const char *src) { nlr_pop(); } else { // uncaught exception - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); } } diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c index fb95130772..ea9b0408f3 100644 --- a/qemu-arm/test_main.c +++ b/qemu-arm/test_main.c @@ -40,7 +40,7 @@ inline void do_str(const char *src) { mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true); if (mp_obj_is_exception_instance(module_fun)) { - mp_obj_print_exception(module_fun); + mp_obj_print_exception(printf_wrapper, NULL, module_fun); tt_abort_msg("Compile error"); } @@ -49,7 +49,7 @@ inline void do_str(const char *src) { mp_call_function_0(module_fun); nlr_pop(); } else { - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); tt_abort_msg("Uncaught exception"); } end: diff --git a/stmhal/extint.c b/stmhal/extint.c index 4fab7c5f2c..a67af65b05 100644 --- a/stmhal/extint.c +++ b/stmhal/extint.c @@ -37,6 +37,7 @@ #include "gc.h" #include "obj.h" #include "runtime.h" +#include "pfenv.h" #include "pin.h" #include "extint.h" @@ -373,7 +374,7 @@ void Handle_EXTI_Irq(uint32_t line) { v->callback_obj = mp_const_none; extint_disable(line); printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line); - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); } gc_unlock(); } diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 36a496aa13..d62b2a373c 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -48,6 +48,7 @@ #include "pyexec.h" #include "pybstdio.h" #include "genhdr/py-version.h" +#include "pfenv.h" pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; STATIC bool repl_display_debugging_info = 0; @@ -87,7 +88,7 @@ STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_ki if (exec_flags & EXEC_FLAG_PRINT_EOF) { stdout_tx_strn("\x04", 1); } - mp_obj_print_exception(module_fun); + mp_obj_print_exception(printf_wrapper, NULL, module_fun); goto finish; } @@ -116,7 +117,7 @@ STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_ki // at the moment, the value of SystemExit is unused ret = PYEXEC_FORCED_EXIT; } else { - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); ret = 0; } } diff --git a/stmhal/timer.c b/stmhal/timer.c index 5c99d51f19..e95fb5f9ef 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -42,6 +42,7 @@ #include "timer.h" #include "servo.h" #include "pin.h" +#include "pfenv.h" /// \moduleref pyb /// \class Timer - periodically call a function @@ -1245,7 +1246,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o } else { printf("uncaught exception in Timer(%u) channel %u interrupt handler\n", tim->tim_id, channel); } - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); } gc_unlock(); } diff --git a/teensy/timer.c b/teensy/timer.c index 81450698b3..a4051e608c 100644 --- a/teensy/timer.c +++ b/teensy/timer.c @@ -35,6 +35,7 @@ #include "qstr.h" #include "obj.h" #include "runtime.h" +#include "pfenv.h" #include MICROPY_HAL_H #include "gc.h" #include "pin.h" @@ -917,7 +918,7 @@ STATIC bool ftm_handle_irq_callback(pyb_timer_obj_t *self, mp_uint_t channel, mp printf("Uncaught exception in Timer(" UINT_FMT ") channel " UINT_FMT " interrupt handler\n", self->tim_id, channel); } - mp_obj_print_exception((mp_obj_t)nlr.ret_val); + mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val); } gc_unlock(); return handled; diff --git a/unix-cpy/main.c b/unix-cpy/main.c index 03e5437c2b..81f39ed279 100644 --- a/unix-cpy/main.c +++ b/unix-cpy/main.c @@ -40,6 +40,7 @@ #include "parsehelper.h" #include "compile.h" #include "runtime.h" +#include "pfenv.h" void do_file(const char *file) { mp_lexer_t *lex = mp_lexer_new_from_file(file); @@ -80,7 +81,7 @@ void do_file(const char *file) { //printf("----------------\n"); if (mp_obj_is_exception_instance(module_fun)) { - mp_obj_print_exception(module_fun); + mp_obj_print_exception(printf_wrapper, NULL, module_fun); } } } diff --git a/unix/main.c b/unix/main.c index 6733bbddad..2a0dc864c4 100644 --- a/unix/main.c +++ b/unix/main.c @@ -53,6 +53,7 @@ #include "genhdr/py-version.h" #include "input.h" #include "stackctrl.h" +#include "pfenv.h" // Command line options, with their defaults STATIC bool compile_only = false; @@ -100,7 +101,7 @@ STATIC int handle_uncaught_exception(mp_obj_t exc) { } // Report all other exceptions - mp_obj_print_exception(exc); + mp_obj_print_exception(printf_wrapper, NULL, exc); return 1; } @@ -150,7 +151,7 @@ STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, if (mp_obj_is_exception_instance(module_fun)) { // compile error - mp_obj_print_exception(module_fun); + mp_obj_print_exception(printf_wrapper, NULL, module_fun); return 1; }