Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ assignment:
| ann_assign_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] {
_Py_AnnAssign(a, b, c, 0, EXTRA)}
| a=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) tc=[TYPE_COMMENT] {
_Py_Assign(a, b, NEW_TYPE_COMMENT(tc), EXTRA) }
_Py_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
| a=target b=augassign c=(yield_expr | star_expressions) {
_Py_AugAssign(a, b->kind, c, EXTRA) }
| invalid_assignment
Expand Down Expand Up @@ -157,13 +157,13 @@ while_stmt[stmt_ty]:

for_stmt[stmt_ty]:
| is_async=[ASYNC] 'for' t=star_targets 'in' ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {
(is_async ? _Py_AsyncFor : _Py_For)(t, ex, b, el, NEW_TYPE_COMMENT(tc), EXTRA) }
(is_async ? _Py_AsyncFor : _Py_For)(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA) }

with_stmt[stmt_ty]:
| is_async=[ASYNC] 'with' '(' a=','.with_item+ ')' ':' b=block {
(is_async ? _Py_AsyncWith : _Py_With)(a, b, NULL, EXTRA) }
| is_async=[ASYNC] 'with' a=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
(is_async ? _Py_AsyncWith : _Py_With)(a, b, NEW_TYPE_COMMENT(tc), EXTRA) }
(is_async ? _Py_AsyncWith : _Py_With)(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
with_item[withitem_ty]:
| e=expression o=['as' t=target { t }] { _Py_withitem(e, o, p->arena) }

Expand Down Expand Up @@ -191,7 +191,7 @@ function_def_raw[stmt_ty]:
| is_async=[ASYNC] 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] ':' tc=[func_type_comment] b=block {
(is_async ? _Py_AsyncFunctionDef : _Py_FunctionDef)(n->v.Name.id,
(params) ? params : CHECK(_PyPegen_empty_arguments(p)),
b, NULL, a, NEW_TYPE_COMMENT(tc), EXTRA) }
b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) }
func_type_comment[PyObject*]:
| NEWLINE t=TYPE_COMMENT &(NEWLINE INDENT) { t } # Must be followed by indented block
| invalid_double_type_comments
Expand Down
8 changes: 4 additions & 4 deletions Parser/pegen/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1606,7 +1606,7 @@ assignment_rule(Parser *p)
UNUSED(end_lineno); // Only used by EXTRA macro
int end_col_offset = token->end_col_offset;
UNUSED(end_col_offset); // Only used by EXTRA macro
res = _Py_Assign ( a , b , NEW_TYPE_COMMENT ( tc ) , EXTRA );
res = _Py_Assign ( a , b , NEW_TYPE_COMMENT ( p , tc ) , EXTRA );
if (res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
return NULL;
Expand Down Expand Up @@ -2891,7 +2891,7 @@ for_stmt_rule(Parser *p)
UNUSED(end_lineno); // Only used by EXTRA macro
int end_col_offset = token->end_col_offset;
UNUSED(end_col_offset); // Only used by EXTRA macro
res = ( is_async ? _Py_AsyncFor : _Py_For ) ( t , ex , b , el , NEW_TYPE_COMMENT ( tc ) , EXTRA );
res = ( is_async ? _Py_AsyncFor : _Py_For ) ( t , ex , b , el , NEW_TYPE_COMMENT ( p , tc ) , EXTRA );
if (res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
return NULL;
Expand Down Expand Up @@ -2994,7 +2994,7 @@ with_stmt_rule(Parser *p)
UNUSED(end_lineno); // Only used by EXTRA macro
int end_col_offset = token->end_col_offset;
UNUSED(end_col_offset); // Only used by EXTRA macro
res = ( is_async ? _Py_AsyncWith : _Py_With ) ( a , b , NEW_TYPE_COMMENT ( tc ) , EXTRA );
res = ( is_async ? _Py_AsyncWith : _Py_With ) ( a , b , NEW_TYPE_COMMENT ( p , tc ) , EXTRA );
if (res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
return NULL;
Expand Down Expand Up @@ -3479,7 +3479,7 @@ function_def_raw_rule(Parser *p)
UNUSED(end_lineno); // Only used by EXTRA macro
int end_col_offset = token->end_col_offset;
UNUSED(end_col_offset); // Only used by EXTRA macro
res = ( is_async ? _Py_AsyncFunctionDef : _Py_FunctionDef ) ( n -> v . Name . id , ( params ) ? params : CHECK ( _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( tc ) , EXTRA );
res = ( is_async ? _Py_AsyncFunctionDef : _Py_FunctionDef ) ( n -> v . Name . id , ( params ) ? params : CHECK ( _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA );
if (res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
return NULL;
Expand Down
10 changes: 5 additions & 5 deletions Parser/pegen/pegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#include "parse_string.h"

PyObject *
_PyPegen_new_type_comment(Parser *p, char *tc)
_PyPegen_new_type_comment(Parser *p, char *s)
{
PyObject *res = PyUnicode_DecodeUTF8(tc, strlen(tc), NULL);
PyObject *res = PyUnicode_DecodeUTF8(s, strlen(s), NULL);
if (res == NULL) {
return NULL;
}
Expand All @@ -20,12 +20,12 @@ _PyPegen_new_type_comment(Parser *p, char *tc)
}

arg_ty
_PyPegen_add_type_comment_to_arg(Parser *p, arg_ty a, char *tc)
_PyPegen_add_type_comment_to_arg(Parser *p, arg_ty a, Token *tc)
{
if (tc == NULL) {
return a;
}
PyObject *tco = NEW_TYPE_COMMENT(tc);
PyObject *tco = NEW_TYPE_COMMENT(p, tc);
if (tco == NULL) {
return NULL;
}
Expand Down Expand Up @@ -1597,7 +1597,7 @@ _PyPegen_get_values(Parser *p, asdl_seq *seq)

/* Constructs a NameDefaultPair */
NameDefaultPair *
_PyPegen_name_default_pair(Parser *p, arg_ty arg, expr_ty value, char *tc)
_PyPegen_name_default_pair(Parser *p, arg_ty arg, expr_ty value, Token *tc)
{
NameDefaultPair *a = PyArena_Malloc(p->arena, sizeof(NameDefaultPair));
if (!a) {
Expand Down
16 changes: 12 additions & 4 deletions Parser/pegen/pegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,18 @@ CHECK_CALL_NULL_ALLOWED(Parser *p, void *result)
#define CHECK(result) CHECK_CALL(p, result)
#define CHECK_NULL_ALLOWED(result) CHECK_CALL_NULL_ALLOWED(p, result)

#define NEW_TYPE_COMMENT(tc) (tc == NULL ? NULL : _PyPegen_new_type_comment(p, PyBytes_AsString(((Token *)tc)->bytes)))

PyObject *_PyPegen_new_type_comment(Parser *, char *);
arg_ty _PyPegen_add_type_comment_to_arg(Parser *, arg_ty, char *);

Py_LOCAL_INLINE(PyObject *)
NEW_TYPE_COMMENT(Parser *p, Token *tc)
{
if (tc == NULL) {
return NULL;
}
return CHECK_CALL_NULL_ALLOWED(p, _PyPegen_new_type_comment(p, PyBytes_AsString(tc->bytes)));

Copy link
Copy Markdown
Member

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?

Suggested change
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);

Copy link
Copy Markdown
Member Author

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.

}

arg_ty _PyPegen_add_type_comment_to_arg(Parser *, arg_ty, Token *);
PyObject *_PyPegen_new_identifier(Parser *, char *);
Parser *_PyPegen_Parser_New(struct tok_state *, int, int, int *, PyArena *);
void _PyPegen_Parser_Free(Parser *);
Expand All @@ -186,7 +194,7 @@ expr_ty _PyPegen_set_expr_context(Parser *, expr_ty, expr_context_ty);
KeyValuePair *_PyPegen_key_value_pair(Parser *, expr_ty, expr_ty);
asdl_seq *_PyPegen_get_keys(Parser *, asdl_seq *);
asdl_seq *_PyPegen_get_values(Parser *, asdl_seq *);
NameDefaultPair *_PyPegen_name_default_pair(Parser *, arg_ty, expr_ty, char *);
NameDefaultPair *_PyPegen_name_default_pair(Parser *, arg_ty, expr_ty, Token *);
SlashWithDefault *_PyPegen_slash_with_default(Parser *, asdl_seq *, asdl_seq *);
StarEtc *_PyPegen_star_etc(Parser *, arg_ty, asdl_seq *, arg_ty);
arguments_ty _PyPegen_make_arguments(Parser *, asdl_seq *, SlashWithDefault *,
Expand Down