Skip to content

[3.10] bpo-44201: Avoid side effects of "invalid_*" rules in the REPL (GH-26298) #26313

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

Merged
merged 1 commit into from
May 22, 2021
Merged
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 Include/errcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extern "C" {
#define E_DECODE 22 /* Error in decoding into Unicode */
#define E_LINECONT 25 /* Unexpected characters after a line continuation */
#define E_BADSINGLE 27 /* Ill-formed single statement input */
#define E_INTERACT_STOP 28 /* Interactive mode stopped tokenization */

#ifdef __cplusplus
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Avoid side effects of checking for specialized syntax errors in the REPL
that was causing it to ask for extra tokens after a syntax error had been
detected. Patch by Pablo Galindo
3 changes: 3 additions & 0 deletions Parser/pegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,9 @@ reset_parser_state(Parser *p)
}
p->mark = 0;
p->call_invalid_rules = 1;
// Don't try to get extra tokens in interactive mode when trying to
// raise specialized errors in the second pass.
p->tok->interactive_underflow = IUNDERFLOW_STOP;
}

static int
Expand Down
9 changes: 9 additions & 0 deletions Parser/tokenizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ tok_new(void)
tok->async_def = 0;
tok->async_def_indent = 0;
tok->async_def_nl = 0;
tok->interactive_underflow = IUNDERFLOW_NORMAL;

return tok;
}
Expand Down Expand Up @@ -845,6 +846,10 @@ tok_underflow_string(struct tok_state *tok) {

static int
tok_underflow_interactive(struct tok_state *tok) {
if (tok->interactive_underflow == IUNDERFLOW_STOP) {
tok->done = E_INTERACT_STOP;
return 1;
}
char *newtok = PyOS_Readline(stdin, stdout, tok->prompt);
if (newtok != NULL) {
char *translated = translate_newlines(newtok, 0, tok);
Expand Down Expand Up @@ -1399,6 +1404,10 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end)
}
}

if (tok->done == E_INTERACT_STOP) {
return ENDMARKER;
}

/* Check for EOF and errors now */
if (c == EOF) {
if (tok->level) {
Expand Down
10 changes: 10 additions & 0 deletions Parser/tokenizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ enum decoding_state {
STATE_NORMAL
};

enum interactive_underflow_t {
/* Normal mode of operation: return a new token when asked in interactie mode */
IUNDERFLOW_NORMAL,
/* Forcefully return ENDMARKER when asked for a new token in interactive mode. This
* can be used to prevent the tokenizer to promt the user for new tokens */
IUNDERFLOW_STOP,
};

/* Tokenizer state */
struct tok_state {
/* Input state; buf <= cur <= inp <= end */
Expand Down Expand Up @@ -74,6 +82,8 @@ struct tok_state {
int async_def_indent; /* Indentation level of the outermost 'async def'. */
int async_def_nl; /* =1 if the outermost 'async def' had at least one
NEWLINE token after it. */
/* How to proceed when asked for a new token in interactive mode */
enum interactive_underflow_t interactive_underflow;
};

extern struct tok_state *PyTokenizer_FromString(const char *, int);
Expand Down