Branch data Line data Source code
1 : :
2 : : /* Tokenizer implementation */
3 : :
4 : : #define PY_SSIZE_T_CLEAN
5 : : #include "Python.h"
6 : : #include "pycore_call.h" // _PyObject_CallNoArgs()
7 : :
8 : : #include <ctype.h>
9 : : #include <assert.h>
10 : :
11 : : #include "tokenizer.h"
12 : : #include "errcode.h"
13 : :
14 : : #include "unicodeobject.h"
15 : : #include "bytesobject.h"
16 : : #include "fileobject.h"
17 : : #include "abstract.h"
18 : :
19 : : /* Alternate tab spacing */
20 : : #define ALTTABSIZE 1
21 : :
22 : : #define is_potential_identifier_start(c) (\
23 : : (c >= 'a' && c <= 'z')\
24 : : || (c >= 'A' && c <= 'Z')\
25 : : || c == '_'\
26 : : || (c >= 128))
27 : :
28 : : #define is_potential_identifier_char(c) (\
29 : : (c >= 'a' && c <= 'z')\
30 : : || (c >= 'A' && c <= 'Z')\
31 : : || (c >= '0' && c <= '9')\
32 : : || c == '_'\
33 : : || (c >= 128))
34 : :
35 : :
36 : : /* Don't ever change this -- it would break the portability of Python code */
37 : : #define TABSIZE 8
38 : :
39 : : #define MAKE_TOKEN(token_type) token_setup(tok, token, token_type, p_start, p_end)
40 : : #define MAKE_TYPE_COMMENT_TOKEN(token_type, col_offset, end_col_offset) (\
41 : : type_comment_token_setup(tok, token, token_type, col_offset, end_col_offset, p_start, p_end))
42 : : #define ADVANCE_LINENO() \
43 : : tok->lineno++; \
44 : : tok->col_offset = 0;
45 : :
46 : : /* Forward */
47 : : static struct tok_state *tok_new(void);
48 : : static int tok_nextc(struct tok_state *tok);
49 : : static void tok_backup(struct tok_state *tok, int c);
50 : : static int syntaxerror(struct tok_state *tok, const char *format, ...);
51 : :
52 : : /* Spaces in this constant are treated as "zero or more spaces or tabs" when
53 : : tokenizing. */
54 : : static const char* type_comment_prefix = "# type: ";
55 : :
56 : : /* Create and initialize a new tok_state structure */
57 : :
58 : : static struct tok_state *
59 : 1585 : tok_new(void)
60 : : {
61 : 1585 : struct tok_state *tok = (struct tok_state *)PyMem_Malloc(
62 : : sizeof(struct tok_state));
63 [ - + ]: 1585 : if (tok == NULL)
64 : 0 : return NULL;
65 : 1585 : tok->buf = tok->cur = tok->inp = NULL;
66 : 1585 : tok->fp_interactive = 0;
67 : 1585 : tok->interactive_src_start = NULL;
68 : 1585 : tok->interactive_src_end = NULL;
69 : 1585 : tok->start = NULL;
70 : 1585 : tok->end = NULL;
71 : 1585 : tok->done = E_OK;
72 : 1585 : tok->fp = NULL;
73 : 1585 : tok->input = NULL;
74 : 1585 : tok->tabsize = TABSIZE;
75 : 1585 : tok->indent = 0;
76 : 1585 : tok->indstack[0] = 0;
77 : 1585 : tok->atbol = 1;
78 : 1585 : tok->pendin = 0;
79 : 1585 : tok->prompt = tok->nextprompt = NULL;
80 : 1585 : tok->lineno = 0;
81 : 1585 : tok->starting_col_offset = -1;
82 : 1585 : tok->col_offset = -1;
83 : 1585 : tok->level = 0;
84 : 1585 : tok->altindstack[0] = 0;
85 : 1585 : tok->decoding_state = STATE_INIT;
86 : 1585 : tok->decoding_erred = 0;
87 : 1585 : tok->enc = NULL;
88 : 1585 : tok->encoding = NULL;
89 : 1585 : tok->cont_line = 0;
90 : 1585 : tok->filename = NULL;
91 : 1585 : tok->decoding_readline = NULL;
92 : 1585 : tok->decoding_buffer = NULL;
93 : 1585 : tok->type_comments = 0;
94 : 1585 : tok->async_hacks = 0;
95 : 1585 : tok->async_def = 0;
96 : 1585 : tok->async_def_indent = 0;
97 : 1585 : tok->async_def_nl = 0;
98 : 1585 : tok->interactive_underflow = IUNDERFLOW_NORMAL;
99 : 1585 : tok->str = NULL;
100 : 1585 : tok->report_warnings = 1;
101 : : #ifdef Py_DEBUG
102 : : tok->debug = _Py_GetConfig()->parser_debug;
103 : : #endif
104 : 1585 : return tok;
105 : : }
106 : :
107 : : static char *
108 : 146 : new_string(const char *s, Py_ssize_t len, struct tok_state *tok)
109 : : {
110 : 146 : char* result = (char *)PyMem_Malloc(len + 1);
111 [ - + ]: 146 : if (!result) {
112 : 0 : tok->done = E_NOMEM;
113 : 0 : return NULL;
114 : : }
115 : 146 : memcpy(result, s, len);
116 : 146 : result[len] = '\0';
117 : 146 : return result;
118 : : }
119 : :
120 : : static char *
121 : 0 : error_ret(struct tok_state *tok) /* XXX */
122 : : {
123 : 0 : tok->decoding_erred = 1;
124 [ # # # # ]: 0 : if (tok->fp != NULL && tok->buf != NULL) /* see _PyTokenizer_Free */
125 : 0 : PyMem_Free(tok->buf);
126 : 0 : tok->buf = tok->cur = tok->inp = NULL;
127 : 0 : tok->start = NULL;
128 : 0 : tok->end = NULL;
129 : 0 : tok->done = E_DECODE;
130 : 0 : return NULL; /* as if it were EOF */
131 : : }
132 : :
133 : :
134 : : static const char *
135 : 0 : get_normal_name(const char *s) /* for utf-8 and latin-1 */
136 : : {
137 : : char buf[13];
138 : : int i;
139 [ # # ]: 0 : for (i = 0; i < 12; i++) {
140 : 0 : int c = s[i];
141 [ # # ]: 0 : if (c == '\0')
142 : 0 : break;
143 [ # # ]: 0 : else if (c == '_')
144 : 0 : buf[i] = '-';
145 : : else
146 : 0 : buf[i] = tolower(c);
147 : : }
148 : 0 : buf[i] = '\0';
149 [ # # ]: 0 : if (strcmp(buf, "utf-8") == 0 ||
150 [ # # ]: 0 : strncmp(buf, "utf-8-", 6) == 0)
151 : 0 : return "utf-8";
152 [ # # ]: 0 : else if (strcmp(buf, "latin-1") == 0 ||
153 [ # # ]: 0 : strcmp(buf, "iso-8859-1") == 0 ||
154 [ # # ]: 0 : strcmp(buf, "iso-latin-1") == 0 ||
155 [ # # ]: 0 : strncmp(buf, "latin-1-", 8) == 0 ||
156 [ # # ]: 0 : strncmp(buf, "iso-8859-1-", 11) == 0 ||
157 [ # # ]: 0 : strncmp(buf, "iso-latin-1-", 12) == 0)
158 : 0 : return "iso-8859-1";
159 : : else
160 : 0 : return s;
161 : : }
162 : :
163 : : /* Return the coding spec in S, or NULL if none is found. */
164 : :
165 : : static int
166 : 1476 : get_coding_spec(const char *s, char **spec, Py_ssize_t size, struct tok_state *tok)
167 : : {
168 : : Py_ssize_t i;
169 : 1476 : *spec = NULL;
170 : : /* Coding spec must be in a comment, and that comment must be
171 : : * the only statement on the source code line. */
172 [ + + ]: 1476 : for (i = 0; i < size - 6; i++) {
173 [ + + ]: 1097 : if (s[i] == '#')
174 : 58 : break;
175 [ + - + - : 1039 : if (s[i] != ' ' && s[i] != '\t' && s[i] != '\014')
+ - ]
176 : 1039 : return 1;
177 : : }
178 [ + + ]: 2897 : for (; i < size - 6; i++) { /* XXX inefficient search */
179 : 2460 : const char* t = s + i;
180 [ - + ]: 2460 : if (memcmp(t, "coding", 6) == 0) {
181 : 0 : const char* begin = NULL;
182 : 0 : t += 6;
183 [ # # # # ]: 0 : if (t[0] != ':' && t[0] != '=')
184 : 0 : continue;
185 : : do {
186 : 0 : t++;
187 [ # # # # ]: 0 : } while (t[0] == ' ' || t[0] == '\t');
188 : :
189 : 0 : begin = t;
190 [ # # ]: 0 : while (Py_ISALNUM(t[0]) ||
191 [ # # # # : 0 : t[0] == '-' || t[0] == '_' || t[0] == '.')
# # ]
192 : 0 : t++;
193 : :
194 [ # # ]: 0 : if (begin < t) {
195 : 0 : char* r = new_string(begin, t - begin, tok);
196 : : const char* q;
197 [ # # ]: 0 : if (!r)
198 : 0 : return 0;
199 : 0 : q = get_normal_name(r);
200 [ # # ]: 0 : if (r != q) {
201 : 0 : PyMem_Free(r);
202 : 0 : r = new_string(q, strlen(q), tok);
203 [ # # ]: 0 : if (!r)
204 : 0 : return 0;
205 : : }
206 : 0 : *spec = r;
207 : 0 : break;
208 : : }
209 : : }
210 : : }
211 : 437 : return 1;
212 : : }
213 : :
214 : : /* Check whether the line contains a coding spec. If it does,
215 : : invoke the set_readline function for the new encoding.
216 : : This function receives the tok_state and the new encoding.
217 : : Return 1 on success, 0 on failure. */
218 : :
219 : : static int
220 : 1476 : check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok,
221 : : int set_readline(struct tok_state *, const char *))
222 : : {
223 : : char *cs;
224 [ - + ]: 1476 : if (tok->cont_line) {
225 : : /* It's a continuation line, so it can't be a coding spec. */
226 : 0 : tok->decoding_state = STATE_NORMAL;
227 : 0 : return 1;
228 : : }
229 [ - + ]: 1476 : if (!get_coding_spec(line, &cs, size, tok)) {
230 : 0 : return 0;
231 : : }
232 [ + - ]: 1476 : if (!cs) {
233 : : Py_ssize_t i;
234 [ + + ]: 1476 : for (i = 0; i < size; i++) {
235 [ + + + + : 1471 : if (line[i] == '#' || line[i] == '\n' || line[i] == '\r')
+ - ]
236 : : break;
237 [ + - + - : 1401 : if (line[i] != ' ' && line[i] != '\t' && line[i] != '\014') {
+ - ]
238 : : /* Stop checking coding spec after a line containing
239 : : * anything except a comment. */
240 : 1401 : tok->decoding_state = STATE_NORMAL;
241 : 1401 : break;
242 : : }
243 : : }
244 : 1476 : return 1;
245 : : }
246 : 0 : tok->decoding_state = STATE_NORMAL;
247 [ # # ]: 0 : if (tok->encoding == NULL) {
248 : : assert(tok->decoding_readline == NULL);
249 [ # # # # ]: 0 : if (strcmp(cs, "utf-8") != 0 && !set_readline(tok, cs)) {
250 : 0 : error_ret(tok);
251 : 0 : PyErr_Format(PyExc_SyntaxError, "encoding problem: %s", cs);
252 : 0 : PyMem_Free(cs);
253 : 0 : return 0;
254 : : }
255 : 0 : tok->encoding = cs;
256 : : } else { /* then, compare cs with BOM */
257 [ # # ]: 0 : if (strcmp(tok->encoding, cs) != 0) {
258 : 0 : error_ret(tok);
259 : 0 : PyErr_Format(PyExc_SyntaxError,
260 : : "encoding problem: %s with BOM", cs);
261 : 0 : PyMem_Free(cs);
262 : 0 : return 0;
263 : : }
264 : 0 : PyMem_Free(cs);
265 : : }
266 : 0 : return 1;
267 : : }
268 : :
269 : : /* See whether the file starts with a BOM. If it does,
270 : : invoke the set_readline function with the new encoding.
271 : : Return 1 on success, 0 on failure. */
272 : :
273 : : static int
274 : 1439 : check_bom(int get_char(struct tok_state *),
275 : : void unget_char(int, struct tok_state *),
276 : : int set_readline(struct tok_state *, const char *),
277 : : struct tok_state *tok)
278 : : {
279 : : int ch1, ch2, ch3;
280 : 1439 : ch1 = get_char(tok);
281 : 1439 : tok->decoding_state = STATE_SEEK_CODING;
282 [ - + ]: 1439 : if (ch1 == EOF) {
283 : 0 : return 1;
284 [ - + ]: 1439 : } else if (ch1 == 0xEF) {
285 : 0 : ch2 = get_char(tok);
286 [ # # ]: 0 : if (ch2 != 0xBB) {
287 : 0 : unget_char(ch2, tok);
288 : 0 : unget_char(ch1, tok);
289 : 0 : return 1;
290 : : }
291 : 0 : ch3 = get_char(tok);
292 [ # # ]: 0 : if (ch3 != 0xBF) {
293 : 0 : unget_char(ch3, tok);
294 : 0 : unget_char(ch2, tok);
295 : 0 : unget_char(ch1, tok);
296 : 0 : return 1;
297 : : }
298 : : } else {
299 : 1439 : unget_char(ch1, tok);
300 : 1439 : return 1;
301 : : }
302 [ # # ]: 0 : if (tok->encoding != NULL)
303 : 0 : PyMem_Free(tok->encoding);
304 : 0 : tok->encoding = new_string("utf-8", 5, tok);
305 [ # # ]: 0 : if (!tok->encoding)
306 : 0 : return 0;
307 : : /* No need to set_readline: input is already utf-8 */
308 : 0 : return 1;
309 : : }
310 : :
311 : : static int
312 : 0 : tok_concatenate_interactive_new_line(struct tok_state *tok, const char *line) {
313 : : assert(tok->fp_interactive);
314 : :
315 [ # # ]: 0 : if (!line) {
316 : 0 : return 0;
317 : : }
318 : :
319 : 0 : Py_ssize_t current_size = tok->interactive_src_end - tok->interactive_src_start;
320 : 0 : Py_ssize_t line_size = strlen(line);
321 [ # # ]: 0 : char last_char = line[line_size > 0 ? line_size - 1 : line_size];
322 [ # # ]: 0 : if (last_char != '\n') {
323 : 0 : line_size += 1;
324 : : }
325 : 0 : char* new_str = tok->interactive_src_start;
326 : :
327 : 0 : new_str = PyMem_Realloc(new_str, current_size + line_size + 1);
328 [ # # ]: 0 : if (!new_str) {
329 [ # # ]: 0 : if (tok->interactive_src_start) {
330 : 0 : PyMem_Free(tok->interactive_src_start);
331 : : }
332 : 0 : tok->interactive_src_start = NULL;
333 : 0 : tok->interactive_src_end = NULL;
334 : 0 : tok->done = E_NOMEM;
335 : 0 : return -1;
336 : : }
337 : 0 : strcpy(new_str + current_size, line);
338 [ # # ]: 0 : if (last_char != '\n') {
339 : : /* Last line does not end in \n, fake one */
340 : 0 : new_str[current_size + line_size - 1] = '\n';
341 : 0 : new_str[current_size + line_size] = '\0';
342 : : }
343 : 0 : tok->interactive_src_start = new_str;
344 : 0 : tok->interactive_src_end = new_str + current_size + line_size;
345 : 0 : return 0;
346 : : }
347 : :
348 : :
349 : : /* Read a line of text from TOK into S, using the stream in TOK.
350 : : Return NULL on failure, else S.
351 : :
352 : : On entry, tok->decoding_buffer will be one of:
353 : : 1) NULL: need to call tok->decoding_readline to get a new line
354 : : 2) PyUnicodeObject *: decoding_feof has called tok->decoding_readline and
355 : : stored the result in tok->decoding_buffer
356 : : 3) PyByteArrayObject *: previous call to tok_readline_recode did not have enough room
357 : : (in the s buffer) to copy entire contents of the line read
358 : : by tok->decoding_readline. tok->decoding_buffer has the overflow.
359 : : In this case, tok_readline_recode is called in a loop (with an expanded buffer)
360 : : until the buffer ends with a '\n' (or until the end of the file is
361 : : reached): see tok_nextc and its calls to tok_reserve_buf.
362 : : */
363 : :
364 : : static int
365 : 2365 : tok_reserve_buf(struct tok_state *tok, Py_ssize_t size)
366 : : {
367 : 2365 : Py_ssize_t cur = tok->cur - tok->buf;
368 : 2365 : Py_ssize_t oldsize = tok->inp - tok->buf;
369 : 2365 : Py_ssize_t newsize = oldsize + Py_MAX(size, oldsize >> 1);
370 [ + + ]: 2365 : if (newsize > tok->end - tok->buf) {
371 : 204 : char *newbuf = tok->buf;
372 [ + - ]: 204 : Py_ssize_t start = tok->start == NULL ? -1 : tok->start - tok->buf;
373 [ + - ]: 204 : Py_ssize_t line_start = tok->start == NULL ? -1 : tok->line_start - tok->buf;
374 : 204 : Py_ssize_t multi_line_start = tok->multi_line_start - tok->buf;
375 : 204 : newbuf = (char *)PyMem_Realloc(newbuf, newsize);
376 [ - + ]: 204 : if (newbuf == NULL) {
377 : 0 : tok->done = E_NOMEM;
378 : 0 : return 0;
379 : : }
380 : 204 : tok->buf = newbuf;
381 : 204 : tok->cur = tok->buf + cur;
382 : 204 : tok->inp = tok->buf + oldsize;
383 : 204 : tok->end = tok->buf + newsize;
384 [ + - ]: 204 : tok->start = start < 0 ? NULL : tok->buf + start;
385 [ + - ]: 204 : tok->line_start = line_start < 0 ? NULL : tok->buf + line_start;
386 [ + - ]: 204 : tok->multi_line_start = multi_line_start < 0 ? NULL : tok->buf + multi_line_start;
387 : : }
388 : 2365 : return 1;
389 : : }
390 : :
391 : : static inline int
392 : 114677 : contains_null_bytes(const char* str, size_t size) {
393 : 114677 : return memchr(str, 0, size) != NULL;
394 : : }
395 : :
396 : : static int
397 : 0 : tok_readline_recode(struct tok_state *tok) {
398 : : PyObject *line;
399 : : const char *buf;
400 : : Py_ssize_t buflen;
401 : 0 : line = tok->decoding_buffer;
402 [ # # ]: 0 : if (line == NULL) {
403 : 0 : line = PyObject_CallNoArgs(tok->decoding_readline);
404 [ # # ]: 0 : if (line == NULL) {
405 : 0 : error_ret(tok);
406 : 0 : goto error;
407 : : }
408 : : }
409 : : else {
410 : 0 : tok->decoding_buffer = NULL;
411 : : }
412 : 0 : buf = PyUnicode_AsUTF8AndSize(line, &buflen);
413 [ # # ]: 0 : if (buf == NULL) {
414 : 0 : error_ret(tok);
415 : 0 : goto error;
416 : : }
417 : : // Make room for the null terminator *and* potentially
418 : : // an extra newline character that we may need to artificially
419 : : // add.
420 : 0 : size_t buffer_size = buflen + 2;
421 [ # # ]: 0 : if (!tok_reserve_buf(tok, buffer_size)) {
422 : 0 : goto error;
423 : : }
424 : 0 : memcpy(tok->inp, buf, buflen);
425 : 0 : tok->inp += buflen;
426 : 0 : *tok->inp = '\0';
427 [ # # # # ]: 0 : if (tok->fp_interactive &&
428 : 0 : tok_concatenate_interactive_new_line(tok, buf) == -1) {
429 : 0 : goto error;
430 : : }
431 : 0 : Py_DECREF(line);
432 : 0 : return 1;
433 : 0 : error:
434 : 0 : Py_XDECREF(line);
435 : 0 : return 0;
436 : : }
437 : :
438 : : /* Set the readline function for TOK to a StreamReader's
439 : : readline function. The StreamReader is named ENC.
440 : :
441 : : This function is called from check_bom and check_coding_spec.
442 : :
443 : : ENC is usually identical to the future value of tok->encoding,
444 : : except for the (currently unsupported) case of UTF-16.
445 : :
446 : : Return 1 on success, 0 on failure. */
447 : :
448 : : static int
449 : 0 : fp_setreadl(struct tok_state *tok, const char* enc)
450 : : {
451 : : PyObject *readline, *open, *stream;
452 : : int fd;
453 : : long pos;
454 : :
455 : 0 : fd = fileno(tok->fp);
456 : : /* Due to buffering the file offset for fd can be different from the file
457 : : * position of tok->fp. If tok->fp was opened in text mode on Windows,
458 : : * its file position counts CRLF as one char and can't be directly mapped
459 : : * to the file offset for fd. Instead we step back one byte and read to
460 : : * the end of line.*/
461 : 0 : pos = ftell(tok->fp);
462 [ # # # # ]: 0 : if (pos == -1 ||
463 [ # # ]: 0 : lseek(fd, (off_t)(pos > 0 ? pos - 1 : pos), SEEK_SET) == (off_t)-1) {
464 : 0 : PyErr_SetFromErrnoWithFilename(PyExc_OSError, NULL);
465 : 0 : return 0;
466 : : }
467 : :
468 : 0 : open = _PyImport_GetModuleAttrString("io", "open");
469 [ # # ]: 0 : if (open == NULL) {
470 : 0 : return 0;
471 : : }
472 : 0 : stream = PyObject_CallFunction(open, "isisOOO",
473 : : fd, "r", -1, enc, Py_None, Py_None, Py_False);
474 : 0 : Py_DECREF(open);
475 [ # # ]: 0 : if (stream == NULL) {
476 : 0 : return 0;
477 : : }
478 : :
479 : 0 : readline = PyObject_GetAttr(stream, &_Py_ID(readline));
480 : 0 : Py_DECREF(stream);
481 [ # # ]: 0 : if (readline == NULL) {
482 : 0 : return 0;
483 : : }
484 : 0 : Py_XSETREF(tok->decoding_readline, readline);
485 : :
486 [ # # ]: 0 : if (pos > 0) {
487 : 0 : PyObject *bufobj = _PyObject_CallNoArgs(readline);
488 [ # # ]: 0 : if (bufobj == NULL) {
489 : 0 : return 0;
490 : : }
491 : 0 : Py_DECREF(bufobj);
492 : : }
493 : :
494 : 0 : return 1;
495 : : }
496 : :
497 : : /* Fetch the next byte from TOK. */
498 : :
499 : 22 : static int fp_getc(struct tok_state *tok) {
500 : 22 : return getc(tok->fp);
501 : : }
502 : :
503 : : /* Unfetch the last byte back into TOK. */
504 : :
505 : 22 : static void fp_ungetc(int c, struct tok_state *tok) {
506 : 22 : ungetc(c, tok->fp);
507 : 22 : }
508 : :
509 : : /* Check whether the characters at s start a valid
510 : : UTF-8 sequence. Return the number of characters forming
511 : : the sequence if yes, 0 if not. The special cases match
512 : : those in stringlib/codecs.h:utf8_decode.
513 : : */
514 : : static int
515 : 73756 : valid_utf8(const unsigned char* s)
516 : : {
517 : 73756 : int expected = 0;
518 : : int length;
519 [ + - ]: 73756 : if (*s < 0x80) {
520 : : /* single-byte code */
521 : 73756 : return 1;
522 : : }
523 [ # # ]: 0 : else if (*s < 0xE0) {
524 : : /* \xC2\x80-\xDF\xBF -- 0080-07FF */
525 [ # # ]: 0 : if (*s < 0xC2) {
526 : : /* invalid sequence
527 : : \x80-\xBF -- continuation byte
528 : : \xC0-\xC1 -- fake 0000-007F */
529 : 0 : return 0;
530 : : }
531 : 0 : expected = 1;
532 : : }
533 [ # # ]: 0 : else if (*s < 0xF0) {
534 : : /* \xE0\xA0\x80-\xEF\xBF\xBF -- 0800-FFFF */
535 [ # # # # ]: 0 : if (*s == 0xE0 && *(s + 1) < 0xA0) {
536 : : /* invalid sequence
537 : : \xE0\x80\x80-\xE0\x9F\xBF -- fake 0000-0800 */
538 : 0 : return 0;
539 : : }
540 [ # # # # ]: 0 : else if (*s == 0xED && *(s + 1) >= 0xA0) {
541 : : /* Decoding UTF-8 sequences in range \xED\xA0\x80-\xED\xBF\xBF
542 : : will result in surrogates in range D800-DFFF. Surrogates are
543 : : not valid UTF-8 so they are rejected.
544 : : See https://www.unicode.org/versions/Unicode5.2.0/ch03.pdf
545 : : (table 3-7) and http://www.rfc-editor.org/rfc/rfc3629.txt */
546 : 0 : return 0;
547 : : }
548 : 0 : expected = 2;
549 : : }
550 [ # # ]: 0 : else if (*s < 0xF5) {
551 : : /* \xF0\x90\x80\x80-\xF4\x8F\xBF\xBF -- 10000-10FFFF */
552 [ # # # # ]: 0 : if (*(s + 1) < 0x90 ? *s == 0xF0 : *s == 0xF4) {
553 : : /* invalid sequence -- one of:
554 : : \xF0\x80\x80\x80-\xF0\x8F\xBF\xBF -- fake 0000-FFFF
555 : : \xF4\x90\x80\x80- -- 110000- overflow */
556 : 0 : return 0;
557 : : }
558 : 0 : expected = 3;
559 : : }
560 : : else {
561 : : /* invalid start byte */
562 : 0 : return 0;
563 : : }
564 : 0 : length = expected + 1;
565 [ # # ]: 0 : for (; expected; expected--)
566 [ # # # # ]: 0 : if (s[expected] < 0x80 || s[expected] >= 0xC0)
567 : 0 : return 0;
568 : 0 : return length;
569 : : }
570 : :
571 : : static int
572 : 2343 : ensure_utf8(char *line, struct tok_state *tok)
573 : : {
574 : 2343 : int badchar = 0;
575 : : unsigned char *c;
576 : : int length;
577 [ + + ]: 76099 : for (c = (unsigned char *)line; *c; c += length) {
578 [ - + ]: 73756 : if (!(length = valid_utf8(c))) {
579 : 0 : badchar = *c;
580 : 0 : break;
581 : : }
582 : : }
583 [ - + ]: 2343 : if (badchar) {
584 : 0 : PyErr_Format(PyExc_SyntaxError,
585 : : "Non-UTF-8 code starting with '\\x%.2x' "
586 : : "in file %U on line %i, "
587 : : "but no encoding declared; "
588 : : "see https://peps.python.org/pep-0263/ for details",
589 : : badchar, tok->filename, tok->lineno);
590 : 0 : return 0;
591 : : }
592 : 2343 : return 1;
593 : : }
594 : :
595 : : /* Fetch a byte from TOK, using the string buffer. */
596 : :
597 : : static int
598 : 1417 : buf_getc(struct tok_state *tok) {
599 : 1417 : return Py_CHARMASK(*tok->str++);
600 : : }
601 : :
602 : : /* Unfetch a byte from TOK, using the string buffer. */
603 : :
604 : : static void
605 : 1417 : buf_ungetc(int c, struct tok_state *tok) {
606 : 1417 : tok->str--;
607 : : assert(Py_CHARMASK(*tok->str) == c); /* tok->cur may point to read-only segment */
608 : 1417 : }
609 : :
610 : : /* Set the readline function for TOK to ENC. For the string-based
611 : : tokenizer, this means to just record the encoding. */
612 : :
613 : : static int
614 : 0 : buf_setreadl(struct tok_state *tok, const char* enc) {
615 : 0 : tok->enc = enc;
616 : 0 : return 1;
617 : : }
618 : :
619 : : /* Return a UTF-8 encoding Python string object from the
620 : : C byte string STR, which is encoded with ENC. */
621 : :
622 : : static PyObject *
623 : 0 : translate_into_utf8(const char* str, const char* enc) {
624 : : PyObject *utf8;
625 : 0 : PyObject* buf = PyUnicode_Decode(str, strlen(str), enc, NULL);
626 [ # # ]: 0 : if (buf == NULL)
627 : 0 : return NULL;
628 : 0 : utf8 = PyUnicode_AsUTF8String(buf);
629 : 0 : Py_DECREF(buf);
630 : 0 : return utf8;
631 : : }
632 : :
633 : :
634 : : static char *
635 : 1563 : translate_newlines(const char *s, int exec_input, struct tok_state *tok) {
636 : 1563 : int skip_next_lf = 0;
637 : 1563 : size_t needed_length = strlen(s) + 2, final_length;
638 : : char *buf, *current;
639 : 1563 : char c = '\0';
640 : 1563 : buf = PyMem_Malloc(needed_length);
641 [ - + ]: 1563 : if (buf == NULL) {
642 : 0 : tok->done = E_NOMEM;
643 : 0 : return NULL;
644 : : }
645 [ + + ]: 5272757 : for (current = buf; *s; s++, current++) {
646 : 5271194 : c = *s;
647 [ - + ]: 5271194 : if (skip_next_lf) {
648 : 0 : skip_next_lf = 0;
649 [ # # ]: 0 : if (c == '\n') {
650 : 0 : c = *++s;
651 [ # # ]: 0 : if (!c)
652 : 0 : break;
653 : : }
654 : : }
655 [ - + ]: 5271194 : if (c == '\r') {
656 : 0 : skip_next_lf = 1;
657 : 0 : c = '\n';
658 : : }
659 : 5271194 : *current = c;
660 : : }
661 : : /* If this is exec input, add a newline to the end of the string if
662 : : there isn't one already. */
663 [ + + + + ]: 1563 : if (exec_input && c != '\n') {
664 : 1246 : *current = '\n';
665 : 1246 : current++;
666 : : }
667 : 1563 : *current = '\0';
668 : 1563 : final_length = current - buf + 1;
669 [ + + + - ]: 1563 : if (final_length < needed_length && final_length) {
670 : : /* should never fail */
671 : 317 : char* result = PyMem_Realloc(buf, final_length);
672 [ - + ]: 317 : if (result == NULL) {
673 : 0 : PyMem_Free(buf);
674 : : }
675 : 317 : buf = result;
676 : : }
677 : 1563 : return buf;
678 : : }
679 : :
680 : : /* Decode a byte string STR for use as the buffer of TOK.
681 : : Look for encoding declarations inside STR, and record them
682 : : inside TOK. */
683 : :
684 : : static char *
685 : 1417 : decode_str(const char *input, int single, struct tok_state *tok)
686 : : {
687 : 1417 : PyObject* utf8 = NULL;
688 : : char *str;
689 : : const char *s;
690 : 1417 : const char *newl[2] = {NULL, NULL};
691 : 1417 : int lineno = 0;
692 : 1417 : tok->input = str = translate_newlines(input, single, tok);
693 [ - + ]: 1417 : if (str == NULL)
694 : 0 : return NULL;
695 : 1417 : tok->enc = NULL;
696 : 1417 : tok->str = str;
697 [ - + ]: 1417 : if (!check_bom(buf_getc, buf_ungetc, buf_setreadl, tok))
698 : 0 : return error_ret(tok);
699 : 1417 : str = tok->str; /* string after BOM if any */
700 : : assert(str);
701 [ - + ]: 1417 : if (tok->enc != NULL) {
702 : 0 : utf8 = translate_into_utf8(str, tok->enc);
703 [ # # ]: 0 : if (utf8 == NULL)
704 : 0 : return error_ret(tok);
705 : 0 : str = PyBytes_AsString(utf8);
706 : : }
707 : 26570 : for (s = str;; s++) {
708 [ + + ]: 26570 : if (*s == '\0') break;
709 [ + + ]: 25331 : else if (*s == '\n') {
710 : : assert(lineno < 2);
711 : 1595 : newl[lineno] = s;
712 : 1595 : lineno++;
713 [ + + ]: 1595 : if (lineno == 2) break;
714 : : }
715 : : }
716 : 1417 : tok->enc = NULL;
717 : : /* need to check line 1 and 2 separately since check_coding_spec
718 : : assumes a single line as input */
719 [ + - ]: 1417 : if (newl[0]) {
720 [ - + ]: 1417 : if (!check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) {
721 : 0 : return NULL;
722 : : }
723 [ + - + + : 1417 : if (tok->enc == NULL && tok->decoding_state != STATE_NORMAL && newl[1]) {
+ + ]
724 [ - + ]: 37 : if (!check_coding_spec(newl[0]+1, newl[1] - newl[0],
725 : : tok, buf_setreadl))
726 : 0 : return NULL;
727 : : }
728 : : }
729 [ - + ]: 1417 : if (tok->enc != NULL) {
730 : : assert(utf8 == NULL);
731 : 0 : utf8 = translate_into_utf8(str, tok->enc);
732 [ # # ]: 0 : if (utf8 == NULL)
733 : 0 : return error_ret(tok);
734 : 0 : str = PyBytes_AS_STRING(utf8);
735 : : }
736 : : assert(tok->decoding_buffer == NULL);
737 : 1417 : tok->decoding_buffer = utf8; /* CAUTION */
738 : 1417 : return str;
739 : : }
740 : :
741 : : /* Set up tokenizer for string */
742 : :
743 : : struct tok_state *
744 : 1417 : _PyTokenizer_FromString(const char *str, int exec_input)
745 : : {
746 : 1417 : struct tok_state *tok = tok_new();
747 : : char *decoded;
748 : :
749 [ - + ]: 1417 : if (tok == NULL)
750 : 0 : return NULL;
751 : 1417 : decoded = decode_str(str, exec_input, tok);
752 [ - + ]: 1417 : if (decoded == NULL) {
753 : 0 : _PyTokenizer_Free(tok);
754 : 0 : return NULL;
755 : : }
756 : :
757 : 1417 : tok->buf = tok->cur = tok->inp = decoded;
758 : 1417 : tok->end = decoded;
759 : 1417 : return tok;
760 : : }
761 : :
762 : : /* Set up tokenizer for UTF-8 string */
763 : :
764 : : struct tok_state *
765 : 146 : _PyTokenizer_FromUTF8(const char *str, int exec_input)
766 : : {
767 : 146 : struct tok_state *tok = tok_new();
768 : : char *translated;
769 [ - + ]: 146 : if (tok == NULL)
770 : 0 : return NULL;
771 : 146 : tok->input = translated = translate_newlines(str, exec_input, tok);
772 [ - + ]: 146 : if (translated == NULL) {
773 : 0 : _PyTokenizer_Free(tok);
774 : 0 : return NULL;
775 : : }
776 : 146 : tok->decoding_state = STATE_NORMAL;
777 : 146 : tok->enc = NULL;
778 : 146 : tok->str = translated;
779 : 146 : tok->encoding = new_string("utf-8", 5, tok);
780 [ - + ]: 146 : if (!tok->encoding) {
781 : 0 : _PyTokenizer_Free(tok);
782 : 0 : return NULL;
783 : : }
784 : :
785 : 146 : tok->buf = tok->cur = tok->inp = translated;
786 : 146 : tok->end = translated;
787 : 146 : return tok;
788 : : }
789 : :
790 : : /* Set up tokenizer for file */
791 : :
792 : : struct tok_state *
793 : 22 : _PyTokenizer_FromFile(FILE *fp, const char* enc,
794 : : const char *ps1, const char *ps2)
795 : : {
796 : 22 : struct tok_state *tok = tok_new();
797 [ - + ]: 22 : if (tok == NULL)
798 : 0 : return NULL;
799 [ - + ]: 22 : if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) {
800 : 0 : _PyTokenizer_Free(tok);
801 : 0 : return NULL;
802 : : }
803 : 22 : tok->cur = tok->inp = tok->buf;
804 : 22 : tok->end = tok->buf + BUFSIZ;
805 : 22 : tok->fp = fp;
806 : 22 : tok->prompt = ps1;
807 : 22 : tok->nextprompt = ps2;
808 [ - + ]: 22 : if (enc != NULL) {
809 : : /* Must copy encoding declaration since it
810 : : gets copied into the parse tree. */
811 : 0 : tok->encoding = new_string(enc, strlen(enc), tok);
812 [ # # ]: 0 : if (!tok->encoding) {
813 : 0 : _PyTokenizer_Free(tok);
814 : 0 : return NULL;
815 : : }
816 : 0 : tok->decoding_state = STATE_NORMAL;
817 : : }
818 : 22 : return tok;
819 : : }
820 : :
821 : : /* Free a tok_state structure */
822 : :
823 : : void
824 : 1585 : _PyTokenizer_Free(struct tok_state *tok)
825 : : {
826 [ + + ]: 1585 : if (tok->encoding != NULL) {
827 : 146 : PyMem_Free(tok->encoding);
828 : : }
829 : 1585 : Py_XDECREF(tok->decoding_readline);
830 : 1585 : Py_XDECREF(tok->decoding_buffer);
831 : 1585 : Py_XDECREF(tok->filename);
832 [ + + + - ]: 1585 : if (tok->fp != NULL && tok->buf != NULL) {
833 : 22 : PyMem_Free(tok->buf);
834 : : }
835 [ + + ]: 1585 : if (tok->input) {
836 : 1563 : PyMem_Free(tok->input);
837 : : }
838 [ - + ]: 1585 : if (tok->interactive_src_start != NULL) {
839 : 0 : PyMem_Free(tok->interactive_src_start);
840 : : }
841 : 1585 : PyMem_Free(tok);
842 : 1585 : }
843 : :
844 : : static int
845 : 2365 : tok_readline_raw(struct tok_state *tok)
846 : : {
847 : : do {
848 [ - + ]: 2365 : if (!tok_reserve_buf(tok, BUFSIZ)) {
849 : 22 : return 0;
850 : : }
851 : 2365 : int n_chars = (int)(tok->end - tok->inp);
852 : 2365 : size_t line_size = 0;
853 : 2365 : char *line = _Py_UniversalNewlineFgetsWithSize(tok->inp, n_chars, tok->fp, NULL, &line_size);
854 [ + + ]: 2365 : if (line == NULL) {
855 : 22 : return 1;
856 : : }
857 [ - + - - ]: 2343 : if (tok->fp_interactive &&
858 : 0 : tok_concatenate_interactive_new_line(tok, line) == -1) {
859 : 0 : return 0;
860 : : }
861 : 2343 : tok->inp += line_size;
862 [ - + ]: 2343 : if (tok->inp == tok->buf) {
863 : 0 : return 0;
864 : : }
865 [ - + ]: 2343 : } while (tok->inp[-1] != '\n');
866 : 2343 : return 1;
867 : : }
868 : :
869 : : static int
870 : 112608 : tok_underflow_string(struct tok_state *tok) {
871 : 112608 : char *end = strchr(tok->inp, '\n');
872 [ + + ]: 112608 : if (end != NULL) {
873 : 112254 : end++;
874 : : }
875 : : else {
876 : 354 : end = strchr(tok->inp, '\0');
877 [ + + ]: 354 : if (end == tok->inp) {
878 : 274 : tok->done = E_EOF;
879 : 274 : return 0;
880 : : }
881 : : }
882 [ + + ]: 112334 : if (tok->start == NULL) {
883 : 95769 : tok->buf = tok->cur;
884 : : }
885 : 112334 : tok->line_start = tok->cur;
886 : 112334 : ADVANCE_LINENO();
887 : 112334 : tok->inp = end;
888 : 112334 : return 1;
889 : : }
890 : :
891 : : static int
892 : 0 : tok_underflow_interactive(struct tok_state *tok) {
893 [ # # ]: 0 : if (tok->interactive_underflow == IUNDERFLOW_STOP) {
894 : 0 : tok->done = E_INTERACT_STOP;
895 : 0 : return 1;
896 : : }
897 [ # # ]: 0 : char *newtok = PyOS_Readline(tok->fp ? tok->fp : stdin, stdout, tok->prompt);
898 [ # # ]: 0 : if (newtok != NULL) {
899 : 0 : char *translated = translate_newlines(newtok, 0, tok);
900 : 0 : PyMem_Free(newtok);
901 [ # # ]: 0 : if (translated == NULL) {
902 : 0 : return 0;
903 : : }
904 : 0 : newtok = translated;
905 : : }
906 [ # # # # : 0 : if (tok->encoding && newtok && *newtok) {
# # ]
907 : : /* Recode to UTF-8 */
908 : : Py_ssize_t buflen;
909 : : const char* buf;
910 : 0 : PyObject *u = translate_into_utf8(newtok, tok->encoding);
911 : 0 : PyMem_Free(newtok);
912 [ # # ]: 0 : if (u == NULL) {
913 : 0 : tok->done = E_DECODE;
914 : 0 : return 0;
915 : : }
916 : 0 : buflen = PyBytes_GET_SIZE(u);
917 : 0 : buf = PyBytes_AS_STRING(u);
918 : 0 : newtok = PyMem_Malloc(buflen+1);
919 [ # # ]: 0 : if (newtok == NULL) {
920 : 0 : Py_DECREF(u);
921 : 0 : tok->done = E_NOMEM;
922 : 0 : return 0;
923 : : }
924 : 0 : strcpy(newtok, buf);
925 : 0 : Py_DECREF(u);
926 : : }
927 [ # # # # ]: 0 : if (tok->fp_interactive &&
928 : 0 : tok_concatenate_interactive_new_line(tok, newtok) == -1) {
929 : 0 : PyMem_Free(newtok);
930 : 0 : return 0;
931 : : }
932 [ # # ]: 0 : if (tok->nextprompt != NULL) {
933 : 0 : tok->prompt = tok->nextprompt;
934 : : }
935 [ # # ]: 0 : if (newtok == NULL) {
936 : 0 : tok->done = E_INTR;
937 : : }
938 [ # # ]: 0 : else if (*newtok == '\0') {
939 : 0 : PyMem_Free(newtok);
940 : 0 : tok->done = E_EOF;
941 : : }
942 [ # # ]: 0 : else if (tok->start != NULL) {
943 : 0 : Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf;
944 : 0 : size_t size = strlen(newtok);
945 : 0 : ADVANCE_LINENO();
946 [ # # ]: 0 : if (!tok_reserve_buf(tok, size + 1)) {
947 : 0 : PyMem_Free(tok->buf);
948 : 0 : tok->buf = NULL;
949 : 0 : PyMem_Free(newtok);
950 : 0 : return 0;
951 : : }
952 : 0 : memcpy(tok->cur, newtok, size + 1);
953 : 0 : PyMem_Free(newtok);
954 : 0 : tok->inp += size;
955 : 0 : tok->multi_line_start = tok->buf + cur_multi_line_start;
956 : : }
957 : : else {
958 : 0 : ADVANCE_LINENO();
959 : 0 : PyMem_Free(tok->buf);
960 : 0 : tok->buf = newtok;
961 : 0 : tok->cur = tok->buf;
962 : 0 : tok->line_start = tok->buf;
963 : 0 : tok->inp = strchr(tok->buf, '\0');
964 : 0 : tok->end = tok->inp + 1;
965 : : }
966 [ # # ]: 0 : if (tok->done != E_OK) {
967 [ # # ]: 0 : if (tok->prompt != NULL) {
968 : 0 : PySys_WriteStderr("\n");
969 : : }
970 : 0 : return 0;
971 : : }
972 : 0 : return 1;
973 : : }
974 : :
975 : : static int
976 : 2365 : tok_underflow_file(struct tok_state *tok) {
977 [ + + ]: 2365 : if (tok->start == NULL) {
978 : 2148 : tok->cur = tok->inp = tok->buf;
979 : : }
980 [ + + ]: 2365 : if (tok->decoding_state == STATE_INIT) {
981 : : /* We have not yet determined the encoding.
982 : : If an encoding is found, use the file-pointer
983 : : reader functions from now on. */
984 [ - + ]: 22 : if (!check_bom(fp_getc, fp_ungetc, fp_setreadl, tok)) {
985 : 0 : error_ret(tok);
986 : 0 : return 0;
987 : : }
988 : : assert(tok->decoding_state != STATE_INIT);
989 : : }
990 : : /* Read until '\n' or EOF */
991 [ - + ]: 2365 : if (tok->decoding_readline != NULL) {
992 : : /* We already have a codec associated with this input. */
993 [ # # ]: 0 : if (!tok_readline_recode(tok)) {
994 : 0 : return 0;
995 : : }
996 : : }
997 : : else {
998 : : /* We want a 'raw' read. */
999 [ - + ]: 2365 : if (!tok_readline_raw(tok)) {
1000 : 0 : return 0;
1001 : : }
1002 : : }
1003 [ + + ]: 2365 : if (tok->inp == tok->cur) {
1004 : 22 : tok->done = E_EOF;
1005 : 22 : return 0;
1006 : : }
1007 [ - + ]: 2343 : if (tok->inp[-1] != '\n') {
1008 : : assert(tok->inp + 1 < tok->end);
1009 : : /* Last line does not end in \n, fake one */
1010 : 0 : *tok->inp++ = '\n';
1011 : 0 : *tok->inp = '\0';
1012 : : }
1013 : :
1014 : 2343 : ADVANCE_LINENO();
1015 [ + + ]: 2343 : if (tok->decoding_state != STATE_NORMAL) {
1016 [ - + ]: 22 : if (tok->lineno > 2) {
1017 : 0 : tok->decoding_state = STATE_NORMAL;
1018 : : }
1019 [ - + ]: 22 : else if (!check_coding_spec(tok->cur, strlen(tok->cur),
1020 : : tok, fp_setreadl))
1021 : : {
1022 : 0 : return 0;
1023 : : }
1024 : : }
1025 : : /* The default encoding is UTF-8, so make sure we don't have any
1026 : : non-UTF-8 sequences in it. */
1027 [ + - - + ]: 2343 : if (!tok->encoding && !ensure_utf8(tok->cur, tok)) {
1028 : 0 : error_ret(tok);
1029 : 0 : return 0;
1030 : : }
1031 : : assert(tok->done == E_OK);
1032 : 2343 : return tok->done == E_OK;
1033 : : }
1034 : :
1035 : : #if defined(Py_DEBUG)
1036 : : static void
1037 : : print_escape(FILE *f, const char *s, Py_ssize_t size)
1038 : : {
1039 : : if (s == NULL) {
1040 : : fputs("NULL", f);
1041 : : return;
1042 : : }
1043 : : putc('"', f);
1044 : : while (size-- > 0) {
1045 : : unsigned char c = *s++;
1046 : : switch (c) {
1047 : : case '\n': fputs("\\n", f); break;
1048 : : case '\r': fputs("\\r", f); break;
1049 : : case '\t': fputs("\\t", f); break;
1050 : : case '\f': fputs("\\f", f); break;
1051 : : case '\'': fputs("\\'", f); break;
1052 : : case '"': fputs("\\\"", f); break;
1053 : : default:
1054 : : if (0x20 <= c && c <= 0x7f)
1055 : : putc(c, f);
1056 : : else
1057 : : fprintf(f, "\\x%02x", c);
1058 : : }
1059 : : }
1060 : : putc('"', f);
1061 : : }
1062 : : #endif
1063 : :
1064 : : /* Get next char, updating state; error code goes into tok->done */
1065 : :
1066 : : static int
1067 : 8176812 : tok_nextc(struct tok_state *tok)
1068 : : {
1069 : : int rc;
1070 : : for (;;) {
1071 [ + + ]: 8176812 : if (tok->cur != tok->inp) {
1072 : 8061247 : tok->col_offset++;
1073 : 8061247 : return Py_CHARMASK(*tok->cur++); /* Fast path */
1074 : : }
1075 [ + + ]: 115565 : if (tok->done != E_OK) {
1076 : 592 : return EOF;
1077 : : }
1078 [ + + ]: 114973 : if (tok->fp == NULL) {
1079 : 112608 : rc = tok_underflow_string(tok);
1080 : : }
1081 [ - + ]: 2365 : else if (tok->prompt != NULL) {
1082 : 0 : rc = tok_underflow_interactive(tok);
1083 : : }
1084 : : else {
1085 : 2365 : rc = tok_underflow_file(tok);
1086 : : }
1087 : : #if defined(Py_DEBUG)
1088 : : if (tok->debug) {
1089 : : fprintf(stderr, "line[%d] = ", tok->lineno);
1090 : : print_escape(stderr, tok->cur, tok->inp - tok->cur);
1091 : : fprintf(stderr, " tok->done = %d\n", tok->done);
1092 : : }
1093 : : #endif
1094 [ + + ]: 114973 : if (!rc) {
1095 : 296 : tok->cur = tok->inp;
1096 : 296 : return EOF;
1097 : : }
1098 : 114677 : tok->line_start = tok->cur;
1099 : :
1100 [ - + ]: 114677 : if (contains_null_bytes(tok->line_start, tok->inp - tok->line_start)) {
1101 : 0 : syntaxerror(tok, "source code cannot contain null bytes");
1102 : 0 : tok->cur = tok->inp;
1103 : 0 : return EOF;
1104 : : }
1105 : : }
1106 : : Py_UNREACHABLE();
1107 : : }
1108 : :
1109 : : /* Back-up one character */
1110 : :
1111 : : static void
1112 : 2715643 : tok_backup(struct tok_state *tok, int c)
1113 : : {
1114 [ + + ]: 2715643 : if (c != EOF) {
1115 [ - + ]: 2715051 : if (--tok->cur < tok->buf) {
1116 : 0 : Py_FatalError("tokenizer beginning of buffer");
1117 : : }
1118 [ - + ]: 2715051 : if ((int)(unsigned char)*tok->cur != c) {
1119 : 0 : Py_FatalError("tok_backup: wrong character");
1120 : : }
1121 : 2715051 : tok->col_offset--;
1122 : : }
1123 : 2715643 : }
1124 : :
1125 : : static int
1126 : 0 : _syntaxerror_range(struct tok_state *tok, const char *format,
1127 : : int col_offset, int end_col_offset,
1128 : : va_list vargs)
1129 : : {
1130 : : PyObject *errmsg, *errtext, *args;
1131 : 0 : errmsg = PyUnicode_FromFormatV(format, vargs);
1132 [ # # ]: 0 : if (!errmsg) {
1133 : 0 : goto error;
1134 : : }
1135 : :
1136 : 0 : errtext = PyUnicode_DecodeUTF8(tok->line_start, tok->cur - tok->line_start,
1137 : : "replace");
1138 [ # # ]: 0 : if (!errtext) {
1139 : 0 : goto error;
1140 : : }
1141 : :
1142 [ # # ]: 0 : if (col_offset == -1) {
1143 : 0 : col_offset = (int)PyUnicode_GET_LENGTH(errtext);
1144 : : }
1145 [ # # ]: 0 : if (end_col_offset == -1) {
1146 : 0 : end_col_offset = col_offset;
1147 : : }
1148 : :
1149 : 0 : Py_ssize_t line_len = strcspn(tok->line_start, "\n");
1150 [ # # ]: 0 : if (line_len != tok->cur - tok->line_start) {
1151 : 0 : Py_DECREF(errtext);
1152 : 0 : errtext = PyUnicode_DecodeUTF8(tok->line_start, line_len,
1153 : : "replace");
1154 : : }
1155 [ # # ]: 0 : if (!errtext) {
1156 : 0 : goto error;
1157 : : }
1158 : :
1159 : 0 : args = Py_BuildValue("(O(OiiNii))", errmsg, tok->filename, tok->lineno,
1160 : : col_offset, errtext, tok->lineno, end_col_offset);
1161 [ # # ]: 0 : if (args) {
1162 : 0 : PyErr_SetObject(PyExc_SyntaxError, args);
1163 : 0 : Py_DECREF(args);
1164 : : }
1165 : :
1166 : 0 : error:
1167 : 0 : Py_XDECREF(errmsg);
1168 : 0 : tok->done = E_ERROR;
1169 : 0 : return ERRORTOKEN;
1170 : : }
1171 : :
1172 : : static int
1173 : 0 : syntaxerror(struct tok_state *tok, const char *format, ...)
1174 : : {
1175 : : va_list vargs;
1176 : 0 : va_start(vargs, format);
1177 : 0 : int ret = _syntaxerror_range(tok, format, -1, -1, vargs);
1178 : 0 : va_end(vargs);
1179 : 0 : return ret;
1180 : : }
1181 : :
1182 : : static int
1183 : 0 : syntaxerror_known_range(struct tok_state *tok,
1184 : : int col_offset, int end_col_offset,
1185 : : const char *format, ...)
1186 : : {
1187 : : va_list vargs;
1188 : 0 : va_start(vargs, format);
1189 : 0 : int ret = _syntaxerror_range(tok, format, col_offset, end_col_offset, vargs);
1190 : 0 : va_end(vargs);
1191 : 0 : return ret;
1192 : : }
1193 : :
1194 : : static int
1195 : 0 : indenterror(struct tok_state *tok)
1196 : : {
1197 : 0 : tok->done = E_TABSPACE;
1198 : 0 : tok->cur = tok->inp;
1199 : 0 : return ERRORTOKEN;
1200 : : }
1201 : :
1202 : : static int
1203 : 0 : parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...)
1204 : : {
1205 [ # # ]: 0 : if (!tok->report_warnings) {
1206 : 0 : return 0;
1207 : : }
1208 : :
1209 : : PyObject *errmsg;
1210 : : va_list vargs;
1211 : 0 : va_start(vargs, format);
1212 : 0 : errmsg = PyUnicode_FromFormatV(format, vargs);
1213 : 0 : va_end(vargs);
1214 [ # # ]: 0 : if (!errmsg) {
1215 : 0 : goto error;
1216 : : }
1217 : :
1218 [ # # ]: 0 : if (PyErr_WarnExplicitObject(category, errmsg, tok->filename,
1219 : : tok->lineno, NULL, NULL) < 0) {
1220 [ # # ]: 0 : if (PyErr_ExceptionMatches(category)) {
1221 : : /* Replace the DeprecationWarning exception with a SyntaxError
1222 : : to get a more accurate error report */
1223 : 0 : PyErr_Clear();
1224 : 0 : syntaxerror(tok, "%U", errmsg);
1225 : : }
1226 : 0 : goto error;
1227 : : }
1228 : 0 : Py_DECREF(errmsg);
1229 : 0 : return 0;
1230 : :
1231 : 0 : error:
1232 : 0 : Py_XDECREF(errmsg);
1233 : 0 : tok->done = E_ERROR;
1234 : 0 : return -1;
1235 : : }
1236 : :
1237 : : static int
1238 : 0 : lookahead(struct tok_state *tok, const char *test)
1239 : : {
1240 : 0 : const char *s = test;
1241 : 0 : int res = 0;
1242 : 0 : while (1) {
1243 : 0 : int c = tok_nextc(tok);
1244 [ # # ]: 0 : if (*s == 0) {
1245 [ # # # # : 0 : res = !is_potential_identifier_char(c);
# # # # #
# # # # #
# # ]
1246 : : }
1247 [ # # ]: 0 : else if (c == *s) {
1248 : 0 : s++;
1249 : 0 : continue;
1250 : : }
1251 : :
1252 : 0 : tok_backup(tok, c);
1253 [ # # ]: 0 : while (s != test) {
1254 : 0 : tok_backup(tok, *--s);
1255 : : }
1256 : 0 : return res;
1257 : : }
1258 : : }
1259 : :
1260 : : static int
1261 : 415621 : verify_end_of_number(struct tok_state *tok, int c, const char *kind)
1262 : : {
1263 : : /* Emit a deprecation warning only if the numeric literal is immediately
1264 : : * followed by one of keywords which can occur after a numeric literal
1265 : : * in valid code: "and", "else", "for", "if", "in", "is" and "or".
1266 : : * It allows to gradually deprecate existing valid code without adding
1267 : : * warning before error in most cases of invalid numeric literal (which
1268 : : * would be confusing and break existing tests).
1269 : : * Raise a syntax error with slightly better message than plain
1270 : : * "invalid syntax" if the numeric literal is immediately followed by
1271 : : * other keyword or identifier.
1272 : : */
1273 : 415621 : int r = 0;
1274 [ - + ]: 415621 : if (c == 'a') {
1275 : 0 : r = lookahead(tok, "nd");
1276 : : }
1277 [ - + ]: 415621 : else if (c == 'e') {
1278 : 0 : r = lookahead(tok, "lse");
1279 : : }
1280 [ - + ]: 415621 : else if (c == 'f') {
1281 : 0 : r = lookahead(tok, "or");
1282 : : }
1283 [ - + ]: 415621 : else if (c == 'i') {
1284 : 0 : int c2 = tok_nextc(tok);
1285 [ # # # # : 0 : if (c2 == 'f' || c2 == 'n' || c2 == 's') {
# # ]
1286 : 0 : r = 1;
1287 : : }
1288 : 0 : tok_backup(tok, c2);
1289 : : }
1290 [ - + ]: 415621 : else if (c == 'o') {
1291 : 0 : r = lookahead(tok, "r");
1292 : : }
1293 [ - + ]: 415621 : else if (c == 'n') {
1294 : 0 : r = lookahead(tok, "ot");
1295 : : }
1296 [ - + ]: 415621 : if (r) {
1297 : 0 : tok_backup(tok, c);
1298 [ # # ]: 0 : if (parser_warn(tok, PyExc_SyntaxWarning,
1299 : : "invalid %s literal", kind))
1300 : : {
1301 : 0 : return 0;
1302 : : }
1303 : 0 : tok_nextc(tok);
1304 : : }
1305 : : else /* In future releases, only error will remain. */
1306 [ + + + - : 415621 : if (is_potential_identifier_char(c)) {
+ + + - +
+ + - + -
- + ]
1307 : 0 : tok_backup(tok, c);
1308 : 0 : syntaxerror(tok, "invalid %s literal", kind);
1309 : 0 : return 0;
1310 : : }
1311 : 415621 : return 1;
1312 : : }
1313 : :
1314 : : /* Verify that the identifier follows PEP 3131.
1315 : : All identifier strings are guaranteed to be "ready" unicode objects.
1316 : : */
1317 : : static int
1318 : 0 : verify_identifier(struct tok_state *tok)
1319 : : {
1320 : : PyObject *s;
1321 [ # # ]: 0 : if (tok->decoding_erred)
1322 : 0 : return 0;
1323 : 0 : s = PyUnicode_DecodeUTF8(tok->start, tok->cur - tok->start, NULL);
1324 [ # # ]: 0 : if (s == NULL) {
1325 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
1326 : 0 : tok->done = E_DECODE;
1327 : : }
1328 : : else {
1329 : 0 : tok->done = E_ERROR;
1330 : : }
1331 : 0 : return 0;
1332 : : }
1333 : 0 : Py_ssize_t invalid = _PyUnicode_ScanIdentifier(s);
1334 [ # # ]: 0 : if (invalid < 0) {
1335 : 0 : Py_DECREF(s);
1336 : 0 : tok->done = E_ERROR;
1337 : 0 : return 0;
1338 : : }
1339 : : assert(PyUnicode_GET_LENGTH(s) > 0);
1340 [ # # ]: 0 : if (invalid < PyUnicode_GET_LENGTH(s)) {
1341 : 0 : Py_UCS4 ch = PyUnicode_READ_CHAR(s, invalid);
1342 [ # # ]: 0 : if (invalid + 1 < PyUnicode_GET_LENGTH(s)) {
1343 : : /* Determine the offset in UTF-8 encoded input */
1344 : 0 : Py_SETREF(s, PyUnicode_Substring(s, 0, invalid + 1));
1345 [ # # ]: 0 : if (s != NULL) {
1346 : 0 : Py_SETREF(s, PyUnicode_AsUTF8String(s));
1347 : : }
1348 [ # # ]: 0 : if (s == NULL) {
1349 : 0 : tok->done = E_ERROR;
1350 : 0 : return 0;
1351 : : }
1352 : 0 : tok->cur = (char *)tok->start + PyBytes_GET_SIZE(s);
1353 : : }
1354 : 0 : Py_DECREF(s);
1355 : : // PyUnicode_FromFormatV() does not support %X
1356 : : char hex[9];
1357 : 0 : (void)PyOS_snprintf(hex, sizeof(hex), "%04X", ch);
1358 [ # # ]: 0 : if (Py_UNICODE_ISPRINTABLE(ch)) {
1359 : 0 : syntaxerror(tok, "invalid character '%c' (U+%s)", ch, hex);
1360 : : }
1361 : : else {
1362 : 0 : syntaxerror(tok, "invalid non-printable character U+%s", hex);
1363 : : }
1364 : 0 : return 0;
1365 : : }
1366 : 0 : Py_DECREF(s);
1367 : 0 : return 1;
1368 : : }
1369 : :
1370 : : static int
1371 : 670016 : tok_decimal_tail(struct tok_state *tok)
1372 : : {
1373 : : int c;
1374 : :
1375 : 4 : while (1) {
1376 : : do {
1377 : 670016 : c = tok_nextc(tok);
1378 [ + + ]: 670016 : } while (isdigit(c));
1379 [ + + ]: 283338 : if (c != '_') {
1380 : 283334 : break;
1381 : : }
1382 : 4 : c = tok_nextc(tok);
1383 [ - + ]: 4 : if (!isdigit(c)) {
1384 : 0 : tok_backup(tok, c);
1385 : 0 : syntaxerror(tok, "invalid decimal literal");
1386 : 0 : return 0;
1387 : : }
1388 : : }
1389 : 283334 : return c;
1390 : : }
1391 : :
1392 : : /* Get next token, after space stripping etc. */
1393 : :
1394 : : static inline int
1395 : 130 : tok_continuation_line(struct tok_state *tok) {
1396 : 130 : int c = tok_nextc(tok);
1397 [ - + ]: 130 : if (c != '\n') {
1398 : 0 : tok->done = E_LINECONT;
1399 : 0 : return -1;
1400 : : }
1401 : 130 : c = tok_nextc(tok);
1402 [ - + ]: 130 : if (c == EOF) {
1403 : 0 : tok->done = E_EOF;
1404 : 0 : tok->cur = tok->inp;
1405 : 0 : return -1;
1406 : : } else {
1407 : 130 : tok_backup(tok, c);
1408 : : }
1409 : 130 : return c;
1410 : : }
1411 : :
1412 : : static int
1413 : 0 : type_comment_token_setup(struct tok_state *tok, struct token *token, int type, int col_offset,
1414 : : int end_col_offset, const char *start, const char *end)
1415 : : {
1416 : 0 : token->level = tok->level;
1417 : 0 : token->lineno = token->end_lineno = tok->lineno;
1418 : 0 : token->col_offset = col_offset;
1419 : 0 : token->end_col_offset = end_col_offset;
1420 : 0 : token->start = start;
1421 : 0 : token->end = end;
1422 : 0 : return type;
1423 : : }
1424 : :
1425 : : static int
1426 : 1370610 : token_setup(struct tok_state *tok, struct token *token, int type, const char *start, const char *end)
1427 : : {
1428 : : assert((start == NULL && end == NULL) || (start != NULL && end != NULL));
1429 : 1370610 : token->level = tok->level;
1430 [ + + ]: 1370610 : token->lineno = type == STRING ? tok->first_lineno : tok->lineno;
1431 : 1370610 : token->end_lineno = tok->lineno;
1432 : 1370610 : token->col_offset = token->end_col_offset = -1;
1433 : 1370610 : token->start = start;
1434 : 1370610 : token->end = end;
1435 : :
1436 [ + + + - ]: 1370610 : if (start != NULL && end != NULL) {
1437 : 1324772 : token->col_offset = tok->starting_col_offset;
1438 : 1324772 : token->end_col_offset = tok->col_offset;
1439 : : }
1440 : 1370610 : return type;
1441 : : }
1442 : :
1443 : : static int
1444 : 1370610 : tok_get(struct tok_state *tok, struct token *token)
1445 : : {
1446 : : int c;
1447 : : int blankline, nonascii;
1448 : :
1449 : 1370610 : const char *p_start = NULL;
1450 : 1370610 : const char *p_end = NULL;
1451 : 1404818 : nextline:
1452 : 1404818 : tok->start = NULL;
1453 : 1404818 : tok->starting_col_offset = -1;
1454 : 1404818 : blankline = 0;
1455 : :
1456 : : /* Get indentation level */
1457 [ + + ]: 1404818 : if (tok->atbol) {
1458 : 98111 : int col = 0;
1459 : 98111 : int altcol = 0;
1460 : 98111 : tok->atbol = 0;
1461 : 98111 : int cont_line_col = 0;
1462 : : for (;;) {
1463 : 806146 : c = tok_nextc(tok);
1464 [ + + ]: 806146 : if (c == ' ') {
1465 : 708035 : col++, altcol++;
1466 : : }
1467 [ - + ]: 98111 : else if (c == '\t') {
1468 : 0 : col = (col / tok->tabsize + 1) * tok->tabsize;
1469 : 0 : altcol = (altcol / ALTTABSIZE + 1) * ALTTABSIZE;
1470 : : }
1471 [ - + ]: 98111 : else if (c == '\014') {/* Control-L (formfeed) */
1472 : 0 : col = altcol = 0; /* For Emacs users */
1473 : : }
1474 [ - + ]: 98111 : else if (c == '\\') {
1475 : : // Indentation cannot be split over multiple physical lines
1476 : : // using backslashes. This means that if we found a backslash
1477 : : // preceded by whitespace, **the first one we find** determines
1478 : : // the level of indentation of whatever comes next.
1479 [ # # ]: 0 : cont_line_col = cont_line_col ? cont_line_col : col;
1480 [ # # ]: 0 : if ((c = tok_continuation_line(tok)) == -1) {
1481 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1482 : : }
1483 : : }
1484 : : else {
1485 : 98111 : break;
1486 : : }
1487 : : }
1488 : 98111 : tok_backup(tok, c);
1489 [ + + + + ]: 98111 : if (c == '#' || c == '\n') {
1490 : : /* Lines with only whitespace and/or comments
1491 : : shouldn't affect the indentation and are
1492 : : not passed to the parser as NEWLINE tokens,
1493 : : except *totally* empty lines in interactive
1494 : : mode, which signal the end of a command group. */
1495 [ + + + + : 25127 : if (col == 0 && c == '\n' && tok->prompt != NULL) {
- + ]
1496 : 0 : blankline = 0; /* Let it through */
1497 : : }
1498 [ - + - - ]: 25127 : else if (tok->prompt != NULL && tok->lineno == 1) {
1499 : : /* In interactive mode, if the first line contains
1500 : : only spaces and/or a comment, let it through. */
1501 : 0 : blankline = 0;
1502 : 0 : col = altcol = 0;
1503 : : }
1504 : : else {
1505 : 25127 : blankline = 1; /* Ignore completely */
1506 : : }
1507 : : /* We can't jump back right here since we still
1508 : : may need to skip to the end of a comment */
1509 : : }
1510 [ + + + + ]: 98111 : if (!blankline && tok->level == 0) {
1511 [ - + ]: 63903 : col = cont_line_col ? cont_line_col : col;
1512 [ - + ]: 63903 : altcol = cont_line_col ? cont_line_col : altcol;
1513 [ + + ]: 63903 : if (col == tok->indstack[tok->indent]) {
1514 : : /* No change */
1515 [ - + ]: 23114 : if (altcol != tok->altindstack[tok->indent]) {
1516 : 0 : return MAKE_TOKEN(indenterror(tok));
1517 : : }
1518 : : }
1519 [ + + ]: 40789 : else if (col > tok->indstack[tok->indent]) {
1520 : : /* Indent -- always one */
1521 [ - + ]: 22771 : if (tok->indent+1 >= MAXINDENT) {
1522 : 0 : tok->done = E_TOODEEP;
1523 : 0 : tok->cur = tok->inp;
1524 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1525 : : }
1526 [ - + ]: 22771 : if (altcol <= tok->altindstack[tok->indent]) {
1527 : 0 : return MAKE_TOKEN(indenterror(tok));
1528 : : }
1529 : 22771 : tok->pendin++;
1530 : 22771 : tok->indstack[++tok->indent] = col;
1531 : 22771 : tok->altindstack[tok->indent] = altcol;
1532 : : }
1533 : : else /* col < tok->indstack[tok->indent] */ {
1534 : : /* Dedent -- any number, must be consistent */
1535 [ + + ]: 40789 : while (tok->indent > 0 &&
1536 [ + + ]: 37860 : col < tok->indstack[tok->indent]) {
1537 : 22771 : tok->pendin--;
1538 : 22771 : tok->indent--;
1539 : : }
1540 [ - + ]: 18018 : if (col != tok->indstack[tok->indent]) {
1541 : 0 : tok->done = E_DEDENT;
1542 : 0 : tok->cur = tok->inp;
1543 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1544 : : }
1545 [ - + ]: 18018 : if (altcol != tok->altindstack[tok->indent]) {
1546 : 0 : return MAKE_TOKEN(indenterror(tok));
1547 : : }
1548 : : }
1549 : : }
1550 : : }
1551 : :
1552 : 1404818 : tok->start = tok->cur;
1553 : 1404818 : tok->starting_col_offset = tok->col_offset;
1554 : :
1555 : : /* Return pending indents/dedents */
1556 [ + + ]: 1404818 : if (tok->pendin != 0) {
1557 [ + + ]: 45542 : if (tok->pendin < 0) {
1558 : 22771 : tok->pendin++;
1559 : 22771 : return MAKE_TOKEN(DEDENT);
1560 : : }
1561 : : else {
1562 : 22771 : tok->pendin--;
1563 : 22771 : return MAKE_TOKEN(INDENT);
1564 : : }
1565 : : }
1566 : :
1567 : : /* Peek ahead at the next character */
1568 : 1359276 : c = tok_nextc(tok);
1569 : 1359276 : tok_backup(tok, c);
1570 : : /* Check if we are closing an async function */
1571 [ + - ]: 1359276 : if (tok->async_def
1572 [ # # ]: 0 : && !blankline
1573 : : /* Due to some implementation artifacts of type comments,
1574 : : * a TYPE_COMMENT at the start of a function won't set an
1575 : : * indentation level and it will produce a NEWLINE after it.
1576 : : * To avoid spuriously ending an async function due to this,
1577 : : * wait until we have some non-newline char in front of us. */
1578 [ # # ]: 0 : && c != '\n'
1579 [ # # ]: 0 : && tok->level == 0
1580 : : /* There was a NEWLINE after ASYNC DEF,
1581 : : so we're past the signature. */
1582 [ # # ]: 0 : && tok->async_def_nl
1583 : : /* Current indentation level is less than where
1584 : : the async function was defined */
1585 [ # # ]: 0 : && tok->async_def_indent >= tok->indent)
1586 : : {
1587 : 0 : tok->async_def = 0;
1588 : 0 : tok->async_def_indent = 0;
1589 : 0 : tok->async_def_nl = 0;
1590 : : }
1591 : :
1592 : 1359276 : again:
1593 : 1359406 : tok->start = NULL;
1594 : : /* Skip spaces */
1595 : : do {
1596 : 1616950 : c = tok_nextc(tok);
1597 [ + + - + : 1616950 : } while (c == ' ' || c == '\t' || c == '\014');
- + ]
1598 : :
1599 : : /* Set start of current token */
1600 [ + - ]: 1359406 : tok->start = tok->cur == NULL ? NULL : tok->cur - 1;
1601 : 1359406 : tok->starting_col_offset = tok->col_offset - 1;
1602 : :
1603 : : /* Skip comment, unless it's a type comment */
1604 [ + + ]: 1359406 : if (c == '#') {
1605 : : const char *prefix, *p, *type_start;
1606 : : int current_starting_col_offset;
1607 : :
1608 [ + - + + ]: 546529 : while (c != EOF && c != '\n') {
1609 : 534690 : c = tok_nextc(tok);
1610 : : }
1611 : :
1612 [ - + ]: 11839 : if (tok->type_comments) {
1613 : 0 : p = tok->start;
1614 : 0 : current_starting_col_offset = tok->starting_col_offset;
1615 : 0 : prefix = type_comment_prefix;
1616 [ # # # # ]: 0 : while (*prefix && p < tok->cur) {
1617 [ # # ]: 0 : if (*prefix == ' ') {
1618 [ # # # # ]: 0 : while (*p == ' ' || *p == '\t') {
1619 : 0 : p++;
1620 : 0 : current_starting_col_offset++;
1621 : : }
1622 [ # # ]: 0 : } else if (*prefix == *p) {
1623 : 0 : p++;
1624 : 0 : current_starting_col_offset++;
1625 : : } else {
1626 : 0 : break;
1627 : : }
1628 : :
1629 : 0 : prefix++;
1630 : : }
1631 : :
1632 : : /* This is a type comment if we matched all of type_comment_prefix. */
1633 [ # # ]: 0 : if (!*prefix) {
1634 : 0 : int is_type_ignore = 1;
1635 : : // +6 in order to skip the word 'ignore'
1636 : 0 : const char *ignore_end = p + 6;
1637 : 0 : const int ignore_end_col_offset = current_starting_col_offset + 6;
1638 : 0 : tok_backup(tok, c); /* don't eat the newline or EOF */
1639 : :
1640 : 0 : type_start = p;
1641 : :
1642 : : /* A TYPE_IGNORE is "type: ignore" followed by the end of the token
1643 : : * or anything ASCII and non-alphanumeric. */
1644 : 0 : is_type_ignore = (
1645 [ # # ]: 0 : tok->cur >= ignore_end && memcmp(p, "ignore", 6) == 0
1646 [ # # # # ]: 0 : && !(tok->cur > ignore_end
1647 [ # # # # ]: 0 : && ((unsigned char)ignore_end[0] >= 128 || Py_ISALNUM(ignore_end[0]))));
1648 : :
1649 [ # # ]: 0 : if (is_type_ignore) {
1650 : 0 : p_start = ignore_end;
1651 : 0 : p_end = tok->cur;
1652 : :
1653 : : /* If this type ignore is the only thing on the line, consume the newline also. */
1654 [ # # ]: 0 : if (blankline) {
1655 : 0 : tok_nextc(tok);
1656 : 0 : tok->atbol = 1;
1657 : : }
1658 : 0 : return MAKE_TYPE_COMMENT_TOKEN(TYPE_IGNORE, ignore_end_col_offset, tok->col_offset);
1659 : : } else {
1660 : 0 : p_start = type_start;
1661 : 0 : p_end = tok->cur;
1662 : 0 : return MAKE_TYPE_COMMENT_TOKEN(TYPE_COMMENT, current_starting_col_offset, tok->col_offset);
1663 : : }
1664 : : }
1665 : : }
1666 : : }
1667 : :
1668 [ - + ]: 1359406 : if (tok->done == E_INTERACT_STOP) {
1669 : 0 : return MAKE_TOKEN(ENDMARKER);
1670 : : }
1671 : :
1672 : : /* Check for EOF and errors now */
1673 [ + + ]: 1359406 : if (c == EOF) {
1674 [ - + ]: 296 : if (tok->level) {
1675 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1676 : : }
1677 [ + - ]: 296 : return MAKE_TOKEN(tok->done == E_EOF ? ENDMARKER : ERRORTOKEN);
1678 : : }
1679 : :
1680 : : /* Identifier (most frequent token!) */
1681 : 1359110 : nonascii = 0;
1682 [ + + + + : 1359110 : if (is_potential_identifier_start(c)) {
+ + + + +
+ - + ]
1683 : : /* Process the various legal combinations of b"", r"", u"", and f"". */
1684 : 210529 : int saw_b = 0, saw_r = 0, saw_u = 0, saw_f = 0;
1685 : : while (1) {
1686 [ + + + + : 242298 : if (!(saw_b || saw_u || saw_f) && (c == 'b' || c == 'B'))
+ + + + +
+ ]
1687 : 3841 : saw_b = 1;
1688 : : /* Since this is a backwards compatibility support literal we don't
1689 : : want to support it in arbitrary order like byte literals. */
1690 [ + + + + : 238457 : else if (!(saw_b || saw_u || saw_r || saw_f)
+ + + + ]
1691 [ + + + + ]: 206694 : && (c == 'u'|| c == 'U')) {
1692 : 1455 : saw_u = 1;
1693 : : }
1694 : : /* ur"" and ru"" are not supported */
1695 [ + + + + : 237002 : else if (!(saw_r || saw_u) && (c == 'r' || c == 'R')) {
+ + + + ]
1696 : 15321 : saw_r = 1;
1697 : : }
1698 [ + + + + : 221681 : else if (!(saw_f || saw_b || saw_u) && (c == 'f' || c == 'F')) {
+ + + + +
+ ]
1699 : 12613 : saw_f = 1;
1700 : : }
1701 : : else {
1702 : : break;
1703 : : }
1704 : 33230 : c = tok_nextc(tok);
1705 [ + + + + ]: 33230 : if (c == '"' || c == '\'') {
1706 : 1461 : goto letter_quote;
1707 : : }
1708 : : }
1709 [ + + + + : 1419827 : while (is_potential_identifier_char(c)) {
+ + + + +
+ + + + +
- + ]
1710 [ - + ]: 1210759 : if (c >= 128) {
1711 : 0 : nonascii = 1;
1712 : : }
1713 : 1210759 : c = tok_nextc(tok);
1714 : : }
1715 : 209068 : tok_backup(tok, c);
1716 [ - + - - ]: 209068 : if (nonascii && !verify_identifier(tok)) {
1717 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1718 : : }
1719 : :
1720 : 209068 : p_start = tok->start;
1721 : 209068 : p_end = tok->cur;
1722 : :
1723 : : /* async/await parsing block. */
1724 [ + + + + ]: 209068 : if (tok->cur - tok->start == 5 && tok->start[0] == 'a') {
1725 : : /* May be an 'async' or 'await' token. For Python 3.7 or
1726 : : later we recognize them unconditionally. For Python
1727 : : 3.5 or 3.6 we recognize 'async' in front of 'def', and
1728 : : either one inside of 'async def'. (Technically we
1729 : : shouldn't recognize these at all for 3.4 or earlier,
1730 : : but there's no *valid* Python 3.4 code that would be
1731 : : rejected, and async functions will be rejected in a
1732 : : later phase.) */
1733 [ - + - - ]: 539 : if (!tok->async_hacks || tok->async_def) {
1734 : : /* Always recognize the keywords. */
1735 [ + + ]: 539 : if (memcmp(tok->start, "async", 5) == 0) {
1736 : 163 : return MAKE_TOKEN(ASYNC);
1737 : : }
1738 [ + + ]: 376 : if (memcmp(tok->start, "await", 5) == 0) {
1739 : 128 : return MAKE_TOKEN(AWAIT);
1740 : : }
1741 : : }
1742 [ # # ]: 0 : else if (memcmp(tok->start, "async", 5) == 0) {
1743 : : /* The current token is 'async'.
1744 : : Look ahead one token to see if that is 'def'. */
1745 : :
1746 : : struct tok_state ahead_tok;
1747 : : struct token ahead_token;
1748 : : int ahead_tok_kind;
1749 : :
1750 : 0 : memcpy(&ahead_tok, tok, sizeof(ahead_tok));
1751 : 0 : ahead_tok_kind = tok_get(&ahead_tok, &ahead_token);
1752 : :
1753 [ # # ]: 0 : if (ahead_tok_kind == NAME
1754 [ # # ]: 0 : && ahead_tok.cur - ahead_tok.start == 3
1755 [ # # ]: 0 : && memcmp(ahead_tok.start, "def", 3) == 0)
1756 : : {
1757 : : /* The next token is going to be 'def', so instead of
1758 : : returning a plain NAME token, return ASYNC. */
1759 : 0 : tok->async_def_indent = tok->indent;
1760 : 0 : tok->async_def = 1;
1761 : 0 : return MAKE_TOKEN(ASYNC);
1762 : : }
1763 : : }
1764 : : }
1765 : :
1766 : 208777 : return MAKE_TOKEN(NAME);
1767 : : }
1768 : :
1769 : : /* Newline */
1770 [ + + ]: 1148581 : if (c == '\n') {
1771 : 97815 : tok->atbol = 1;
1772 [ + + + + ]: 97815 : if (blankline || tok->level > 0) {
1773 : 34208 : goto nextline;
1774 : : }
1775 : 63607 : p_start = tok->start;
1776 : 63607 : p_end = tok->cur - 1; /* Leave '\n' out of the string */
1777 : 63607 : tok->cont_line = 0;
1778 [ - + ]: 63607 : if (tok->async_def) {
1779 : : /* We're somewhere inside an 'async def' function, and
1780 : : we've encountered a NEWLINE after its signature. */
1781 : 0 : tok->async_def_nl = 1;
1782 : : }
1783 : 63607 : return MAKE_TOKEN(NEWLINE);
1784 : : }
1785 : :
1786 : : /* Period or number starting with period? */
1787 [ + + ]: 1050766 : if (c == '.') {
1788 : 29903 : c = tok_nextc(tok);
1789 [ + + ]: 29903 : if (isdigit(c)) {
1790 : 2 : goto fraction;
1791 [ + + ]: 29901 : } else if (c == '.') {
1792 : 25 : c = tok_nextc(tok);
1793 [ + - ]: 25 : if (c == '.') {
1794 : 25 : p_start = tok->start;
1795 : 25 : p_end = tok->cur;
1796 : 25 : return MAKE_TOKEN(ELLIPSIS);
1797 : : }
1798 : : else {
1799 : 0 : tok_backup(tok, c);
1800 : : }
1801 : 0 : tok_backup(tok, '.');
1802 : : }
1803 : : else {
1804 : 29876 : tok_backup(tok, c);
1805 : : }
1806 : 29876 : p_start = tok->start;
1807 : 29876 : p_end = tok->cur;
1808 : 29876 : return MAKE_TOKEN(DOT);
1809 : : }
1810 : :
1811 : : /* Number */
1812 [ + + ]: 1020863 : if (isdigit(c)) {
1813 [ + + ]: 415619 : if (c == '0') {
1814 : : /* Hex, octal or binary -- maybe. */
1815 : 133074 : c = tok_nextc(tok);
1816 [ + + - + ]: 133074 : if (c == 'x' || c == 'X') {
1817 : : /* Hex */
1818 : 393 : c = tok_nextc(tok);
1819 : : do {
1820 [ - + ]: 393 : if (c == '_') {
1821 : 0 : c = tok_nextc(tok);
1822 : : }
1823 [ - + ]: 393 : if (!isxdigit(c)) {
1824 : 0 : tok_backup(tok, c);
1825 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid hexadecimal literal"));
1826 : : }
1827 : : do {
1828 : 1665 : c = tok_nextc(tok);
1829 [ + + ]: 1665 : } while (isxdigit(c));
1830 [ - + ]: 393 : } while (c == '_');
1831 [ - + ]: 393 : if (!verify_end_of_number(tok, c, "hexadecimal")) {
1832 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1833 : : }
1834 : : }
1835 [ + + - + ]: 132681 : else if (c == 'o' || c == 'O') {
1836 : : /* Octal */
1837 : 81 : c = tok_nextc(tok);
1838 : : do {
1839 [ - + ]: 81 : if (c == '_') {
1840 : 0 : c = tok_nextc(tok);
1841 : : }
1842 [ + - - + ]: 81 : if (c < '0' || c >= '8') {
1843 [ # # ]: 0 : if (isdigit(c)) {
1844 : 0 : return MAKE_TOKEN(syntaxerror(tok,
1845 : : "invalid digit '%c' in octal literal", c));
1846 : : }
1847 : : else {
1848 : 0 : tok_backup(tok, c);
1849 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid octal literal"));
1850 : : }
1851 : : }
1852 : : do {
1853 : 344 : c = tok_nextc(tok);
1854 [ + + + + ]: 344 : } while ('0' <= c && c < '8');
1855 [ - + ]: 81 : } while (c == '_');
1856 [ - + ]: 81 : if (isdigit(c)) {
1857 : 0 : return MAKE_TOKEN(syntaxerror(tok,
1858 : : "invalid digit '%c' in octal literal", c));
1859 : : }
1860 [ - + ]: 81 : if (!verify_end_of_number(tok, c, "octal")) {
1861 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1862 : : }
1863 : : }
1864 [ + + - + ]: 132600 : else if (c == 'b' || c == 'B') {
1865 : : /* Binary */
1866 : 6 : c = tok_nextc(tok);
1867 : : do {
1868 [ - + ]: 6 : if (c == '_') {
1869 : 0 : c = tok_nextc(tok);
1870 : : }
1871 [ + - - + ]: 6 : if (c != '0' && c != '1') {
1872 [ # # ]: 0 : if (isdigit(c)) {
1873 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c));
1874 : : }
1875 : : else {
1876 : 0 : tok_backup(tok, c);
1877 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid binary literal"));
1878 : : }
1879 : : }
1880 : : do {
1881 : 9 : c = tok_nextc(tok);
1882 [ + + + + ]: 9 : } while (c == '0' || c == '1');
1883 [ - + ]: 6 : } while (c == '_');
1884 [ - + ]: 6 : if (isdigit(c)) {
1885 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c));
1886 : : }
1887 [ - + ]: 6 : if (!verify_end_of_number(tok, c, "binary")) {
1888 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1889 : : }
1890 : : }
1891 : : else {
1892 : 132594 : int nonzero = 0;
1893 : : /* maybe old-style octal; c is first char of it */
1894 : : /* in any case, allow '0' as a literal */
1895 : : while (1) {
1896 [ - + ]: 132594 : if (c == '_') {
1897 : 0 : c = tok_nextc(tok);
1898 [ # # ]: 0 : if (!isdigit(c)) {
1899 : 0 : tok_backup(tok, c);
1900 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal"));
1901 : : }
1902 : : }
1903 [ + - ]: 132594 : if (c != '0') {
1904 : 132594 : break;
1905 : : }
1906 : 0 : c = tok_nextc(tok);
1907 : : }
1908 : 132594 : char* zeros_end = tok->cur;
1909 [ - + ]: 132594 : if (isdigit(c)) {
1910 : 0 : nonzero = 1;
1911 : 0 : c = tok_decimal_tail(tok);
1912 [ # # ]: 0 : if (c == 0) {
1913 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1914 : : }
1915 : : }
1916 [ + + ]: 132594 : if (c == '.') {
1917 : 354 : c = tok_nextc(tok);
1918 : 354 : goto fraction;
1919 : : }
1920 [ + - - + ]: 132240 : else if (c == 'e' || c == 'E') {
1921 : 0 : goto exponent;
1922 : : }
1923 [ + - - + ]: 132240 : else if (c == 'j' || c == 'J') {
1924 : 0 : goto imaginary;
1925 : : }
1926 [ - + ]: 132240 : else if (nonzero) {
1927 : : /* Old-style octal: now disallowed. */
1928 : 0 : tok_backup(tok, c);
1929 : 0 : return MAKE_TOKEN(syntaxerror_known_range(
1930 : : tok, (int)(tok->start + 1 - tok->line_start),
1931 : : (int)(zeros_end - tok->line_start),
1932 : : "leading zeros in decimal integer "
1933 : : "literals are not permitted; "
1934 : : "use an 0o prefix for octal integers"));
1935 : : }
1936 [ - + ]: 132240 : if (!verify_end_of_number(tok, c, "decimal")) {
1937 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1938 : : }
1939 : : }
1940 : : }
1941 : : else {
1942 : : /* Decimal */
1943 : 282545 : c = tok_decimal_tail(tok);
1944 [ - + ]: 282545 : if (c == 0) {
1945 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1946 : : }
1947 : : {
1948 : : /* Accept floating point numbers. */
1949 [ + + ]: 282545 : if (c == '.') {
1950 : 614 : c = tok_nextc(tok);
1951 : 970 : fraction:
1952 : : /* Fraction */
1953 [ + + ]: 970 : if (isdigit(c)) {
1954 : 714 : c = tok_decimal_tail(tok);
1955 [ - + ]: 714 : if (c == 0) {
1956 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1957 : : }
1958 : : }
1959 : : }
1960 [ + + + + ]: 282901 : if (c == 'e' || c == 'E') {
1961 : : int e;
1962 : 75 : exponent:
1963 : 75 : e = c;
1964 : : /* Exponent part */
1965 : 75 : c = tok_nextc(tok);
1966 [ + - + + ]: 75 : if (c == '+' || c == '-') {
1967 : 36 : c = tok_nextc(tok);
1968 [ - + ]: 36 : if (!isdigit(c)) {
1969 : 0 : tok_backup(tok, c);
1970 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal"));
1971 : : }
1972 [ - + ]: 39 : } else if (!isdigit(c)) {
1973 : 0 : tok_backup(tok, c);
1974 [ # # ]: 0 : if (!verify_end_of_number(tok, e, "decimal")) {
1975 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1976 : : }
1977 : 0 : tok_backup(tok, e);
1978 : 0 : p_start = tok->start;
1979 : 0 : p_end = tok->cur;
1980 : 0 : return MAKE_TOKEN(NUMBER);
1981 : : }
1982 : 75 : c = tok_decimal_tail(tok);
1983 [ - + ]: 75 : if (c == 0) {
1984 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1985 : : }
1986 : : }
1987 [ + + - + ]: 282901 : if (c == 'j' || c == 'J') {
1988 : : /* Imaginary part */
1989 : 3 : imaginary:
1990 : 3 : c = tok_nextc(tok);
1991 [ - + ]: 3 : if (!verify_end_of_number(tok, c, "imaginary")) {
1992 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1993 : : }
1994 : : }
1995 [ - + ]: 282898 : else if (!verify_end_of_number(tok, c, "decimal")) {
1996 : 0 : return MAKE_TOKEN(ERRORTOKEN);
1997 : : }
1998 : : }
1999 : : }
2000 : 415621 : tok_backup(tok, c);
2001 : 415621 : p_start = tok->start;
2002 : 415621 : p_end = tok->cur;
2003 : 415621 : return MAKE_TOKEN(NUMBER);
2004 : : }
2005 : :
2006 : 605244 : letter_quote:
2007 : : /* String */
2008 [ + + + + ]: 606705 : if (c == '\'' || c == '"') {
2009 : 22069 : int quote = c;
2010 : 22069 : int quote_size = 1; /* 1 or 3 */
2011 : 22069 : int end_quote_size = 0;
2012 : :
2013 : : /* Nodes of type STRING, especially multi line strings
2014 : : must be handled differently in order to get both
2015 : : the starting line number and the column offset right.
2016 : : (cf. issue 16806) */
2017 : 22069 : tok->first_lineno = tok->lineno;
2018 : 22069 : tok->multi_line_start = tok->line_start;
2019 : :
2020 : : /* Find the quote size and start of string */
2021 : 22069 : c = tok_nextc(tok);
2022 [ + + ]: 22069 : if (c == quote) {
2023 : 3639 : c = tok_nextc(tok);
2024 [ + + ]: 3639 : if (c == quote) {
2025 : 2993 : quote_size = 3;
2026 : : }
2027 : : else {
2028 : 646 : end_quote_size = 1; /* empty string found */
2029 : : }
2030 : : }
2031 [ + + ]: 22069 : if (c != quote) {
2032 : 19076 : tok_backup(tok, c);
2033 : : }
2034 : :
2035 : : /* Get rest of string */
2036 [ + + ]: 1070462 : while (end_quote_size != quote_size) {
2037 : 1048393 : c = tok_nextc(tok);
2038 [ - + ]: 1048393 : if (tok->done == E_DECODE)
2039 : 0 : break;
2040 [ + - + + : 1048393 : if (c == EOF || (quote_size == 1 && c == '\n')) {
- + ]
2041 : : assert(tok->multi_line_start != NULL);
2042 : : // shift the tok_state's location into
2043 : : // the start of string, and report the error
2044 : : // from the initial quote character
2045 : 0 : tok->cur = (char *)tok->start;
2046 : 0 : tok->cur++;
2047 : 0 : tok->line_start = tok->multi_line_start;
2048 : 0 : int start = tok->lineno;
2049 : 0 : tok->lineno = tok->first_lineno;
2050 [ # # ]: 0 : if (quote_size == 3) {
2051 : 0 : syntaxerror(tok, "unterminated triple-quoted string literal"
2052 : : " (detected at line %d)", start);
2053 [ # # ]: 0 : if (c != '\n') {
2054 : 0 : tok->done = E_EOFS;
2055 : : }
2056 : 0 : return MAKE_TOKEN(ERRORTOKEN);
2057 : : }
2058 : : else {
2059 : 0 : syntaxerror(tok, "unterminated string literal (detected at"
2060 : : " line %d)", start);
2061 [ # # ]: 0 : if (c != '\n') {
2062 : 0 : tok->done = E_EOLS;
2063 : : }
2064 : 0 : return MAKE_TOKEN(ERRORTOKEN);
2065 : : }
2066 : : }
2067 [ + + ]: 1048393 : if (c == quote) {
2068 : 28751 : end_quote_size += 1;
2069 : : }
2070 : : else {
2071 : 1019642 : end_quote_size = 0;
2072 [ + + ]: 1019642 : if (c == '\\') {
2073 : 1563 : tok_nextc(tok); /* skip escaped char */
2074 : : }
2075 : : }
2076 : : }
2077 : :
2078 : 22069 : p_start = tok->start;
2079 : 22069 : p_end = tok->cur;
2080 : 22069 : return MAKE_TOKEN(STRING);
2081 : : }
2082 : :
2083 : : /* Line continuation */
2084 [ + + ]: 584636 : if (c == '\\') {
2085 [ - + ]: 130 : if ((c = tok_continuation_line(tok)) == -1) {
2086 : 0 : return MAKE_TOKEN(ERRORTOKEN);
2087 : : }
2088 : 130 : tok->cont_line = 1;
2089 : 130 : goto again; /* Read next line */
2090 : : }
2091 : :
2092 : : /* Check for two-character token */
2093 : : {
2094 : 584506 : int c2 = tok_nextc(tok);
2095 : 584506 : int current_token = _PyToken_TwoChars(c, c2);
2096 [ + + ]: 584506 : if (current_token != OP) {
2097 : 4052 : int c3 = tok_nextc(tok);
2098 : 4052 : int current_token3 = _PyToken_ThreeChars(c, c2, c3);
2099 [ + + ]: 4052 : if (current_token3 != OP) {
2100 : 21 : current_token = current_token3;
2101 : : }
2102 : : else {
2103 : 4031 : tok_backup(tok, c3);
2104 : : }
2105 : 4052 : p_start = tok->start;
2106 : 4052 : p_end = tok->cur;
2107 : 4052 : return MAKE_TOKEN(current_token);
2108 : : }
2109 : 580454 : tok_backup(tok, c2);
2110 : : }
2111 : :
2112 : : /* Keep track of parentheses nesting level */
2113 [ + + + ]: 580454 : switch (c) {
2114 : 43139 : case '(':
2115 : : case '[':
2116 : : case '{':
2117 [ - + ]: 43139 : if (tok->level >= MAXLEVEL) {
2118 : 0 : return MAKE_TOKEN(syntaxerror(tok, "too many nested parentheses"));
2119 : : }
2120 : 43139 : tok->parenstack[tok->level] = c;
2121 : 43139 : tok->parenlinenostack[tok->level] = tok->lineno;
2122 : 43139 : tok->parencolstack[tok->level] = (int)(tok->start - tok->line_start);
2123 : 43139 : tok->level++;
2124 : 43139 : break;
2125 : 43139 : case ')':
2126 : : case ']':
2127 : : case '}':
2128 [ - + ]: 43139 : if (!tok->level) {
2129 : 0 : return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c));
2130 : : }
2131 : 43139 : tok->level--;
2132 : 43139 : int opening = tok->parenstack[tok->level];
2133 [ + + - + : 43139 : if (!((opening == '(' && c == ')') ||
+ + + - ]
2134 [ - + ]: 4776 : (opening == '[' && c == ']') ||
2135 [ - + ]: 506 : (opening == '{' && c == '}')))
2136 : : {
2137 [ # # ]: 0 : if (tok->parenlinenostack[tok->level] != tok->lineno) {
2138 : 0 : return MAKE_TOKEN(syntaxerror(tok,
2139 : : "closing parenthesis '%c' does not match "
2140 : : "opening parenthesis '%c' on line %d",
2141 : : c, opening, tok->parenlinenostack[tok->level]));
2142 : : }
2143 : : else {
2144 : 0 : return MAKE_TOKEN(syntaxerror(tok,
2145 : : "closing parenthesis '%c' does not match "
2146 : : "opening parenthesis '%c'",
2147 : : c, opening));
2148 : : }
2149 : : }
2150 : 43139 : break;
2151 : : }
2152 : :
2153 [ - + ]: 580454 : if (!Py_UNICODE_ISPRINTABLE(c)) {
2154 : : char hex[9];
2155 : 0 : (void)PyOS_snprintf(hex, sizeof(hex), "%04X", c);
2156 : 0 : return MAKE_TOKEN(syntaxerror(tok, "invalid non-printable character U+%s", hex));
2157 : : }
2158 : :
2159 : : /* Punctuation character */
2160 : 580454 : p_start = tok->start;
2161 : 580454 : p_end = tok->cur;
2162 : 580454 : return MAKE_TOKEN(_PyToken_OneChar(c));
2163 : : }
2164 : :
2165 : : int
2166 : 1370610 : _PyTokenizer_Get(struct tok_state *tok, struct token *token)
2167 : : {
2168 : 1370610 : int result = tok_get(tok, token);
2169 [ - + ]: 1370610 : if (tok->decoding_erred) {
2170 : 0 : result = ERRORTOKEN;
2171 : 0 : tok->done = E_DECODE;
2172 : : }
2173 : 1370610 : return result;
2174 : : }
2175 : :
2176 : : #if defined(__wasi__) || (defined(__EMSCRIPTEN__) && (__EMSCRIPTEN_major__ >= 3))
2177 : : // fdopen() with borrowed fd. WASI does not provide dup() and Emscripten's
2178 : : // dup() emulation with open() is slow.
2179 : : typedef union {
2180 : : void *cookie;
2181 : : int fd;
2182 : : } borrowed;
2183 : :
2184 : : static ssize_t
2185 : : borrow_read(void *cookie, char *buf, size_t size)
2186 : : {
2187 : : borrowed b = {.cookie = cookie};
2188 : : return read(b.fd, (void *)buf, size);
2189 : : }
2190 : :
2191 : : static FILE *
2192 : : fdopen_borrow(int fd) {
2193 : : // supports only reading. seek fails. close and write are no-ops.
2194 : : cookie_io_functions_t io_cb = {borrow_read, NULL, NULL, NULL};
2195 : : borrowed b = {.fd = fd};
2196 : : return fopencookie(b.cookie, "r", io_cb);
2197 : : }
2198 : : #else
2199 : : static FILE *
2200 : 0 : fdopen_borrow(int fd) {
2201 : 0 : fd = _Py_dup(fd);
2202 [ # # ]: 0 : if (fd < 0) {
2203 : 0 : return NULL;
2204 : : }
2205 : 0 : return fdopen(fd, "r");
2206 : : }
2207 : : #endif
2208 : :
2209 : : /* Get the encoding of a Python file. Check for the coding cookie and check if
2210 : : the file starts with a BOM.
2211 : :
2212 : : _PyTokenizer_FindEncodingFilename() returns NULL when it can't find the
2213 : : encoding in the first or second line of the file (in which case the encoding
2214 : : should be assumed to be UTF-8).
2215 : :
2216 : : The char* returned is malloc'ed via PyMem_Malloc() and thus must be freed
2217 : : by the caller. */
2218 : :
2219 : : char *
2220 : 0 : _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename)
2221 : : {
2222 : : struct tok_state *tok;
2223 : : FILE *fp;
2224 : 0 : char *encoding = NULL;
2225 : :
2226 : 0 : fp = fdopen_borrow(fd);
2227 [ # # ]: 0 : if (fp == NULL) {
2228 : 0 : return NULL;
2229 : : }
2230 : 0 : tok = _PyTokenizer_FromFile(fp, NULL, NULL, NULL);
2231 [ # # ]: 0 : if (tok == NULL) {
2232 : 0 : fclose(fp);
2233 : 0 : return NULL;
2234 : : }
2235 [ # # ]: 0 : if (filename != NULL) {
2236 : 0 : tok->filename = Py_NewRef(filename);
2237 : : }
2238 : : else {
2239 : 0 : tok->filename = PyUnicode_FromString("<string>");
2240 [ # # ]: 0 : if (tok->filename == NULL) {
2241 : 0 : fclose(fp);
2242 : 0 : _PyTokenizer_Free(tok);
2243 : 0 : return encoding;
2244 : : }
2245 : : }
2246 : : struct token token;
2247 : : // We don't want to report warnings here because it could cause infinite recursion
2248 : : // if fetching the encoding shows a warning.
2249 : 0 : tok->report_warnings = 0;
2250 [ # # # # ]: 0 : while (tok->lineno < 2 && tok->done == E_OK) {
2251 : 0 : _PyTokenizer_Get(tok, &token);
2252 : : }
2253 : 0 : fclose(fp);
2254 [ # # ]: 0 : if (tok->encoding) {
2255 : 0 : encoding = (char *)PyMem_Malloc(strlen(tok->encoding) + 1);
2256 [ # # ]: 0 : if (encoding) {
2257 : 0 : strcpy(encoding, tok->encoding);
2258 : : }
2259 : : }
2260 : 0 : _PyTokenizer_Free(tok);
2261 : 0 : return encoding;
2262 : : }
2263 : :
2264 : : #ifdef Py_DEBUG
2265 : : void
2266 : : tok_dump(int type, char *start, char *end)
2267 : : {
2268 : : fprintf(stderr, "%s", _PyParser_TokenNames[type]);
2269 : : if (type == NAME || type == NUMBER || type == STRING || type == OP)
2270 : : fprintf(stderr, "(%.*s)", (int)(end - start), start);
2271 : : }
2272 : : #endif // Py_DEBUG
|