diff --git a/CHANGELOG.md b/CHANGELOG.md index 907265452..f8c71c321 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [15.0.1.1] ### Added - I2S additions (#23543) +- Berry f-strings now support ':' in expression ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_lexer.c b/lib/libesp32/berry/src/be_lexer.c index 6aee7afa8..e93353c28 100644 --- a/lib/libesp32/berry/src/be_lexer.c +++ b/lib/libesp32/berry/src/be_lexer.c @@ -539,9 +539,11 @@ static void scan_f_string(blexer *lexer) /* if end of string is reached before '}' raise en error */ for (; i < buf_unparsed_fstr.len; i++) { ch = buf_unparsed_fstr.s[i]; - if (ch == ':' || ch == '}') { break; } - save_char(lexer, ch); /* copy any character unless it's ':' or '}' */ + /* stop parsing if single ':' or '}' */ + if (ch == '}' || (ch == ':' && buf_unparsed_fstr.s[i+1] != ':')) { break; } + save_char(lexer, ch); /* copy any character unless it's '}' or single ':' */ if (ch == '=') { break; } /* '=' is copied but breaks parsing as well */ + if (ch == ':') { save_char(lexer, ch); i++; } /* if '::' then encode the second ':' but don't parse it again in next iteration */ } /* safe check if we reached the end of the string */ if (i >= buf_unparsed_fstr.len) { be_raise(lexer->vm, "syntax_error", "'}' expected"); } @@ -588,11 +590,17 @@ static void scan_f_string(blexer *lexer) save_char(lexer, ','); /* add ',' to start next argument to `format()` */ for (; i < buf_unparsed_fstr.len; i++) { ch = buf_unparsed_fstr.s[i]; - if (ch == '=' || ch == ':' || ch == '}') { break; } - save_char(lexer, ch); /* copy expression until we reach ':', '=' or '}' */ + if (ch == ':' && (buf_unparsed_fstr.s[i+1] == ':')) { + save_char(lexer, ch); + i++; /* skip second ':' */ + } else if (ch == '=' || ch == ':' || ch == '}') { + break; + } else { + save_char(lexer, ch); /* copy expression until we reach ':', '=' or '}' */ + } } /* no need to check for end of string here, it was done already in first pass */ - if (ch == ':' || ch == '=') { /* if '=' or ':', skip everyting until '}' */ + if (ch == '=' || ch == ':') { /* if '=' or ':', skip everyting until '}' */ i++; for (; i < buf_unparsed_fstr.len; i++) { ch = buf_unparsed_fstr.s[i]; diff --git a/lib/libesp32/berry/tests/string.be b/lib/libesp32/berry/tests/string.be index 448ca5215..61d323aee 100644 --- a/lib/libesp32/berry/tests/string.be +++ b/lib/libesp32/berry/tests/string.be @@ -175,6 +175,13 @@ assert(f"S = {a}" == 'S = foobar{0}') assert(f"S = {a:i}" == 'S = 0') assert(f"{a=}" == 'a=foobar{0}') +# new option for f-strings, '::' encodes for ':' +assert(f"{true ? 1 :: 2}" == "1") +assert(f"{false ? 1 :: 2}" == "2") +assert(f"{false ? 1 :: 2 : i}" == " 2") +assert(f"{false ? 1 :: 2:i}" == "2") +assert(f"{false ? 1 :: 2:04i}" == "0002") + # startswith case sensitive assert(string.startswith("", "") == true) assert(string.startswith("qwerty", "qw") == true)