Skip to content

Commit abb1d45

Browse files
committed
gh-153569: move tokenizer input state and relocation into the reader
1 parent 7bfa97f commit abb1d45

10 files changed

Lines changed: 89 additions & 124 deletions

File tree

Lib/test/test_repl.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,8 @@ def read_until(marker, start=0):
184184

185185
@cpython_only
186186
def test_lexer_buffer_realloc_with_null_start(self):
187-
# gh-144759: NULL pointer arithmetic in the lexer when start and
188-
# multi_line_start are NULL (uninitialized in tok_mode_stack[0])
189-
# and the lexer buffer is reallocated while parsing long input.
187+
# gh-144759: NULL pointer arithmetic when the lexer buffer grows
188+
# while parsing long input.
190189
long_value = "a" * 2000
191190
user_input = dedent(f"""\
192191
x = f'{{{long_value!r}}}'

Parser/lexer/lexer.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,16 @@ _PyLexer_get_normal(struct tok_state *tok, ftstring_state *current, struct token
197197
}
198198
tok_backup(tok, c);
199199
if (c == '#' || c == '\n' || c == '\r') {
200+
int interactive = _PyTok_ReaderIsInteractive(tok);
200201
/* Lines with only whitespace and/or comments
201202
shouldn't affect the indentation and are
202203
not passed to the parser as NEWLINE tokens,
203204
except *totally* empty lines in interactive
204205
mode, which signal the end of a command group. */
205-
if (col == 0 && c == '\n' && tok->prompt != NULL) {
206+
if (col == 0 && c == '\n' && interactive) {
206207
blankline = 0; /* Let it through */
207208
}
208-
else if (tok->prompt != NULL && tok->lineno == 1) {
209+
else if (interactive && tok->lineno == 1) {
209210
/* In interactive mode, if the first line contains
210211
only spaces and/or a comment, let it through. */
211212
blankline = 0;

Parser/lexer/state.c

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,11 @@
11
#include "Python.h"
2-
#include "pycore_pystate.h"
32
#include "pycore_token.h"
43
#include "errcode.h"
54

65
#include "state.h"
76
#include "../tokenizer/helpers.h"
87
#include "../tokenizer/reader.h"
98

10-
/* Create and initialize a new tok_state structure */
11-
struct tok_state *
12-
_PyTokenizer_tok_new(void)
13-
{
14-
struct tok_state *tok = (struct tok_state *)PyMem_Calloc(
15-
1,
16-
sizeof(struct tok_state));
17-
if (tok == NULL) {
18-
PyErr_NoMemory();
19-
return NULL;
20-
}
21-
22-
tok->cur = tok->inp = 0;
23-
tok->line_start = -1;
24-
tok->fp_interactive = 0;
25-
tok->interactive_src_start = NULL;
26-
tok->interactive_src_end = NULL;
27-
tok->start = -1;
28-
tok->done = E_OK;
29-
tok->fp = NULL;
30-
tok->indent = 0;
31-
tok->indstack[0] = 0;
32-
tok->atbol = 1;
33-
tok->pendin = 0;
34-
tok->prompt = NULL;
35-
tok->lineno = 0;
36-
tok->start_loc = (_PyTok_Loc){-1, -1};
37-
tok->level = 0;
38-
tok->altindstack[0] = 0;
39-
tok->encoding = NULL;
40-
tok->filename = NULL;
41-
tok->module = NULL;
42-
tok->type_comments = 0;
43-
tok->interactive_underflow = IUNDERFLOW_NORMAL;
44-
tok->str = NULL;
45-
tok->report_warnings = 1;
46-
tok->tok_extra_tokens = 0;
47-
tok->comment_newline = 0;
48-
tok->implicit_newline = 0;
49-
_PyTok_SourceInit(&tok->source);
50-
tok->reader = NULL;
51-
tok->ftstring_stack = tok->ftstring_stack_inline;
52-
tok->ftstring_capacity = FTSTRING_STACK_INLINE_CAPACITY;
53-
#ifdef Py_DEBUG
54-
tok->debug = _Py_GetConfig()->parser_debug;
55-
#endif
56-
return tok;
57-
}
58-
599
ftstring_state *
6010
_PyLexer_PushFTString(struct tok_state *tok)
6111
{

Parser/lexer/state.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@
1010
#define MAXFTSTRINGLEVEL 150
1111
#define FTSTRING_STACK_INLINE_CAPACITY 1
1212

13-
enum interactive_underflow_t {
14-
/* Normal mode of operation: return a new token when asked in interactive mode */
15-
IUNDERFLOW_NORMAL,
16-
/* Forcefully return ENDMARKER when asked for a new token in interactive mode. This
17-
* can be used to prevent the tokenizer to prompt the user for new tokens */
18-
IUNDERFLOW_STOP,
19-
};
2013

2114

2215
typedef enum {
@@ -74,17 +67,13 @@ struct tok_state {
7467
_PyTok_Off start;
7568
_PyTok_Off line_start;
7669
_PyTok_SourceText source;
77-
int fp_interactive; /* If the file descriptor is interactive */
78-
char *interactive_src_start; /* The start of the source parsed so far in interactive mode */
79-
char *interactive_src_end; /* The end of the source parsed so far in interactive mode */
8070
int done; /* E_OK normally, E_EOF at EOF, otherwise error code */
8171
/* NB If done != E_OK, cur must be == inp!!! */
8272
FILE *fp; /* Rest of input; NULL if tokenizing a string */
8373
int indent; /* Current indentation index */
8474
int indstack[MAXINDENT]; /* Stack of indents */
8575
int atbol; /* Nonzero if at begin of new line */
8676
int pendin; /* Pending indents (if > 0) or dedents (if < 0) */
87-
const char *prompt; /* For interactive prompting */
8877
int lineno; /* Current line number */
8978
_PyTok_Loc start_loc;
9079
int level; /* () [] {} Parentheses nesting level */
@@ -98,15 +87,11 @@ struct tok_state {
9887
int altindstack[MAXINDENT]; /* Stack of alternate indents */
9988
/* Stuff for PEP 0263 */
10089
char *encoding; /* Source encoding. */
101-
char* str; /* Source string being tokenized (if tokenizing from a string)*/
10290

10391
struct _PyTok_Reader *reader;
10492

10593
int type_comments; /* Whether to look for type comments */
10694

107-
/* How to proceed when asked for a new token in interactive mode */
108-
enum interactive_underflow_t interactive_underflow;
109-
int report_warnings;
11095
ftstring_state *ftstring_stack;
11196
ftstring_state ftstring_stack_inline[FTSTRING_STACK_INLINE_CAPACITY];
11297
int ftstring_depth;
@@ -182,7 +167,6 @@ _PyLexer_ByteColumn(const struct tok_state *tok)
182167

183168
int _PyLexer_token_setup(struct tok_state *tok, struct token *token, int type, _PyTok_Off start, _PyTok_Off end);
184169

185-
struct tok_state *_PyTokenizer_tok_new(void);
186170
void _PyTokenizer_Free(struct tok_state *);
187171
ftstring_state *_PyLexer_PushFTString(struct tok_state *);
188172
void _PyLexer_PopFTString(struct tok_state *);

Parser/tokenizer/api.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,11 @@ _PyTokenizer_HasTrailingStatement(const struct tok_state *tok)
160160
int
161161
_PyTokenizer_IsInteractive(const struct tok_state *tok)
162162
{
163-
return tok->prompt != NULL;
163+
return _PyTok_ReaderIsInteractive(tok);
164164
}
165165

166166
void
167167
_PyTokenizer_StopInteractive(struct tok_state *tok)
168168
{
169-
tok->interactive_underflow = IUNDERFLOW_STOP;
169+
_PyTok_ReaderStopInteractive(tok);
170170
}

Parser/tokenizer/decoder.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ _PyTok_NormalizeNewlines(const char *data, Py_ssize_t len, int preserve_crlf,
103103
}
104104
result[write] = '\0';
105105
*out_len = write;
106-
*implicit_newline = implicit;
106+
if (implicit_newline != NULL) {
107+
*implicit_newline = implicit;
108+
}
107109
return result;
108110
}
109111

@@ -390,10 +392,9 @@ _PyTok_PrepareString(struct tok_state *tok, const char *input, int utf8_only,
390392
if (stored < 0) {
391393
return -1;
392394
}
393-
tok->str = tok->source.bytes != NULL ? tok->source.bytes : (char *)"";
394395
if (!utf8_only &&
395396
(tok->encoding == NULL || strcmp(tok->encoding, "utf-8") == 0) &&
396-
!_PyTokenizer_ensure_utf8(tok->str, tok, 1)) {
397+
!_PyTokenizer_ensure_utf8(_PyTok_SourceData(&tok->source), tok, 1)) {
397398
return -1;
398399
}
399400
return 0;

Parser/tokenizer/helpers.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,6 @@ _PyTokenizer_indenterror(struct tok_state *tok)
137137
int
138138
_PyTokenizer_warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char)
139139
{
140-
if (!tok->report_warnings) {
141-
return 0;
142-
}
143-
144140
PyObject *msg = PyUnicode_FromFormat(
145141
"\"\\%c\" is an invalid escape sequence. "
146142
"Such sequences will not work in the future. "
@@ -226,10 +222,6 @@ _PyTokenizer_raise_init_error(PyObject *filename)
226222
int
227223
_PyTokenizer_parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...)
228224
{
229-
if (!tok->report_warnings) {
230-
return 0;
231-
}
232-
233225
PyObject *errmsg;
234226
va_list vargs;
235227
va_start(vargs, format);

0 commit comments

Comments
 (0)