Skip to content

Commit 8023fd8

Browse files
committed
gh-153569: borrow diagnostic lines through the source API
1 parent abb1d45 commit 8023fd8

3 files changed

Lines changed: 60 additions & 4 deletions

File tree

Modules/_testinternalcapi/tokenizer.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ check_system_error(int failed, const char *message)
2323
return 0;
2424
}
2525

26+
static int
27+
check_line_view(const _PyTok_SourceText *source, Py_ssize_t lineno,
28+
const char *expected)
29+
{
30+
Py_ssize_t len;
31+
const char *line = _PyTok_SourceLineView(source, lineno, &len);
32+
return check(len == (Py_ssize_t)strlen(expected) &&
33+
memcmp(line, expected, len) == 0,
34+
"wrong source line view");
35+
}
36+
2637
static int
2738
same_cursor(const _PyTok_Cursor *left, const _PyTok_Cursor *right)
2839
{
@@ -40,6 +51,10 @@ test_tokenizer_source(PyObject *Py_UNUSED(module),
4051
_PyTok_SourceText source;
4152
_PyTok_SourceInit(&source);
4253

54+
if (check_line_view(&source, 1, "") < 0) {
55+
goto error;
56+
}
57+
4358
_PyTok_Loc loc;
4459
_PyTok_Line line;
4560
if (check(_PyTok_SourceLocation(
@@ -67,10 +82,20 @@ test_tokenizer_source(PyObject *Py_UNUSED(module),
6782
"wrong first source offset") < 0 ||
6883
check(_PyTok_SourceAppendLine(
6984
&source, "\xce\xb2\n", 3, 1) == 6,
70-
"wrong second source offset") < 0 ||
71-
check(_PyTok_SourceAppendLine(
72-
&source, "nul\0x\n", 6, 0) == 9,
73-
"wrong third source offset") < 0) {
85+
"wrong second source offset") < 0) {
86+
goto error;
87+
}
88+
89+
if (check_line_view(&source, PY_SSIZE_T_MIN, "alpha") < 0 ||
90+
check_line_view(&source, 1, "alpha") < 0 ||
91+
check_line_view(&source, 2, "\xce\xb2") < 0 ||
92+
check_line_view(&source, 3, "") < 0 ||
93+
check_line_view(&source, PY_SSIZE_T_MAX, "") < 0) {
94+
goto error;
95+
}
96+
97+
if (check(_PyTok_SourceAppendLine(&source, "nul\0x\n", 6, 0) == 9,
98+
"wrong third source offset") < 0) {
7499
goto error;
75100
}
76101

@@ -195,6 +220,11 @@ test_tokenizer_source(PyObject *Py_UNUSED(module),
195220
goto error;
196221
}
197222

223+
if (check_line_view(&source, 1, "tail") < 0 ||
224+
check_line_view(&source, PY_SSIZE_T_MAX, "tail") < 0) {
225+
goto error;
226+
}
227+
198228
_PyTok_SourceDiscard(&source);
199229
if (check(_PyTok_SourceAppendLine(&source, "a\n", 2, 0) == 4,
200230
"wrong retained source offset") < 0 ||

Parser/tokenizer/source.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,26 @@ _PyTok_SourceAppendLine(_PyTok_SourceText *source, const char *bytes,
190190
return source->base_offset + start;
191191
}
192192

193+
const char *
194+
_PyTok_SourceLineView(const _PyTok_SourceText *source, Py_ssize_t lineno,
195+
Py_ssize_t *len)
196+
{
197+
assert(len != NULL);
198+
const char *line = _PyTok_SourceData(source);
199+
const char *end = line + source->len;
200+
while (lineno > 1) {
201+
const char *newline = memchr(line, '\n', end - line);
202+
if (newline == NULL) {
203+
break;
204+
}
205+
line = newline + 1;
206+
lineno--;
207+
}
208+
const char *newline = memchr(line, '\n', end - line);
209+
*len = (newline != NULL ? newline : end) - line;
210+
return line;
211+
}
212+
193213
const char *
194214
_PyTok_SourceSpanView(const _PyTok_SourceText *source, _PyTok_Span span,
195215
Py_ssize_t *len)

Parser/tokenizer/source.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ PyAPI_FUNC(void) _PyTok_SourceDiscard(_PyTok_SourceText *);
4949
PyAPI_FUNC(_PyTok_Off) _PyTok_SourceAppendLine(
5050
_PyTok_SourceText *source, const char *bytes, Py_ssize_t len,
5151
int implicit_newline);
52+
/* Return borrowed bytes excluding '\n', writing the byte length to *len.
53+
Line numbers are 1-based and clamp to the first or final line; a trailing
54+
'\n' adds an empty final line. The view need not be NUL-terminated.
55+
This does not set an exception. Append, discard, and clear invalidate the view. */
56+
PyAPI_FUNC(const char *) _PyTok_SourceLineView(
57+
const _PyTok_SourceText *source, Py_ssize_t lineno, Py_ssize_t *len);
5258
/* The returned view is invalidated by SourceAppendLine and SourceClear. */
5359
PyAPI_FUNC(const char *) _PyTok_SourceSpanView(
5460
const _PyTok_SourceText *, _PyTok_Span, Py_ssize_t *);

0 commit comments

Comments
 (0)