Skip to content

Commit 6f220e4

Browse files
committed
gh-153569: include token types in tokenizer results
1 parent c9086df commit 6f220e4

7 files changed

Lines changed: 36 additions & 28 deletions

File tree

Parser/lexer/lexer.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,9 +511,10 @@ _PyLexer_get_normal(struct tok_state *tok, ftstring_state *current, struct token
511511
}
512512

513513

514-
int
514+
void
515515
_PyTokenizer_Get(struct tok_state *tok, struct token *token)
516516
{
517+
_PyToken_Free(token);
517518
ftstring_state *current = _PyLexer_CurrentFTString(tok);
518519
int result;
519520
if (current == NULL) {
@@ -535,5 +536,5 @@ _PyTokenizer_Get(struct tok_state *tok, struct token *token)
535536
if (tok_failed(tok)) {
536537
result = ERRORTOKEN;
537538
}
538-
return result;
539+
token->type = result;
539540
}

Parser/lexer/state.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,14 @@ _PyTokenizer_Free(struct tok_state *tok)
7474
PyMem_Free(tok);
7575
}
7676

77-
void
78-
_PyToken_Free(struct token *token) {
79-
Py_XDECREF(token->metadata);
80-
}
81-
8277
void
8378
_PyToken_Init(struct token *token) {
84-
#ifdef Py_DEBUG
85-
token->span = (_PyTok_Span){-1, -1};
86-
token->start_loc = (_PyTok_Loc){-1, -1};
87-
token->end_loc = (_PyTok_Loc){-1, -1};
88-
#endif
89-
token->metadata = NULL;
79+
*token = (struct token){
80+
.type = -1,
81+
.span = {-1, -1},
82+
.start_loc = {-1, -1},
83+
.end_loc = {-1, -1},
84+
};
9085
}
9186

9287
int

Parser/pegen.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ initialize_token(Parser *p, Token *parser_token, struct token *new_token, int to
206206
parser_token->metadata = NULL;
207207
if (new_token->metadata != NULL) {
208208
if (_PyArena_AddPyObject(p->arena, new_token->metadata) < 0) {
209-
Py_DECREF(new_token->metadata);
210209
return -1;
211210
}
212211
parser_token->metadata = new_token->metadata;
@@ -260,10 +259,10 @@ _PyPegen_fill_token(Parser *p)
260259
{
261260
struct token new_token;
262261
_PyToken_Init(&new_token);
263-
int type = _PyTokenizer_Get(p->tok, &new_token);
262+
_PyTokenizer_Get(p->tok, &new_token);
264263

265264
// Record and skip '# type: ignore' comments
266-
while (type == TYPE_IGNORE) {
265+
while (new_token.type == TYPE_IGNORE) {
267266
Py_ssize_t len;
268267
const char *text = _PyToken_TextView(p->tok, &new_token, &len);
269268
char *tag = PyMem_Malloc((size_t)len + 1);
@@ -278,9 +277,11 @@ _PyPegen_fill_token(Parser *p)
278277
PyErr_NoMemory();
279278
goto error;
280279
}
281-
type = _PyTokenizer_Get(p->tok, &new_token);
280+
_PyTokenizer_Get(p->tok, &new_token);
282281
}
283282

283+
int type = new_token.type;
284+
284285
// If we have reached the end and we are in single input mode we need to insert a newline and reset the parsing
285286
if (p->start_rule == Py_single_input && type == ENDMARKER && p->parsing_started) {
286287
type = NEWLINE; /* Add an extra newline */
@@ -300,7 +301,9 @@ _PyPegen_fill_token(Parser *p)
300301
}
301302

302303
Token *t = p->tokens[p->fill];
303-
return initialize_token(p, t, &new_token, type);
304+
int result = initialize_token(p, t, &new_token, type);
305+
_PyToken_Free(&new_token);
306+
return result;
304307
error:
305308
_PyToken_Free(&new_token);
306309
return -1;

Parser/pegen_errors.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) {
138138
_PyToken_Init(&new_token);
139139

140140
for (;;) {
141-
switch (_PyTokenizer_Get(p->tok, &new_token)) {
141+
_PyTokenizer_Get(p->tok, &new_token);
142+
switch (new_token.type) {
142143
case ERRORTOKEN: {
143144
if (PyErr_Occurred()) {
144145
ret = -1;

Parser/tokenizer/api.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ _PyTokenizer_SpanView(const struct tok_state *tok, _PyTok_Span span,
6363

6464
void
6565
_PyToken_GetView(const struct tok_state *tok, const struct token *token,
66-
int type, _PyToken_View *view)
66+
_PyToken_View *view)
6767
{
6868
assert(view != NULL);
6969
assert((token->span.start == -1 && token->span.end == -1) ||
@@ -75,7 +75,7 @@ _PyToken_GetView(const struct tok_state *tok, const struct token *token,
7575
? NULL : _PyLexer_BufferPointer(tok, token->span.start);
7676
view->length = token->span.end - token->span.start;
7777
view->end_line = _PyLexer_BufferPointer(tok, tok->line_start);
78-
view->line = ISSTRINGLIT(type)
78+
view->line = ISSTRINGLIT(token->type)
7979
? view->text - token->start_loc.byte_col : view->end_line;
8080
view->line_length = tok->inp - tok->line_start +
8181
(view->end_line - view->line);

Parser/tokenizer/tokenizer.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct tok_state;
99
/* Initialize before use. metadata owns a reference released by _PyToken_Free;
1010
a consumer taking that reference must set metadata to NULL. */
1111
struct token {
12+
int type;
1213
int level;
1314
int is_raw;
1415
_PyTok_Span span;
@@ -52,11 +53,17 @@ typedef struct {
5253
const char *encoding;
5354
} _PyTokenizer_Info;
5455

55-
int _PyTokenizer_Get(struct tok_state *, struct token *);
56+
/* Get replaces the initialized token, releasing its previous metadata.
57+
Errors are returned as ERRORTOKEN, with or without a Python exception. */
58+
void _PyTokenizer_Get(struct tok_state *, struct token *);
5659
void _PyTokenizer_Free(struct tok_state *);
5760
void _PyTokenizer_raise_init_error(PyObject *filename);
5861
void _PyToken_Init(struct token *);
59-
void _PyToken_Free(struct token *);
62+
static inline void
63+
_PyToken_Free(struct token *token)
64+
{
65+
Py_CLEAR(token->metadata);
66+
}
6067

6168
/* Views and borrowed snapshot references remain valid until the tokenizer is
6269
mutated or freed. Source spans may be discarded when reading more input. */
@@ -65,10 +72,10 @@ _PyTokenizer_Diagnostic _PyTokenizer_GetDiagnostic(const struct tok_state *);
6572
/* An absent token span has a nonnull empty text view. */
6673
const char *_PyToken_TextView(
6774
const struct tok_state *, const struct token *, Py_ssize_t *);
68-
/* Pair the token with the type returned by the most recent Get. text is NULL
69-
for an absent span; line includes the token's complete physical line range. */
75+
/* Use the token from the most recent Get. text is NULL for an absent span;
76+
line includes the token's complete physical line range. */
7077
void _PyToken_GetView(
71-
const struct tok_state *tok, const struct token *token, int type,
78+
const struct tok_state *tok, const struct token *token,
7279
_PyToken_View *view);
7380
const char *_PyTokenizer_SpanView(
7481
const struct tok_state *, _PyTok_Span, Py_ssize_t *);

Python/Python-tokenize.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ tokenizeriter_next(PyObject *op)
257257
struct token token;
258258
_PyToken_Init(&token);
259259

260-
int type = _PyTokenizer_Get(it->tok, &token);
260+
_PyTokenizer_Get(it->tok, &token);
261+
int type = token.type;
261262
if (type == ERRORTOKEN) {
262263
if(!PyErr_Occurred()) {
263264
_tokenizer_error(it);
@@ -271,7 +272,7 @@ tokenizeriter_next(PyObject *op)
271272
goto exit;
272273
}
273274
_PyToken_View view;
274-
_PyToken_GetView(it->tok, &token, type, &view);
275+
_PyToken_GetView(it->tok, &token, &view);
275276
const char *token_start = view.text;
276277
PyObject *str;
277278
if (token.span.start < 0) {

0 commit comments

Comments
 (0)