Skip to content

Commit 68400fb

Browse files
committed
gh-153569: store f-string state as source spans
1 parent adf9365 commit 68400fb

10 files changed

Lines changed: 121 additions & 207 deletions

File tree

Lib/test/test_fstring.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,10 @@ def __repr__(self):
16791679

16801680
self.assertEqual(f'{" # nooo "=}', '" # nooo "=\' # nooo \'')
16811681
self.assertEqual(f'{" \" # nooo \" "=}', '" \\" # nooo \\" "=\' " # nooo " \'')
1682+
self.assertEqual(f'{"""a" # inside"""=}',
1683+
'"""a" # inside"""=\'a" # inside\'')
1684+
self.assertEqual(f"{'''a' # inside'''=}",
1685+
"'''a' # inside'''=\"a' # inside\"")
16821686

16831687
self.assertEqual(f'{ # some comment goes here
16841688
"""hello"""=}', ' \n """hello"""=\'hello\'')

Lib/test/test_tstring.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,5 +287,9 @@ def test_triple_quoted(self):
287287
)
288288
self.assertEqual(fstring(t), "\n Hello,\n Python\n ")
289289

290+
t = t'{"""a" # inside"""}'
291+
self.assertEqual(t.interpolations[0].expression,
292+
'"""a" # inside"""')
293+
290294
if __name__ == '__main__':
291295
unittest.main()

Parser/lexer/buffer.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ _PyLexer_SnapshotBuffer(struct tok_state *tok, const char *base,
1414
? -1 : tok->line_start - tok->buf;
1515
snapshot->multi_line_start = tok->multi_line_start == NULL
1616
? -1 : tok->multi_line_start - tok->buf;
17-
for (int index = tok->tok_mode_stack_index; index >= 0; --index) {
18-
tokenizer_mode *mode = &tok->tok_mode_stack[index];
19-
mode->start_offset = mode->start == NULL ? -1 : mode->start - tok->buf;
20-
mode->multi_line_start_offset = mode->multi_line_start == NULL
21-
? -1 : mode->multi_line_start - tok->buf;
22-
}
2317
}
2418

2519
void
@@ -35,11 +29,4 @@ _PyLexer_RestoreBuffer(struct tok_state *tok, char *base,
3529
? NULL : tok->buf + snapshot->line_start;
3630
tok->multi_line_start = snapshot->multi_line_start < 0
3731
? NULL : tok->buf + snapshot->multi_line_start;
38-
for (int index = tok->tok_mode_stack_index; index >= 0; --index) {
39-
tokenizer_mode *mode = &tok->tok_mode_stack[index];
40-
mode->start = mode->start_offset < 0
41-
? NULL : tok->buf + mode->start_offset;
42-
mode->multi_line_start = mode->multi_line_start_offset < 0
43-
? NULL : tok->buf + mode->multi_line_start_offset;
44-
}
4532
}

Parser/lexer/lexer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
555555
int cursor_in_format_with_debug =
556556
cursor == 1 && (current_tok->in_debug || in_format_spec);
557557
int cursor_valid = cursor == 0 || cursor_in_format_with_debug;
558-
if ((cursor_valid) && !_PyLexer_update_ftstring_expr(tok, c)) {
559-
return MAKE_TOKEN(ENDMARKER);
558+
if (cursor_valid) {
559+
_PyLexer_update_ftstring_expr(tok, c);
560560
}
561561
if ((cursor_valid) && c != '{' && _PyLexer_set_ftstring_expr(tok, token, c)) {
562562
return MAKE_TOKEN(ERRORTOKEN);

Parser/lexer/lexer.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,24 @@
33

44
#include "state.h"
55

6-
int _PyLexer_update_ftstring_expr(struct tok_state *tok, char cur);
7-
86
int _PyTokenizer_Get(struct tok_state *, struct token *);
97

8+
static inline const char *
9+
_PyLexer_SpanView(const struct tok_state *tok, _PyTok_Span span,
10+
Py_ssize_t *length)
11+
{
12+
assert(length != NULL);
13+
assert(_PyTok_SpanIsValid(span));
14+
assert(tok->buf != NULL);
15+
assert(tok->inp >= tok->buf);
16+
if (span.start >= tok->buf_offset &&
17+
span.end - tok->buf_offset <= tok->inp - tok->buf) {
18+
*length = span.end - span.start;
19+
return tok->buf + (span.start - tok->buf_offset);
20+
}
21+
return _PyTok_SourceSpanView(&tok->source, span, length);
22+
}
23+
1024
/* The view points into the current input window. The next
1125
_PyTokenizer_Get() call may discard it. */
1226
static inline const char *
@@ -18,12 +32,7 @@ _PyToken_TextView(const struct tok_state *tok, const struct token *token,
1832
*length = 0;
1933
return "";
2034
}
21-
assert(tok->buf != NULL);
22-
assert(tok->inp >= tok->buf);
23-
assert(token->span.start >= tok->buf_offset);
24-
assert(token->span.end - tok->buf_offset <= tok->inp - tok->buf);
25-
*length = token->span.end - token->span.start;
26-
return tok->buf + (token->span.start - tok->buf_offset);
35+
return _PyLexer_SpanView(tok, token->span, length);
2736
}
2837

2938
#endif

Parser/lexer/lexer_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ TOK_NEXT_MODE(struct tok_state *tok)
4646

4747
int _PyLexer_nextc(struct tok_state *);
4848
void _PyLexer_backup(struct tok_state *, int);
49+
void _PyLexer_update_ftstring_expr(struct tok_state *, char);
4950
int _PyLexer_set_ftstring_expr(struct tok_state *, struct token *, char);
5051
int _PyLexer_check_string_prefixes(struct tok_state *, int, int, int, int, int);
5152
int _PyLexer_scan_number(struct tok_state *, struct token *, int, int);

Parser/lexer/state.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,6 @@ _PyTokenizer_tok_new(void)
6060
return tok;
6161
}
6262

63-
static void
64-
free_fstring_expressions(struct tok_state *tok)
65-
{
66-
int index;
67-
tokenizer_mode *mode;
68-
69-
for (index = tok->tok_mode_stack_index; index >= 0; --index) {
70-
mode = &(tok->tok_mode_stack[index]);
71-
if (mode->last_expr_buffer != NULL) {
72-
PyMem_Free(mode->last_expr_buffer);
73-
mode->last_expr_buffer = NULL;
74-
mode->last_expr_size = 0;
75-
mode->last_expr_end = -1;
76-
mode->in_format_spec = 0;
77-
}
78-
}
79-
}
80-
8163
/* Free a tok_state structure */
8264
void
8365
_PyTokenizer_Free(struct tok_state *tok)
@@ -89,7 +71,6 @@ _PyTokenizer_Free(struct tok_state *tok)
8971
Py_XDECREF(tok->module);
9072
_PyTok_ReaderFree(tok);
9173
_PyTok_SourceClear(&tok->source);
92-
free_fstring_expressions(tok);
9374
PyMem_Free(tok);
9475
}
9576

Parser/lexer/state.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,11 @@ typedef struct _tokenizer_mode {
5050
char quote;
5151
int quote_size;
5252
int raw;
53-
const char* start;
54-
const char* multi_line_start;
53+
_PyTok_Off start;
54+
_PyTok_Off multi_line_start;
5555
int first_line;
5656

57-
Py_ssize_t start_offset;
58-
Py_ssize_t multi_line_start_offset;
59-
60-
Py_ssize_t last_expr_size;
61-
Py_ssize_t last_expr_end;
62-
char* last_expr_buffer;
57+
_PyTok_Span debug_expr;
6358
int in_debug;
6459
int in_format_spec;
6560

0 commit comments

Comments
 (0)