Coverage Report

Created: 2026-10-17 06:15

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
7.23k
#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
316k
{
21
316k
    return kind == _PYTOK_READER_FILE || kind == _PYTOK_READER_READLINE;
22
316k
}
23
24
void
25
_PyTok_ReaderFree(struct tok_state *tok)
26
65.0k
{
27
65.0k
    _PyTok_Reader *reader = tok->reader;
28
65.0k
    if (reader == NULL) {
29
0
        return;
30
0
    }
31
65.0k
    Py_XDECREF(reader->readline);
32
65.0k
    Py_XDECREF(reader->decoder);
33
65.0k
    for (int i = 0;
34
195k
         i < (int)Py_ARRAY_LENGTH(reader->prefetched_lines); i++) {
35
130k
        _PyTok_ChunkClear(&reader->prefetched_lines[i]);
36
130k
    }
37
65.0k
    PyMem_Free(reader->encoding);
38
65.0k
    PyMem_Free(reader->file_buffer);
39
65.0k
    PyMem_Free(reader->decoded);
40
65.0k
    PyMem_Free(reader);
41
65.0k
    tok->reader = NULL;
42
65.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
76.1k
{
66
76.1k
    assert(initial_capacity > 0);
67
76.1k
    if (needed <= *capacity) {
68
14.0k
        return 0;
69
14.0k
    }
70
    // Grow geometrically to avoid reallocating for every longer line.
71
62.1k
    Py_ssize_t cap = *capacity > 0 ? *capacity : initial_capacity;
72
65.7k
    while (cap < needed) {
73
3.61k
        if (cap > PY_SSIZE_T_MAX / READER_BUFFER_GROWTH_FACTOR) {
74
0
            cap = needed;
75
0
            break;
76
0
        }
77
3.61k
        cap *= READER_BUFFER_GROWTH_FACTOR;
78
3.61k
    }
79
62.1k
    char *resized = PyMem_Realloc(*buffer, cap);
80
62.1k
    if (resized == NULL) {
81
0
        PyErr_NoMemory();
82
0
        return -1;
83
0
    }
84
62.1k
    *buffer = resized;
85
62.1k
    *capacity = cap;
86
62.1k
    return 0;
87
62.1k
}
88
89
static int
90
append_decoded(_PyTok_Reader *reader, const char *data, Py_ssize_t len)
91
12
{
92
12
    if (len == 0) {
93
4
        return 0;
94
4
    }
95
8
    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
8
    if (len < 0 || reader->decoded_len > PY_SSIZE_T_MAX - len - 1 ||
104
8
            _PyTok_ReserveBuffer(&reader->decoded, &reader->decoded_cap,
105
8
                                reader->decoded_len + len + 1, BUFSIZ) < 0) {
106
0
        PyErr_NoMemory();
107
0
        return -1;
108
0
    }
109
8
    memcpy(reader->decoded + reader->decoded_len, data, (size_t)len);
110
8
    reader->decoded_len += len;
111
8
    reader->decoded[reader->decoded_len] = '\0';
112
8
    return 0;
113
8
}
114
115
static int
116
append_implicit_newline(_PyTok_Reader *reader)
117
16
{
118
16
    if (reader->decoded_pos == reader->decoded_len ||
119
12
            reader->decoded[reader->decoded_len - 1] == '\n') {
120
12
        return 0;
121
12
    }
122
4
    if (append_decoded(reader, "\n", 1) < 0) {
123
0
        return -1;
124
0
    }
125
4
    reader->decoded_tail_is_implicit = 1;
126
4
    return 0;
127
4
}
128
129
static int
130
pop_decoded_line(_PyTok_Reader *reader, _PyTok_Chunk *chunk)
131
368
{
132
368
    assert(reader->decoded_pos >= 0 && reader->decoded_pos <= reader->decoded_len);
133
368
    assert(reader->decoded_scan >= reader->decoded_pos &&
134
368
           reader->decoded_scan <= reader->decoded_len);
135
368
    if (reader->decoded_pos == reader->decoded_len) {
136
364
        return 0;
137
364
    }
138
4
    char *start = reader->decoded + reader->decoded_pos;
139
    // Previously scanned bytes cannot contain a newline.
140
4
    char *newline = memchr(reader->decoded + reader->decoded_scan, '\n',
141
4
                           reader->decoded_len - reader->decoded_scan);
142
4
    if (newline == NULL) {
143
0
        reader->decoded_scan = reader->decoded_len;
144
0
        return 0;
145
0
    }
146
4
    Py_ssize_t len = newline - start + 1;
147
4
    chunk->data = start;
148
4
    chunk->len = len;
149
4
    chunk->ownership = _PYTOK_CHUNK_BORROWED;
150
4
    reader->decoded_pos += len;
151
4
    reader->decoded_scan = reader->decoded_pos;
152
4
    chunk->implicit_newline = reader->decoded_pos == reader->decoded_len &&
153
4
        reader->decoded_tail_is_implicit;
154
4
    if (reader->decoded_pos == reader->decoded_len) {
155
4
        reader->decoded_pos = reader->decoded_len = 0;
156
4
        reader->decoded_scan = 0;
157
4
        reader->decoded_tail_is_implicit = 0;
158
4
    }
159
4
    return 1;
160
4
}
161
162
static int
163
chunk_is_line(const _PyTok_Chunk *chunk)
164
344
{
165
344
    if (chunk->len == 0 || chunk->data[chunk->len - 1] != '\n') {
166
8
        return 0;
167
8
    }
168
336
    return memchr(chunk->data, '\n', chunk->len - 1) == NULL;
169
344
}
170
171
static _PyTok_ReadResult
172
next_prepared(struct tok_state *tok, _PyTok_Chunk *chunk)
173
315k
{
174
315k
    if (tok->lineno >= tok->source.nlines) {
175
59.9k
        return _PYTOK_READ_EOF;
176
59.9k
    }
177
255k
    _PyTok_Span tail = {tok->inp, tok->source.base_offset + tok->source.len};
178
255k
    _PyTok_Off newline = _PyTok_SourceFindByte(&tok->source, tail, '\n');
179
255k
    _PyTok_Span line = {tail.start, newline >= 0 ? newline + 1 : tail.end};
180
255k
    chunk->data = (char *)_PyTok_SourceSpanView(
181
255k
        &tok->source, line, &chunk->len);
182
255k
    chunk->ownership = _PYTOK_CHUNK_BORROWED;
183
255k
    chunk->implicit_newline = line.end == tail.end &&
184
62.3k
        tok->reader->prepared_final_newline_is_implicit;
185
255k
    return _PYTOK_READ_LINE;
186
315k
}
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
12
{
295
12
    _PyTok_Reader *reader = tok->reader;
296
12
    if (reader->decoder_finalized) {
297
0
        return 0;
298
0
    }
299
12
    reader->decoder_finalized = 1;
300
12
    if (reader->decoder != NULL) {
301
4
        _PyTok_Chunk input = {
302
4
            .data = "",
303
4
            .ownership = _PYTOK_CHUNK_BORROWED,
304
4
        };
305
4
        int decoded = _PyTok_DecodeChunk(tok, &input, 1);
306
4
        if (decoded == 0 &&
307
4
                append_decoded(reader, input.data, input.len) < 0) {
308
0
            tok->done = E_NOMEM;
309
0
            decoded = -1;
310
0
        }
311
4
        _PyTok_ChunkClear(&input);
312
4
        if (decoded < 0) {
313
0
            return -1;
314
0
        }
315
4
    }
316
12
    if (append_implicit_newline(reader) < 0) {
317
0
        tok->done = E_NOMEM;
318
0
        return -1;
319
0
    }
320
12
    return 0;
321
12
}
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
352
{
391
352
    _PyTok_Reader *reader = tok->reader;
392
368
    for (;;) {
393
368
        if (pop_decoded_line(reader, chunk)) {
394
4
            return _PYTOK_READ_LINE;
395
4
        }
396
364
        if (reader->decoder_finalized) {
397
12
            return _PYTOK_READ_EOF;
398
12
        }
399
400
352
        PyObject *raw = PyObject_CallNoArgs(reader->readline);
401
352
        if (raw == NULL) {
402
8
            if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
403
8
                PyErr_Clear();
404
8
                if (finalize_decoding(tok) < 0) {
405
0
                    return _PYTOK_READ_ERROR;
406
0
                }
407
8
                continue;
408
8
            }
409
0
            return _PYTOK_READ_ERROR;
410
8
        }
411
412
344
        _PyTok_Chunk input = {0};
413
344
        if (reader->encoding != NULL) {
414
4
            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
4
            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
4
            input.owner = raw;
431
4
            input.data = PyBytes_AS_STRING(raw);
432
4
            input.len = PyBytes_GET_SIZE(raw);
433
4
            input.ownership = _PYTOK_CHUNK_PYOBJECT;
434
4
            int decoded;
435
4
            if (reader->decoder == NULL &&
436
4
                    strcmp(reader->encoding, "utf-8") == 0 &&
437
4
                    chunk_is_line(&input)) {
438
0
                decoded = _PyTok_DecodeOnce(
439
0
                    tok, &input, "utf-8", "replace");
440
0
            }
441
4
            else {
442
4
                decoded = _PyTok_StartDecoder(tok, "replace");
443
4
                if (decoded == 0) {
444
4
                    decoded = _PyTok_DecodeChunk(tok, &input, 0);
445
4
                }
446
4
            }
447
4
            if (decoded < 0) {
448
0
                _PyTok_ChunkClear(&input);
449
0
                return _PYTOK_READ_ERROR;
450
0
            }
451
4
        }
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
340
        if (reader->decoded_pos == reader->decoded_len &&
479
340
                chunk_is_line(&input)) {
480
336
            *chunk = input;
481
336
            return _PYTOK_READ_LINE;
482
336
        }
483
484
4
        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
4
        _PyTok_ChunkClear(&input);
490
4
        if (reader->decoded_pos < reader->decoded_len &&
491
4
                reader->decoded[reader->decoded_len - 1] != '\n') {
492
4
            int pending = _PyTok_DecoderHasBufferedInput(tok);
493
4
            if (pending < 0) {
494
0
                return _PYTOK_READ_ERROR;
495
0
            }
496
4
            if (!pending && append_implicit_newline(reader) < 0) {
497
0
                tok->done = E_NOMEM;
498
0
                return _PYTOK_READ_ERROR;
499
0
            }
500
4
        }
501
4
    }
502
352
}
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
409k
{
553
409k
    return tok->reader->kind == _PYTOK_READER_INTERACTIVE;
554
409k
}
555
556
const char *
557
_PyTokenizer_RetainedSource(const struct tok_state *tok)
558
54.4k
{
559
54.4k
    if (tok->reader->kind == _PYTOK_READER_PREPARED) {
560
54.4k
        return _PyTok_SourceData(&tok->source);
561
54.4k
    }
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
54.2k
{
571
54.2k
    if (_PyTok_ReaderIsInteractive(tok)) {
572
0
        tok->reader->stop_interactive = 1;
573
0
    }
574
54.2k
}
575
576
static _PyTok_ReadResult
577
reader_next(struct tok_state *tok, _PyTok_Chunk *chunk)
578
316k
{
579
316k
    *chunk = (_PyTok_Chunk){0};
580
316k
    switch (tok->reader->kind) {
581
315k
        case _PYTOK_READER_PREPARED:
582
315k
            return next_prepared(tok, chunk);
583
0
        case _PYTOK_READER_FILE:
584
0
            return next_file(tok, chunk);
585
352
        case _PYTOK_READER_READLINE:
586
352
            return next_readline(tok, chunk);
587
0
        case _PYTOK_READER_INTERACTIVE:
588
0
            return next_interactive(tok, chunk);
589
316k
    }
590
316k
    Py_UNREACHABLE();
591
316k
}
592
593
static void
594
reset_streaming_buffer(struct tok_state *tok)
595
324
{
596
324
    assert(tok->cur >= tok->buf_offset && tok->cur <= tok->inp);
597
324
    _PyTok_SourceDiscard(&tok->source);
598
324
    tok->buf_offset = tok->source.base_offset;
599
324
    tok->cur = tok->inp = tok->source.base_offset;
600
324
    tok->line_start = tok->buf_offset;
601
324
}
602
603
int
604
_PyTok_ReaderUnderflow(struct tok_state *tok)
605
316k
{
606
316k
    assert(tok->cur >= tok->buf_offset && tok->cur <= tok->inp);
607
316k
    _PyTok_Reader *reader = tok->reader;
608
316k
    _PyTok_ReaderKind kind = reader->kind;
609
316k
    int prepared = kind == _PYTOK_READER_PREPARED;
610
316k
    int streaming = reader_is_streaming(kind);
611
316k
    int reset_buffer = tok->start < 0 &&
612
304k
        _PyLexer_CurrentFTString(tok) == NULL;
613
614
316k
    _PyTok_Chunk chunk;
615
316k
    _PyTok_ReadResult result = reader_next(tok, &chunk);
616
316k
    if (result != _PYTOK_READ_LINE) {
617
59.9k
        if (reset_buffer && streaming) {
618
12
            reset_streaming_buffer(tok);
619
12
        }
620
59.9k
        if (result == _PYTOK_READ_EOF) {
621
59.9k
            tok->done = E_EOF;
622
59.9k
        }
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
59.9k
        if (kind == _PYTOK_READER_INTERACTIVE &&
636
0
                result != _PYTOK_READ_STOPPED) {
637
0
            PySys_WriteStderr("\n");
638
0
        }
639
59.9k
        return 0;
640
59.9k
    }
641
256k
    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
256k
    if (!prepared) {
649
340
        if (streaming && reset_buffer) {
650
312
            reset_streaming_buffer(tok);
651
312
        }
652
340
        _PyTok_Off source_start = _PyTok_SourceAppendLine(
653
340
            &tok->source, chunk.data, chunk.len);
654
340
        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
340
        if (reset_buffer) {
661
312
            tok->cur = source_start;
662
312
            tok->buf_offset = source_start;
663
312
            tok->line_start = tok->buf_offset;
664
312
        }
665
340
        tok->inp = source_start + chunk.len;
666
340
    }
667
255k
    else {
668
255k
        if (reset_buffer) {
669
240k
            tok->buf_offset = tok->inp;
670
240k
        }
671
255k
        tok->inp += chunk.len;
672
255k
    }
673
256k
    tok->implicit_newline = chunk.implicit_newline;
674
675
256k
    tok->lineno++;
676
256k
    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
256k
    _PyTok_ChunkClear(&chunk);
686
256k
    return 1;
687
256k
}
688
689
static struct tok_state *
690
tokenizer_new_with_reader(_PyTok_ReaderKind kind)
691
65.0k
{
692
65.0k
    struct tok_state *tok = PyMem_Calloc(1, sizeof(*tok));
693
65.0k
    if (tok == NULL) {
694
0
        PyErr_NoMemory();
695
0
        return NULL;
696
0
    }
697
65.0k
    tok->start = tok->line_start = -1;
698
65.0k
    _PyTok_SourceInit(&tok->source);
699
65.0k
    tok->done = E_OK;
700
65.0k
    tok->layout.at_bol = 1;
701
65.0k
    tok->start_loc = (_PyTok_Loc){-1, -1};
702
65.0k
    tok->ftstring_stack = tok->ftstring_stack_inline;
703
65.0k
    tok->ftstring_capacity = FTSTRING_STACK_INLINE_CAPACITY;
704
#ifdef Py_DEBUG
705
    tok->debug = _Py_GetConfig()->parser_debug;
706
#endif
707
65.0k
    tok->reader = PyMem_Calloc(1, sizeof(*tok->reader));
708
65.0k
    if (tok->reader == NULL) {
709
0
        PyErr_NoMemory();
710
0
        _PyTokenizer_Free(tok);
711
0
        return NULL;
712
0
    }
713
65.0k
    tok->reader->kind = kind;
714
65.0k
    if (kind == _PYTOK_READER_PREPARED) {
715
65.0k
        return tok;
716
65.0k
    }
717
20
    if (reader_is_streaming(kind)) {
718
20
        tok->cur = tok->inp = tok->source.base_offset;
719
20
        tok->line_start = tok->buf_offset;
720
20
    }
721
20
    return tok;
722
65.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
65.0k
{
728
65.0k
    struct tok_state *tok = tokenizer_new_with_reader(_PYTOK_READER_PREPARED);
729
65.0k
    if (tok == NULL) {
730
0
        return NULL;
731
0
    }
732
65.0k
    if (_PyTok_PrepareString(
733
65.0k
            tok, input, utf8_only, exec_input, preserve_crlf) < 0) {
734
2.52k
        _PyTokenizer_Free(tok);
735
2.52k
        return NULL;
736
2.52k
    }
737
62.5k
    tok->cur = tok->inp = tok->source.base_offset;
738
62.5k
    tok->line_start = tok->source.base_offset;
739
62.5k
    return tok;
740
65.0k
}
741
742
struct tok_state *
743
_PyTokenizer_FromString(const char *input, int exec_input, int preserve_crlf)
744
22.2k
{
745
22.2k
    return tokenizer_from_string(input, 0, exec_input, preserve_crlf);
746
22.2k
}
747
748
struct tok_state *
749
_PyTokenizer_FromUTF8(const char *input, int exec_input, int preserve_crlf)
750
42.7k
{
751
42.7k
    return tokenizer_from_string(input, 1, exec_input, preserve_crlf);
752
42.7k
}
753
754
struct tok_state *
755
_PyTokenizer_FromReadline(PyObject *readline, const char *encoding)
756
20
{
757
20
    struct tok_state *tok = tokenizer_new_with_reader(_PYTOK_READER_READLINE);
758
20
    if (tok == NULL) {
759
0
        return NULL;
760
0
    }
761
20
    if (encoding != NULL && _PyTok_SetEncoding(tok, encoding) < 0) {
762
0
        _PyTokenizer_Free(tok);
763
0
        return NULL;
764
0
    }
765
20
    tok->reader->readline = Py_NewRef(readline);
766
20
    return tok;
767
20
}
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
}