Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Parser/tokenizer/reader.c
Line
Count
Source
1
#include "Python.h"
2
#include "pycore_fileutils.h"
3
#include "pycore_pystate.h"
4
#include "pycore_runtime.h"
5
6
#include "errcode.h"
7
#include "helpers.h"
8
#include "reader.h"
9
#include "reader_internal.h"
10
#include "../lexer/state.h"
11
12
0
#define READER_BUFFER_GROWTH_FACTOR 2
13
14
#ifdef HAVE_UNISTD_H
15
#  include <unistd.h>
16
#endif
17
18
static inline int
19
reader_is_streaming(_PyTok_ReaderKind kind)
20
343k
{
21
343k
    return kind == _PYTOK_READER_FILE || kind == _PYTOK_READER_READLINE;
22
343k
}
23
24
void
25
_PyTok_ReaderFree(struct tok_state *tok)
26
76.0k
{
27
76.0k
    _PyTok_Reader *reader = tok->reader;
28
76.0k
    if (reader == NULL) {
29
0
        return;
30
0
    }
31
76.0k
    Py_XDECREF(reader->readline);
32
76.0k
    Py_XDECREF(reader->decoder);
33
76.0k
    for (int i = 0;
34
228k
         i < (int)Py_ARRAY_LENGTH(reader->prefetched_lines); i++) {
35
152k
        _PyTok_ChunkClear(&reader->prefetched_lines[i]);
36
152k
    }
37
76.0k
    PyMem_Free(reader->encoding);
38
76.0k
    PyMem_Free(reader->file_buffer);
39
76.0k
    PyMem_Free(reader->decoded);
40
76.0k
    PyMem_Free(reader);
41
76.0k
    tok->reader = NULL;
42
76.0k
}
43
44
int
45
_PyTokenizer_Traverse(struct tok_state *tok, visitproc visit, void *arg)
46
0
{
47
0
    Py_VISIT(tok->filename);
48
0
    Py_VISIT(tok->module);
49
0
    _PyTok_Reader *reader = tok->reader;
50
0
    Py_VISIT(reader->readline);
51
0
    Py_VISIT(reader->decoder);
52
0
    for (int i = 0;
53
0
         i < (int)Py_ARRAY_LENGTH(reader->prefetched_lines); i++) {
54
0
        _PyTok_Chunk *chunk = &reader->prefetched_lines[i];
55
0
        if (chunk->ownership == _PYTOK_CHUNK_PYOBJECT) {
56
0
            Py_VISIT(chunk->owner);
57
0
        }
58
0
    }
59
0
    return 0;
60
0
}
61
62
int
63
_PyTok_ReserveBuffer(char **buffer, Py_ssize_t *capacity, Py_ssize_t needed,
64
                     Py_ssize_t initial_capacity)
65
0
{
66
0
    assert(initial_capacity > 0);
67
0
    if (needed <= *capacity) {
68
0
        return 0;
69
0
    }
70
    // Grow geometrically to avoid reallocating for every longer line.
71
0
    Py_ssize_t cap = *capacity > 0 ? *capacity : initial_capacity;
72
0
    while (cap < needed) {
73
0
        if (cap > PY_SSIZE_T_MAX / READER_BUFFER_GROWTH_FACTOR) {
74
0
            cap = needed;
75
0
            break;
76
0
        }
77
0
        cap *= READER_BUFFER_GROWTH_FACTOR;
78
0
    }
79
0
    char *resized = PyMem_Realloc(*buffer, cap);
80
0
    if (resized == NULL) {
81
0
        PyErr_NoMemory();
82
0
        return -1;
83
0
    }
84
0
    *buffer = resized;
85
0
    *capacity = cap;
86
0
    return 0;
87
0
}
88
89
static int
90
append_decoded(_PyTok_Reader *reader, const char *data, Py_ssize_t len)
91
0
{
92
0
    if (len == 0) {
93
0
        return 0;
94
0
    }
95
0
    if (reader->decoded_pos > 0) {
96
0
        Py_ssize_t remaining = reader->decoded_len - reader->decoded_pos;
97
0
        memmove(reader->decoded, reader->decoded + reader->decoded_pos,
98
0
                (size_t)remaining);
99
0
        reader->decoded_scan -= reader->decoded_pos;
100
0
        reader->decoded_pos = 0;
101
0
        reader->decoded_len = remaining;
102
0
    }
103
0
    if (len < 0 || reader->decoded_len > PY_SSIZE_T_MAX - len - 1 ||
104
0
            _PyTok_ReserveBuffer(&reader->decoded, &reader->decoded_cap,
105
0
                                reader->decoded_len + len + 1, BUFSIZ) < 0) {
106
0
        PyErr_NoMemory();
107
0
        return -1;
108
0
    }
109
0
    memcpy(reader->decoded + reader->decoded_len, data, (size_t)len);
110
0
    reader->decoded_len += len;
111
0
    reader->decoded[reader->decoded_len] = '\0';
112
0
    return 0;
113
0
}
114
115
static int
116
append_implicit_newline(_PyTok_Reader *reader)
117
8
{
118
8
    if (reader->decoded_pos == reader->decoded_len ||
119
8
            reader->decoded[reader->decoded_len - 1] == '\n') {
120
8
        return 0;
121
8
    }
122
0
    if (append_decoded(reader, "\n", 1) < 0) {
123
0
        return -1;
124
0
    }
125
0
    reader->decoded_tail_is_implicit = 1;
126
0
    return 0;
127
0
}
128
129
static int
130
pop_decoded_line(_PyTok_Reader *reader, _PyTok_Chunk *chunk)
131
352
{
132
352
    assert(reader->decoded_pos >= 0 && reader->decoded_pos <= reader->decoded_len);
133
352
    assert(reader->decoded_scan >= reader->decoded_pos &&
134
352
           reader->decoded_scan <= reader->decoded_len);
135
352
    if (reader->decoded_pos == reader->decoded_len) {
136
352
        return 0;
137
352
    }
138
0
    char *start = reader->decoded + reader->decoded_pos;
139
    // Previously scanned bytes cannot contain a newline.
140
0
    char *newline = memchr(reader->decoded + reader->decoded_scan, '\n',
141
0
                           reader->decoded_len - reader->decoded_scan);
142
0
    if (newline == NULL) {
143
0
        reader->decoded_scan = reader->decoded_len;
144
0
        return 0;
145
0
    }
146
0
    Py_ssize_t len = newline - start + 1;
147
0
    chunk->data = start;
148
0
    chunk->len = len;
149
0
    chunk->ownership = _PYTOK_CHUNK_BORROWED;
150
0
    reader->decoded_pos += len;
151
0
    reader->decoded_scan = reader->decoded_pos;
152
0
    chunk->implicit_newline = reader->decoded_pos == reader->decoded_len &&
153
0
        reader->decoded_tail_is_implicit;
154
0
    if (reader->decoded_pos == reader->decoded_len) {
155
0
        reader->decoded_pos = reader->decoded_len = 0;
156
0
        reader->decoded_scan = 0;
157
0
        reader->decoded_tail_is_implicit = 0;
158
0
    }
159
0
    return 1;
160
0
}
161
162
static int
163
chunk_is_line(const _PyTok_Chunk *chunk)
164
336
{
165
336
    if (chunk->len == 0 || chunk->data[chunk->len - 1] != '\n') {
166
0
        return 0;
167
0
    }
168
336
    return memchr(chunk->data, '\n', chunk->len - 1) == NULL;
169
336
}
170
171
static _PyTok_ReadResult
172
next_prepared(struct tok_state *tok, _PyTok_Chunk *chunk)
173
343k
{
174
343k
    if (tok->lineno >= tok->source.nlines) {
175
70.7k
        return _PYTOK_READ_EOF;
176
70.7k
    }
177
272k
    _PyTok_Span tail = {tok->inp, tok->source.base_offset + tok->source.len};
178
272k
    _PyTok_Off newline = _PyTok_SourceFindByte(&tok->source, tail, '\n');
179
272k
    _PyTok_Span line = {tail.start, newline >= 0 ? newline + 1 : tail.end};
180
272k
    chunk->data = (char *)_PyTok_SourceSpanView(
181
272k
        &tok->source, line, &chunk->len);
182
272k
    chunk->ownership = _PYTOK_CHUNK_BORROWED;
183
272k
    chunk->implicit_newline = line.end == tail.end
184
272k
        ? tok->reader->prepared_final_newline : 0;
185
272k
    return _PYTOK_READ_LINE;
186
343k
}
187
188
static _PyTok_ReadResult
189
read_file_line(struct tok_state *tok, _PyTok_Chunk *chunk)
190
0
{
191
0
    _PyTok_Reader *reader = tok->reader;
192
0
    Py_ssize_t len = 0;
193
0
    for (;;) {
194
0
        if (len > PY_SSIZE_T_MAX - BUFSIZ) {
195
0
            PyErr_NoMemory();
196
0
            return _PYTOK_READ_ERROR;
197
0
        }
198
0
        if (_PyTok_ReserveBuffer(&reader->file_buffer, &reader->file_buffer_cap,
199
0
                                len + BUFSIZ, BUFSIZ) < 0) {
200
0
            return _PYTOK_READ_ERROR;
201
0
        }
202
0
        int available = (int)Py_MIN(reader->file_buffer_cap - len, INT_MAX);
203
0
        size_t read = 0;
204
0
        char *result = _Py_UniversalNewlineFgetsWithSize(
205
0
            reader->file_buffer + len, available, reader->fp, NULL, &read);
206
0
        if (result == NULL) {
207
0
            if (len == 0) {
208
0
                return _PYTOK_READ_EOF;
209
0
            }
210
0
            break;
211
0
        }
212
0
        len += (Py_ssize_t)read;
213
0
        if (len > 0 && reader->file_buffer[len - 1] == '\n') {
214
0
            break;
215
0
        }
216
0
    }
217
0
    int implicit = reader->file_buffer[len - 1] != '\n';
218
0
    chunk->data = reader->file_buffer;
219
0
    chunk->len = len;
220
0
    chunk->implicit_newline = implicit;
221
0
    chunk->ownership = _PYTOK_CHUNK_BORROWED;
222
0
    return _PYTOK_READ_LINE;
223
0
}
224
225
static int
226
initialize_file(struct tok_state *tok)
227
0
{
228
0
    _PyTok_Reader *reader = tok->reader;
229
0
    reader->file_initialized = 1;
230
0
    if (reader->encoding != NULL) {
231
0
        return _PyTok_StartDecoder(tok, "strict");
232
0
    }
233
234
0
    _PyTok_ReadResult result = read_file_line(
235
0
        tok, &reader->prefetched_lines[0]);
236
0
    if (result == _PYTOK_READ_EOF) {
237
0
        reader->file_eof = 1;
238
0
        return 0;
239
0
    }
240
0
    if (result != _PYTOK_READ_LINE) {
241
0
        return -1;
242
0
    }
243
0
    Py_ssize_t bom_len;
244
0
    _PyTok_EncodingResult detection = _PyTok_DetectEncoding(
245
0
        tok, &reader->prefetched_lines[0], NULL, 0, &bom_len);
246
0
    if (detection == _PYTOK_ENCODING_ERROR) {
247
0
        return -1;
248
0
    }
249
0
    if (detection == _PYTOK_ENCODING_NEED_SECOND_LINE) {
250
0
        char *first = _PyTok_CopyBytes(
251
0
            reader->prefetched_lines[0].data,
252
0
            reader->prefetched_lines[0].len);
253
0
        if (first == NULL) {
254
0
            tok->done = E_NOMEM;
255
0
            return -1;
256
0
        }
257
0
        reader->prefetched_lines[0].data = first;
258
0
        reader->prefetched_lines[0].ownership = _PYTOK_CHUNK_PYMEM;
259
0
        result = read_file_line(tok, &reader->prefetched_lines[1]);
260
0
        if (result == _PYTOK_READ_EOF) {
261
0
            reader->file_eof = 1;
262
0
        }
263
0
        else if (result != _PYTOK_READ_LINE) {
264
0
            return -1;
265
0
        }
266
0
        _PyTok_Chunk *second = reader->prefetched_lines[1].data != NULL
267
0
            ? &reader->prefetched_lines[1] : NULL;
268
0
        detection = _PyTok_DetectEncoding(
269
0
            tok, &reader->prefetched_lines[0], second, 1, &bom_len);
270
0
        if (detection == _PYTOK_ENCODING_ERROR) {
271
0
            return -1;
272
0
        }
273
0
    }
274
0
    if (bom_len != 0) {
275
0
        _PyTok_Chunk *first = &reader->prefetched_lines[0];
276
0
        if (first->ownership == _PYTOK_CHUNK_PYMEM) {
277
0
            memmove(first->data, first->data + bom_len,
278
0
                    (size_t)(first->len - bom_len));
279
0
            first->data[first->len - bom_len] = '\0';
280
0
        }
281
0
        else {
282
0
            first->data += bom_len;
283
0
        }
284
0
        first->len -= bom_len;
285
0
    }
286
0
    if (_PyTok_StartDecoder(tok, "strict") < 0) {
287
0
        return -1;
288
0
    }
289
0
    return 0;
290
0
}
291
292
static int
293
finalize_decoding(struct tok_state *tok)
294
8
{
295
8
    _PyTok_Reader *reader = tok->reader;
296
8
    if (reader->decoder_finalized) {
297
0
        return 0;
298
0
    }
299
8
    reader->decoder_finalized = 1;
300
8
    if (reader->decoder != NULL) {
301
0
        _PyTok_Chunk input = {
302
0
            .data = "",
303
0
            .ownership = _PYTOK_CHUNK_BORROWED,
304
0
        };
305
0
        int decoded = _PyTok_DecodeChunk(tok, &input, 1);
306
0
        if (decoded == 0 &&
307
0
                append_decoded(reader, input.data, input.len) < 0) {
308
0
            tok->done = E_NOMEM;
309
0
            decoded = -1;
310
0
        }
311
0
        _PyTok_ChunkClear(&input);
312
0
        if (decoded < 0) {
313
0
            return -1;
314
0
        }
315
0
    }
316
8
    if (append_implicit_newline(reader) < 0) {
317
0
        tok->done = E_NOMEM;
318
0
        return -1;
319
0
    }
320
8
    return 0;
321
8
}
322
323
static _PyTok_ReadResult
324
next_file(struct tok_state *tok, _PyTok_Chunk *chunk)
325
0
{
326
0
    _PyTok_Reader *reader = tok->reader;
327
0
    if (!reader->file_initialized && initialize_file(tok) < 0) {
328
0
        return _PYTOK_READ_ERROR;
329
0
    }
330
0
    for (;;) {
331
0
        if (pop_decoded_line(reader, chunk)) {
332
0
            return _PYTOK_READ_LINE;
333
0
        }
334
0
        _PyTok_Chunk input = {0};
335
0
        if (reader->prefetched_lines[0].data != NULL) {
336
0
            input = reader->prefetched_lines[0];
337
0
            reader->prefetched_lines[0] = (_PyTok_Chunk){0};
338
0
        }
339
0
        else if (reader->prefetched_lines[1].data != NULL) {
340
0
            input = reader->prefetched_lines[1];
341
0
            reader->prefetched_lines[1] = (_PyTok_Chunk){0};
342
0
        }
343
0
        else if (!reader->file_eof) {
344
0
            _PyTok_ReadResult result = read_file_line(tok, &input);
345
0
            if (result == _PYTOK_READ_ERROR) {
346
0
                return result;
347
0
            }
348
0
            if (result == _PYTOK_READ_EOF) {
349
0
                reader->file_eof = 1;
350
0
            }
351
0
        }
352
0
        if (input.data != NULL) {
353
0
            int implicit = input.implicit_newline;
354
0
            if (reader->decoder == NULL && !implicit) {
355
0
                *chunk = input;
356
0
                return _PYTOK_READ_LINE;
357
0
            }
358
0
            int decoded = _PyTok_DecodeChunk(tok, &input, 0);
359
0
            if (decoded == 0 && reader->decoded_pos == reader->decoded_len &&
360
0
                    chunk_is_line(&input)) {
361
0
                *chunk = input;
362
0
                return _PYTOK_READ_LINE;
363
0
            }
364
0
            if (decoded == 0 &&
365
0
                    append_decoded(reader, input.data, input.len) < 0) {
366
0
                tok->done = E_NOMEM;
367
0
                decoded = -1;
368
0
            }
369
0
            if (decoded == 0 && implicit) {
370
0
                reader->decoded_tail_is_implicit = 1;
371
0
            }
372
0
            _PyTok_ChunkClear(&input);
373
0
            if (decoded < 0) {
374
0
                return _PYTOK_READ_ERROR;
375
0
            }
376
0
            continue;
377
0
        }
378
0
        if (!reader->decoder_finalized) {
379
0
            if (finalize_decoding(tok) < 0) {
380
0
                return _PYTOK_READ_ERROR;
381
0
            }
382
0
            continue;
383
0
        }
384
0
        return _PYTOK_READ_EOF;
385
0
    }
386
0
}
387
388
static _PyTok_ReadResult
389
next_readline(struct tok_state *tok, _PyTok_Chunk *chunk)
390
344
{
391
344
    _PyTok_Reader *reader = tok->reader;
392
352
    for (;;) {
393
352
        if (pop_decoded_line(reader, chunk)) {
394
0
            return _PYTOK_READ_LINE;
395
0
        }
396
352
        if (reader->decoder_finalized) {
397
8
            return _PYTOK_READ_EOF;
398
8
        }
399
400
344
        PyObject *raw = PyObject_CallNoArgs(reader->readline);
401
344
        if (raw == NULL) {
402
4
            if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
403
4
                PyErr_Clear();
404
4
                if (finalize_decoding(tok) < 0) {
405
0
                    return _PYTOK_READ_ERROR;
406
0
                }
407
4
                continue;
408
4
            }
409
0
            return _PYTOK_READ_ERROR;
410
4
        }
411
412
340
        _PyTok_Chunk input = {0};
413
340
        if (reader->encoding != NULL) {
414
0
            if (!PyBytes_Check(raw)) {
415
0
                PyErr_SetString(PyExc_TypeError,
416
0
                                "readline() returned a non-bytes object");
417
0
                Py_DECREF(raw);
418
0
                return _PYTOK_READ_ERROR;
419
0
            }
420
0
            if (PyBytes_GET_SIZE(raw) == 0) {
421
0
                Py_DECREF(raw);
422
0
                if (_PyTok_StartDecoder(tok, "replace") < 0) {
423
0
                    return _PYTOK_READ_ERROR;
424
0
                }
425
0
                if (finalize_decoding(tok) < 0) {
426
0
                    return _PYTOK_READ_ERROR;
427
0
                }
428
0
                continue;
429
0
            }
430
0
            input.owner = raw;
431
0
            input.data = PyBytes_AS_STRING(raw);
432
0
            input.len = PyBytes_GET_SIZE(raw);
433
0
            input.ownership = _PYTOK_CHUNK_PYOBJECT;
434
0
            int decoded;
435
0
            if (reader->decoder == NULL &&
436
0
                    strcmp(reader->encoding, "utf-8") == 0 &&
437
0
                    chunk_is_line(&input)) {
438
0
                decoded = _PyTok_DecodeOnce(
439
0
                    tok, &input, "utf-8", "replace");
440
0
            }
441
0
            else {
442
0
                decoded = _PyTok_StartDecoder(tok, "replace");
443
0
                if (decoded == 0) {
444
0
                    decoded = _PyTok_DecodeChunk(tok, &input, 0);
445
0
                }
446
0
            }
447
0
            if (decoded < 0) {
448
0
                _PyTok_ChunkClear(&input);
449
0
                return _PYTOK_READ_ERROR;
450
0
            }
451
0
        }
452
340
        else {
453
340
            if (!PyUnicode_Check(raw)) {
454
0
                PyErr_SetString(PyExc_TypeError,
455
0
                                "readline() returned a non-string object");
456
0
                Py_DECREF(raw);
457
0
                return _PYTOK_READ_ERROR;
458
0
            }
459
340
            Py_ssize_t utf8_len;
460
340
            const char *utf8 = PyUnicode_AsUTF8AndSize(raw, &utf8_len);
461
340
            if (utf8 == NULL) {
462
0
                Py_DECREF(raw);
463
0
                return _PYTOK_READ_ERROR;
464
0
            }
465
340
            input.owner = raw;
466
340
            input.data = (char *)utf8;
467
340
            input.len = utf8_len;
468
340
            input.ownership = _PYTOK_CHUNK_PYOBJECT;
469
340
            if (input.len == 0) {
470
4
                _PyTok_ChunkClear(&input);
471
4
                if (finalize_decoding(tok) < 0) {
472
0
                    return _PYTOK_READ_ERROR;
473
0
                }
474
4
                continue;
475
4
            }
476
340
        }
477
478
336
        if (reader->decoded_pos == reader->decoded_len &&
479
336
                chunk_is_line(&input)) {
480
336
            *chunk = input;
481
336
            return _PYTOK_READ_LINE;
482
336
        }
483
484
0
        if (append_decoded(reader, input.data, input.len) < 0) {
485
0
            _PyTok_ChunkClear(&input);
486
0
            tok->done = E_NOMEM;
487
0
            return _PYTOK_READ_ERROR;
488
0
        }
489
0
        _PyTok_ChunkClear(&input);
490
0
        if (reader->decoded_pos < reader->decoded_len &&
491
0
                reader->decoded[reader->decoded_len - 1] != '\n') {
492
0
            int pending = _PyTok_DecoderHasBufferedInput(tok);
493
0
            if (pending < 0) {
494
0
                return _PYTOK_READ_ERROR;
495
0
            }
496
0
            if (!pending && append_implicit_newline(reader) < 0) {
497
0
                tok->done = E_NOMEM;
498
0
                return _PYTOK_READ_ERROR;
499
0
            }
500
0
        }
501
0
    }
502
344
}
503
504
static _PyTok_ReadResult
505
next_interactive(struct tok_state *tok, _PyTok_Chunk *chunk)
506
0
{
507
0
    _PyTok_Reader *reader = tok->reader;
508
0
    if (reader->stop_interactive) {
509
0
        return _PYTOK_READ_STOPPED;
510
0
    }
511
0
    char *input = PyOS_Readline(
512
0
        reader->fp != NULL ? reader->fp : stdin, stdout, reader->prompt);
513
0
    if (reader->nextprompt != NULL) {
514
0
        reader->prompt = reader->nextprompt;
515
0
    }
516
0
    if (input == NULL) {
517
0
        return _PYTOK_READ_INTERRUPT;
518
0
    }
519
0
    Py_ssize_t len = strlen(input);
520
0
    if (len == 0) {
521
0
        PyMem_Free(input);
522
0
        return _PYTOK_READ_EOF;
523
0
    }
524
0
    _PyTok_Chunk decoded = {
525
0
        .data = input,
526
0
        .len = len,
527
0
        .ownership = _PYTOK_CHUNK_PYMEM,
528
0
    };
529
0
    if (reader->encoding != NULL &&
530
0
            _PyTok_DecodeOnce(
531
0
                tok, &decoded, reader->encoding, NULL) < 0) {
532
0
        _PyTok_ChunkClear(&decoded);
533
0
        return _PYTOK_READ_ERROR;
534
0
    }
535
0
    if (memchr(decoded.data, '\r', decoded.len) == NULL) {
536
0
        *chunk = decoded;
537
0
        return _PYTOK_READ_LINE;
538
0
    }
539
0
    chunk->data = _PyTok_NormalizeNewlines(
540
0
        decoded.data, decoded.len, &chunk->len);
541
0
    _PyTok_ChunkClear(&decoded);
542
0
    if (chunk->data == NULL) {
543
0
        tok->done = E_NOMEM;
544
0
        return _PYTOK_READ_ERROR;
545
0
    }
546
0
    chunk->ownership = _PYTOK_CHUNK_PYMEM;
547
0
    return _PYTOK_READ_LINE;
548
0
}
549
550
int
551
_PyTok_ReaderIsInteractive(const struct tok_state *tok)
552
473k
{
553
473k
    return tok->reader->kind == _PYTOK_READER_INTERACTIVE;
554
473k
}
555
556
const char *
557
_PyTokenizer_RetainedSource(const struct tok_state *tok)
558
65.3k
{
559
65.3k
    if (tok->reader->kind == _PYTOK_READER_PREPARED) {
560
65.3k
        return _PyTok_SourceData(&tok->source);
561
65.3k
    }
562
0
    if (tok->reader->kind == _PYTOK_READER_INTERACTIVE) {
563
0
        return tok->source.bytes;
564
0
    }
565
0
    return NULL;
566
0
}
567
568
void
569
_PyTok_ReaderStopInteractive(struct tok_state *tok)
570
65.0k
{
571
65.0k
    if (_PyTok_ReaderIsInteractive(tok)) {
572
0
        tok->reader->stop_interactive = 1;
573
0
    }
574
65.0k
}
575
576
static _PyTok_ReadResult
577
reader_next(struct tok_state *tok, _PyTok_Chunk *chunk)
578
343k
{
579
343k
    *chunk = (_PyTok_Chunk){0};
580
343k
    switch (tok->reader->kind) {
581
343k
        case _PYTOK_READER_PREPARED:
582
343k
            return next_prepared(tok, chunk);
583
0
        case _PYTOK_READER_FILE:
584
0
            return next_file(tok, chunk);
585
344
        case _PYTOK_READER_READLINE:
586
344
            return next_readline(tok, chunk);
587
0
        case _PYTOK_READER_INTERACTIVE:
588
0
            return next_interactive(tok, chunk);
589
343k
    }
590
343k
    Py_UNREACHABLE();
591
343k
}
592
593
static void
594
reset_streaming_buffer(struct tok_state *tok)
595
316
{
596
316
    assert(tok->cur >= tok->buf_offset && tok->cur <= tok->inp);
597
316
    _PyTok_SourceDiscard(&tok->source);
598
316
    tok->buf_offset = tok->source.base_offset;
599
316
    tok->cur = tok->inp = tok->source.base_offset;
600
316
    tok->line_start = tok->buf_offset;
601
316
}
602
603
int
604
_PyTok_ReaderUnderflow(struct tok_state *tok)
605
343k
{
606
343k
    assert(tok->cur >= tok->buf_offset && tok->cur <= tok->inp);
607
343k
    _PyTok_Reader *reader = tok->reader;
608
343k
    _PyTok_ReaderKind kind = reader->kind;
609
343k
    int prepared = kind == _PYTOK_READER_PREPARED;
610
343k
    int streaming = reader_is_streaming(kind);
611
343k
    int reset_buffer = tok->start < 0 &&
612
330k
        _PyLexer_CurrentFTString(tok) == NULL;
613
614
343k
    _PyTok_Chunk chunk;
615
343k
    _PyTok_ReadResult result = reader_next(tok, &chunk);
616
343k
    if (result != _PYTOK_READ_LINE) {
617
70.7k
        if (reset_buffer && streaming) {
618
8
            reset_streaming_buffer(tok);
619
8
        }
620
70.7k
        if (result == _PYTOK_READ_EOF) {
621
70.7k
            tok->done = E_EOF;
622
70.7k
        }
623
0
        else if (result == _PYTOK_READ_STOPPED) {
624
0
            tok->done = E_INTERACT_STOP;
625
0
        }
626
0
        else if (result == _PYTOK_READ_INTERRUPT) {
627
0
            tok->done = E_INTR;
628
0
        }
629
0
        else {
630
0
            if (tok->done == E_OK) {
631
0
                tok->done = PyErr_ExceptionMatches(PyExc_MemoryError)
632
0
                    ? E_NOMEM : E_ERROR;
633
0
            }
634
0
        }
635
70.7k
        if (kind == _PYTOK_READER_INTERACTIVE &&
636
0
                result != _PYTOK_READ_STOPPED) {
637
0
            PySys_WriteStderr("\n");
638
0
        }
639
70.7k
        return 0;
640
70.7k
    }
641
272k
    if (tok->lineno == INT_MAX) {
642
0
        PyErr_SetString(PyExc_OverflowError, "too many tokenizer source lines");
643
0
        tok->done = E_ERROR;
644
0
        _PyTok_ChunkClear(&chunk);
645
0
        return 0;
646
0
    }
647
648
272k
    if (!prepared) {
649
336
        if (streaming && reset_buffer) {
650
308
            reset_streaming_buffer(tok);
651
308
        }
652
336
        _PyTok_Off source_start = _PyTok_SourceAppendLine(
653
336
            &tok->source, chunk.data, chunk.len);
654
336
        if (source_start < 0) {
655
0
            _PyTok_ChunkClear(&chunk);
656
0
            tok->done = PyErr_ExceptionMatches(PyExc_MemoryError)
657
0
                ? E_NOMEM : E_ERROR;
658
0
            return 0;
659
0
        }
660
336
        if (reset_buffer) {
661
308
            tok->cur = source_start;
662
308
            tok->buf_offset = source_start;
663
308
            tok->line_start = tok->buf_offset;
664
308
        }
665
336
        tok->inp = source_start + chunk.len;
666
336
    }
667
272k
    else {
668
272k
        if (reset_buffer) {
669
256k
            tok->buf_offset = tok->inp;
670
256k
        }
671
272k
        tok->inp += chunk.len;
672
272k
    }
673
272k
    tok->implicit_newline = chunk.implicit_newline;
674
675
272k
    tok->lineno++;
676
272k
    if (kind == _PYTOK_READER_FILE &&
677
0
            (reader->encoding == NULL ||
678
0
             strcmp(reader->encoding, "utf-8") == 0) &&
679
0
            !_PyTokenizer_ensure_utf8(
680
0
                _PyTok_SourcePointer(&tok->source, tok->cur),
681
0
                tok, tok->lineno)) {
682
0
        _PyTok_ChunkClear(&chunk);
683
0
        return 0;
684
0
    }
685
272k
    _PyTok_ChunkClear(&chunk);
686
272k
    return 1;
687
272k
}
688
689
static struct tok_state *
690
tokenizer_new_with_reader(_PyTok_ReaderKind kind)
691
76.0k
{
692
76.0k
    struct tok_state *tok = PyMem_Calloc(1, sizeof(*tok));
693
76.0k
    if (tok == NULL) {
694
0
        PyErr_NoMemory();
695
0
        return NULL;
696
0
    }
697
76.0k
    tok->start = tok->line_start = -1;
698
76.0k
    _PyTok_SourceInit(&tok->source);
699
76.0k
    tok->done = E_OK;
700
76.0k
    tok->layout.at_bol = 1;
701
76.0k
    tok->start_loc = (_PyTok_Loc){-1, -1};
702
76.0k
    tok->ftstring_stack = tok->ftstring_stack_inline;
703
76.0k
    tok->ftstring_capacity = FTSTRING_STACK_INLINE_CAPACITY;
704
#ifdef Py_DEBUG
705
    tok->debug = _Py_GetConfig()->parser_debug;
706
#endif
707
76.0k
    tok->reader = PyMem_Calloc(1, sizeof(*tok->reader));
708
76.0k
    if (tok->reader == NULL) {
709
0
        PyErr_NoMemory();
710
0
        _PyTokenizer_Free(tok);
711
0
        return NULL;
712
0
    }
713
76.0k
    tok->reader->kind = kind;
714
76.0k
    if (kind == _PYTOK_READER_PREPARED) {
715
76.0k
        return tok;
716
76.0k
    }
717
16
    if (reader_is_streaming(kind)) {
718
16
        tok->cur = tok->inp = tok->source.base_offset;
719
16
        tok->line_start = tok->buf_offset;
720
16
    }
721
16
    return tok;
722
76.0k
}
723
724
static struct tok_state *
725
tokenizer_from_string(const char *input, int utf8_only, int exec_input,
726
                      int preserve_crlf)
727
76.0k
{
728
76.0k
    struct tok_state *tok = tokenizer_new_with_reader(_PYTOK_READER_PREPARED);
729
76.0k
    if (tok == NULL) {
730
0
        return NULL;
731
0
    }
732
76.0k
    if (_PyTok_PrepareString(
733
76.0k
            tok, input, utf8_only, exec_input, preserve_crlf) < 0) {
734
2.65k
        _PyTokenizer_Free(tok);
735
2.65k
        return NULL;
736
2.65k
    }
737
73.3k
    tok->cur = tok->inp = tok->source.base_offset;
738
73.3k
    tok->line_start = tok->source.base_offset;
739
73.3k
    return tok;
740
76.0k
}
741
742
struct tok_state *
743
_PyTokenizer_FromString(const char *input, int exec_input, int preserve_crlf)
744
22.9k
{
745
22.9k
    return tokenizer_from_string(input, 0, exec_input, preserve_crlf);
746
22.9k
}
747
748
struct tok_state *
749
_PyTokenizer_FromUTF8(const char *input, int exec_input, int preserve_crlf)
750
53.0k
{
751
53.0k
    return tokenizer_from_string(input, 1, exec_input, preserve_crlf);
752
53.0k
}
753
754
struct tok_state *
755
_PyTokenizer_FromReadline(PyObject *readline, const char *encoding)
756
16
{
757
16
    struct tok_state *tok = tokenizer_new_with_reader(_PYTOK_READER_READLINE);
758
16
    if (tok == NULL) {
759
0
        return NULL;
760
0
    }
761
16
    if (encoding != NULL && _PyTok_SetEncoding(tok, encoding) < 0) {
762
0
        _PyTokenizer_Free(tok);
763
0
        return NULL;
764
0
    }
765
16
    tok->reader->readline = Py_NewRef(readline);
766
16
    return tok;
767
16
}
768
769
struct tok_state *
770
_PyTokenizer_FromFile(FILE *fp, const char *encoding,
771
                      const char *ps1, const char *ps2)
772
0
{
773
0
    _PyTok_ReaderKind kind = ps1 != NULL || ps2 != NULL
774
0
        ? _PYTOK_READER_INTERACTIVE : _PYTOK_READER_FILE;
775
0
    struct tok_state *tok = tokenizer_new_with_reader(kind);
776
0
    if (tok == NULL) {
777
0
        return NULL;
778
0
    }
779
0
    if (encoding != NULL && _PyTok_SetEncoding(tok, encoding) < 0) {
780
0
        _PyTokenizer_Free(tok);
781
0
        return NULL;
782
0
    }
783
0
    tok->reader->fp = fp;
784
0
    tok->reader->prompt = ps1;
785
0
    tok->reader->nextprompt = ps2;
786
0
    return tok;
787
0
}
788
789
#if defined(__wasi__) || (defined(__EMSCRIPTEN__) && (__EMSCRIPTEN_major__ >= 3))
790
/* WASI has no dup(), and Emscripten's emulation is slow. */
791
typedef union {
792
    void *cookie;
793
    int fd;
794
} borrowed_fd;
795
796
static ssize_t
797
borrow_read(void *cookie, char *buffer, size_t size)
798
{
799
    borrowed_fd borrowed = {.cookie = cookie};
800
    return read(borrowed.fd, buffer, size);
801
}
802
803
static FILE *
804
fdopen_borrow(int fd)
805
{
806
    cookie_io_functions_t callbacks = {borrow_read, NULL, NULL, NULL};
807
    borrowed_fd borrowed = {.fd = fd};
808
    return fopencookie(borrowed.cookie, "r", callbacks);
809
}
810
#else
811
static FILE *
812
fdopen_borrow(int fd)
813
0
{
814
0
    int copy = _Py_dup(fd);
815
0
    if (copy < 0) {
816
0
        return NULL;
817
0
    }
818
0
    FILE *fp = fdopen(copy, "r");
819
0
    if (fp == NULL) {
820
0
        int saved_errno = errno;
821
0
        close(copy);
822
0
        errno = saved_errno;
823
0
    }
824
0
    return fp;
825
0
}
826
#endif
827
828
char *
829
_PyTokenizer_FindEncodingFilename(int fd, PyObject *filename)
830
0
{
831
0
    FILE *fp = fdopen_borrow(fd);
832
0
    if (fp == NULL) {
833
0
        return NULL;
834
0
    }
835
0
    struct tok_state *tok = _PyTokenizer_FromFile(fp, NULL, NULL, NULL);
836
0
    if (tok == NULL) {
837
0
        fclose(fp);
838
0
        return NULL;
839
0
    }
840
0
    _Py_DECLARE_STR(anon_string, "<string>");
841
0
    tok->filename = Py_NewRef(filename != NULL ? filename : &_Py_STR(anon_string));
842
0
    char *encoding = NULL;
843
0
    if (initialize_file(tok) == 0) {
844
0
        encoding = tok->reader->encoding;
845
        tok->reader->encoding = NULL;
846
0
    }
847
0
    fclose(fp);
848
0
    _PyTokenizer_Free(tok);
849
0
    return encoding;
850
0
}