Skip to content

Commit

Permalink
unix/main: Use standard pyexec/repl for unix & windows ports.
Browse files Browse the repository at this point in the history
This improves repl usage consistency across ports.
Only enabled when MICROPY_USE_READLINE == 1 (default).

Signed-off-by: Andrew Leech <[email protected]>
  • Loading branch information
andrewleech authored and pi-anl committed Jul 9, 2024
1 parent 4365732 commit 03e992d
Show file tree
Hide file tree
Showing 19 changed files with 42 additions and 110 deletions.
1 change: 0 additions & 1 deletion extmod/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args);
#endif

static mp_obj_t machine_soft_reset(void) {
pyexec_system_exit = PYEXEC_FORCED_EXIT;
mp_raise_type(&mp_type_SystemExit);
}
static MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset);
Expand Down
3 changes: 0 additions & 3 deletions ports/qemu-arm/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@
// This file is never compiled standalone, it's included directly from
// extmod/modmachine.c via MICROPY_PY_MACHINE_INCLUDEFILE.

// This variable is needed for machine.soft_reset(), but the variable is otherwise unused.
int pyexec_system_exit = 0;

static void mp_machine_idle(void) {
// Do nothing.
}
2 changes: 2 additions & 0 deletions ports/unix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
97 changes: 16 additions & 81 deletions ports/unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand All @@ -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);
}
Expand Down
3 changes: 0 additions & 3 deletions ports/unix/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@
#define MICROPY_PAGE_MASK (MICROPY_PAGE_SIZE - 1)
#endif

// This variable is needed for machine.soft_reset(), but the variable is otherwise unused.
int pyexec_system_exit = 0;

uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) {
uintptr_t addr = mp_obj_get_int_truncated(addr_o);
if ((addr & (align - 1)) != 0) {
Expand Down
6 changes: 6 additions & 0 deletions ports/unix/mphalport.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,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 <malloc.h>
Expand Down
1 change: 1 addition & 0 deletions ports/windows/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,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
Expand Down
1 change: 1 addition & 0 deletions ports/windows/micropython.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<ClCompile Include="@(PyExtModSource)" />
<ClCompile Include="$(PyBaseDir)shared\readline\*.c" />
<ClCompile Include="$(PyBaseDir)shared\runtime\gchelper_generic.c" />
<ClCompile Include="$(PyBaseDir)shared\runtime\pyexec.c" />
<ClCompile Include="$(PyBaseDir)ports\windows\*.c" />
<ClCompile Include="$(PyBaseDir)ports\windows\msvc\*.c" />
<ClCompile Include="$(PyBaseDir)ports\unix\gccollect.c"/>
Expand Down
15 changes: 7 additions & 8 deletions shared/runtime/pyexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
#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;
int pyexec_system_exit = 0;

#if MICROPY_REPL_INFO
static bool repl_display_debugging_info = 0;
Expand All @@ -65,7 +65,7 @@ static bool repl_display_debugging_info = 0;
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
static int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, mp_uint_t exec_flags) {
int ret = 0;
mp_int_t ret = 0;
#if MICROPY_REPL_INFO
uint32_t start = 0;
#endif
Expand All @@ -74,9 +74,6 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
MICROPY_BOARD_BEFORE_PYTHON_EXEC(input_kind, exec_flags);
#endif

// by default a SystemExit exception returns 0
pyexec_system_exit = 0;

nlr_buf_t nlr;
nlr.ret_val = NULL;
if (nlr_push(&nlr) == 0) {
Expand Down Expand Up @@ -144,9 +141,11 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
}

// check for SystemExit
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
// at the moment, the value of SystemExit is unused
ret = pyexec_system_exit;
mp_obj_base_t *exc = nlr.ret_val;
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
mp_obj_t v = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc));
mp_obj_get_int_maybe(v, &ret); // get errno value
ret |= PYEXEC_FORCED_EXIT;
} else {
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
ret = 0;
Expand Down
5 changes: 0 additions & 5 deletions shared/runtime/pyexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ typedef enum {

extern pyexec_mode_kind_t pyexec_mode_kind;

// Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through
// the pyexec functions if a SystemExit exception is raised by the running code.
// It will reset to 0 at the start of each execution (eg each REPL entry).
extern int pyexec_system_exit;

#define PYEXEC_FORCED_EXIT (0x100)

int pyexec_raw_repl(void);
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_autocomplete.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # tests for autocompletion
>>> import sys
>>> not_exist.
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_autoindent.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # tests for autoindent
>>> if 1:
... print(1)
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_basic.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # basic REPL tests
>>> print(1)
1
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_cont.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # check REPL allows to continue input
>>> 1 \\\\
... + 2
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_emacs_keys.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # REPL tests of GNU-ish readline navigation
>>> # history buffer navigation
>>> 1
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_inspect.py.exp
Original file line number Diff line number Diff line change
@@ -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
>>>
2 changes: 1 addition & 1 deletion tests/cmdline/repl_micropyinspect.py.exp
Original file line number Diff line number Diff line change
@@ -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
>>>
2 changes: 1 addition & 1 deletion tests/cmdline/repl_sys_ps1_ps2.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # test changing ps1/ps2
>>> import sys
>>> sys.ps1 = "PS1"
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_words_move.py.exp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MicroPython \.\+ version
Use \.\+
Type "help()" for more information.
>>> # word movement
>>> # backward-word, start in word
>>> \.\+
Expand Down

0 comments on commit 03e992d

Please sign in to comment.