8000 py: Implement partial PEP-498 (f-string) support (v3) by jimmo · Pull Request #7649 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

py: Implement partial PEP-498 (f-string) support (v3) #7649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

jimmo
Copy link
Member
@jimmo jimmo commented Aug 12, 2021

Extends on #6247 which was originally based on #4998 by @klardotsh

This is a slightly more extensive re-work with the aim of reducing code size and also now supporting the = operator which I find quite useful (a=1; f'{a=}' --> 'a=1'. I've also split the tests into regular tests (that now run on CPython too) and cpydiff tests for the deviations from PEP498.

The limitations are the same as the previous approach (due to it being implemented in the lexer not the parser) and the quirks with literal concatenation. I think this is a reasonable trade-off (in the spirit of #6247 (comment)) and has been working for CircuitPython for a while now.

This is +380 bytes on PYBV11 (compared to +432 previously for #6247).


py: Implement partial PEP-498 (f-string) support

This implements (most of) the PEP-498 spec for f-strings and is based on
https://github.com/micropython/micropython/pull/4998 by @klardotsh.

It is implemented in the lexer as a syntax translation to `str.format`:
  f"{a}" --> "{}".format(a)

It also supports:
  f"{a=}" --> "a={}".format(a)

This is done by extracting the arguments into a temporary vstr buffer, then
after the string has been tokenized, the lexer input queue is saved and the
contents of the temporary vstr buffer are injected ito the lexer instead.

There are four main limitations:
- raw f-strings (`fr` or `rf` prefixes) are not supported and will raise
  `SyntaxError: raw f-strings are not supported`.

- literal concatenation of f-strings with adjacent strings will fail
    "{}" f"{a}" --> "{}{}".format(a)    (str.format will incorrectly use the
                                         braces from the non-f-string)
    f"{a}" f"{a}" --> "{}".format(a) "{}".format(a) (cannot concatenate)

- PEP-498 requires the full parser to understand the interpolated argument,
  however because this entirely runs in the lexer it cannot resolve nested
  braces in expressions like
    f"{'}'}"

- The !r, !s, and !a conversions are not supported.

Includes tests and cpydiffs.

@@ -0,0 +1,18 @@
"""
categories: Core
description: f-strings don't the !r, !s, and !a conversions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing a word after "don't"?

Copy link
< 8000 /details>
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed.

@klardotsh
Copy link

I'm detached from the world of Micro and CircuitPythons these days quite a bit, and frankly went through enough bouts of FOSS burnout in 2019+2020 (plus, ya know... gestures at everything going on in the world and specifically the US where I live) that I mostly backed out of contributing to open-source entirely until this summer rolled around (in a bit different of a space now).

I want to just give @jimmo a huge thanks for adopting this and shepherding it across the line, cleaning up the few messes I left behind, and also for the personal emails you sent last spring offering support. You're a great human. Thanks for that.

jimmo added 2 commits August 13, 2021 10:41
This implements (most of) the PEP-498 spec for f-strings and is based on
micropython#4998 by @klardotsh.

It is implemented in the lexer as a syntax translation to `str.format`:
  f"{a}" --> "{}".format(a)

It also supports:
  f"{a=}" --> "a={}".format(a)

This is done by extracting the arguments into a temporary vstr buffer,
then after the string has been tokenized, the lexer input queue is saved
and the contents of the temporary vstr buffer are injected ito the lexer
instead.

There are four main limitations:
- raw f-strings (`fr` or `rf` prefixes) are not supported and will raise
  `SyntaxError: raw f-strings are not supported`.

- literal concatenation of f-strings with adjacent strings will fail
    "{}" f"{a}" --> "{}{}".format(a)    (str.format will incorrectly use
                                         the braces from the non-f-string)
    f"{a}" f"{a}" --> "{}".format(a) "{}".format(a) (cannot concatenate)

- PEP-498 requires the full parser to understand the interpolated
  argument, however because this entirely runs in the lexer it cannot
  resolve nested braces in expressions like
    f"{'}'}"

- The !r, !s, and !a conversions are not supported.

Includes tests and cpydiffs.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
@dpgeorge dpgeorge added the py-core Relates to py/ directory in source label Aug 14, 2021
@dpgeorge
Copy link
Member

Rebased and merged in 692d36d and 5733c49 with the following minor changes:

  • MICROPY_PY_FSTRING renamed to MICROPY_PY_FSTRINGS
  • fstring_args_idx type changed from uint16_t to size_t
  • tests/cmdline/cmd_parsetree.py.exp fixed up to be more restrictive in what it tests

A big thanks to @klardotsh for the initial idea and work on this feature, the implementation is quite simple conceptually, for what is a very hairy feature. Also big thanks to @jimmo for taking it the last mile.

@dpgeorge dpgeorge closed this Aug 14, 2021
tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Feb 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
py-core Relates to py/ directory in source
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0