Branch data Line data Source code
1 : : #include <Python.h>
2 : : #include "pycore_ast.h" // _PyAST_Validate(),
3 : : #include "pycore_pystate.h" // _PyThreadState_GET()
4 : : #include <errcode.h>
5 : :
6 : : #include "tokenizer.h"
7 : : #include "pegen.h"
8 : :
9 : : // Internal parser functions
10 : :
11 : : asdl_stmt_seq*
12 : 0 : _PyPegen_interactive_exit(Parser *p)
13 : : {
14 [ # # ]: 0 : if (p->errcode) {
15 : 0 : *(p->errcode) = E_EOF;
16 : : }
17 : 0 : return NULL;
18 : : }
19 : :
20 : : Py_ssize_t
21 : 0 : _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset)
22 : : {
23 : 0 : const char *str = PyUnicode_AsUTF8(line);
24 [ # # ]: 0 : if (!str) {
25 : 0 : return -1;
26 : : }
27 : 0 : Py_ssize_t len = strlen(str);
28 [ # # ]: 0 : if (col_offset > len + 1) {
29 : 0 : col_offset = len + 1;
30 : : }
31 : : assert(col_offset >= 0);
32 : 0 : PyObject *text = PyUnicode_DecodeUTF8(str, col_offset, "replace");
33 [ # # ]: 0 : if (!text) {
34 : 0 : return -1;
35 : : }
36 : 0 : Py_ssize_t size = PyUnicode_GET_LENGTH(text);
37 : 0 : Py_DECREF(text);
38 : 0 : return size;
39 : : }
40 : :
41 : : // Here, mark is the start of the node, while p->mark is the end.
42 : : // If node==NULL, they should be the same.
43 : : int
44 : 7835749 : _PyPegen_insert_memo(Parser *p, int mark, int type, void *node)
45 : : {
46 : : // Insert in front
47 : 7835749 : Memo *m = _PyArena_Malloc(p->arena, sizeof(Memo));
48 [ - + ]: 7835749 : if (m == NULL) {
49 : 0 : return -1;
50 : : }
51 : 7835749 : m->type = type;
52 : 7835749 : m->node = node;
53 : 7835749 : m->mark = p->mark;
54 : 7835749 : m->next = p->tokens[mark]->memo;
55 : 7835749 : p->tokens[mark]->memo = m;
56 : 7835749 : return 0;
57 : : }
58 : :
59 : : // Like _PyPegen_insert_memo(), but updates an existing node if found.
60 : : int
61 : 7862743 : _PyPegen_update_memo(Parser *p, int mark, int type, void *node)
62 : : {
63 [ + + ]: 38673908 : for (Memo *m = p->tokens[mark]->memo; m != NULL; m = m->next) {
64 [ + + ]: 34601092 : if (m->type == type) {
65 : : // Update existing node.
66 : 3789927 : m->node = node;
67 : 3789927 : m->mark = p->mark;
68 : 3789927 : return 0;
69 : : }
70 : : }
71 : : // Insert new node.
72 : 4072816 : return _PyPegen_insert_memo(p, mark, type, node);
73 : : }
74 : :
75 : : static int
76 : 0 : init_normalization(Parser *p)
77 : : {
78 [ # # ]: 0 : if (p->normalize) {
79 : 0 : return 1;
80 : : }
81 : 0 : p->normalize = _PyImport_GetModuleAttrString("unicodedata", "normalize");
82 [ # # ]: 0 : if (!p->normalize)
83 : : {
84 : 0 : return 0;
85 : : }
86 : 0 : return 1;
87 : : }
88 : :
89 : : static int
90 : 1585 : growable_comment_array_init(growable_comment_array *arr, size_t initial_size) {
91 : : assert(initial_size > 0);
92 : 1585 : arr->items = PyMem_Malloc(initial_size * sizeof(*arr->items));
93 : 1585 : arr->size = initial_size;
94 : 1585 : arr->num_items = 0;
95 : :
96 : 1585 : return arr->items != NULL;
97 : : }
98 : :
99 : : static int
100 : 0 : growable_comment_array_add(growable_comment_array *arr, int lineno, char *comment) {
101 [ # # ]: 0 : if (arr->num_items >= arr->size) {
102 : 0 : size_t new_size = arr->size * 2;
103 : 0 : void *new_items_array = PyMem_Realloc(arr->items, new_size * sizeof(*arr->items));
104 [ # # ]: 0 : if (!new_items_array) {
105 : 0 : return 0;
106 : : }
107 : 0 : arr->items = new_items_array;
108 : 0 : arr->size = new_size;
109 : : }
110 : :
111 : 0 : arr->items[arr->num_items].lineno = lineno;
112 : 0 : arr->items[arr->num_items].comment = comment; // Take ownership
113 : 0 : arr->num_items++;
114 : 0 : return 1;
115 : : }
116 : :
117 : : static void
118 : 1585 : growable_comment_array_deallocate(growable_comment_array *arr) {
119 [ - + ]: 1585 : for (unsigned i = 0; i < arr->num_items; i++) {
120 : 0 : PyMem_Free(arr->items[i].comment);
121 : : }
122 : 1585 : PyMem_Free(arr->items);
123 : 1585 : }
124 : :
125 : : static int
126 : 208777 : _get_keyword_or_name_type(Parser *p, struct token *new_token)
127 : : {
128 : 208777 : int name_len = new_token->end_col_offset - new_token->col_offset;
129 : : assert(name_len > 0);
130 : :
131 [ + + ]: 208777 : if (name_len >= p->n_keyword_lists ||
132 [ + - ]: 169658 : p->keywords[name_len] == NULL ||
133 [ + + ]: 169658 : p->keywords[name_len]->type == -1) {
134 : 46347 : return NAME;
135 : : }
136 [ + - + + ]: 855931 : for (KeywordToken *k = p->keywords[name_len]; k != NULL && k->type != -1; k++) {
137 [ + + ]: 746303 : if (strncmp(k->str, new_token->start, name_len) == 0) {
138 : 52802 : return k->type;
139 : : }
140 : : }
141 : 109628 : return NAME;
142 : : }
143 : :
144 : : static int
145 : 1370610 : initialize_token(Parser *p, Token *parser_token, struct token *new_token, int token_type) {
146 : : assert(parser_token != NULL);
147 : :
148 [ + + ]: 1370610 : parser_token->type = (token_type == NAME) ? _get_keyword_or_name_type(p, new_token) : token_type;
149 : 1370610 : parser_token->bytes = PyBytes_FromStringAndSize(new_token->start, new_token->end - new_token->start);
150 [ - + ]: 1370610 : if (parser_token->bytes == NULL) {
151 : 0 : return -1;
152 : : }
153 [ - + ]: 1370610 : if (_PyArena_AddPyObject(p->arena, parser_token->bytes) < 0) {
154 : 0 : Py_DECREF(parser_token->bytes);
155 : 0 : return -1;
156 : : }
157 : :
158 : 1370610 : parser_token->level = new_token->level;
159 : 1370610 : parser_token->lineno = new_token->lineno;
160 : 2747735 : parser_token->col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + new_token->col_offset
161 [ + + ]: 1370610 : : new_token->col_offset;
162 : 1370610 : parser_token->end_lineno = new_token->end_lineno;
163 : 2747735 : parser_token->end_col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + new_token->end_col_offset
164 [ + + ]: 1370610 : : new_token->end_col_offset;
165 : :
166 : 1370610 : p->fill += 1;
167 : :
168 [ - + - - ]: 1370610 : if (token_type == ERRORTOKEN && p->tok->done == E_DECODE) {
169 : 0 : return _Pypegen_raise_decode_error(p);
170 : : }
171 : :
172 [ - + ]: 1370610 : return (token_type == ERRORTOKEN ? _Pypegen_tokenizer_error(p) : 0);
173 : : }
174 : :
175 : : static int
176 : 5970 : _resize_tokens_array(Parser *p) {
177 : 5970 : int newsize = p->size * 2;
178 : 5970 : Token **new_tokens = PyMem_Realloc(p->tokens, newsize * sizeof(Token *));
179 [ - + ]: 5970 : if (new_tokens == NULL) {
180 : 0 : PyErr_NoMemory();
181 : 0 : return -1;
182 : : }
183 : 5970 : p->tokens = new_tokens;
184 : :
185 [ + + ]: 2008557 : for (int i = p->size; i < newsize; i++) {
186 : 2002587 : p->tokens[i] = PyMem_Calloc(1, sizeof(Token));
187 [ - + ]: 2002587 : if (p->tokens[i] == NULL) {
188 : 0 : p->size = i; // Needed, in order to cleanup correctly after parser fails
189 : 0 : PyErr_NoMemory();
190 : 0 : return -1;
191 : : }
192 : : }
193 : 5970 : p->size = newsize;
194 : 5970 : return 0;
195 : : }
196 : :
197 : : int
198 : 1370610 : _PyPegen_fill_token(Parser *p)
199 : : {
200 : : struct token new_token;
201 : 1370610 : int type = _PyTokenizer_Get(p->tok, &new_token);
202 : :
203 : : // Record and skip '# type: ignore' comments
204 [ - + ]: 1370610 : while (type == TYPE_IGNORE) {
205 : 0 : Py_ssize_t len = new_token.end_col_offset - new_token.col_offset;
206 : 0 : char *tag = PyMem_Malloc(len + 1);
207 [ # # ]: 0 : if (tag == NULL) {
208 : 0 : PyErr_NoMemory();
209 : 0 : return -1;
210 : : }
211 : 0 : strncpy(tag, new_token.start, len);
212 : 0 : tag[len] = '\0';
213 : : // Ownership of tag passes to the growable array
214 [ # # ]: 0 : if (!growable_comment_array_add(&p->type_ignore_comments, p->tok->lineno, tag)) {
215 : 0 : PyErr_NoMemory();
216 : 0 : return -1;
217 : : }
218 : 0 : type = _PyTokenizer_Get(p->tok, &new_token);
219 : : }
220 : :
221 : : // If we have reached the end and we are in single input mode we need to insert a newline and reset the parsing
222 [ + + + + : 1370610 : if (p->start_rule == Py_single_input && type == ENDMARKER && p->parsing_started) {
+ - ]
223 : 1 : type = NEWLINE; /* Add an extra newline */
224 : 1 : p->parsing_started = 0;
225 : :
226 [ - + - - ]: 1 : if (p->tok->indent && !(p->flags & PyPARSE_DONT_IMPLY_DEDENT)) {
227 : 0 : p->tok->pendin = -p->tok->indent;
228 : 0 : p->tok->indent = 0;
229 : : }
230 : : }
231 : : else {
232 : 1370609 : p->parsing_started = 1;
233 : : }
234 : :
235 : : // Check if we are at the limit of the token array capacity and resize if needed
236 [ + + - + ]: 1370610 : if ((p->fill == p->size) && (_resize_tokens_array(p) != 0)) {
237 : 0 : return -1;
238 : : }
239 : :
240 : 1370610 : Token *t = p->tokens[p->fill];
241 : 1370610 : return initialize_token(p, t, &new_token, type);
242 : : }
243 : :
244 : : #if defined(Py_DEBUG)
245 : : // Instrumentation to count the effectiveness of memoization.
246 : : // The array counts the number of tokens skipped by memoization,
247 : : // indexed by type.
248 : :
249 : : #define NSTATISTICS _PYPEGEN_NSTATISTICS
250 : : #define memo_statistics _PyRuntime.parser.memo_statistics
251 : :
252 : : void
253 : : _PyPegen_clear_memo_statistics()
254 : : {
255 : : for (int i = 0; i < NSTATISTICS; i++) {
256 : : memo_statistics[i] = 0;
257 : : }
258 : : }
259 : :
260 : : PyObject *
261 : : _PyPegen_get_memo_statistics()
262 : : {
263 : : PyObject *ret = PyList_New(NSTATISTICS);
264 : : if (ret == NULL) {
265 : : return NULL;
266 : : }
267 : : for (int i = 0; i < NSTATISTICS; i++) {
268 : : PyObject *value = PyLong_FromLong(memo_statistics[i]);
269 : : if (value == NULL) {
270 : : Py_DECREF(ret);
271 : : return NULL;
272 : : }
273 : : // PyList_SetItem borrows a reference to value.
274 : : if (PyList_SetItem(ret, i, value) < 0) {
275 : : Py_DECREF(ret);
276 : : return NULL;
277 : : }
278 : : }
279 : : return ret;
280 : : }
281 : : #endif
282 : :
283 : : int // bool
284 : 32609153 : _PyPegen_is_memoized(Parser *p, int type, void *pres)
285 : : {
286 [ + + ]: 32609153 : if (p->mark == p->fill) {
287 [ - + ]: 452199 : if (_PyPegen_fill_token(p) < 0) {
288 : 0 : p->error_indicator = 1;
289 : 0 : return -1;
290 : : }
291 : : }
292 : :
293 : 32609153 : Token *t = p->tokens[p->mark];
294 : :
295 [ + + ]: 101487050 : for (Memo *m = t->memo; m != NULL; m = m->next) {
296 [ + + ]: 93651301 : if (m->type == type) {
297 : : #if defined(PY_DEBUG)
298 : : if (0 <= type && type < NSTATISTICS) {
299 : : long count = m->mark - p->mark;
300 : : // A memoized negative result counts for one.
301 : : if (count <= 0) {
302 : : count = 1;
303 : : }
304 : : memo_statistics[type] += count;
305 : : }
306 : : #endif
307 : 24773404 : p->mark = m->mark;
308 : 24773404 : *(void **)(pres) = m->node;
309 : 24773404 : return 1;
310 : : }
311 : : }
312 : 7835749 : return 0;
313 : : }
314 : :
315 : : int
316 : 0 : _PyPegen_lookahead_with_name(int positive, expr_ty (func)(Parser *), Parser *p)
317 : : {
318 : 0 : int mark = p->mark;
319 : 0 : void *res = func(p);
320 : 0 : p->mark = mark;
321 : 0 : return (res != NULL) == positive;
322 : : }
323 : :
324 : : int
325 : 14 : _PyPegen_lookahead_with_string(int positive, expr_ty (func)(Parser *, const char*), Parser *p, const char* arg)
326 : : {
327 : 14 : int mark = p->mark;
328 : 14 : void *res = func(p, arg);
329 : 14 : p->mark = mark;
330 : 14 : return (res != NULL) == positive;
331 : : }
332 : :
333 : : int
334 : 941615 : _PyPegen_lookahead_with_int(int positive, Token *(func)(Parser *, int), Parser *p, int arg)
335 : : {
336 : 941615 : int mark = p->mark;
337 : 941615 : void *res = func(p, arg);
338 : 941615 : p->mark = mark;
339 : 941615 : return (res != NULL) == positive;
340 : : }
341 : :
342 : : int
343 : 1386959 : _PyPegen_lookahead(int positive, void *(func)(Parser *), Parser *p)
344 : : {
345 : 1386959 : int mark = p->mark;
346 : 1386959 : void *res = (void*)func(p);
347 : 1386959 : p->mark = mark;
348 : 1386959 : return (res != NULL) == positive;
349 : : }
350 : :
351 : : Token *
352 : 29837980 : _PyPegen_expect_token(Parser *p, int type)
353 : : {
354 [ + + ]: 29837980 : if (p->mark == p->fill) {
355 [ - + ]: 795901 : if (_PyPegen_fill_token(p) < 0) {
356 : 0 : p->error_indicator = 1;
357 : 0 : return NULL;
358 : : }
359 : : }
360 : 29837980 : Token *t = p->tokens[p->mark];
361 [ + + ]: 29837980 : if (t->type != type) {
362 : 27279260 : return NULL;
363 : : }
364 : 2558720 : p->mark += 1;
365 : 2558720 : return t;
366 : : }
367 : :
368 : : void*
369 : 0 : _PyPegen_expect_forced_result(Parser *p, void* result, const char* expected) {
370 : :
371 [ # # ]: 0 : if (p->error_indicator == 1) {
372 : 0 : return NULL;
373 : : }
374 [ # # ]: 0 : if (result == NULL) {
375 : 0 : RAISE_SYNTAX_ERROR("expected (%s)", expected);
376 : 0 : return NULL;
377 : : }
378 : 0 : return result;
379 : : }
380 : :
381 : : Token *
382 : 17608 : _PyPegen_expect_forced_token(Parser *p, int type, const char* expected) {
383 : :
384 [ - + ]: 17608 : if (p->error_indicator == 1) {
385 : 0 : return NULL;
386 : : }
387 : :
388 [ + + ]: 17608 : if (p->mark == p->fill) {
389 [ - + ]: 9921 : if (_PyPegen_fill_token(p) < 0) {
390 : 0 : p->error_indicator = 1;
391 : 0 : return NULL;
392 : : }
393 : : }
394 : 17608 : Token *t = p->tokens[p->mark];
395 [ - + ]: 17608 : if (t->type != type) {
396 : 0 : RAISE_SYNTAX_ERROR_KNOWN_LOCATION(t, "expected '%s'", expected);
397 : 0 : return NULL;
398 : : }
399 : 17608 : p->mark += 1;
400 : 17608 : return t;
401 : : }
402 : :
403 : : expr_ty
404 : 61940 : _PyPegen_expect_soft_keyword(Parser *p, const char *keyword)
405 : : {
406 [ + + ]: 61940 : if (p->mark == p->fill) {
407 [ - + ]: 17 : if (_PyPegen_fill_token(p) < 0) {
408 : 0 : p->error_indicator = 1;
409 : 0 : return NULL;
410 : : }
411 : : }
412 : 61940 : Token *t = p->tokens[p->mark];
413 [ + + ]: 61940 : if (t->type != NAME) {
414 : 37207 : return NULL;
415 : : }
416 : 24733 : const char *s = PyBytes_AsString(t->bytes);
417 [ - + ]: 24733 : if (!s) {
418 : 0 : p->error_indicator = 1;
419 : 0 : return NULL;
420 : : }
421 [ + + ]: 24733 : if (strcmp(s, keyword) != 0) {
422 : 24695 : return NULL;
423 : : }
424 : 38 : return _PyPegen_name_token(p);
425 : : }
426 : :
427 : : Token *
428 : 306539 : _PyPegen_get_last_nonnwhitespace_token(Parser *p)
429 : : {
430 : : assert(p->mark >= 0);
431 : 306539 : Token *token = NULL;
432 [ + - ]: 353253 : for (int m = p->mark - 1; m >= 0; m--) {
433 : 353253 : token = p->tokens[m];
434 [ + - + + : 353253 : if (token->type != ENDMARKER && (token->type < NEWLINE || token->type > DEDENT)) {
+ + ]
435 : : break;
436 : : }
437 : : }
438 : 306539 : return token;
439 : : }
440 : :
441 : : PyObject *
442 : 534374 : _PyPegen_new_identifier(Parser *p, const char *n)
443 : : {
444 : 534374 : PyObject *id = PyUnicode_DecodeUTF8(n, strlen(n), NULL);
445 [ - + ]: 534374 : if (!id) {
446 : 0 : goto error;
447 : : }
448 : : /* PyUnicode_DecodeUTF8 should always return a ready string. */
449 : : assert(PyUnicode_IS_READY(id));
450 : : /* Check whether there are non-ASCII characters in the
451 : : identifier; if so, normalize to NFKC. */
452 [ - + ]: 534374 : if (!PyUnicode_IS_ASCII(id))
453 : : {
454 : : PyObject *id2;
455 [ # # ]: 0 : if (!init_normalization(p))
456 : : {
457 : 0 : Py_DECREF(id);
458 : 0 : goto error;
459 : : }
460 : 0 : PyObject *form = PyUnicode_InternFromString("NFKC");
461 [ # # ]: 0 : if (form == NULL)
462 : : {
463 : 0 : Py_DECREF(id);
464 : 0 : goto error;
465 : : }
466 : 0 : PyObject *args[2] = {form, id};
467 : 0 : id2 = _PyObject_FastCall(p->normalize, args, 2);
468 : 0 : Py_DECREF(id);
469 : 0 : Py_DECREF(form);
470 [ # # ]: 0 : if (!id2) {
471 : 0 : goto error;
472 : : }
473 [ # # ]: 0 : if (!PyUnicode_Check(id2))
474 : : {
475 : 0 : PyErr_Format(PyExc_TypeError,
476 : : "unicodedata.normalize() must return a string, not "
477 : : "%.200s",
478 : : _PyType_Name(Py_TYPE(id2)));
479 : 0 : Py_DECREF(id2);
480 : 0 : goto error;
481 : : }
482 : 0 : id = id2;
483 : : }
484 : 534374 : PyUnicode_InternInPlace(&id);
485 [ - + ]: 534374 : if (_PyArena_AddPyObject(p->arena, id) < 0)
486 : : {
487 : 0 : Py_DECREF(id);
488 : 0 : goto error;
489 : : }
490 : 534374 : return id;
491 : :
492 : 0 : error:
493 : 0 : p->error_indicator = 1;
494 : 0 : return NULL;
495 : : }
496 : :
497 : : static expr_ty
498 : 1799794 : _PyPegen_name_from_token(Parser *p, Token* t)
499 : : {
500 [ + + ]: 1799794 : if (t == NULL) {
501 : 1265420 : return NULL;
502 : : }
503 : 534374 : const char *s = PyBytes_AsString(t->bytes);
504 [ - + ]: 534374 : if (!s) {
505 : 0 : p->error_indicator = 1;
506 : 0 : return NULL;
507 : : }
508 : 534374 : PyObject *id = _PyPegen_new_identifier(p, s);
509 [ - + ]: 534374 : if (id == NULL) {
510 : 0 : p->error_indicator = 1;
511 : 0 : return NULL;
512 : : }
513 : 534374 : return _PyAST_Name(id, Load, t->lineno, t->col_offset, t->end_lineno,
514 : : t->end_col_offset, p->arena);
515 : : }
516 : :
517 : : expr_ty
518 : 1799794 : _PyPegen_name_token(Parser *p)
519 : : {
520 : 1799794 : Token *t = _PyPegen_expect_token(p, NAME);
521 : 1799794 : return _PyPegen_name_from_token(p, t);
522 : : }
523 : :
524 : : void *
525 : 1013729 : _PyPegen_string_token(Parser *p)
526 : : {
527 : 1013729 : return _PyPegen_expect_token(p, STRING);
528 : : }
529 : :
530 : 0 : expr_ty _PyPegen_soft_keyword_token(Parser *p) {
531 : 0 : Token *t = _PyPegen_expect_token(p, NAME);
532 [ # # ]: 0 : if (t == NULL) {
533 : 0 : return NULL;
534 : : }
535 : : char *the_token;
536 : : Py_ssize_t size;
537 : 0 : PyBytes_AsStringAndSize(t->bytes, &the_token, &size);
538 [ # # ]: 0 : for (char **keyword = p->soft_keywords; *keyword != NULL; keyword++) {
539 [ # # ]: 0 : if (strncmp(*keyword, the_token, size) == 0) {
540 : 0 : return _PyPegen_name_from_token(p, t);
541 : : }
542 : : }
543 : 0 : return NULL;
544 : : }
545 : :
546 : : static PyObject *
547 : 832141 : parsenumber_raw(const char *s)
548 : : {
549 : : const char *end;
550 : : long x;
551 : : double dx;
552 : : Py_complex compl;
553 : : int imflag;
554 : :
555 : : assert(s != NULL);
556 : 832141 : errno = 0;
557 : 832141 : end = s + strlen(s) - 1;
558 [ + + - + ]: 832141 : imflag = *end == 'j' || *end == 'J';
559 [ + + ]: 832141 : if (s[0] == '0') {
560 : 266553 : x = (long)PyOS_strtoul(s, (char **)&end, 0);
561 [ + + + - ]: 266553 : if (x < 0 && errno == 0) {
562 : 2 : return PyLong_FromString(s, (char **)0, 0);
563 : : }
564 : : }
565 : : else {
566 : 565588 : x = PyOS_strtol(s, (char **)&end, 0);
567 : : }
568 [ + + ]: 832139 : if (*end == '\0') {
569 [ + + ]: 830013 : if (errno != 0) {
570 : 26 : return PyLong_FromString(s, (char **)0, 0);
571 : : }
572 : 829987 : return PyLong_FromLong(x);
573 : : }
574 : : /* XXX Huge floats may silently fail */
575 [ + + ]: 2126 : if (imflag) {
576 : 6 : compl.real = 0.;
577 : 6 : compl.imag = PyOS_string_to_double(s, (char **)&end, NULL);
578 [ - + - - ]: 6 : if (compl.imag == -1.0 && PyErr_Occurred()) {
579 : 0 : return NULL;
580 : : }
581 : 6 : return PyComplex_FromCComplex(compl);
582 : : }
583 : 2120 : dx = PyOS_string_to_double(s, NULL, NULL);
584 [ - + - - ]: 2120 : if (dx == -1.0 && PyErr_Occurred()) {
585 : 0 : return NULL;
586 : : }
587 : 2120 : return PyFloat_FromDouble(dx);
588 : : }
589 : :
590 : : static PyObject *
591 : 832141 : parsenumber(const char *s)
592 : : {
593 : : char *dup;
594 : : char *end;
595 : 832141 : PyObject *res = NULL;
596 : :
597 : : assert(s != NULL);
598 : :
599 [ + + ]: 832141 : if (strchr(s, '_') == NULL) {
600 : 832135 : return parsenumber_raw(s);
601 : : }
602 : : /* Create a duplicate without underscores. */
603 : 6 : dup = PyMem_Malloc(strlen(s) + 1);
604 [ - + ]: 6 : if (dup == NULL) {
605 : 0 : return PyErr_NoMemory();
606 : : }
607 : 6 : end = dup;
608 [ + + ]: 50 : for (; *s; s++) {
609 [ + + ]: 44 : if (*s != '_') {
610 : 36 : *end++ = *s;
611 : : }
612 : : }
613 : 6 : *end = '\0';
614 : 6 : res = parsenumber_raw(dup);
615 : 6 : PyMem_Free(dup);
616 : 6 : return res;
617 : : }
618 : :
619 : : expr_ty
620 : 922774 : _PyPegen_number_token(Parser *p)
621 : : {
622 : 922774 : Token *t = _PyPegen_expect_token(p, NUMBER);
623 [ + + ]: 922774 : if (t == NULL) {
624 : 90633 : return NULL;
625 : : }
626 : :
627 : 832141 : const char *num_raw = PyBytes_AsString(t->bytes);
628 [ - + ]: 832141 : if (num_raw == NULL) {
629 : 0 : p->error_indicator = 1;
630 : 0 : return NULL;
631 : : }
632 : :
633 [ - + - - ]: 832141 : if (p->feature_version < 6 && strchr(num_raw, '_') != NULL) {
634 : 0 : p->error_indicator = 1;
635 : 0 : return RAISE_SYNTAX_ERROR("Underscores in numeric literals are only supported "
636 : : "in Python 3.6 and greater");
637 : : }
638 : :
639 : 832141 : PyObject *c = parsenumber(num_raw);
640 : :
641 [ - + ]: 832141 : if (c == NULL) {
642 : 0 : p->error_indicator = 1;
643 : 0 : PyThreadState *tstate = _PyThreadState_GET();
644 : : // The only way a ValueError should happen in _this_ code is via
645 : : // PyLong_FromString hitting a length limit.
646 [ # # ]: 0 : if (tstate->current_exception != NULL &&
647 [ # # ]: 0 : Py_TYPE(tstate->current_exception) == (PyTypeObject *)PyExc_ValueError
648 : : ) {
649 : 0 : PyObject *exc = PyErr_GetRaisedException();
650 : : /* Intentionally omitting columns to avoid a wall of 1000s of '^'s
651 : : * on the error message. Nobody is going to overlook their huge
652 : : * numeric literal once given the line. */
653 : 0 : RAISE_ERROR_KNOWN_LOCATION(
654 : : p, PyExc_SyntaxError,
655 : 0 : t->lineno, -1 /* col_offset */,
656 : 0 : t->end_lineno, -1 /* end_col_offset */,
657 : : "%S - Consider hexadecimal for huge integer literals "
658 : : "to avoid decimal conversion limits.",
659 : : exc);
660 : 0 : Py_DECREF(exc);
661 : : }
662 : 0 : return NULL;
663 : : }
664 : :
665 [ - + ]: 832141 : if (_PyArena_AddPyObject(p->arena, c) < 0) {
666 : 0 : Py_DECREF(c);
667 : 0 : p->error_indicator = 1;
668 : 0 : return NULL;
669 : : }
670 : :
671 : 832141 : return _PyAST_Constant(c, NULL, t->lineno, t->col_offset, t->end_lineno,
672 : : t->end_col_offset, p->arena);
673 : : }
674 : :
675 : : /* Check that the source for a single input statement really is a single
676 : : statement by looking at what is left in the buffer after parsing.
677 : : Trailing whitespace and comments are OK. */
678 : : static int // bool
679 : 56 : bad_single_statement(Parser *p)
680 : : {
681 : 56 : char *cur = p->tok->cur;
682 : 56 : char c = *cur;
683 : :
684 : : for (;;) {
685 [ - + - + : 56 : while (c == ' ' || c == '\t' || c == '\n' || c == '\014') {
- + - + ]
686 : 0 : c = *++cur;
687 : : }
688 : :
689 [ + - ]: 56 : if (!c) {
690 : 56 : return 0;
691 : : }
692 : :
693 [ # # ]: 0 : if (c != '#') {
694 : 0 : return 1;
695 : : }
696 : :
697 : : /* Suck up comment. */
698 [ # # # # ]: 0 : while (c && c != '\n') {
699 : 0 : c = *++cur;
700 : : }
701 : : }
702 : : }
703 : :
704 : : static int
705 : 351 : compute_parser_flags(PyCompilerFlags *flags)
706 : : {
707 : 351 : int parser_flags = 0;
708 [ + + ]: 351 : if (!flags) {
709 : 4 : return 0;
710 : : }
711 [ - + ]: 347 : if (flags->cf_flags & PyCF_DONT_IMPLY_DEDENT) {
712 : 0 : parser_flags |= PyPARSE_DONT_IMPLY_DEDENT;
713 : : }
714 [ + + ]: 347 : if (flags->cf_flags & PyCF_IGNORE_COOKIE) {
715 : 146 : parser_flags |= PyPARSE_IGNORE_COOKIE;
716 : : }
717 [ - + ]: 347 : if (flags->cf_flags & CO_FUTURE_BARRY_AS_BDFL) {
718 : 0 : parser_flags |= PyPARSE_BARRY_AS_BDFL;
719 : : }
720 [ - + ]: 347 : if (flags->cf_flags & PyCF_TYPE_COMMENTS) {
721 : 0 : parser_flags |= PyPARSE_TYPE_COMMENTS;
722 : : }
723 [ + + - + ]: 347 : if ((flags->cf_flags & PyCF_ONLY_AST) && flags->cf_feature_version < 7) {
724 : 0 : parser_flags |= PyPARSE_ASYNC_HACKS;
725 : : }
726 [ - + ]: 347 : if (flags->cf_flags & PyCF_ALLOW_INCOMPLETE_INPUT) {
727 : 0 : parser_flags |= PyPARSE_ALLOW_INCOMPLETE_INPUT;
728 : : }
729 : 347 : return parser_flags;
730 : : }
731 : :
732 : : // Parser API
733 : :
734 : : Parser *
735 : 1585 : _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags,
736 : : int feature_version, int *errcode, PyArena *arena)
737 : : {
738 : 1585 : Parser *p = PyMem_Malloc(sizeof(Parser));
739 [ - + ]: 1585 : if (p == NULL) {
740 : 0 : return (Parser *) PyErr_NoMemory();
741 : : }
742 : : assert(tok != NULL);
743 : 1585 : tok->type_comments = (flags & PyPARSE_TYPE_COMMENTS) > 0;
744 : 1585 : tok->async_hacks = (flags & PyPARSE_ASYNC_HACKS) > 0;
745 : 1585 : p->tok = tok;
746 : 1585 : p->keywords = NULL;
747 : 1585 : p->n_keyword_lists = -1;
748 : 1585 : p->soft_keywords = NULL;
749 : 1585 : p->tokens = PyMem_Malloc(sizeof(Token *));
750 [ - + ]: 1585 : if (!p->tokens) {
751 : 0 : PyMem_Free(p);
752 : 0 : return (Parser *) PyErr_NoMemory();
753 : : }
754 : 1585 : p->tokens[0] = PyMem_Calloc(1, sizeof(Token));
755 [ - + ]: 1585 : if (!p->tokens[0]) {
756 : 0 : PyMem_Free(p->tokens);
757 : 0 : PyMem_Free(p);
758 : 0 : return (Parser *) PyErr_NoMemory();
759 : : }
760 [ - + ]: 1585 : if (!growable_comment_array_init(&p->type_ignore_comments, 10)) {
761 : 0 : PyMem_Free(p->tokens[0]);
762 : 0 : PyMem_Free(p->tokens);
763 : 0 : PyMem_Free(p);
764 : 0 : return (Parser *) PyErr_NoMemory();
765 : : }
766 : :
767 : 1585 : p->mark = 0;
768 : 1585 : p->fill = 0;
769 : 1585 : p->size = 1;
770 : :
771 : 1585 : p->errcode = errcode;
772 : 1585 : p->arena = arena;
773 : 1585 : p->start_rule = start_rule;
774 : 1585 : p->parsing_started = 0;
775 : 1585 : p->normalize = NULL;
776 : 1585 : p->error_indicator = 0;
777 : :
778 : 1585 : p->starting_lineno = 0;
779 : 1585 : p->starting_col_offset = 0;
780 : 1585 : p->flags = flags;
781 : 1585 : p->feature_version = feature_version;
782 : 1585 : p->known_err_token = NULL;
783 : 1585 : p->level = 0;
784 : 1585 : p->call_invalid_rules = 0;
785 : : #ifdef Py_DEBUG
786 : : p->debug = _Py_GetConfig()->parser_debug;
787 : : #endif
788 : 1585 : return p;
789 : : }
790 : :
791 : : void
792 : 1585 : _PyPegen_Parser_Free(Parser *p)
793 : : {
794 : 1585 : Py_XDECREF(p->normalize);
795 [ + + ]: 2005757 : for (int i = 0; i < p->size; i++) {
796 : 2004172 : PyMem_Free(p->tokens[i]);
797 : : }
798 : 1585 : PyMem_Free(p->tokens);
799 : 1585 : growable_comment_array_deallocate(&p->type_ignore_comments);
800 : 1585 : PyMem_Free(p);
801 : 1585 : }
802 : :
803 : : static void
804 : 0 : reset_parser_state_for_error_pass(Parser *p)
805 : : {
806 [ # # ]: 0 : for (int i = 0; i < p->fill; i++) {
807 : 0 : p->tokens[i]->memo = NULL;
808 : : }
809 : 0 : p->mark = 0;
810 : 0 : p->call_invalid_rules = 1;
811 : : // Don't try to get extra tokens in interactive mode when trying to
812 : : // raise specialized errors in the second pass.
813 : 0 : p->tok->interactive_underflow = IUNDERFLOW_STOP;
814 : 0 : }
815 : :
816 : : static inline int
817 : 0 : _is_end_of_source(Parser *p) {
818 : 0 : int err = p->tok->done;
819 [ # # # # : 0 : return err == E_EOF || err == E_EOFS || err == E_EOLS;
# # ]
820 : : }
821 : :
822 : : void *
823 : 1585 : _PyPegen_run_parser(Parser *p)
824 : : {
825 : 1585 : void *res = _PyPegen_parse(p);
826 : : assert(p->level == 0);
827 [ - + ]: 1585 : if (res == NULL) {
828 [ # # # # ]: 0 : if ((p->flags & PyPARSE_ALLOW_INCOMPLETE_INPUT) && _is_end_of_source(p)) {
829 : 0 : PyErr_Clear();
830 : 0 : return RAISE_SYNTAX_ERROR("incomplete input");
831 : : }
832 [ # # # # ]: 0 : if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_SyntaxError)) {
833 : 0 : return NULL;
834 : : }
835 : : // Make a second parser pass. In this pass we activate heavier and slower checks
836 : : // to produce better error messages and more complete diagnostics. Extra "invalid_*"
837 : : // rules will be active during parsing.
838 : 0 : Token *last_token = p->tokens[p->fill - 1];
839 : 0 : reset_parser_state_for_error_pass(p);
840 : 0 : _PyPegen_parse(p);
841 : :
842 : : // Set SyntaxErrors accordingly depending on the parser/tokenizer status at the failure
843 : : // point.
844 : 0 : _Pypegen_set_syntax_error(p, last_token);
845 : 0 : return NULL;
846 : : }
847 : :
848 [ + + - + ]: 1585 : if (p->start_rule == Py_single_input && bad_single_statement(p)) {
849 : 0 : p->tok->done = E_BADSINGLE; // This is not necessary for now, but might be in the future
850 : 0 : return RAISE_SYNTAX_ERROR("multiple statements found while compiling a single statement");
851 : : }
852 : :
853 : : // test_peg_generator defines _Py_TEST_PEGEN to not call PyAST_Validate()
854 : : #if defined(Py_DEBUG) && !defined(_Py_TEST_PEGEN)
855 : : if (p->start_rule == Py_single_input ||
856 : : p->start_rule == Py_file_input ||
857 : : p->start_rule == Py_eval_input)
858 : : {
859 : : if (!_PyAST_Validate(res)) {
860 : : return NULL;
861 : : }
862 : : }
863 : : #endif
864 : 1585 : return res;
865 : : }
866 : :
867 : : mod_ty
868 : 22 : _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filename_ob,
869 : : const char *enc, const char *ps1, const char *ps2,
870 : : PyCompilerFlags *flags, int *errcode, PyArena *arena)
871 : : {
872 : 22 : struct tok_state *tok = _PyTokenizer_FromFile(fp, enc, ps1, ps2);
873 [ - + ]: 22 : if (tok == NULL) {
874 [ # # ]: 0 : if (PyErr_Occurred()) {
875 : 0 : _PyPegen_raise_tokenizer_init_error(filename_ob);
876 : 0 : return NULL;
877 : : }
878 : 0 : return NULL;
879 : : }
880 [ + - + - : 44 : if (!tok->fp || ps1 != NULL || ps2 != NULL ||
+ - - + ]
881 : 22 : PyUnicode_CompareWithASCIIString(filename_ob, "<stdin>") == 0) {
882 : 0 : tok->fp_interactive = 1;
883 : : }
884 : : // This transfers the ownership to the tokenizer
885 : 22 : tok->filename = Py_NewRef(filename_ob);
886 : :
887 : : // From here on we need to clean up even if there's an error
888 : 22 : mod_ty result = NULL;
889 : :
890 : 22 : int parser_flags = compute_parser_flags(flags);
891 : 22 : Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, PY_MINOR_VERSION,
892 : : errcode, arena);
893 [ - + ]: 22 : if (p == NULL) {
894 : 0 : goto error;
895 : : }
896 : :
897 : 22 : result = _PyPegen_run_parser(p);
898 : 22 : _PyPegen_Parser_Free(p);
899 : :
900 : 22 : error:
901 : 22 : _PyTokenizer_Free(tok);
902 : 22 : return result;
903 : : }
904 : :
905 : : mod_ty
906 : 329 : _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filename_ob,
907 : : PyCompilerFlags *flags, PyArena *arena)
908 : : {
909 : 329 : int exec_input = start_rule == Py_file_input;
910 : :
911 : : struct tok_state *tok;
912 [ + + + + ]: 329 : if (flags != NULL && flags->cf_flags & PyCF_IGNORE_COOKIE) {
913 : 146 : tok = _PyTokenizer_FromUTF8(str, exec_input);
914 : : } else {
915 : 183 : tok = _PyTokenizer_FromString(str, exec_input);
916 : : }
917 [ - + ]: 329 : if (tok == NULL) {
918 [ # # ]: 0 : if (PyErr_Occurred()) {
919 : 0 : _PyPegen_raise_tokenizer_init_error(filename_ob);
920 : : }
921 : 0 : return NULL;
922 : : }
923 : : // This transfers the ownership to the tokenizer
924 : 329 : tok->filename = Py_NewRef(filename_ob);
925 : :
926 : : // We need to clear up from here on
927 : 329 : mod_ty result = NULL;
928 : :
929 : 329 : int parser_flags = compute_parser_flags(flags);
930 [ + + ]: 325 : int feature_version = flags && (flags->cf_flags & PyCF_ONLY_AST) ?
931 [ + + ]: 654 : flags->cf_feature_version : PY_MINOR_VERSION;
932 : 329 : Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, feature_version,
933 : : NULL, arena);
934 [ - + ]: 329 : if (p == NULL) {
935 : 0 : goto error;
936 : : }
937 : :
938 : 329 : result = _PyPegen_run_parser(p);
939 : 329 : _PyPegen_Parser_Free(p);
940 : :
941 : 329 : error:
942 : 329 : _PyTokenizer_Free(tok);
943 : 329 : return result;
944 : : }
|