Skip to content
Snippets Groups Projects
Commit 97790455 authored by Damien George's avatar Damien George
Browse files

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.
parent 72d70cb0
Branches
No related tags found
No related merge requests found
...@@ -14,43 +14,66 @@ bool str_startswith_word(const char *str, const char *head) { ...@@ -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])); return head[i] == '\0' && (str[i] == '\0' || !unichar_isalpha(str[i]));
} }
bool mp_repl_is_compound_stmt(const char *line) { bool mp_repl_continue_with_input(const char *input) {
// compound if line starts with a certain keyword // check for blank input
if ( if (input[0] == '\0') {
str_startswith_word(line, "if") return false;
|| 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;
} }
// 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_paren = 0;
int n_brack = 0; int n_brack = 0;
int n_brace = 0; int n_brace = 0;
int in_triple_quote = 0; int in_triple_quote = 0;
for (const char *l = line; *l; l++) { const char *i;
switch (*l) { for (i = input; *i; i++) {
switch (*i) {
case '(': n_paren += 1; break; case '(': n_paren += 1; break;
case ')': n_paren -= 1; break; case ')': n_paren -= 1; break;
case '[': n_brack += 1; break; case '[': n_brack += 1; break;
case ']': n_brack -= 1; break; case ']': n_brack -= 1; break;
case '{': n_brace += 1; break; case '{': n_brace += 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 '"': case '"':
if (l[1] == '"' && l[2] == '"') { if (in_triple_quote != '\'' && i[1] == '"' && i[2] == '"') {
l += 2; i += 2;
in_triple_quote = 1 - in_triple_quote; in_triple_quote = '"' - in_triple_quote;
} }
break; 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 #endif // MICROPY_ENABLE_REPL_HELPERS
#if MICROPY_ENABLE_REPL_HELPERS #if MICROPY_ENABLE_REPL_HELPERS
bool mp_repl_is_compound_stmt(const char *line); bool mp_repl_continue_with_input(const char *input);
#endif #endif
...@@ -283,17 +283,14 @@ void pyexec_repl(void) { ...@@ -283,17 +283,14 @@ void pyexec_repl(void) {
continue; continue;
} }
if (mp_repl_is_compound_stmt(vstr_str(&line))) { while (mp_repl_continue_with_input(vstr_str(&line))) {
for (;;) {
vstr_add_char(&line, '\n'); vstr_add_char(&line, '\n');
int len = vstr_len(&line);
int ret = readline(&line, "... "); int ret = readline(&line, "... ");
if (ret == VCP_CHAR_CTRL_D || vstr_len(&line) == len) { if (ret == VCP_CHAR_CTRL_D) {
// done entering compound statement // stop entering compound statement
break; break;
} }
} }
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true); parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true);
......
...@@ -204,17 +204,14 @@ friendly_repl_reset: ...@@ -204,17 +204,14 @@ friendly_repl_reset:
continue; continue;
} }
if (mp_repl_is_compound_stmt(vstr_str(&line))) { while (mp_repl_continue_with_input(vstr_str(&line))) {
for (;;) {
vstr_add_char(&line, '\n'); vstr_add_char(&line, '\n');
int len = vstr_len(&line);
int ret = readline(&line, "... "); int ret = readline(&line, "... ");
if (ret == VCP_CHAR_CTRL_D || vstr_len(&line) == len) { if (ret == VCP_CHAR_CTRL_D) {
// done entering compound statement // stop entering compound statement
break; break;
} }
} }
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true); parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true);
......
...@@ -399,17 +399,14 @@ void do_repl(void) { ...@@ -399,17 +399,14 @@ void do_repl(void) {
continue; continue;
} }
if (mp_repl_is_compound_stmt(vstr_str(&line))) { while (mp_repl_continue_with_input(vstr_str(&line))) {
for (;;) {
vstr_add_char(&line, '\n'); vstr_add_char(&line, '\n');
int len = vstr_len(&line);
int ret = readline(&line, "... "); int ret = readline(&line, "... ");
if (ret == 0 || vstr_len(&line) == len) { if (ret == 0) {
// done entering compound statement // stop entering compound statement
break; break;
} }
} }
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
mp_parse_error_kind_t parse_error_kind; mp_parse_error_kind_t parse_error_kind;
......
...@@ -146,10 +146,9 @@ STATIC void do_repl(void) { ...@@ -146,10 +146,9 @@ STATIC void do_repl(void) {
// EOF // EOF
return; return;
} }
if (mp_repl_is_compound_stmt(line)) { while (mp_repl_continue_with_input(line)) {
for (;;) {
char *line2 = prompt("... "); char *line2 = prompt("... ");
if (line2 == NULL || strlen(line2) == 0) { if (line2 == NULL) {
break; break;
} }
char *line3 = strjoin(line, '\n', line2); char *line3 = strjoin(line, '\n', line2);
...@@ -157,7 +156,6 @@ STATIC void do_repl(void) { ...@@ -157,7 +156,6 @@ STATIC void do_repl(void) {
free(line2); free(line2);
line = line3; line = line3;
} }
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true); execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true);
......
...@@ -126,10 +126,9 @@ static void do_repl(void) { ...@@ -126,10 +126,9 @@ static void do_repl(void) {
// EOF // EOF
return; return;
} }
if (mp_repl_is_compound_stmt(line)) { while (mp_repl_continue_with_input(line)) {
for (;;) {
char *line2 = prompt("... "); char *line2 = prompt("... ");
if (line2 == NULL || strlen(line2) == 0) { if (line2 == NULL) {
break; break;
} }
char *line3 = str_join(line, '\n', line2); char *line3 = str_join(line, '\n', line2);
...@@ -137,7 +136,6 @@ static void do_repl(void) { ...@@ -137,7 +136,6 @@ static void do_repl(void) {
free(line2); free(line2);
line = line3; line = line3;
} }
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true); execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment