Skip to content

unix/main: Use standard pyexec/repl for unix port. #12802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# These should also not be modified by git.
tests/basics/string_cr_conversion.py -text
tests/basics/string_crlf_conversion.py -text
tests/micropython/test_normalize_newlines.py.exp -text
ports/stm32/pybcdc.inf_template -text
ports/stm32/usbhost/** -text
ports/cc3200/hal/aes.c -text
Expand Down
1 change: 1 addition & 0 deletions ports/unix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ SRC_C += \

SHARED_SRC_C += $(addprefix shared/,\
runtime/gchelper_generic.c \
runtime/pyexec.c \
timeutils/timeutils.c \
$(SHARED_SRC_C_EXTRA) \
)
Expand Down
132 changes: 41 additions & 91 deletions ports/unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@
#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;
bool mp_compile_only = false;
static uint emit_opt = MP_EMIT_OPT_NONE;

#if MICROPY_ENABLE_GC
Expand Down Expand Up @@ -109,8 +110,6 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) {
}

#define LEX_SRC_STR (1)
#define LEX_SRC_VSTR (2)
#define LEX_SRC_FILENAME (3)
#define LEX_SRC_STDIN (4)

// Returns standard error codes: 0 for success, 1 for all other errors,
Expand All @@ -126,12 +125,6 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
if (source_kind == LEX_SRC_STR) {
const char *line = source;
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
} else if (source_kind == LEX_SRC_VSTR) {
const vstr_t *vstr = source;
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false);
} else if (source_kind == LEX_SRC_FILENAME) {
const char *filename = (const char *)source;
lex = mp_lexer_new_from_file(qstr_from_str(filename));
} else { // LEX_SRC_STDIN
lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false);
}
Expand All @@ -157,7 +150,7 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu

mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl);

if (!compile_only) {
if (!mp_compile_only) {
// execute it
mp_call_function_0(module_fun);
}
Expand Down Expand Up @@ -194,91 +187,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 @@ -297,22 +226,43 @@ 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);
int ret = pyexec_file(file);
// pyexec returns 1 for success, 0 for exception, PYEXEC_FORCED_EXIT for SystemExit
// Convert to unix port's expected codes: 0 for success, 1 for exception, FORCED_EXIT|val for SystemExit
if (ret == 1) {
return 0; // success
} else if (ret & PYEXEC_FORCED_EXIT) {
return ret; // SystemExit with exit value in lower 8 bits
} else {
return 1; // exception
}
}

static int do_str(const char *str) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be possible to replace the execute_from_lexer() below with pyexec_vstr() (just make a temporary vstr on the C stack and populate it with str and strlen(str)).

Might be worth doing that as part of this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute_from_lexer is also still used for a couple of other things. I've trimmed it down a bit to remove now-unused functionality but would it be better refactored into a couple of new pyexec_str_single() and pyexec_stdin() functions in pyexec just to consolidate the location of all this sort of code? These functions are only needed on desktop really so would probably want extra #defines around them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but would it be better refactored into a couple of new pyexec_str_single() and pyexec_stdin() functions in pyexec just to consolidate the location of all this sort of code?

Yes, I think we should do that and get rid of execute_from_lexer. I was going to do that in a follow-up PR, but if you want to do it here, feel free.

These functions are only needed on desktop really so would probably want extra #defines around them.

Yes.

return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false);
vstr_t vstr;
vstr_init(&vstr, strlen(str));
vstr_add_strn(&vstr, str, strlen(str));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allocates RAM unnecessarily. I suggest using vstr_init_fixed_buf().

int ret = pyexec_vstr(&vstr, false);
vstr_clear(&vstr);
if (ret == 1) {
return 0; // success
} else if (ret & PYEXEC_FORCED_EXIT) {
return ret; // SystemExit with exit value in lower 8 bits
} else {
return 1; // exception
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should be factored/shared with do_file().

}

static void print_help(char **argv) {
Expand Down Expand Up @@ -381,7 +331,7 @@ static void pre_process_options(int argc, char **argv) {
}
if (0) {
} else if (strcmp(argv[a + 1], "compile-only") == 0) {
compile_only = true;
mp_compile_only = true;
} else if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
emit_opt = MP_EMIT_OPT_BYTECODE;
#if MICROPY_EMIT_NATIVE
Expand Down
3 changes: 3 additions & 0 deletions ports/unix/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ typedef long mp_off_t;
// Enable sys.executable.
#define MICROPY_PY_SYS_EXECUTABLE (1)

// Enable support for compile-only mode.
#define MICROPY_PYEXEC_COMPILE_ONLY (1)

#define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)

// Bare-metal ports don't have stderr. Printing debug to stderr may give tests
Expand Down
4 changes: 4 additions & 0 deletions ports/unix/mphalport.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
#include <errno.h>
#include <unistd.h>
#include <stdbool.h>

#ifndef CHAR_CTRL_C
#define CHAR_CTRL_C (3)
Expand Down Expand Up @@ -112,3 +113,6 @@ enum {

void mp_hal_get_mac(int idx, uint8_t buf[6]);
#endif

// Global variable to control compile-only mode.
extern bool mp_compile_only;
1 change: 1 addition & 0 deletions ports/windows/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,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
3 changes: 3 additions & 0 deletions ports/windows/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@
#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr
#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr

// Enable support for compile-only mode.
#define MICROPY_PYEXEC_COMPILE_ONLY (1)

#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
#define MICROPY_ERROR_PRINTER (&mp_stderr_print)
#define MICROPY_WARNINGS (1)
Expand Down
9 changes: 8 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ target-version = "py37"

[tool.ruff.lint]
exclude = [ # Ruff finds Python SyntaxError in these files
"tests/cmdline/cmd_compile_only_error.py",
"tests/cmdline/repl_autocomplete.py",
"tests/cmdline/repl_autocomplete_underscore.py",
"tests/cmdline/repl_autoindent.py",
Expand Down Expand Up @@ -67,5 +68,11 @@ mccabe.max-complexity = 40
# basics: needs careful attention before applying automatic formatting
# repl_: not real python files
# viper_args: uses f(*)
exclude = ["tests/basics/*.py", "tests/*/repl_*.py", "tests/micropython/viper_args.py"]
exclude = [
"tests/basics/*.py",
"tests/*/repl_*.py",
"tests/cmdline/cmd_compile_only_error.py",
"tests/micropython/test_normalize_newlines.py",
"tests/micropython/viper_args.py",
]
quote-style = "preserve"
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy