From ad27be1d974a9980dd5b71906be81429194999c5 Mon Sep 17 00:00:00 2001 From: Andrew Leech <> Date: Thu, 26 Oct 2023 09:02:16 +1100 Subject: [PATCH] unix/main: Use standard pyexec/repl for unix & windows ports. This improves repl usage consistency across ports. Only enabled when MICROPY_USE_READLINE == 1 (default). Signed-off-by: Andrew Leech --- ports/unix/Makefile | 2 + ports/unix/main.c | 97 ++++-------------------- ports/unix/mphalport.h | 6 ++ ports/windows/Makefile | 1 + ports/windows/micropython.vcxproj | 1 + shared/runtime/pyexec.c | 1 + tests/cmdline/repl_autocomplete.py.exp | 2 +- tests/cmdline/repl_autoindent.py.exp | 2 +- tests/cmdline/repl_basic.py.exp | 2 +- tests/cmdline/repl_cont.py.exp | 2 +- tests/cmdline/repl_emacs_keys.py.exp | 2 +- tests/cmdline/repl_inspect.py.exp | 2 +- tests/cmdline/repl_micropyinspect.py.exp | 2 +- tests/cmdline/repl_sys_ps1_ps2.py.exp | 2 +- tests/cmdline/repl_words_move.py.exp | 2 +- 15 files changed, 36 insertions(+), 90 deletions(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 9f5e01a5ff9b7..9a8f1d4f23fc8 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -124,8 +124,10 @@ endif ifeq ($(MICROPY_USE_READLINE),1) INC += -I$(TOP)/shared/readline +INC += -I$(TOP)/shared/runtime CFLAGS += -DMICROPY_USE_READLINE=1 SHARED_SRC_C_EXTRA += readline/readline.c +SHARED_SRC_C_EXTRA += runtime/pyexec.c endif ifeq ($(MICROPY_PY_TERMIOS),1) CFLAGS += -DMICROPY_PY_TERMIOS=1 diff --git a/ports/unix/main.c b/ports/unix/main.c index 468fc409640b3..3e4168031fc90 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -53,6 +53,7 @@ #include "extmod/vfs_posix.h" #include "genhdr/mpversion.h" #include "input.h" +#include "shared/runtime/pyexec.h" // Command line options, with their defaults STATIC bool compile_only = false; @@ -193,91 +194,27 @@ STATIC char *strjoin(const char *s1, int sep_char, const char *s2) { #endif STATIC int do_repl(void) { - mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION); - mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE); - mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); - + int ret = 0; #if MICROPY_USE_READLINE == 1 - - // use MicroPython supplied readline - - vstr_t line; - vstr_init(&line, 16); + // use MicroPython supplied readline based repl + mp_hal_stdio_mode_raw(); for (;;) { - mp_hal_stdio_mode_raw(); - - input_restart: - vstr_reset(&line); - int ret = readline(&line, mp_repl_get_ps1()); - mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; - - if (ret == CHAR_CTRL_C) { - // cancel input - mp_hal_stdout_tx_str("\r\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // EOF - printf("\n"); - mp_hal_stdio_mode_orig(); - vstr_clear(&line); - return 0; - } else if (ret == CHAR_CTRL_E) { - // paste mode - mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== "); - vstr_reset(&line); - for (;;) { - char c = mp_hal_stdin_rx_chr(); - if (c == CHAR_CTRL_C) { - // cancel everything - mp_hal_stdout_tx_str("\n"); - goto input_restart; - } else if (c == CHAR_CTRL_D) { - // end of input - mp_hal_stdout_tx_str("\n"); - break; - } else { - // add char to buffer and echo - vstr_add_byte(&line, c); - if (c == '\r') { - mp_hal_stdout_tx_str("\n=== "); - } else { - mp_hal_stdout_tx_strn(&c, 1); - } - } - } - parse_input_kind = MP_PARSE_FILE_INPUT; - } else if (line.len == 0) { - if (ret != 0) { - printf("\n"); + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if ((ret = pyexec_raw_repl()) != 0) { + break; } - goto input_restart; } else { - // got a line with non-zero length, see if it needs continuing - while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { - vstr_add_byte(&line, '\n'); - ret = readline(&line, mp_repl_get_ps2()); - if (ret == CHAR_CTRL_C) { - // cancel everything - printf("\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // stop entering compound statement - break; - } + if ((ret = pyexec_friendly_repl()) != 0) { + break; } } - - mp_hal_stdio_mode_orig(); - - ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true); - if (ret & FORCED_EXIT) { - return ret; - } } - + mp_hal_stdio_mode_orig(); #else - // use simple readline + mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION); + mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE); + mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); for (;;) { char *line = prompt((char *)mp_repl_get_ps1()); @@ -296,16 +233,14 @@ STATIC int do_repl(void) { line = line3; } - int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); + ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); free(line); - if (ret & FORCED_EXIT) { - return ret; - } } - #endif + return ret; } + STATIC int do_file(const char *file) { return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false); } diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index 724fc8af5f28f..8432fdd5b0597 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -36,6 +36,12 @@ void mp_hal_set_interrupt_char(char c); void mp_hal_stdio_mode_raw(void); void mp_hal_stdio_mode_orig(void); +// pyexec/repl needs stdio to be in raw mode, but this may be cleared before running code. +#if MICROPY_REPL_RESET_RAW_BEFORE_EXEC +#define MICROPY_BOARD_BEFORE_PYTHON_EXEC(input_kind, exec_flags) mp_hal_stdio_mode_orig() +#define MICROPY_BOARD_AFTER_PYTHON_EXEC(input_kind, exec_flags, ret_val, ret) mp_hal_stdio_mode_raw() +#endif + #if MICROPY_PY_BUILTINS_INPUT && MICROPY_USE_READLINE == 0 #include diff --git a/ports/windows/Makefile b/ports/windows/Makefile index 2215ce38d1e98..02f1d40dd0baf 100644 --- a/ports/windows/Makefile +++ b/ports/windows/Makefile @@ -76,6 +76,7 @@ OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) ifeq ($(MICROPY_USE_READLINE),1) CFLAGS += -DMICROPY_USE_READLINE=1 SRC_C += shared/readline/readline.c +SRC_C += shared/runtime/pyexec.c endif LIB += -lws2_32 diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj index d5affd9e23ba4..e09b373084a39 100644 --- a/ports/windows/micropython.vcxproj +++ b/ports/windows/micropython.vcxproj @@ -88,6 +88,7 @@ + diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 9f6d9a100206e..60376189aa042 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -41,6 +41,7 @@ #endif #include "shared/readline/readline.h" #include "shared/runtime/pyexec.h" +#include "extmod/modplatform.h" #include "genhdr/mpversion.h" pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; diff --git a/tests/cmdline/repl_autocomplete.py.exp b/tests/cmdline/repl_autocomplete.py.exp index 75002985e3c63..8cf71bb447d43 100644 --- a/tests/cmdline/repl_autocomplete.py.exp +++ b/tests/cmdline/repl_autocomplete.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # tests for autocompletion >>> import sys >>> not_exist. diff --git a/tests/cmdline/repl_autoindent.py.exp b/tests/cmdline/repl_autoindent.py.exp index 9127a7d31d903..f45bf840f092a 100644 --- a/tests/cmdline/repl_autoindent.py.exp +++ b/tests/cmdline/repl_autoindent.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # tests for autoindent >>> if 1: ... print(1) diff --git a/tests/cmdline/repl_basic.py.exp b/tests/cmdline/repl_basic.py.exp index 2b390ea98bb75..a190684743285 100644 --- a/tests/cmdline/repl_basic.py.exp +++ b/tests/cmdline/repl_basic.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # basic REPL tests >>> print(1) 1 diff --git a/tests/cmdline/repl_cont.py.exp b/tests/cmdline/repl_cont.py.exp index 834c18a4d3699..d0d20adc49617 100644 --- a/tests/cmdline/repl_cont.py.exp +++ b/tests/cmdline/repl_cont.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # check REPL allows to continue input >>> 1 \\\\ ... + 2 diff --git a/tests/cmdline/repl_emacs_keys.py.exp b/tests/cmdline/repl_emacs_keys.py.exp index 6102c19639a8a..b8b7b794f2d7c 100644 --- a/tests/cmdline/repl_emacs_keys.py.exp +++ b/tests/cmdline/repl_emacs_keys.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # REPL tests of GNU-ish readline navigation >>> # history buffer navigation >>> 1 diff --git a/tests/cmdline/repl_inspect.py.exp b/tests/cmdline/repl_inspect.py.exp index 051acfd153a61..89ae142019b8e 100644 --- a/tests/cmdline/repl_inspect.py.exp +++ b/tests/cmdline/repl_inspect.py.exp @@ -1,6 +1,6 @@ test MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # cmdline: -i -c print("test") >>> # -c option combined with -i option results in REPL >>> diff --git a/tests/cmdline/repl_micropyinspect.py.exp b/tests/cmdline/repl_micropyinspect.py.exp index 93ff43546eace..504bb07d7d45e 100644 --- a/tests/cmdline/repl_micropyinspect.py.exp +++ b/tests/cmdline/repl_micropyinspect.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # cmdline: cmdline/repl_micropyinspect >>> # setting MICROPYINSPECT environment variable before program exit triggers REPL >>> diff --git a/tests/cmdline/repl_sys_ps1_ps2.py.exp b/tests/cmdline/repl_sys_ps1_ps2.py.exp index 9e82db5e313e4..6781660bf337d 100644 --- a/tests/cmdline/repl_sys_ps1_ps2.py.exp +++ b/tests/cmdline/repl_sys_ps1_ps2.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # test changing ps1/ps2 >>> import sys >>> sys.ps1 = "PS1" diff --git a/tests/cmdline/repl_words_move.py.exp b/tests/cmdline/repl_words_move.py.exp index 86f6b7788989e..c4d22a0d9a7fc 100644 --- a/tests/cmdline/repl_words_move.py.exp +++ b/tests/cmdline/repl_words_move.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # word movement >>> # backward-word, start in word >>> \.\+