Skip to content

py: Implement decorator syntax relaxation from CPython 3.9. #8503

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

RayaneCTX
Copy link
Contributor

@RayaneCTX RayaneCTX commented Apr 8, 2022

Synopsis: Implements the decorator syntax relaxation added to CPython 3.9 (any expression can be a decorator argument, syntactically).

Details: Details and rationale are provided below, on a per file change basis.

py/grammar.h: The grammar file hosts the core change associated with this pull request. The decorator rule is changed to match a namedexpr_test rule rather than a dotted_name rule. However, since the compiler currently relies on the dotted_name rule to easily detect built-in decorators (e.g. @micropython.bytecode), a new way of detecting these built-ins needed to be found:

  1. [DISCARDED] One possibility is to have the parser try to match a dotted_name (or proxy thereof) first and a namedexpr_test second, but since the parser does not backtrack through lexical tokens, it is not obvious to me how to accomplish this.
  2. [DISCARDED] Another possibility is to write code in the compiler to visit the AST rooted at the namedexpr_test rule of a given decorator and determine whether said decorator is a built-in that way. This could potentially be an expensive operation and/or lead to a significant increase in code size.
  3. [SELECTED] A third option is to introduce a grammar rule built_in_decorator that tries to match a "micropython" string, and backtracks into a namedexpr_test rule if there is no match. This relies on the fact that all built-in decorators start with "micropython". One possible concern is that any decorator starting with the "micropython" NAME token must match with a built-in decorator, otherwise a syntax error is issued. This is, however, congruent with current behavior: this is exactly what the compile_built_in_decorator function would do (before this commit).

py/parse.c: A check is added to attempt to match the "micropython" string to a NAME token when parsing a built_in_decrator rule.

py/compile.c: Since the compile_built_in_decorator function is not used anywhere else, this function can be simplified to match the new grammar.

tests/basics: The old decorator.py test is renamed to decorator_minimal.py. A new set of tests are added in decorator_full.py. The decorator.py test is amended with additional tests for syntax, type and name errors. A decorator_full.py.exp decorator.py.exp file is added to work out of the box with CPython versions older than 3.9.

tests/cmdline/cmd_parsetree.py.exp: Updated the expected rule IDs since the grammar is changed.

tools/ci.sh: Excludes the decorator_full.py test from the minimal build since it uses several unsupported features (e.g. decimal/complex numbers).

ports/qemu_arm/Makefile.test: Excludes the decorator_full.py test here as well.

Signed-off-by: Rayane Chatrieux rayane.chatrieux@gmail.com

print("TypeError")

decs = [
"1.+2j",
Copy link
Member

Choose a reason for hiding this comment

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

Can this test be modified so it runs on miminal targets, ie so that there doesn't need to be special handling in the test suite runners to exclude this full decorator test from certain ports?

Can this complex number be replaced with something else (or just removed)? Is it testing something (providing test coverage) that can't be tested in any other way? If so it would be good to move just this complex-number based test to another file and put it in the tests/float/ directory so it's automatically skipped.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the complex number test and cleaned up the test runners in the latest commit.

@RayaneCTX RayaneCTX force-pushed the decorator-syntax-relaxation branch from 51f36ba to 76a8b0c Compare April 11, 2022 22:17
@RayaneCTX
Copy link
Contributor Author

Amended the commit message to the correct format.

@stinos
Copy link
Contributor

stinos commented Apr 12, 2022

First commit is 'py: Implements ....', that should be 'py: Implement ....' i.e. commits are in the imperative mood.

@RayaneCTX RayaneCTX force-pushed the decorator-syntax-relaxation branch from 76a8b0c to e3b7d1d Compare April 12, 2022 13:55
@RayaneCTX
Copy link
Contributor Author

RayaneCTX commented Apr 12, 2022

First commit is 'py: Implements ....', that should be 'py: Implement ....' i.e. commits are in the imperative mood.

Squashed and pushed with an updated commit message.

@RayaneCTX RayaneCTX force-pushed the decorator-syntax-relaxation branch from e3b7d1d to be8df3d Compare April 12, 2022 15:11
@RayaneCTX RayaneCTX changed the title py: Implements decorator syntax relaxation from CPython 3.9. py: Implement decorator syntax relaxation from CPython 3.9. Apr 12, 2022
py/grammar.h: The grammar file hosts the core change associated with
this pull request. The decorator rule is changed to match a
namedexpr_test rule rather than a dotted_name rule. However, since the
compiler currently relies on the dotted_name rule to easily detect
built-in decorators (e.g. @micropython.bytecode), a new way of detecting
these built-ins needed to be found:

    1. One possibility is to have the grammar try to match a dotted_name
       first and a namedexpr_test second, but since the parser does not
       bactrack through lexical tokens, it is not obvious to me how to
       accomplish this.

    2. Another possiblity is to write code in the compiler to visit the
       AST rooted at the namedexpr_test rule of a given decorator and
       determine whether said decorator is a built-in that way. This
       could potentially be an expensive operation and/or lead to a
       significant increase in code size.

    3. [SELECTED] A third option is to introduce a grammar rule
       built_in_decorator that tries to match a "micropython" string,
       and backtracks into a namedexpr_test rule if there is no match.
       This relies on the fact that all built-in decorators start with
       "micropython". One possible concern is that any decorator
       starting with the "micropython" NAME token must match with a
       built-in decorator, otherwise a syntax error is issued. This is,
       however, congruent with current behavior: this is exactly what
       the compile_built_in_decorator function would do (before this
       commit).

py/parse.c: Add a check to attempt to match the "micropython"
string to a NAME token when parsing a built_in_decrator rule. The parser
backtracks out of the rule if there is no match.

py/compile.c: Since the compile_built_in_decorator function is not used
anywhere else, I took the liberty to simplify this function to match the
new grammar.

tests/basics: Amend the decorator.py test with additional tests for
syntax, type and name errors. Adds an expected output file so that this
test works out-of-the-box with older versions of CPython than 3.9.

tests/cmdline/cmd_parsetree.py.exp: Update the expected rule IDs in the
expected output since the grammar is changed.

Signed-off-by: Rayane Chatrieux <rayane.chatrieux@gmail.com>
@RayaneCTX RayaneCTX force-pushed the decorator-syntax-relaxation branch from be8df3d to 808fdbb Compare April 12, 2022 19:22
// decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
// decorator: '@' decorator_arg NEWLINE
// decorator_arg: built_in_decorator | namedexpr_test
// built_in_decorator: 'micropython' '.' NAME
Copy link
Member

Choose a reason for hiding this comment

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

I think it might be cleaner/simpler to define the grammar like this:

decorator: '@' namedexpr_test NEWLINE

and then handle detection and compilation of the builtin decorator in py/compile.c (that way it can potentially support more complex builtin decorators, eg @micropython.bytecode(opt=2)).

@projectgus
Copy link
Contributor

This is an automated heads-up that we've just merged a Pull Request
that removes the STATIC macro from MicroPython's C API.

See #13763

A search suggests this PR might apply the STATIC macro to some C code. If it
does, then next time you rebase the PR (or merge from master) then you should
please replace all the STATIC keywords with static.

Although this is an automated message, feel free to @-reply to me directly if
you have any questions about this.

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