Branch data Line data Source code
1 : : #include <stdbool.h>
2 : :
3 : : #include <Python.h>
4 : :
5 : : #include "tokenizer.h"
6 : : #include "pegen.h"
7 : : #include "string_parser.h"
8 : :
9 : : //// STRING HANDLING FUNCTIONS ////
10 : :
11 : : static int
12 : 0 : warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t)
13 : : {
14 : 0 : unsigned char c = *first_invalid_escape;
15 [ # # # # ]: 0 : int octal = ('4' <= c && c <= '7');
16 : 0 : PyObject *msg =
17 : : octal
18 : 0 : ? PyUnicode_FromFormat("invalid octal escape sequence '\\%.3s'",
19 : : first_invalid_escape)
20 [ # # ]: 0 : : PyUnicode_FromFormat("invalid escape sequence '\\%c'", c);
21 [ # # ]: 0 : if (msg == NULL) {
22 : 0 : return -1;
23 : : }
24 : : PyObject *category;
25 [ # # ]: 0 : if (p->feature_version >= 12) {
26 : 0 : category = PyExc_SyntaxWarning;
27 : : }
28 : : else {
29 : 0 : category = PyExc_DeprecationWarning;
30 : : }
31 [ # # ]: 0 : if (PyErr_WarnExplicitObject(category, msg, p->tok->filename,
32 : : t->lineno, NULL, NULL) < 0) {
33 [ # # ]: 0 : if (PyErr_ExceptionMatches(category)) {
34 : : /* Replace the DeprecationWarning exception with a SyntaxError
35 : : to get a more accurate error report */
36 : 0 : PyErr_Clear();
37 : :
38 : : /* This is needed, in order for the SyntaxError to point to the token t,
39 : : since _PyPegen_raise_error uses p->tokens[p->fill - 1] for the
40 : : error location, if p->known_err_token is not set. */
41 : 0 : p->known_err_token = t;
42 [ # # ]: 0 : if (octal) {
43 : 0 : RAISE_SYNTAX_ERROR("invalid octal escape sequence '\\%.3s'",
44 : : first_invalid_escape);
45 : : }
46 : : else {
47 : 0 : RAISE_SYNTAX_ERROR("invalid escape sequence '\\%c'", c);
48 : : }
49 : : }
50 : 0 : Py_DECREF(msg);
51 : 0 : return -1;
52 : : }
53 : 0 : Py_DECREF(msg);
54 : 0 : return 0;
55 : : }
56 : :
57 : : static PyObject *
58 : 0 : decode_utf8(const char **sPtr, const char *end)
59 : : {
60 : : const char *s;
61 : : const char *t;
62 : 0 : t = s = *sPtr;
63 [ # # # # ]: 0 : while (s < end && (*s & 0x80)) {
64 : 0 : s++;
65 : : }
66 : 0 : *sPtr = s;
67 : 0 : return PyUnicode_DecodeUTF8(t, s - t, NULL);
68 : : }
69 : :
70 : : static PyObject *
71 : 2190 : decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t)
72 : : {
73 : : PyObject *v;
74 : : PyObject *u;
75 : : char *buf;
76 : : char *p;
77 : : const char *end;
78 : :
79 : : /* check for integer overflow */
80 [ - + ]: 2190 : if (len > SIZE_MAX / 6) {
81 : 0 : return NULL;
82 : : }
83 : : /* "ä" (2 bytes) may become "\U000000E4" (10 bytes), or 1:5
84 : : "\ä" (3 bytes) may become "\u005c\U000000E4" (16 bytes), or ~1:6 */
85 : 2190 : u = PyBytes_FromStringAndSize((char *)NULL, len * 6);
86 [ - + ]: 2190 : if (u == NULL) {
87 : 0 : return NULL;
88 : : }
89 : 2190 : p = buf = PyBytes_AsString(u);
90 [ - + ]: 2190 : if (p == NULL) {
91 : 0 : return NULL;
92 : : }
93 : 2190 : end = s + len;
94 [ + + ]: 49516 : while (s < end) {
95 [ + + ]: 47326 : if (*s == '\\') {
96 : 966 : *p++ = *s++;
97 [ + - - + ]: 966 : if (s >= end || *s & 0x80) {
98 : 0 : strcpy(p, "u005c");
99 : 0 : p += 5;
100 [ # # ]: 0 : if (s >= end) {
101 : 0 : break;
102 : : }
103 : : }
104 : : }
105 [ - + ]: 47326 : if (*s & 0x80) {
106 : : PyObject *w;
107 : : int kind;
108 : : const void *data;
109 : : Py_ssize_t w_len;
110 : : Py_ssize_t i;
111 : 0 : w = decode_utf8(&s, end);
112 [ # # ]: 0 : if (w == NULL) {
113 : 0 : Py_DECREF(u);
114 : 0 : return NULL;
115 : : }
116 : 0 : kind = PyUnicode_KIND(w);
117 : 0 : data = PyUnicode_DATA(w);
118 : 0 : w_len = PyUnicode_GET_LENGTH(w);
119 [ # # ]: 0 : for (i = 0; i < w_len; i++) {
120 : 0 : Py_UCS4 chr = PyUnicode_READ(kind, data, i);
121 : 0 : sprintf(p, "\\U%08x", chr);
122 : 0 : p += 10;
123 : : }
124 : : /* Should be impossible to overflow */
125 : : assert(p - buf <= PyBytes_GET_SIZE(u));
126 : 0 : Py_DECREF(w);
127 : : }
128 : : else {
129 : 47326 : *p++ = *s++;
130 : : }
131 : : }
132 : 2190 : len = p - buf;
133 : 2190 : s = buf;
134 : :
135 : : const char *first_invalid_escape;
136 : 2190 : v = _PyUnicode_DecodeUnicodeEscapeInternal(s, len, NULL, NULL, &first_invalid_escape);
137 : :
138 [ + - - + ]: 2190 : if (v != NULL && first_invalid_escape != NULL) {
139 [ # # ]: 0 : if (warn_invalid_escape_sequence(parser, first_invalid_escape, t) < 0) {
140 : : /* We have not decref u before because first_invalid_escape points
141 : : inside u. */
142 : 0 : Py_XDECREF(u);
143 : 0 : Py_DECREF(v);
144 : 0 : return NULL;
145 : : }
146 : : }
147 : 2190 : Py_XDECREF(u);
148 : 2190 : return v;
149 : : }
150 : :
151 : : static PyObject *
152 : 65 : decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
153 : : {
154 : : const char *first_invalid_escape;
155 : 65 : PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, &first_invalid_escape);
156 [ - + ]: 65 : if (result == NULL) {
157 : 0 : return NULL;
158 : : }
159 : :
160 [ - + ]: 65 : if (first_invalid_escape != NULL) {
161 [ # # ]: 0 : if (warn_invalid_escape_sequence(p, first_invalid_escape, t) < 0) {
162 : 0 : Py_DECREF(result);
163 : 0 : return NULL;
164 : : }
165 : : }
166 : 65 : return result;
167 : : }
168 : :
169 : : /* s must include the bracketing quote characters, and r, b, u,
170 : : &/or f prefixes (if any), and embedded escape sequences (if any).
171 : : _PyPegen_parsestr parses it, and sets *result to decoded Python string object.
172 : : If the string is an f-string, set *fstr and *fstrlen to the unparsed
173 : : string object. Return 0 if no errors occurred. */
174 : : int
175 : 22069 : _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
176 : : const char **fstr, Py_ssize_t *fstrlen, Token *t)
177 : : {
178 : 22069 : const char *s = PyBytes_AsString(t->bytes);
179 [ - + ]: 22069 : if (s == NULL) {
180 : 0 : return -1;
181 : : }
182 : :
183 : : size_t len;
184 : 22069 : int quote = Py_CHARMASK(*s);
185 : 22069 : int fmode = 0;
186 : 22069 : *bytesmode = 0;
187 : 22069 : *rawmode = 0;
188 : 22069 : *result = NULL;
189 : 22069 : *fstr = NULL;
190 [ + + ]: 22069 : if (Py_ISALPHA(quote)) {
191 [ + + + + ]: 2931 : while (!*bytesmode || !*rawmode) {
192 [ + + - + ]: 2926 : if (quote == 'b' || quote == 'B') {
193 : 280 : quote =(unsigned char)*++s;
194 : 280 : *bytesmode = 1;
195 : : }
196 [ + - - + ]: 2646 : else if (quote == 'u' || quote == 'U') {
197 : 0 : quote = (unsigned char)*++s;
198 : : }
199 [ + + - + ]: 2646 : else if (quote == 'r' || quote == 'R') {
200 : 198 : quote = (unsigned char)*++s;
201 : 198 : *rawmode = 1;
202 : : }
203 [ + + - + ]: 2448 : else if (quote == 'f' || quote == 'F') {
204 : 992 : quote = (unsigned char)*++s;
205 : 992 : fmode = 1;
206 : : }
207 : : else {
208 : : break;
209 : : }
210 : : }
211 : : }
212 : :
213 : : /* fstrings are only allowed in Python 3.6 and greater */
214 [ + + - + ]: 22069 : if (fmode && p->feature_version < 6) {
215 : 0 : p->error_indicator = 1;
216 : 0 : RAISE_SYNTAX_ERROR("Format strings are only supported in Python 3.6 and greater");
217 : 0 : return -1;
218 : : }
219 : :
220 [ + + - + ]: 22069 : if (fmode && *bytesmode) {
221 : 0 : PyErr_BadInternalCall();
222 : 0 : return -1;
223 : : }
224 [ + + - + ]: 22069 : if (quote != '\'' && quote != '\"') {
225 : 0 : PyErr_BadInternalCall();
226 : 0 : return -1;
227 : : }
228 : : /* Skip the leading quote char. */
229 : 22069 : s++;
230 : 22069 : len = strlen(s);
231 [ - + ]: 22069 : if (len > INT_MAX) {
232 : 0 : PyErr_SetString(PyExc_OverflowError, "string to parse is too long");
233 : 0 : return -1;
234 : : }
235 [ - + ]: 22069 : if (s[--len] != quote) {
236 : : /* Last quote char must match the first. */
237 : 0 : PyErr_BadInternalCall();
238 : 0 : return -1;
239 : : }
240 [ + + + + : 22069 : if (len >= 4 && s[0] == quote && s[1] == quote) {
+ - ]
241 : : /* A triple quoted string. We've already skipped one quote at
242 : : the start and one at the end of the string. Now skip the
243 : : two at the start. */
244 : 2993 : s += 2;
245 : 2993 : len -= 2;
246 : : /* And check that the last two match. */
247 [ + - - + ]: 2993 : if (s[--len] != quote || s[--len] != quote) {
248 : 0 : PyErr_BadInternalCall();
249 : 0 : return -1;
250 : : }
251 : : }
252 : :
253 [ + + ]: 22069 : if (fmode) {
254 : : /* Just return the bytes. The caller will parse the resulting
255 : : string. */
256 : 992 : *fstr = s;
257 : 992 : *fstrlen = len;
258 : 992 : return 0;
259 : : }
260 : :
261 : : /* Not an f-string. */
262 : : /* Avoid invoking escape decoding routines if possible. */
263 [ + + + + ]: 21077 : *rawmode = *rawmode || strchr(s, '\\') == NULL;
264 [ + + ]: 21077 : if (*bytesmode) {
265 : : /* Disallow non-ASCII characters. */
266 : : const char *ch;
267 [ + + ]: 1567 : for (ch = s; *ch; ch++) {
268 [ - + ]: 1287 : if (Py_CHARMASK(*ch) >= 0x80) {
269 : 0 : RAISE_SYNTAX_ERROR(
270 : : "bytes can only contain ASCII "
271 : : "literal characters");
272 : 0 : return -1;
273 : : }
274 : : }
275 [ + + ]: 280 : if (*rawmode) {
276 : 215 : *result = PyBytes_FromStringAndSize(s, len);
277 : : }
278 : : else {
279 : 65 : *result = decode_bytes_with_escapes(p, s, len, t);
280 : : }
281 : : }
282 : : else {
283 [ + + ]: 20797 : if (*rawmode) {
284 : 20170 : *result = PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL);
285 : : }
286 : : else {
287 : 627 : *result = decode_unicode_with_escapes(p, s, len, t);
288 : : }
289 : : }
290 [ - + ]: 21077 : return *result == NULL ? -1 : 0;
291 : : }
292 : :
293 : :
294 : :
295 : : // FSTRING STUFF
296 : :
297 : : /* Fix locations for the given node and its children.
298 : :
299 : : `parent` is the enclosing node.
300 : : `expr_start` is the starting position of the expression (pointing to the open brace).
301 : : `n` is the node which locations are going to be fixed relative to parent.
302 : : `expr_str` is the child node's string representation, including braces.
303 : : */
304 : : static bool
305 : 1234 : fstring_find_expr_location(Token *parent, const char* expr_start, char *expr_str, int *p_lines, int *p_cols)
306 : : {
307 : 1234 : *p_lines = 0;
308 : 1234 : *p_cols = 0;
309 : : assert(expr_start != NULL && *expr_start == '{');
310 [ + - + - ]: 1234 : if (parent && parent->bytes) {
311 : 1234 : const char *parent_str = PyBytes_AsString(parent->bytes);
312 [ - + ]: 1234 : if (!parent_str) {
313 : 0 : return false;
314 : : }
315 : : // The following is needed, in order to correctly shift the column
316 : : // offset, in the case that (disregarding any whitespace) a newline
317 : : // immediately follows the opening curly brace of the fstring expression.
318 : 1234 : bool newline_after_brace = 1;
319 : 1234 : const char *start = expr_start + 1;
320 [ + - + - : 1234 : while (start && *start != '}' && *start != '\n') {
+ - ]
321 [ + - + - : 1234 : if (*start != ' ' && *start != '\t' && *start != '\f') {
+ - ]
322 : 1234 : newline_after_brace = 0;
323 : 1234 : break;
324 : : }
325 : 0 : start++;
326 : : }
327 : :
328 : : // Account for the characters from the last newline character to our
329 : : // left until the beginning of expr_start.
330 [ + - ]: 1234 : if (!newline_after_brace) {
331 : 1234 : start = expr_start;
332 [ + + + + ]: 20979 : while (start > parent_str && *start != '\n') {
333 : 19745 : start--;
334 : : }
335 : 1234 : *p_cols += (int)(expr_start - start);
336 [ + + ]: 1234 : if (*start == '\n') {
337 : 4 : *p_cols -= 1;
338 : : }
339 : : }
340 : : /* adjust the start based on the number of newlines encountered
341 : : before the f-string expression */
342 [ + + ]: 21296 : for (const char *p = parent_str; p < expr_start; p++) {
343 [ + + ]: 20062 : if (*p == '\n') {
344 : 10 : (*p_lines)++;
345 : : }
346 : : }
347 : : }
348 : 1234 : return true;
349 : : }
350 : :
351 : :
352 : : /* Compile this expression in to an expr_ty. Add parens around the
353 : : expression, in order to allow leading spaces in the expression. */
354 : : static expr_ty
355 : 1234 : fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
356 : : Token *t)
357 : : {
358 : 1234 : expr_ty expr = NULL;
359 : : char *str;
360 : : Py_ssize_t len;
361 : : const char *s;
362 : 1234 : expr_ty result = NULL;
363 : :
364 : : assert(expr_end >= expr_start);
365 : : assert(*(expr_start-1) == '{');
366 : : assert(*expr_end == '}' || *expr_end == '!' || *expr_end == ':' ||
367 : : *expr_end == '=');
368 : :
369 : : /* If the substring is all whitespace, it's an error. We need to catch this
370 : : here, and not when we call PyParser_SimpleParseStringFlagsFilename,
371 : : because turning the expression '' in to '()' would go from being invalid
372 : : to valid. */
373 [ + - ]: 1234 : for (s = expr_start; s != expr_end; s++) {
374 : 1234 : char c = *s;
375 : : /* The Python parser ignores only the following whitespace
376 : : characters (\r already is converted to \n). */
377 [ + - + - : 1234 : if (!(c == ' ' || c == '\t' || c == '\n' || c == '\f')) {
+ - + - ]
378 : 1234 : break;
379 : : }
380 : : }
381 : :
382 [ - + ]: 1234 : if (s == expr_end) {
383 [ # # # # : 0 : if (*expr_end == '!' || *expr_end == ':' || *expr_end == '=') {
# # ]
384 : 0 : RAISE_SYNTAX_ERROR("f-string: expression required before '%c'", *expr_end);
385 : 0 : return NULL;
386 : : }
387 : 0 : RAISE_SYNTAX_ERROR("f-string: empty expression not allowed");
388 : 0 : return NULL;
389 : : }
390 : :
391 : 1234 : len = expr_end - expr_start;
392 : : /* Allocate 3 extra bytes: open paren, close paren, null byte. */
393 : 1234 : str = PyMem_Calloc(len + 3, sizeof(char));
394 [ - + ]: 1234 : if (str == NULL) {
395 : 0 : PyErr_NoMemory();
396 : 0 : return NULL;
397 : : }
398 : :
399 : : // The call to fstring_find_expr_location is responsible for finding the column offset
400 : : // the generated AST nodes need to be shifted to the right, which is equal to the number
401 : : // of the f-string characters before the expression starts.
402 : 1234 : memcpy(str+1, expr_start, len);
403 : : int lines, cols;
404 [ - + ]: 1234 : if (!fstring_find_expr_location(t, expr_start-1, str+1, &lines, &cols)) {
405 : 0 : PyMem_Free(str);
406 : 0 : return NULL;
407 : : }
408 : :
409 : : // The parentheses are needed in order to allow for leading whitespace within
410 : : // the f-string expression. This consequently gets parsed as a group (see the
411 : : // group rule in python.gram).
412 : 1234 : str[0] = '(';
413 : 1234 : str[len+1] = ')';
414 : :
415 : 1234 : struct tok_state* tok = _PyTokenizer_FromString(str, 1);
416 [ - + ]: 1234 : if (tok == NULL) {
417 : 0 : PyMem_Free(str);
418 : 0 : return NULL;
419 : : }
420 : 1234 : tok->filename = Py_NewRef(p->tok->filename);
421 : 1234 : tok->lineno = t->lineno + lines - 1;
422 : :
423 : 1234 : Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version,
424 : : NULL, p->arena);
425 : :
426 : 1234 : p2->starting_lineno = t->lineno + lines;
427 [ + + ]: 1234 : p2->starting_col_offset = lines != 0 ? cols : t->col_offset + cols;
428 : :
429 : 1234 : expr = _PyPegen_run_parser(p2);
430 : :
431 [ - + ]: 1234 : if (expr == NULL) {
432 : 0 : goto exit;
433 : : }
434 : 1234 : result = expr;
435 : :
436 : 1234 : exit:
437 : 1234 : PyMem_Free(str);
438 : 1234 : _PyPegen_Parser_Free(p2);
439 : 1234 : _PyTokenizer_Free(tok);
440 : 1234 : return result;
441 : : }
442 : :
443 : : /* Return -1 on error.
444 : :
445 : : Return 0 if we reached the end of the literal.
446 : :
447 : : Return 1 if we haven't reached the end of the literal, but we want
448 : : the caller to process the literal up to this point. Used for
449 : : doubled braces.
450 : : */
451 : : static int
452 : 2292 : fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
453 : : PyObject **literal, int recurse_lvl, Token *t)
454 : : {
455 : : /* Get any literal string. It ends when we hit an un-doubled left
456 : : brace (which isn't part of a unicode name escape such as
457 : : "\N{EULER CONSTANT}"), or the end of the string. */
458 : :
459 : 2292 : const char *s = *str;
460 : 2292 : const char *literal_start = s;
461 : 2292 : int result = 0;
462 : :
463 : : assert(*literal == NULL);
464 [ + + ]: 21072 : while (s < end) {
465 : 20080 : char ch = *s++;
466 [ + + + + : 20080 : if (!raw && ch == '\\' && s < end) {
+ - ]
467 : 64 : ch = *s++;
468 [ - + ]: 64 : if (ch == 'N') {
469 : : /* We need to look at and skip matching braces for "\N{name}"
470 : : sequences because otherwise we'll think the opening '{'
471 : : starts an expression, which is not the case with "\N".
472 : : Keep looking for either a matched '{' '}' pair, or the end
473 : : of the string. */
474 : :
475 [ # # # # ]: 0 : if (s < end && *s++ == '{') {
476 [ # # # # ]: 0 : while (s < end && *s++ != '}') {
477 : : }
478 : 0 : continue;
479 : : }
480 : :
481 : : /* This is an invalid "\N" sequence, since it's a "\N" not
482 : : followed by a "{". Just keep parsing this literal. This
483 : : error will be caught later by
484 : : decode_unicode_with_escapes(). */
485 : 0 : continue;
486 : : }
487 [ - + - - ]: 64 : if (ch == '{' && warn_invalid_escape_sequence(p, s-1, t) < 0) {
488 : 0 : return -1;
489 : : }
490 : : }
491 [ + + + + ]: 20080 : if (ch == '{' || ch == '}') {
492 : : /* Check for doubled braces, but only at the top level. If
493 : : we checked at every level, then f'{0:{3}}' would fail
494 : : with the two closing braces. */
495 [ + + ]: 1300 : if (recurse_lvl == 0) {
496 [ + - + + ]: 1263 : if (s < end && *s == ch) {
497 : : /* We're going to tell the caller that the literal ends
498 : : here, but that they should continue scanning. But also
499 : : skip over the second brace when we resume scanning. */
500 : 32 : *str = s + 1;
501 : 32 : result = 1;
502 : 32 : goto done;
503 : : }
504 : :
505 : : /* Where a single '{' is the start of a new expression, a
506 : : single '}' is not allowed. */
507 [ - + ]: 1231 : if (ch == '}') {
508 : 0 : *str = s - 1;
509 : 0 : RAISE_SYNTAX_ERROR("f-string: single '}' is not allowed");
510 : 0 : return -1;
511 : : }
512 : : }
513 : : /* We're either at a '{', which means we're starting another
514 : : expression; or a '}', which means we're at the end of this
515 : : f-string (for a nested format_spec). */
516 : 1268 : s--;
517 : 1268 : break;
518 : : }
519 : : }
520 : 2260 : *str = s;
521 : : assert(s <= end);
522 : : assert(s == end || *s == '{' || *s == '}');
523 : 2292 : done:
524 [ + + ]: 2292 : if (literal_start != s) {
525 [ + + ]: 1576 : if (raw) {
526 : 13 : *literal = PyUnicode_DecodeUTF8Stateful(literal_start,
527 : : s - literal_start,
528 : : NULL, NULL);
529 : : }
530 : : else {
531 : 1563 : *literal = decode_unicode_with_escapes(p, literal_start,
532 : 1563 : s - literal_start, t);
533 : : }
534 [ - + ]: 1576 : if (!*literal) {
535 : 0 : return -1;
536 : : }
537 : : }
538 : 2292 : return result;
539 : : }
540 : :
541 : : /* Forward declaration because parsing is recursive. */
542 : : static expr_ty
543 : : fstring_parse(Parser *p, const char **str, const char *end, int raw, int recurse_lvl,
544 : : Token *first_token, Token* t, Token *last_token);
545 : :
546 : : /* Parse the f-string at *str, ending at end. We know *str starts an
547 : : expression (so it must be a '{'). Returns the FormattedValue node, which
548 : : includes the expression, conversion character, format_spec expression, and
549 : : optionally the text of the expression (if = is used).
550 : :
551 : : Note that I don't do a perfect job here: I don't make sure that a
552 : : closing brace doesn't match an opening paren, for example. It
553 : : doesn't need to error on all invalid expressions, just correctly
554 : : find the end of all valid ones. Any errors inside the expression
555 : : will be caught when we parse it later.
556 : :
557 : : *expression is set to the expression. For an '=' "debug" expression,
558 : : *expr_text is set to the debug text (the original text of the expression,
559 : : including the '=' and any whitespace around it, as a string object). If
560 : : not a debug expression, *expr_text set to NULL. */
561 : : static int
562 : 1234 : fstring_find_expr(Parser *p, const char **str, const char *end, int raw, int recurse_lvl,
563 : : PyObject **expr_text, expr_ty *expression, Token *first_token,
564 : : Token *t, Token *last_token)
565 : : {
566 : : /* Return -1 on error, else 0. */
567 : :
568 : : const char *expr_start;
569 : : const char *expr_end;
570 : : expr_ty simple_expression;
571 : 1234 : expr_ty format_spec = NULL; /* Optional format specifier. */
572 : 1234 : int conversion = -1; /* The conversion char. Use default if not
573 : : specified, or !r if using = and no format
574 : : spec. */
575 : :
576 : : /* 0 if we're not in a string, else the quote char we're trying to
577 : : match (single or double quote). */
578 : 1234 : char quote_char = 0;
579 : :
580 : : /* If we're inside a string, 1=normal, 3=triple-quoted. */
581 : 1234 : int string_type = 0;
582 : :
583 : : /* Keep track of nesting level for braces/parens/brackets in
584 : : expressions. */
585 : 1234 : Py_ssize_t nested_depth = 0;
586 : : char parenstack[MAXLEVEL];
587 : :
588 : 1234 : *expr_text = NULL;
589 : :
590 : : /* Can only nest one level deep. */
591 [ - + ]: 1234 : if (recurse_lvl >= 2) {
592 : 0 : RAISE_SYNTAX_ERROR("f-string: expressions nested too deeply");
593 : 0 : goto error;
594 : : }
595 : :
596 : : /* The first char must be a left brace, or we wouldn't have gotten
597 : : here. Skip over it. */
598 : : assert(**str == '{');
599 : 1234 : *str += 1;
600 : :
601 : 1234 : expr_start = *str;
602 [ + - ]: 13089 : for (; *str < end; (*str)++) {
603 : : char ch;
604 : :
605 : : /* Loop invariants. */
606 : : assert(nested_depth >= 0);
607 : : assert(*str >= expr_start && *str < end);
608 : : if (quote_char) {
609 : : assert(string_type == 1 || string_type == 3);
610 : : } else {
611 : : assert(string_type == 0);
612 : : }
613 : :
614 : 13089 : ch = **str;
615 : : /* Nowhere inside an expression is a backslash allowed. */
616 [ - + ]: 13089 : if (ch == '\\') {
617 : : /* Error: can't include a backslash character, inside
618 : : parens or strings or not. */
619 : 0 : RAISE_SYNTAX_ERROR(
620 : : "f-string expression part "
621 : : "cannot include a backslash");
622 : 0 : goto error;
623 : : }
624 [ + + ]: 13089 : if (quote_char) {
625 : : /* We're inside a string. See if we're at the end. */
626 : : /* This code needs to implement the same non-error logic
627 : : as tok_get from tokenizer.c, at the letter_quote
628 : : label. To actually share that code would be a
629 : : nightmare. But, it's unlikely to change and is small,
630 : : so duplicate it here. Note we don't need to catch all
631 : : of the errors, since they'll be caught when parsing the
632 : : expression. We just need to match the non-error
633 : : cases. Thus we can ignore \n in single-quoted strings,
634 : : for example. Or non-terminated strings. */
635 [ + + ]: 164 : if (ch == quote_char) {
636 : : /* Does this match the string_type (single or triple
637 : : quoted)? */
638 [ - + ]: 64 : if (string_type == 3) {
639 [ # # # # : 0 : if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) {
# # ]
640 : : /* We're at the end of a triple quoted string. */
641 : 0 : *str += 2;
642 : 0 : string_type = 0;
643 : 0 : quote_char = 0;
644 : 0 : continue;
645 : : }
646 : : } else {
647 : : /* We're at the end of a normal string. */
648 : 64 : quote_char = 0;
649 : 64 : string_type = 0;
650 : 64 : continue;
651 : : }
652 : : }
653 [ + + + + ]: 12925 : } else if (ch == '\'' || ch == '"') {
654 : : /* Is this a triple quoted string? */
655 [ + - + + : 64 : if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) {
- + ]
656 : 0 : string_type = 3;
657 : 0 : *str += 2;
658 : : } else {
659 : : /* Start of a normal string. */
660 : 64 : string_type = 1;
661 : : }
662 : : /* Start looking for the end of the string. */
663 : 64 : quote_char = ch;
664 [ + + + - : 12861 : } else if (ch == '[' || ch == '{' || ch == '(') {
+ + ]
665 [ - + ]: 225 : if (nested_depth >= MAXLEVEL) {
666 : 0 : RAISE_SYNTAX_ERROR("f-string: too many nested parenthesis");
667 : 0 : goto error;
668 : : }
669 : 225 : parenstack[nested_depth] = ch;
670 : 225 : nested_depth++;
671 [ - + ]: 12636 : } else if (ch == '#') {
672 : : /* Error: can't include a comment character, inside parens
673 : : or not. */
674 : 0 : RAISE_SYNTAX_ERROR("f-string expression part cannot include '#'");
675 : 0 : goto error;
676 [ + + + + ]: 12636 : } else if (nested_depth == 0 &&
677 [ + + + + : 10950 : (ch == '!' || ch == ':' || ch == '}' ||
+ + ]
678 [ + + - + ]: 10024 : ch == '=' || ch == '>' || ch == '<')) {
679 : : /* See if there's a next character. */
680 [ + + ]: 1239 : if (*str+1 < end) {
681 : 1007 : char next = *(*str+1);
682 : :
683 : : /* For "!=". since '=' is not an allowed conversion character,
684 : : nothing is lost in this test. */
685 [ + + + - : 1007 : if ((ch == '!' && next == '=') || /* != */
+ + ]
686 [ + - - + ]: 1007 : (ch == '=' && next == '=') || /* == */
687 [ - - + + ]: 1007 : (ch == '<' && next == '=') || /* <= */
688 [ - + ]: 5 : (ch == '>' && next == '=') /* >= */
689 : : ) {
690 : 0 : *str += 1;
691 : 0 : continue;
692 : : }
693 : : }
694 : : /* Don't get out of the loop for these, if they're single
695 : : chars (not part of 2-char tokens). If by themselves, they
696 : : don't end an expression (unlike say '!'). */
697 [ + + - + ]: 1239 : if (ch == '>' || ch == '<') {
698 : 5 : continue;
699 : : }
700 : :
701 : : /* Normal way out of this loop. */
702 : 1234 : break;
703 [ + + + - : 11397 : } else if (ch == ']' || ch == '}' || ch == ')') {
+ + ]
704 [ - + ]: 225 : if (!nested_depth) {
705 : 0 : RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", ch);
706 : 0 : goto error;
707 : : }
708 : 225 : nested_depth--;
709 : 225 : int opening = (unsigned char)parenstack[nested_depth];
710 [ + + - + : 225 : if (!((opening == '(' && ch == ')') ||
+ - - - ]
711 [ - + ]: 50 : (opening == '[' && ch == ']') ||
712 [ # # ]: 0 : (opening == '{' && ch == '}')))
713 : : {
714 : 0 : RAISE_SYNTAX_ERROR(
715 : : "f-string: closing parenthesis '%c' "
716 : : "does not match opening parenthesis '%c'",
717 : : ch, opening);
718 : 0 : goto error;
719 : : }
720 : : } else {
721 : : /* Just consume this char and loop around. */
722 : : }
723 : : }
724 : 1234 : expr_end = *str;
725 : : /* If we leave the above loop in a string or with mismatched parens, we
726 : : don't really care. We'll get a syntax error when compiling the
727 : : expression. But, we can produce a better error message, so let's just
728 : : do that.*/
729 [ - + ]: 1234 : if (quote_char) {
730 : 0 : RAISE_SYNTAX_ERROR("f-string: unterminated string");
731 : 0 : goto error;
732 : : }
733 [ - + ]: 1234 : if (nested_depth) {
734 : 0 : int opening = (unsigned char)parenstack[nested_depth - 1];
735 : 0 : RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", opening);
736 : 0 : goto error;
737 : : }
738 : :
739 [ - + ]: 1234 : if (*str >= end) {
740 : 0 : goto unexpected_end_of_string;
741 : : }
742 : :
743 : : /* Compile the expression as soon as possible, so we show errors
744 : : related to the expression before errors related to the
745 : : conversion or format_spec. */
746 : 1234 : simple_expression = fstring_compile_expr(p, expr_start, expr_end, t);
747 [ - + ]: 1234 : if (!simple_expression) {
748 : 0 : goto error;
749 : : }
750 : :
751 : : /* Check for =, which puts the text value of the expression in
752 : : expr_text. */
753 [ + + ]: 1234 : if (**str == '=') {
754 [ - + ]: 3 : if (p->feature_version < 8) {
755 : 0 : RAISE_SYNTAX_ERROR("f-string: self documenting expressions are "
756 : : "only supported in Python 3.8 and greater");
757 : 0 : goto error;
758 : : }
759 : 3 : *str += 1;
760 : :
761 : : /* Skip over ASCII whitespace. No need to test for end of string
762 : : here, since we know there's at least a trailing quote somewhere
763 : : ahead. */
764 [ - + ]: 3 : while (Py_ISSPACE(**str)) {
765 : 0 : *str += 1;
766 : : }
767 [ - + ]: 3 : if (*str >= end) {
768 : 0 : goto unexpected_end_of_string;
769 : : }
770 : : /* Set *expr_text to the text of the expression. */
771 : 3 : *expr_text = PyUnicode_FromStringAndSize(expr_start, *str-expr_start);
772 [ - + ]: 3 : if (!*expr_text) {
773 : 0 : goto error;
774 : : }
775 : : }
776 : :
777 : : /* Check for a conversion char, if present. */
778 [ + + ]: 1234 : if (**str == '!') {
779 : 308 : *str += 1;
780 : 308 : const char *conv_start = *str;
781 : : while (1) {
782 [ - + ]: 616 : if (*str >= end) {
783 : 0 : goto unexpected_end_of_string;
784 : : }
785 [ + + + + ]: 616 : if (**str == '}' || **str == ':') {
786 : : break;
787 : : }
788 : 308 : *str += 1;
789 : : }
790 [ - + ]: 308 : if (*str == conv_start) {
791 : 0 : RAISE_SYNTAX_ERROR(
792 : : "f-string: missed conversion character");
793 : 0 : goto error;
794 : : }
795 : :
796 : 308 : conversion = (unsigned char)*conv_start;
797 : : /* Validate the conversion. */
798 [ + - + + ]: 308 : if ((*str != conv_start + 1) ||
799 [ - + - - ]: 306 : !(conversion == 's' || conversion == 'r' || conversion == 'a'))
800 : : {
801 : 0 : PyObject *conv_obj = PyUnicode_FromStringAndSize(conv_start,
802 : 0 : *str-conv_start);
803 [ # # ]: 0 : if (conv_obj) {
804 : 0 : RAISE_SYNTAX_ERROR(
805 : : "f-string: invalid conversion character %R: "
806 : : "expected 's', 'r', or 'a'",
807 : : conv_obj);
808 : 0 : Py_DECREF(conv_obj);
809 : : }
810 : 0 : goto error;
811 : : }
812 : :
813 : : }
814 : :
815 : : /* Check for the format spec, if present. */
816 : : assert(*str < end);
817 [ + + ]: 1234 : if (**str == ':') {
818 : 34 : *str += 1;
819 [ - + ]: 34 : if (*str >= end) {
820 : 0 : goto unexpected_end_of_string;
821 : : }
822 : :
823 : : /* Parse the format spec. */
824 : 34 : format_spec = fstring_parse(p, str, end, raw, recurse_lvl+1,
825 : : first_token, t, last_token);
826 [ - + ]: 34 : if (!format_spec) {
827 : 0 : goto error;
828 : : }
829 : : }
830 : :
831 [ + - - + ]: 1234 : if (*str >= end || **str != '}') {
832 : 0 : goto unexpected_end_of_string;
833 : : }
834 : :
835 : : /* We're at a right brace. Consume it. */
836 : : assert(*str < end);
837 : : assert(**str == '}');
838 : 1234 : *str += 1;
839 : :
840 : : /* If we're in = mode (detected by non-NULL expr_text), and have no format
841 : : spec and no explicit conversion, set the conversion to 'r'. */
842 [ + + + - : 1234 : if (*expr_text && format_spec == NULL && conversion == -1) {
+ - ]
843 : 3 : conversion = 'r';
844 : : }
845 : :
846 : : /* And now create the FormattedValue node that represents this
847 : : entire expression with the conversion and format spec. */
848 : : //TODO: Fix this
849 : 1234 : *expression = _PyAST_FormattedValue(simple_expression, conversion,
850 : : format_spec, first_token->lineno,
851 : : first_token->col_offset,
852 : : last_token->end_lineno,
853 : : last_token->end_col_offset, p->arena);
854 [ - + ]: 1234 : if (!*expression) {
855 : 0 : goto error;
856 : : }
857 : :
858 : 1234 : return 0;
859 : :
860 : 0 : unexpected_end_of_string:
861 : 0 : RAISE_SYNTAX_ERROR("f-string: expecting '}'");
862 : : /* Falls through to error. */
863 : :
864 : 0 : error:
865 : 0 : Py_XDECREF(*expr_text);
866 : 0 : return -1;
867 : :
868 : : }
869 : :
870 : : /* Return -1 on error.
871 : :
872 : : Return 0 if we have a literal (possible zero length) and an
873 : : expression (zero length if at the end of the string.
874 : :
875 : : Return 1 if we have a literal, but no expression, and we want the
876 : : caller to call us again. This is used to deal with doubled
877 : : braces.
878 : :
879 : : When called multiple times on the string 'a{{b{0}c', this function
880 : : will return:
881 : :
882 : : 1. the literal 'a{' with no expression, and a return value
883 : : of 1. Despite the fact that there's no expression, the return
884 : : value of 1 means we're not finished yet.
885 : :
886 : : 2. the literal 'b' and the expression '0', with a return value of
887 : : 0. The fact that there's an expression means we're not finished.
888 : :
889 : : 3. literal 'c' with no expression and a return value of 0. The
890 : : combination of the return value of 0 with no expression means
891 : : we're finished.
892 : : */
893 : : static int
894 : 2292 : fstring_find_literal_and_expr(Parser *p, const char **str, const char *end, int raw,
895 : : int recurse_lvl, PyObject **literal,
896 : : PyObject **expr_text, expr_ty *expression,
897 : : Token *first_token, Token *t, Token *last_token)
898 : : {
899 : : int result;
900 : :
901 : : assert(*literal == NULL && *expression == NULL);
902 : :
903 : : /* Get any literal string. */
904 : 2292 : result = fstring_find_literal(p, str, end, raw, literal, recurse_lvl, t);
905 [ - + ]: 2292 : if (result < 0) {
906 : 0 : goto error;
907 : : }
908 : :
909 : : assert(result == 0 || result == 1);
910 : :
911 [ + + ]: 2292 : if (result == 1) {
912 : : /* We have a literal, but don't look at the expression. */
913 : 32 : return 1;
914 : : }
915 : :
916 [ + + + + ]: 2260 : if (*str >= end || **str == '}') {
917 : : /* We're at the end of the string or the end of a nested
918 : : f-string: no expression. The top-level error case where we
919 : : expect to be at the end of the string but we're at a '}' is
920 : : handled later. */
921 : 1026 : return 0;
922 : : }
923 : :
924 : : /* We must now be the start of an expression, on a '{'. */
925 : : assert(**str == '{');
926 : :
927 [ - + ]: 1234 : if (fstring_find_expr(p, str, end, raw, recurse_lvl, expr_text,
928 : : expression, first_token, t, last_token) < 0) {
929 : 0 : goto error;
930 : : }
931 : :
932 : 1234 : return 0;
933 : :
934 : 0 : error:
935 [ # # ]: 0 : Py_CLEAR(*literal);
936 : 0 : return -1;
937 : : }
938 : :
939 : : #ifdef NDEBUG
940 : : #define ExprList_check_invariants(l)
941 : : #else
942 : : static void
943 : : ExprList_check_invariants(ExprList *l)
944 : : {
945 : : /* Check our invariants. Make sure this object is "live", and
946 : : hasn't been deallocated. */
947 : : assert(l->size >= 0);
948 : : assert(l->p != NULL);
949 : : if (l->size <= EXPRLIST_N_CACHED) {
950 : : assert(l->data == l->p);
951 : : }
952 : : }
953 : : #endif
954 : :
955 : : static void
956 : 21325 : ExprList_Init(ExprList *l)
957 : : {
958 : 21325 : l->allocated = EXPRLIST_N_CACHED;
959 : 21325 : l->size = 0;
960 : :
961 : : /* Until we start allocating dynamically, p points to data. */
962 : 21325 : l->p = l->data;
963 : :
964 : : ExprList_check_invariants(l);
965 : 21325 : }
966 : :
967 : : static int
968 : 2677 : ExprList_Append(ExprList *l, expr_ty exp)
969 : : {
970 : : ExprList_check_invariants(l);
971 [ - + ]: 2677 : if (l->size >= l->allocated) {
972 : : /* We need to alloc (or realloc) the memory. */
973 : 0 : Py_ssize_t new_size = l->allocated * 2;
974 : :
975 : : /* See if we've ever allocated anything dynamically. */
976 [ # # ]: 0 : if (l->p == l->data) {
977 : : Py_ssize_t i;
978 : : /* We're still using the cached data. Switch to
979 : : alloc-ing. */
980 : 0 : l->p = PyMem_Malloc(sizeof(expr_ty) * new_size);
981 [ # # ]: 0 : if (!l->p) {
982 : 0 : return -1;
983 : : }
984 : : /* Copy the cached data into the new buffer. */
985 [ # # ]: 0 : for (i = 0; i < l->size; i++) {
986 : 0 : l->p[i] = l->data[i];
987 : : }
988 : : } else {
989 : : /* Just realloc. */
990 : 0 : expr_ty *tmp = PyMem_Realloc(l->p, sizeof(expr_ty) * new_size);
991 [ # # ]: 0 : if (!tmp) {
992 : 0 : PyMem_Free(l->p);
993 : 0 : l->p = NULL;
994 : 0 : return -1;
995 : : }
996 : 0 : l->p = tmp;
997 : : }
998 : :
999 : 0 : l->allocated = new_size;
1000 : : assert(l->allocated == 2 * l->size);
1001 : : }
1002 : :
1003 : 2677 : l->p[l->size++] = exp;
1004 : :
1005 : : ExprList_check_invariants(l);
1006 : 2677 : return 0;
1007 : : }
1008 : :
1009 : : static void
1010 : 892 : ExprList_Dealloc(ExprList *l)
1011 : : {
1012 : : ExprList_check_invariants(l);
1013 : :
1014 : : /* If there's been an error, or we've never dynamically allocated,
1015 : : do nothing. */
1016 [ + - - + ]: 892 : if (!l->p || l->p == l->data) {
1017 : : /* Do nothing. */
1018 : : } else {
1019 : : /* We have dynamically allocated. Free the memory. */
1020 : 0 : PyMem_Free(l->p);
1021 : : }
1022 : 892 : l->p = NULL;
1023 : 892 : l->size = -1;
1024 : 892 : }
1025 : :
1026 : : static asdl_expr_seq *
1027 : 892 : ExprList_Finish(ExprList *l, PyArena *arena)
1028 : : {
1029 : : asdl_expr_seq *seq;
1030 : :
1031 : : ExprList_check_invariants(l);
1032 : :
1033 : : /* Allocate the asdl_seq and copy the expressions in to it. */
1034 : 892 : seq = _Py_asdl_expr_seq_new(l->size, arena);
1035 [ + - ]: 892 : if (seq) {
1036 : : Py_ssize_t i;
1037 [ + + ]: 3569 : for (i = 0; i < l->size; i++) {
1038 : 2677 : asdl_seq_SET(seq, i, l->p[i]);
1039 : : }
1040 : : }
1041 : 892 : ExprList_Dealloc(l);
1042 : 892 : return seq;
1043 : : }
1044 : :
1045 : : #ifdef NDEBUG
1046 : : #define FstringParser_check_invariants(state)
1047 : : #else
1048 : : static void
1049 : : FstringParser_check_invariants(FstringParser *state)
1050 : : {
1051 : : if (state->last_str) {
1052 : : assert(PyUnicode_CheckExact(state->last_str));
1053 : : }
1054 : : ExprList_check_invariants(&state->expr_list);
1055 : : }
1056 : : #endif
1057 : :
1058 : : void
1059 : 21325 : _PyPegen_FstringParser_Init(FstringParser *state)
1060 : : {
1061 : 21325 : state->last_str = NULL;
1062 : 21325 : state->fmode = 0;
1063 : 21325 : ExprList_Init(&state->expr_list);
1064 : : FstringParser_check_invariants(state);
1065 : 21325 : }
1066 : :
1067 : : void
1068 : 0 : _PyPegen_FstringParser_Dealloc(FstringParser *state)
1069 : : {
1070 : : FstringParser_check_invariants(state);
1071 : :
1072 : 0 : Py_XDECREF(state->last_str);
1073 : 0 : ExprList_Dealloc(&state->expr_list);
1074 : 0 : }
1075 : :
1076 : : /* Make a Constant node, but decref the PyUnicode object being added. */
1077 : : static expr_ty
1078 : 21605 : make_str_node_and_del(Parser *p, PyObject **str, Token* first_token, Token *last_token)
1079 : : {
1080 : 21605 : PyObject *s = *str;
1081 : 21605 : PyObject *kind = NULL;
1082 : 21605 : *str = NULL;
1083 : : assert(PyUnicode_CheckExact(s));
1084 [ - + ]: 21605 : if (_PyArena_AddPyObject(p->arena, s) < 0) {
1085 : 0 : Py_DECREF(s);
1086 : 0 : return NULL;
1087 : : }
1088 : 21605 : const char* the_str = PyBytes_AsString(first_token->bytes);
1089 [ + - - + ]: 21605 : if (the_str && the_str[0] == 'u') {
1090 : 0 : kind = _PyPegen_new_identifier(p, "u");
1091 : : }
1092 : :
1093 [ + - - + ]: 21605 : if (kind == NULL && PyErr_Occurred()) {
1094 : 0 : return NULL;
1095 : : }
1096 : :
1097 : 21605 : return _PyAST_Constant(s, kind, first_token->lineno, first_token->col_offset,
1098 : : last_token->end_lineno, last_token->end_col_offset,
1099 : : p->arena);
1100 : :
1101 : : }
1102 : :
1103 : :
1104 : : /* Add a non-f-string (that is, a regular literal string). str is
1105 : : decref'd. */
1106 : : int
1107 : 22376 : _PyPegen_FstringParser_ConcatAndDel(FstringParser *state, PyObject *str)
1108 : : {
1109 : : FstringParser_check_invariants(state);
1110 : :
1111 : : assert(PyUnicode_CheckExact(str));
1112 : :
1113 [ + + ]: 22376 : if (PyUnicode_GET_LENGTH(str) == 0) {
1114 : 580 : Py_DECREF(str);
1115 : 580 : return 0;
1116 : : }
1117 : :
1118 [ + + ]: 21796 : if (!state->last_str) {
1119 : : /* We didn't have a string before, so just remember this one. */
1120 : 21025 : state->last_str = str;
1121 : : } else {
1122 : : /* Concatenate this with the previous string. */
1123 : 771 : PyUnicode_AppendAndDel(&state->last_str, str);
1124 [ - + ]: 771 : if (!state->last_str) {
1125 : 0 : return -1;
1126 : : }
1127 : : }
1128 : : FstringParser_check_invariants(state);
1129 : 21796 : return 0;
1130 : : }
1131 : :
1132 : : /* Parse an f-string. The f-string is in *str to end, with no
1133 : : 'f' or quotes. */
1134 : : int
1135 : 1026 : _PyPegen_FstringParser_ConcatFstring(Parser *p, FstringParser *state, const char **str,
1136 : : const char *end, int raw, int recurse_lvl,
1137 : : Token *first_token, Token* t, Token *last_token)
1138 : : {
1139 : : FstringParser_check_invariants(state);
1140 : 1026 : state->fmode = 1;
1141 : :
1142 : : /* Parse the f-string. */
1143 : 1266 : while (1) {
1144 : 2292 : PyObject *literal = NULL;
1145 : 2292 : PyObject *expr_text = NULL;
1146 : 2292 : expr_ty expression = NULL;
1147 : :
1148 : : /* If there's a zero length literal in front of the
1149 : : expression, literal will be NULL. If we're at the end of
1150 : : the f-string, expression will be NULL (unless result == 1,
1151 : : see below). */
1152 : 2292 : int result = fstring_find_literal_and_expr(p, str, end, raw, recurse_lvl,
1153 : : &literal, &expr_text,
1154 : : &expression, first_token, t, last_token);
1155 [ - + ]: 2292 : if (result < 0) {
1156 : 0 : return -1;
1157 : : }
1158 : :
1159 : : /* Add the literal, if any. */
1160 [ + + - + ]: 2292 : if (literal && _PyPegen_FstringParser_ConcatAndDel(state, literal) < 0) {
1161 : 0 : Py_XDECREF(expr_text);
1162 : 0 : return -1;
1163 : : }
1164 : : /* Add the expr_text, if any. */
1165 [ + + - + ]: 2292 : if (expr_text && _PyPegen_FstringParser_ConcatAndDel(state, expr_text) < 0) {
1166 : 0 : return -1;
1167 : : }
1168 : :
1169 : : /* We've dealt with the literal and expr_text, their ownership has
1170 : : been transferred to the state object. Don't look at them again. */
1171 : :
1172 : : /* See if we should just loop around to get the next literal
1173 : : and expression, while ignoring the expression this
1174 : : time. This is used for un-doubling braces, as an
1175 : : optimization. */
1176 [ + + ]: 2292 : if (result == 1) {
1177 : 32 : continue;
1178 : : }
1179 : :
1180 [ + + ]: 2260 : if (!expression) {
1181 : : /* We're done with this f-string. */
1182 : 1026 : break;
1183 : : }
1184 : :
1185 : : /* We know we have an expression. Convert any existing string
1186 : : to a Constant node. */
1187 [ + + ]: 1234 : if (state->last_str) {
1188 : : /* Convert the existing last_str literal to a Constant node. */
1189 : 950 : expr_ty last_str = make_str_node_and_del(p, &state->last_str, first_token, last_token);
1190 [ + - - + ]: 950 : if (!last_str || ExprList_Append(&state->expr_list, last_str) < 0) {
1191 : 0 : return -1;
1192 : : }
1193 : : }
1194 : :
1195 [ - + ]: 1234 : if (ExprList_Append(&state->expr_list, expression) < 0) {
1196 : 0 : return -1;
1197 : : }
1198 : : }
1199 : :
1200 : : /* If recurse_lvl is zero, then we must be at the end of the
1201 : : string. Otherwise, we must be at a right brace. */
1202 : :
1203 [ + + - + ]: 1026 : if (recurse_lvl == 0 && *str < end-1) {
1204 : 0 : RAISE_SYNTAX_ERROR("f-string: unexpected end of string");
1205 : 0 : return -1;
1206 : : }
1207 [ + + - + ]: 1026 : if (recurse_lvl != 0 && **str != '}') {
1208 : 0 : RAISE_SYNTAX_ERROR("f-string: expecting '}'");
1209 : 0 : return -1;
1210 : : }
1211 : :
1212 : : FstringParser_check_invariants(state);
1213 : 1026 : return 0;
1214 : : }
1215 : :
1216 : : /* Convert the partial state reflected in last_str and expr_list to an
1217 : : expr_ty. The expr_ty can be a Constant, or a JoinedStr. */
1218 : : expr_ty
1219 : 21054 : _PyPegen_FstringParser_Finish(Parser *p, FstringParser *state, Token* first_token,
1220 : : Token *last_token)
1221 : : {
1222 : : asdl_expr_seq *seq;
1223 : :
1224 : : FstringParser_check_invariants(state);
1225 : :
1226 : : /* If we're just a constant string with no expressions, return
1227 : : that. */
1228 [ + + ]: 21054 : if (!state->fmode) {
1229 : : assert(!state->expr_list.size);
1230 [ + + ]: 20162 : if (!state->last_str) {
1231 : : /* Create a zero length string. */
1232 : 580 : state->last_str = PyUnicode_FromStringAndSize(NULL, 0);
1233 [ - + ]: 580 : if (!state->last_str) {
1234 : 0 : goto error;
1235 : : }
1236 : : }
1237 : 20162 : return make_str_node_and_del(p, &state->last_str, first_token, last_token);
1238 : : }
1239 : :
1240 : : /* Create a Constant node out of last_str, if needed. It will be the
1241 : : last node in our expression list. */
1242 [ + + ]: 892 : if (state->last_str) {
1243 : 493 : expr_ty str = make_str_node_and_del(p, &state->last_str, first_token, last_token);
1244 [ + - - + ]: 493 : if (!str || ExprList_Append(&state->expr_list, str) < 0) {
1245 : 0 : goto error;
1246 : : }
1247 : : }
1248 : : /* This has already been freed. */
1249 : : assert(state->last_str == NULL);
1250 : :
1251 : 892 : seq = ExprList_Finish(&state->expr_list, p->arena);
1252 [ - + ]: 892 : if (!seq) {
1253 : 0 : goto error;
1254 : : }
1255 : :
1256 : 892 : return _PyAST_JoinedStr(seq, first_token->lineno, first_token->col_offset,
1257 : : last_token->end_lineno, last_token->end_col_offset,
1258 : : p->arena);
1259 : :
1260 : 0 : error:
1261 : 0 : _PyPegen_FstringParser_Dealloc(state);
1262 : 0 : return NULL;
1263 : : }
1264 : :
1265 : : /* Given an f-string (with no 'f' or quotes) that's in *str and ends
1266 : : at end, parse it into an expr_ty. Return NULL on error. Adjust
1267 : : str to point past the parsed portion. */
1268 : : static expr_ty
1269 : 34 : fstring_parse(Parser *p, const char **str, const char *end, int raw,
1270 : : int recurse_lvl, Token *first_token, Token* t, Token *last_token)
1271 : : {
1272 : : FstringParser state;
1273 : :
1274 : 34 : _PyPegen_FstringParser_Init(&state);
1275 [ - + ]: 34 : if (_PyPegen_FstringParser_ConcatFstring(p, &state, str, end, raw, recurse_lvl,
1276 : : first_token, t, last_token) < 0) {
1277 : 0 : _PyPegen_FstringParser_Dealloc(&state);
1278 : 0 : return NULL;
1279 : : }
1280 : :
1281 : 34 : return _PyPegen_FstringParser_Finish(p, &state, t, t);
1282 : : }
|