Skip to content

Commit 8c56c04

Browse files
committed
gh-153569: hide tokenizer state behind token and source operations
1 parent 09117bc commit 8c56c04

19 files changed

Lines changed: 493 additions & 264 deletions

Makefile.pre.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ TOKENIZER_OBJS= \
401401
Parser/lexer/string.o \
402402
Parser/tokenizer/cursor.o \
403403
Parser/tokenizer/decoder.o \
404+
Parser/tokenizer/api.o \
404405
Parser/tokenizer/reader.o \
405406
Parser/tokenizer/source.o \
406407
Parser/tokenizer/helpers.o
@@ -419,6 +420,7 @@ TOKENIZER_HEADERS= \
419420
Parser/tokenizer/reader.h \
420421
Parser/tokenizer/reader_internal.h \
421422
Parser/tokenizer/source.h \
423+
Parser/tokenizer/types.h \
422424
Parser/tokenizer/tokenizer.h \
423425
Parser/tokenizer/helpers.h
424426

PCbuild/_freeze_module.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
<ClCompile Include="..\Parser\lexer\number.c" />
188188
<ClCompile Include="..\Parser\lexer\string.c" />
189189
<ClCompile Include="..\Parser\tokenizer\decoder.c" />
190+
<ClCompile Include="..\Parser\tokenizer\api.c" />
190191
<ClCompile Include="..\Parser\tokenizer\reader.c" />
191192
<ClCompile Include="..\Parser\tokenizer\source.c" />
192193
<ClCompile Include="..\Parser\tokenizer\helpers.c" />

PCbuild/_freeze_module.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@
478478
<ClCompile Include="..\Parser\tokenizer\decoder.c">
479479
<Filter>Source Files</Filter>
480480
</ClCompile>
481+
<ClCompile Include="..\Parser\tokenizer\api.c">
482+
<Filter>Source Files</Filter>
483+
</ClCompile>
481484
<ClCompile Include="..\Parser\tokenizer\reader.c">
482485
<Filter>Source Files</Filter>
483486
</ClCompile>

PCbuild/pythoncore.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@
427427
<ClInclude Include="..\Parser\tokenizer\cursor.h" />
428428
<ClInclude Include="..\Parser\tokenizer\reader.h" />
429429
<ClInclude Include="..\Parser\tokenizer\reader_internal.h" />
430+
<ClInclude Include="..\Parser\tokenizer\types.h" />
430431
<ClInclude Include="..\Parser\tokenizer\source.h" />
431432
<ClInclude Include="..\Parser\tokenizer\helpers.h" />
432433
<ClInclude Include="..\Parser\tokenizer\tokenizer.h" />
@@ -597,6 +598,7 @@
597598
<ClCompile Include="..\Parser\tokenizer\cursor.c" />
598599
<ClCompile Include="..\Parser\tokenizer\source.c" />
599600
<ClCompile Include="..\Parser\tokenizer\decoder.c" />
601+
<ClCompile Include="..\Parser\tokenizer\api.c" />
600602
<ClCompile Include="..\Parser\tokenizer\reader.c" />
601603
<ClCompile Include="..\Parser\tokenizer\helpers.c" />
602604
<ClCompile Include="..\Parser\token.c" />

PCbuild/pythoncore.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@
342342
<ClInclude Include="..\Parser\tokenizer\reader_internal.h">
343343
<Filter>Parser</Filter>
344344
</ClInclude>
345+
<ClInclude Include="..\Parser\tokenizer\types.h">
346+
<Filter>Parser</Filter>
347+
</ClInclude>
345348
<ClInclude Include="..\Parser\tokenizer\source.h">
346349
<Filter>Parser</Filter>
347350
</ClInclude>
@@ -1373,6 +1376,9 @@
13731376
<ClCompile Include="..\Parser\tokenizer\decoder.c">
13741377
<Filter>Parser</Filter>
13751378
</ClCompile>
1379+
<ClCompile Include="..\Parser\tokenizer\api.c">
1380+
<Filter>Parser</Filter>
1381+
</ClCompile>
13761382
<ClCompile Include="..\Parser\tokenizer\reader.c">
13771383
<Filter>Parser</Filter>
13781384
</ClCompile>

Parser/action_helpers.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,14 +1001,33 @@ result_token_with_metadata(Parser *p, void *result, PyObject *metadata)
10011001
return res;
10021002
}
10031003

1004+
static char
1005+
formatted_string_prefix(const Parser *p)
1006+
{
1007+
int nested = 0;
1008+
for (int i = p->mark - 1; i >= 0; i--) {
1009+
int type = p->tokens[i]->type;
1010+
if (type == FSTRING_END || type == TSTRING_END) {
1011+
nested++;
1012+
}
1013+
else if (type == FSTRING_START || type == TSTRING_START) {
1014+
if (nested == 0) {
1015+
return type == TSTRING_START ? 't' : 'f';
1016+
}
1017+
nested--;
1018+
}
1019+
}
1020+
Py_UNREACHABLE();
1021+
}
1022+
10041023
ResultTokenWithMetadata *
10051024
_PyPegen_check_fstring_conversion(Parser *p, Token* conv_token, expr_ty conv)
10061025
{
10071026
if (conv_token->lineno != conv->lineno || conv_token->end_col_offset != conv->col_offset) {
10081027
return RAISE_SYNTAX_ERROR_KNOWN_RANGE(
10091028
conv_token, conv,
10101029
"%c-string: conversion type must come right after the exclamation mark",
1011-
TOK_GET_STRING_PREFIX(p->tok)
1030+
formatted_string_prefix(p)
10121031
);
10131032
}
10141033

@@ -1017,7 +1036,7 @@ _PyPegen_check_fstring_conversion(Parser *p, Token* conv_token, expr_ty conv)
10171036
!(first == 's' || first == 'r' || first == 'a')) {
10181037
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(conv,
10191038
"%c-string: invalid conversion character %R: expected 's', 'r', or 'a'",
1020-
TOK_GET_STRING_PREFIX(p->tok),
1039+
formatted_string_prefix(p),
10211040
conv->v.Name.id);
10221041
return NULL;
10231042
}
@@ -1344,7 +1363,8 @@ _PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant, Token* tok
13441363
}
13451364

13461365
static asdl_expr_seq *
1347-
_get_resized_exprs(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token *b, enum string_kind_t string_kind)
1366+
_get_resized_exprs(Parser *p, Token *a, asdl_expr_seq *raw_expressions,
1367+
Token *b, int is_tstring)
13481368
{
13491369
Py_ssize_t n_items = asdl_seq_LEN(raw_expressions);
13501370
Py_ssize_t total_items = n_items;
@@ -1370,15 +1390,13 @@ _get_resized_exprs(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token *b
13701390
for (Py_ssize_t i = 0; i < n_items; i++) {
13711391
expr_ty item = asdl_seq_GET(raw_expressions, i);
13721392

1373-
// This should correspond to a JoinedStr node of two elements
1374-
// created _PyPegen_formatted_value. This situation can only be the result of
1375-
// a (f|t)-string debug expression where the first element is a constant with the text and the second
1376-
// a formatted value with the expression.
1393+
/* Debug expressions arrive as JoinedStr(text, value); flatten them
1394+
into the surrounding string. */
13771395
if (item->kind == JoinedStr_kind) {
13781396
asdl_expr_seq *values = item->v.JoinedStr.values;
13791397
if (asdl_seq_LEN(values) != 2) {
13801398
PyErr_Format(PyExc_SystemError,
1381-
string_kind == TSTRING
1399+
is_tstring
13821400
? "unexpected TemplateStr node without debug data in t-string at line %d"
13831401
: "unexpected JoinedStr node without debug data in f-string at line %d",
13841402
item->lineno);
@@ -1390,7 +1408,9 @@ _get_resized_exprs(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token *b
13901408
asdl_seq_SET(seq, index++, first);
13911409

13921410
expr_ty second = asdl_seq_GET(values, 1);
1393-
assert((string_kind == TSTRING && second->kind == Interpolation_kind) || second->kind == FormattedValue_kind);
1411+
assert((is_tstring &&
1412+
second->kind == Interpolation_kind) ||
1413+
second->kind == FormattedValue_kind);
13941414
asdl_seq_SET(seq, index++, second);
13951415

13961416
continue;
@@ -1432,7 +1452,7 @@ _get_resized_exprs(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token *b
14321452
expr_ty
14331453
_PyPegen_template_str(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token *b) {
14341454

1435-
asdl_expr_seq *resized_exprs = _get_resized_exprs(p, a, raw_expressions, b, TSTRING);
1455+
asdl_expr_seq *resized_exprs = _get_resized_exprs(p, a, raw_expressions, b, 1);
14361456
if (resized_exprs == NULL) {
14371457
return NULL;
14381458
}
@@ -1444,7 +1464,7 @@ _PyPegen_template_str(Parser *p, Token *a, asdl_expr_seq *raw_expressions, Token
14441464
expr_ty
14451465
_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) {
14461466

1447-
asdl_expr_seq *resized_exprs = _get_resized_exprs(p, a, raw_expressions, b, FSTRING);
1467+
asdl_expr_seq *resized_exprs = _get_resized_exprs(p, a, raw_expressions, b, 0);
14481468
if (resized_exprs == NULL) {
14491469
return NULL;
14501470
}
@@ -1460,12 +1480,7 @@ expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) {
14601480
return NULL;
14611481
}
14621482

1463-
// Check if we're inside a raw f-string for format spec decoding
1464-
int is_raw = 0;
1465-
if (INSIDE_FSTRING(p->tok)) {
1466-
tokenizer_mode *mode = TOK_GET_MODE(p->tok);
1467-
is_raw = mode->raw;
1468-
}
1483+
int is_raw = tok->is_raw;
14691484

14701485
PyObject* str = _PyPegen_decode_string(p, is_raw, bstr, bsize, tok);
14711486
if (str == NULL) {
@@ -2047,13 +2062,14 @@ _warn_relative_import_of_lazy(Parser *p, asdl_seq *dots, expr_ty module)
20472062
return -1;
20482063
}
20492064

2065+
_PyTokenizer_Info info = _PyTokenizer_GetInfo(p->tok);
20502066
int res = _PyErr_EmitSyntaxWarning(msg,
2051-
p->tok->filename,
2067+
info.filename,
20522068
module->lineno,
20532069
module->col_offset + 1,
20542070
module->end_lineno,
20552071
module->end_col_offset + 1,
2056-
p->tok->module);
2072+
info.module);
20572073
Py_DECREF(msg);
20582074
return res;
20592075
}

Parser/lexer/lexer.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,4 @@
55

66
int _PyLexer_update_ftstring_expr(struct tok_state *tok, char cur);
77

8-
int _PyTokenizer_Get(struct tok_state *, struct token *);
9-
10-
/* The view points into the current input window. The next
11-
_PyTokenizer_Get() call may discard it. */
12-
static inline const char *
13-
_PyToken_TextView(const struct tok_state *tok, const struct token *token,
14-
Py_ssize_t *length)
15-
{
16-
assert(length != NULL);
17-
if (token->span.start < 0) {
18-
assert(token->span.start == -1 && token->span.end == -1);
19-
*length = 0;
20-
return "";
21-
}
22-
assert(_PyTok_SpanIsValid(token->span));
23-
assert(tok->buf != NULL);
24-
assert(tok->inp >= tok->buf);
25-
assert(token->span.start >= tok->buf_offset);
26-
assert(token->span.end - tok->buf_offset <= tok->inp - tok->buf);
27-
*length = token->span.end - token->span.start;
28-
return tok->buf + (token->span.start - tok->buf_offset);
29-
}
30-
318
#endif

Parser/lexer/state.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ int
132132
_PyLexer_token_setup(struct tok_state *tok, struct token *token, int type, const char *start, const char *end)
133133
{
134134
token->level = tok->level;
135+
token->is_raw = ISSTRINGLIT(type)
136+
&& tok->tok_mode_stack[tok->tok_mode_stack_index].raw;
135137
token->span = buffer_span(tok, start, end);
136138
int lineno = ISSTRINGLIT(type) ? tok->first_lineno : tok->lineno;
137139
token->start_loc = (_PyTok_Loc){lineno, -1};

Parser/lexer/state.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "object.h"
55
#include "../tokenizer/source.h"
6+
#include "../tokenizer/tokenizer.h"
67

78
#define MAXINDENT 100 /* Max indentation level */
89
#define MAXLEVEL 200 /* Max parentheses level */
@@ -21,13 +22,6 @@ enum interactive_underflow_t {
2122
IUNDERFLOW_STOP,
2223
};
2324

24-
struct token {
25-
int level;
26-
_PyTok_Span span;
27-
_PyTok_Loc start_loc;
28-
_PyTok_Loc end_loc;
29-
PyObject *metadata;
30-
};
3125

3226
enum tokenizer_mode_kind_t {
3327
TOK_REGULAR_MODE,
@@ -129,12 +123,37 @@ struct tok_state {
129123
#endif
130124
};
131125

126+
static inline _PyTok_Off
127+
_PyLexer_BufferOffset(const struct tok_state *tok, const char *position)
128+
{
129+
const char *base = _PyTok_SourceData(&tok->source);
130+
assert(position >= base && position <= base + tok->source.len);
131+
return tok->source.base_offset + (position - base);
132+
}
133+
134+
static inline const char *
135+
_PyLexer_BufferPointer(const struct tok_state *tok, _PyTok_Off offset)
136+
{
137+
assert(offset >= tok->source.base_offset);
138+
assert(offset - tok->source.base_offset <= tok->source.len);
139+
return _PyTok_SourceData(&tok->source) + (offset - tok->source.base_offset);
140+
}
141+
142+
static inline const char *
143+
_PyLexer_BufferSpanView(const struct tok_state *tok, _PyTok_Span span,
144+
Py_ssize_t *length)
145+
{
146+
assert(length != NULL);
147+
assert(_PyTok_SpanIsValid(span));
148+
*length = span.end - span.start;
149+
(void)_PyLexer_BufferPointer(tok, span.end);
150+
return _PyLexer_BufferPointer(tok, span.start);
151+
}
152+
132153
int _PyLexer_token_setup(struct tok_state *tok, struct token *token, int type, const char *start, const char *end);
133154

134155
struct tok_state *_PyTokenizer_tok_new(void);
135156
void _PyTokenizer_Free(struct tok_state *);
136-
void _PyToken_Free(struct token *);
137-
void _PyToken_Init(struct token *);
138157

139158

140159
#endif

0 commit comments

Comments
 (0)