Coverage Report

Created: 2026-08-13 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/Parser/tokenizer/string_tokenizer.c
Line
Count
Source
1
#include "Python.h"
2
#include "errcode.h"
3
4
#include "helpers.h"
5
#include "../lexer/state.h"
6
7
static int
8
331k
tok_underflow_string(struct tok_state *tok) {
9
331k
    char *end = strchr(tok->inp, '\n');
10
331k
    if (end != NULL) {
11
317k
        end++;
12
317k
    }
13
14.0k
    else {
14
14.0k
        end = strchr(tok->inp, '\0');
15
14.0k
        if (end == tok->inp) {
16
10.1k
            tok->done = E_EOF;
17
10.1k
            return 0;
18
10.1k
        }
19
14.0k
    }
20
321k
    if (tok->start == NULL) {
21
261k
        tok->buf = tok->cur;
22
261k
    }
23
321k
    tok->line_start = tok->cur;
24
321k
    ADVANCE_LINENO();
25
321k
    tok->inp = end;
26
321k
    return 1;
27
331k
}
28
29
/* Fetch a byte from TOK, using the string buffer. */
30
static int
31
13.5k
buf_getc(struct tok_state *tok) {
32
13.5k
    return Py_CHARMASK(*tok->str++);
33
13.5k
}
34
35
/* Unfetch a byte from TOK, using the string buffer. */
36
static void
37
13.5k
buf_ungetc(int c, struct tok_state *tok) {
38
13.5k
    tok->str--;
39
13.5k
    assert(Py_CHARMASK(*tok->str) == c);        /* tok->cur may point to read-only segment */
40
13.5k
}
41
42
/* Set the readline function for TOK to ENC. For the string-based
43
   tokenizer, this means to just record the encoding. */
44
static int
45
4.83k
buf_setreadl(struct tok_state *tok, const char* enc) {
46
4.83k
    tok->enc = enc;
47
4.83k
    return 1;
48
4.83k
}
49
50
/* Decode a byte string STR for use as the buffer of TOK.
51
   Look for encoding declarations inside STR, and record them
52
   inside TOK.  */
53
static char *
54
decode_str(const char *input, int single, struct tok_state *tok, int preserve_crlf)
55
13.5k
{
56
13.5k
    PyObject* utf8 = NULL;
57
13.5k
    char *str;
58
13.5k
    const char *s;
59
13.5k
    const char *newl[2] = {NULL, NULL};
60
13.5k
    int lineno = 0;
61
13.5k
    tok->input = str = _PyTokenizer_translate_newlines(input, single, preserve_crlf, tok);
62
13.5k
    if (str == NULL)
63
0
        return NULL;
64
13.5k
    tok->enc = NULL;
65
13.5k
    tok->str = str;
66
13.5k
    if (!_PyTokenizer_check_bom(buf_getc, buf_ungetc, buf_setreadl, tok))
67
0
        return _PyTokenizer_error_ret(tok);
68
13.5k
    str = tok->str;             /* string after BOM if any */
69
13.5k
    assert(str);
70
13.5k
    if (tok->enc != NULL) {
71
0
        utf8 = _PyTokenizer_translate_into_utf8(str, tok->enc);
72
0
        if (utf8 == NULL)
73
0
            return _PyTokenizer_error_ret(tok);
74
0
        str = PyBytes_AsString(utf8);
75
0
    }
76
5.18M
    for (s = str;; s++) {
77
5.18M
        if (*s == '\0') break;
78
5.17M
        else if (*s == '\n') {
79
14.8k
            assert(lineno < 2);
80
14.8k
            newl[lineno] = s;
81
14.8k
            lineno++;
82
14.8k
            if (lineno == 2) break;
83
14.8k
        }
84
5.18M
    }
85
13.5k
    tok->enc = NULL;
86
    /* need to check line 1 and 2 separately since check_coding_spec
87
       assumes a single line as input */
88
13.5k
    if (newl[0]) {
89
9.83k
        tok->lineno = 1;
90
9.83k
        if (!_PyTokenizer_check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) {
91
1
            return NULL;
92
1
        }
93
9.83k
        if (tok->enc == NULL && tok->decoding_state != STATE_NORMAL && newl[1]) {
94
684
            tok->lineno = 2;
95
684
            if (!_PyTokenizer_check_coding_spec(newl[0]+1, newl[1] - newl[0],
96
684
                                   tok, buf_setreadl))
97
1
                return NULL;
98
684
        }
99
9.83k
    }
100
13.5k
    tok->lineno = 0;
101
13.5k
    if (tok->enc != NULL) {
102
4.83k
        assert(utf8 == NULL);
103
4.83k
        utf8 = _PyTokenizer_translate_into_utf8(str, tok->enc);
104
4.83k
        if (utf8 == NULL)
105
1.67k
            return _PyTokenizer_error_ret(tok);
106
3.15k
        str = PyBytes_AS_STRING(utf8);
107
3.15k
    }
108
8.70k
    else if (!_PyTokenizer_ensure_utf8(str, tok, 1)) {
109
238
        return _PyTokenizer_error_ret(tok);
110
238
    }
111
11.6k
    if (utf8 != NULL) {
112
3.15k
        char *translated = _PyTokenizer_translate_newlines(
113
3.15k
            str, single, preserve_crlf, tok);
114
3.15k
        if (translated == NULL) {
115
0
            Py_DECREF(utf8);
116
0
            return _PyTokenizer_error_ret(tok);
117
0
        }
118
3.15k
        PyMem_Free(tok->input);
119
3.15k
        tok->input = translated;
120
3.15k
        str = translated;
121
3.15k
        Py_CLEAR(utf8);
122
3.15k
    }
123
11.6k
    tok->str = str;
124
11.6k
    assert(tok->decoding_buffer == NULL);
125
11.6k
    tok->decoding_buffer = utf8; /* CAUTION */
126
11.6k
    return str;
127
11.6k
}
128
129
/* Set up tokenizer for string */
130
struct tok_state *
131
_PyTokenizer_FromString(const char *str, int exec_input, int preserve_crlf)
132
13.5k
{
133
13.5k
    struct tok_state *tok = _PyTokenizer_tok_new();
134
13.5k
    char *decoded;
135
136
13.5k
    if (tok == NULL)
137
0
        return NULL;
138
13.5k
    decoded = decode_str(str, exec_input, tok, preserve_crlf);
139
13.5k
    if (decoded == NULL) {
140
1.91k
        _PyTokenizer_Free(tok);
141
1.91k
        return NULL;
142
1.91k
    }
143
144
11.6k
    tok->buf = tok->cur = tok->inp = decoded;
145
11.6k
    tok->end = decoded;
146
11.6k
    tok->underflow = &tok_underflow_string;
147
11.6k
    return tok;
148
13.5k
}