From 11ed94797d492cabdaf09396feb69a690e86f739 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 19 Nov 2021 10:36:16 +1100 Subject: [PATCH] py/lexer: Support nested [] and {} characters within f-string params. Signed-off-by: Damien George --- py/lexer.c | 11 +++++++++-- tests/basics/string_fstring.py | 7 +++++++ tests/cpydiff/core_fstring_parser.py | 8 ++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/py/lexer.c b/py/lexer.c index 69c7d14a7..ac406bd46 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -363,9 +363,16 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) // (MicroPython limitation) note: this is completely unaware of // Python syntax and will not handle any expression containing '}' or ':'. // e.g. f'{"}"}' or f'{foo({})}'. - while (!is_end(lex) && !is_char_or(lex, ':', '}')) { + unsigned int nested_bracket_level = 0; + while (!is_end(lex) && (nested_bracket_level != 0 || !is_char_or(lex, ':', '}'))) { + unichar c = CUR_CHAR(lex); + if (c == '[' || c == '{') { + nested_bracket_level += 1; + } else if (c == ']' || c == '}') { + nested_bracket_level -= 1; + } // like the default case at the end of this function, stay 8-bit clean - vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex)); + vstr_add_byte(&lex->fstring_args, c); next_char(lex); } if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') { diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py index 4f7225fca..7e8a97fd3 100644 --- a/tests/basics/string_fstring.py +++ b/tests/basics/string_fstring.py @@ -22,6 +22,13 @@ def foo(a, b): return f'{x}{y}{a}{b}' print(foo(7, 8)) +# ':' character within {...} that should not be interpreted as format specifiers. +print(f"a{[0,1,2][0:2]}") +print(f"a{[0,15,2][0:2][-1]:04x}") + +# Nested '{' and '}' characters. +print(f"a{ {0,1,2}}") + # PEP-0498 specifies that '\\' and '#' must be disallowed explicitly, whereas # MicroPython relies on the syntax error as a result of the substitution. diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py index 6917f3cfa..22bbc5866 100644 --- a/tests/cpydiff/core_fstring_parser.py +++ b/tests/cpydiff/core_fstring_parser.py @@ -1,9 +1,9 @@ """ categories: Core -description: f-strings cannot support expressions that require parsing to resolve nested braces +description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets cause: MicroPython is optimised for code space. -workaround: Only use simple expressions inside f-strings +workaround: Always use balanced braces and brackets in expressions inside f-strings """ -f'{"hello {} world"}' -f"{repr({})}" +print(f'{"hello { world"}') +print(f'{"hello ] world"}')