-
-
Notifications
You must be signed in to change notification settings - Fork 31.3k
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
bpo-40334: Support type comments #19780
Conversation
This does not yet support the "long form" for arguments with type comments. We also totally skip `# type: ignore` comments, and there is no support for func_type_input yet.
This involved a complete refactor of the part of the grammar used to recognise formal parameters in function definitions. I renamed many of the rules involved. The rewrite always includes the comma following a parameter in that argument, so that we can also include the type comment, if any (which follows the comma). The final parameter may not be followed by a comma, so we allow the comma to be omitted, but only if a close parenthesis follows instead (preceded by the type comment, if any). Some additional complications are needed because the code generator doesn't actually support alternatives that may be empty. PS. I didn't refactor the corresponding rules for lambdas, since they don't have type comments.
Wait, I forgot to un-skip the test for long-form arguments and it segfaults. On it. |
Hm... when parsing something as simple as
it seems the end column number for |
Dang I already have conflicts. Looking... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this! Apart from all the TYPE_COMMENTS
work, I strongly feel that the arguments
improvements made a significant difference in readability.
It seems there's a failure in |
The test_type_comments failure is new, looking now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All your other suggestions will appear in the next commit.
Parser/pegen/pegen.c
Outdated
@@ -25,7 +25,7 @@ _PyPegen_add_type_comment(Parser *p, arg_ty a, char *tc) | |||
if (tc == NULL) { | |||
return a; | |||
} | |||
PyObject *tco = _PyPegen_new_type_comment(p, tc); | |||
PyObject *tco = NEW_TYPE_COMMENT(tc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't NEW_TYPE_COMMENT
expect tc
to be a Token *
, i.e. that tc->bytes
is a bytes object? I feel that NEW_TYPE_COMMENT
would better be off as an inline function.
Also, all the calls to |
Parser/pegen/pegen.c
Outdated
@@ -1483,13 +1597,13 @@ _PyPegen_get_values(Parser *p, asdl_seq *seq) | |||
|
|||
/* Constructs a NameDefaultPair */ | |||
NameDefaultPair * | |||
_PyPegen_name_default_pair(Parser *p, arg_ty arg, expr_ty value) | |||
_PyPegen_name_default_pair(Parser *p, arg_ty arg, expr_ty value, char *tc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tc
should be a Token *
here.
Parser/pegen/pegen.c
Outdated
} | ||
|
||
arg_ty | ||
_PyPegen_add_type_comment_to_arg(Parser *p, arg_ty a, char *tc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tc
should be a Token *
here.
To recap, because it might not be clear what my latest reviews are suggesting. I think that the following are needed:
I'd also make |
Got it. I'm putting the CHECK_CALL_NULL_ALLOWED call inside NEW_TYPE_COMMENT -- does that make sense? I don't see that pattern used elsewhere. |
Parser/pegen/pegen.h
Outdated
if (tc == NULL) { | ||
return NULL; | ||
} | ||
return CHECK_CALL_NULL_ALLOWED(p, _PyPegen_new_type_comment(p, PyBytes_AsString(tc->bytes))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will segfault if PyBytes_AsString
fails. I think the best way to do it is assign it to a variable beforehand and check for NULL
, but that means the the CHECK_NULL_ALLOWED
call cannot be inside NEW_TYPE_COMMENT
or it has to be called multiple times, once for each time a function is called that could potentially return NULL
, which isn't much more beautiful than having it in the grammar IMHO. What do you think?
return CHECK_CALL_NULL_ALLOWED(p, _PyPegen_new_type_comment(p, PyBytes_AsString(tc->bytes))); | |
char *bytes = PyBytes_AsString(tc->bytes); | |
if (!bytes) { | |
return NULL; | |
} | |
return _PyPegen_new_type_comment(p, bytes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I will try again. I really don't want to litter the grammar with CHECK_CALL_NULL_ALLOWED(NEW_TYPE_COMMENT(p, tc))
so I am changing NEW_TYPE_COMMENT
to set p->error_indicator
on every error exit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last thing and it's good to go.
Grammar/python.gram
Outdated
# type_expressions allow */** but ignore them | ||
type_expressions[asdl_seq*]: | ||
| a=','.expression+ ',' '*' b=expression ',' '**' c=expression { | ||
_PyPegen_seq_append_to_end(p, _PyPegen_seq_append_to_end(p, a, b), c) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_PyPegen_seq_append_to_end(p, _PyPegen_seq_append_to_end(p, a, b), c) } | |
_PyPegen_seq_append_to_end(p, CHECK(_PyPegen_seq_append_to_end(p, a, b)), c) } |
@lysnikolaou Thank you so much for all your help on this one! It's been invaluable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My pleasure!
Currently working on support for |
Oops. Fixing in #19828 |
This doesn't seem to be able to handle function type comments where there aren't "normal" argument types preceding the *args and **kwargs types. I've opened #19894 with a fix, but it's my first time working with CPython's grammar, so apologies in advance for any crimes against parsers committed. |
This implements full support for
# type: <type>
comments,# type: ignore <stuff>
comments, and thefunc_type
parsing mode forast.parse()
andcompile()
.Closes we-like-parsers#95
https://bugs.python.org/issue40334