Skip to content

Commit e5fbabb

Browse files
pablogsalmaurycy
andauthored
gh-153568: Don't materialize parser token text that is never read (#153576)
* gh-153568: Don't materialize parser token text that is never read Only tokens whose text is actually consumed get a bytes object; operators and structural tokens no longer allocate one. * Update Parser/pegen.c Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com> * gh-153568: Preserve keyword token text --------- Co-authored-by: Maurycy Pawłowski-Wieroński <maurycy@maurycy.com>
1 parent c215919 commit e5fbabb

2 files changed

Lines changed: 39 additions & 6 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up the parser by not materializing the text of tokens whose text is
2+
never read.

Parser/pegen.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,32 @@ _get_keyword_or_name_type(Parser *p, const char *text, Py_ssize_t length)
197197
return NAME;
198198
}
199199

200+
// Token types whose text is consumed by grammar actions or helpers, other
201+
// than NAME-derived tokens (identifiers and keywords), which always keep
202+
// their text: error actions may print keyword text (e.g. invalid_kwarg's
203+
// "cannot assign to True"). For every other type the token text is never
204+
// read again, so materializing a PyBytes for it is wasted work.
205+
static inline int
206+
token_needs_text(int type)
207+
{
208+
switch (type) {
209+
case NAME:
210+
case NUMBER:
211+
case STRING:
212+
case FSTRING_START:
213+
case FSTRING_MIDDLE:
214+
case FSTRING_END:
215+
case TSTRING_START:
216+
case TSTRING_MIDDLE:
217+
case TSTRING_END:
218+
case TYPE_COMMENT:
219+
case NOTEQUAL: // _PyPegen_check_barry_as_flufl() reads its text
220+
return 1;
221+
default:
222+
return 0;
223+
}
224+
}
225+
200226
static int
201227
initialize_token(Parser *p, Token *parser_token, struct token *new_token, int token_type) {
202228
assert(parser_token != NULL);
@@ -205,13 +231,18 @@ initialize_token(Parser *p, Token *parser_token, struct token *new_token, int to
205231
const char *text = _PyToken_TextView(p->tok, new_token, &length);
206232
parser_token->type = token_type == NAME
207233
? _get_keyword_or_name_type(p, text, length) : token_type;
208-
parser_token->bytes = PyBytes_FromStringAndSize(text, length);
209-
if (parser_token->bytes == NULL) {
210-
return -1;
234+
if (token_type == NAME || token_needs_text(parser_token->type)) {
235+
parser_token->bytes = PyBytes_FromStringAndSize(text, length);
236+
if (parser_token->bytes == NULL) {
237+
return -1;
238+
}
239+
if (_PyArena_AddPyObject(p->arena, parser_token->bytes) < 0) {
240+
Py_DECREF(parser_token->bytes);
241+
return -1;
242+
}
211243
}
212-
if (_PyArena_AddPyObject(p->arena, parser_token->bytes) < 0) {
213-
Py_DECREF(parser_token->bytes);
214-
return -1;
244+
else {
245+
parser_token->bytes = NULL;
215246
}
216247

217248
parser_token->metadata = NULL;

0 commit comments

Comments
 (0)