Improve REPL detecting when input needs to continue.
Full CPython compatibility with this requires actually parsing the input so far collected, and if it fails parsing due to lack of tokens, then continue collecting input. It's not worth doing it this way. Not having compatibility at this level does not hurt the goals of Micro Python.
This commit is contained in:
parent
72d70cb045
commit
97790455fe
63
py/repl.c
63
py/repl.c
|
@ -14,43 +14,66 @@ bool str_startswith_word(const char *str, const char *head) {
|
|||
return head[i] == '\0' && (str[i] == '\0' || !unichar_isalpha(str[i]));
|
||||
}
|
||||
|
||||
bool mp_repl_is_compound_stmt(const char *line) {
|
||||
// compound if line starts with a certain keyword
|
||||
if (
|
||||
str_startswith_word(line, "if")
|
||||
|| str_startswith_word(line, "while")
|
||||
|| str_startswith_word(line, "for")
|
||||
|| str_startswith_word(line, "try")
|
||||
|| str_startswith_word(line, "with")
|
||||
|| str_startswith_word(line, "def")
|
||||
|| str_startswith_word(line, "class")
|
||||
|| str_startswith_word(line, "@")
|
||||
) {
|
||||
return true;
|
||||
bool mp_repl_continue_with_input(const char *input) {
|
||||
// check for blank input
|
||||
if (input[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// also "compound" if unmatched open bracket or triple quote
|
||||
// check if input starts with a certain keyword
|
||||
bool starts_with_compound_keyword =
|
||||
input[0] == '@'
|
||||
|| str_startswith_word(input, "if")
|
||||
|| str_startswith_word(input, "while")
|
||||
|| str_startswith_word(input, "for")
|
||||
|| str_startswith_word(input, "try")
|
||||
|| str_startswith_word(input, "with")
|
||||
|| str_startswith_word(input, "def")
|
||||
|| str_startswith_word(input, "class")
|
||||
;
|
||||
|
||||
// check for unmatched open bracket or triple quote
|
||||
// TODO don't look at triple quotes inside single quotes
|
||||
int n_paren = 0;
|
||||
int n_brack = 0;
|
||||
int n_brace = 0;
|
||||
int in_triple_quote = 0;
|
||||
for (const char *l = line; *l; l++) {
|
||||
switch (*l) {
|
||||
const char *i;
|
||||
for (i = input; *i; i++) {
|
||||
switch (*i) {
|
||||
case '(': n_paren += 1; break;
|
||||
case ')': n_paren -= 1; break;
|
||||
case '[': n_brack += 1; break;
|
||||
case ']': n_brack -= 1; break;
|
||||
case '{': n_brace += 1; break;
|
||||
case '}': n_brace -= 1; break;
|
||||
case '\'':
|
||||
if (in_triple_quote != '"' && i[1] == '\'' && i[2] == '\'') {
|
||||
i += 2;
|
||||
in_triple_quote = '\'' - in_triple_quote;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (l[1] == '"' && l[2] == '"') {
|
||||
l += 2;
|
||||
in_triple_quote = 1 - in_triple_quote;
|
||||
if (in_triple_quote != '\'' && i[1] == '"' && i[2] == '"') {
|
||||
i += 2;
|
||||
in_triple_quote = '"' - in_triple_quote;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n_paren > 0 || n_brack > 0 || n_brace > 0 || in_triple_quote != 0;
|
||||
|
||||
// continue if unmatched brackets or quotes
|
||||
if (n_paren > 0 || n_brack > 0 || n_brace > 0 || in_triple_quote != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// continue if compound keyword and last line was not empty
|
||||
if (starts_with_compound_keyword && i[-1] != '\n') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise, don't continue
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_REPL_HELPERS
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#if MICROPY_ENABLE_REPL_HELPERS
|
||||
bool mp_repl_is_compound_stmt(const char *line);
|
||||
bool mp_repl_continue_with_input(const char *input);
|
||||
#endif
|
||||
|
|
15
stm/pyexec.c
15
stm/pyexec.c
|
@ -283,15 +283,12 @@ void pyexec_repl(void) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mp_repl_is_compound_stmt(vstr_str(&line))) {
|
||||
for (;;) {
|
||||
vstr_add_char(&line, '\n');
|
||||
int len = vstr_len(&line);
|
||||
int ret = readline(&line, "... ");
|
||||
if (ret == VCP_CHAR_CTRL_D || vstr_len(&line) == len) {
|
||||
// done entering compound statement
|
||||
break;
|
||||
}
|
||||
while (mp_repl_continue_with_input(vstr_str(&line))) {
|
||||
vstr_add_char(&line, '\n');
|
||||
int ret = readline(&line, "... ");
|
||||
if (ret == VCP_CHAR_CTRL_D) {
|
||||
// stop entering compound statement
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,15 +204,12 @@ friendly_repl_reset:
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mp_repl_is_compound_stmt(vstr_str(&line))) {
|
||||
for (;;) {
|
||||
vstr_add_char(&line, '\n');
|
||||
int len = vstr_len(&line);
|
||||
int ret = readline(&line, "... ");
|
||||
if (ret == VCP_CHAR_CTRL_D || vstr_len(&line) == len) {
|
||||
// done entering compound statement
|
||||
break;
|
||||
}
|
||||
while (mp_repl_continue_with_input(vstr_str(&line))) {
|
||||
vstr_add_char(&line, '\n');
|
||||
int ret = readline(&line, "... ");
|
||||
if (ret == VCP_CHAR_CTRL_D) {
|
||||
// stop entering compound statement
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -399,15 +399,12 @@ void do_repl(void) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mp_repl_is_compound_stmt(vstr_str(&line))) {
|
||||
for (;;) {
|
||||
vstr_add_char(&line, '\n');
|
||||
int len = vstr_len(&line);
|
||||
int ret = readline(&line, "... ");
|
||||
if (ret == 0 || vstr_len(&line) == len) {
|
||||
// done entering compound statement
|
||||
break;
|
||||
}
|
||||
while (mp_repl_continue_with_input(vstr_str(&line))) {
|
||||
vstr_add_char(&line, '\n');
|
||||
int ret = readline(&line, "... ");
|
||||
if (ret == 0) {
|
||||
// stop entering compound statement
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
18
unix/main.c
18
unix/main.c
|
@ -146,17 +146,15 @@ STATIC void do_repl(void) {
|
|||
// EOF
|
||||
return;
|
||||
}
|
||||
if (mp_repl_is_compound_stmt(line)) {
|
||||
for (;;) {
|
||||
char *line2 = prompt("... ");
|
||||
if (line2 == NULL || strlen(line2) == 0) {
|
||||
break;
|
||||
}
|
||||
char *line3 = strjoin(line, '\n', line2);
|
||||
free(line);
|
||||
free(line2);
|
||||
line = line3;
|
||||
while (mp_repl_continue_with_input(line)) {
|
||||
char *line2 = prompt("... ");
|
||||
if (line2 == NULL) {
|
||||
break;
|
||||
}
|
||||
char *line3 = strjoin(line, '\n', line2);
|
||||
free(line);
|
||||
free(line2);
|
||||
line = line3;
|
||||
}
|
||||
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
|
||||
|
|
|
@ -126,17 +126,15 @@ static void do_repl(void) {
|
|||
// EOF
|
||||
return;
|
||||
}
|
||||
if (mp_repl_is_compound_stmt(line)) {
|
||||
for (;;) {
|
||||
char *line2 = prompt("... ");
|
||||
if (line2 == NULL || strlen(line2) == 0) {
|
||||
break;
|
||||
}
|
||||
char *line3 = str_join(line, '\n', line2);
|
||||
free(line);
|
||||
free(line2);
|
||||
line = line3;
|
||||
while (mp_repl_continue_with_input(line)) {
|
||||
char *line2 = prompt("... ");
|
||||
if (line2 == NULL) {
|
||||
break;
|
||||
}
|
||||
char *line3 = str_join(line, '\n', line2);
|
||||
free(line);
|
||||
free(line2);
|
||||
line = line3;
|
||||
}
|
||||
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
|
||||
|
|
Loading…
Reference in New Issue