-
-
Notifications
You must be signed in to change notification settings - Fork 54
[2.7, 3.5] Support the per-argument function comment syntax #5
Changes from all commits
8325e39
3aa01a1
4c8a2ec
314d17d
97915b0
78206fc
87e46fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -732,17 +732,18 @@ static arguments_ty | |
ast_for_arguments(struct compiling *c, const node *n) | ||
{ | ||
/* parameters: '(' [varargslist] ')' | ||
varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | ||
| '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] | ||
varargslist: ((fpdef ['=' test] ',' [TYPE_COMMENT])* | ||
('*' NAME [',' [TYPE_COMMENT] '**' NAME] [TYPE_COMMENT] | '**' NAME [TYPE_COMMENT]) | | ||
fpdef ['=' test] (',' [TYPE_COMMENT] fpdef ['=' test])* [','] [TYPE_COMMENT]) | ||
*/ | ||
int i, j, k, n_args = 0, n_defaults = 0, found_default = 0; | ||
asdl_seq *args, *defaults; | ||
int i, j, k, l, n_args = 0, n_all_args = 0, n_defaults = 0, found_default = 0; | ||
asdl_seq *args, *defaults, *type_comments = NULL; | ||
identifier vararg = NULL, kwarg = NULL; | ||
node *ch; | ||
|
||
if (TYPE(n) == parameters) { | ||
if (NCH(n) == 2) /* () as argument list */ | ||
return arguments(NULL, NULL, NULL, NULL, c->c_arena); | ||
return arguments(NULL, NULL, NULL, NULL, NULL, c->c_arena); | ||
n = CHILD(n, 1); | ||
} | ||
REQ(n, varargslist); | ||
|
@@ -754,20 +755,30 @@ ast_for_arguments(struct compiling *c, const node *n) | |
n_args++; | ||
if (TYPE(ch) == EQUAL) | ||
n_defaults++; | ||
if (TYPE(ch) == STAR || TYPE(ch) == DOUBLESTAR) | ||
n_all_args++; | ||
} | ||
n_all_args += n_args; | ||
args = (n_args ? asdl_seq_new(n_args, c->c_arena) : NULL); | ||
if (!args && n_args) | ||
return NULL; | ||
defaults = (n_defaults ? asdl_seq_new(n_defaults, c->c_arena) : NULL); | ||
if (!defaults && n_defaults) | ||
return NULL; | ||
/* type_comments will be lazily initialized if needed. If there are no | ||
per-argument type comments, it will remain NULL. Otherwise, it will be | ||
an asdl_seq with length equal to the number of args (including varargs | ||
and kwargs, if present) and with members set to the string of each arg's | ||
type comment, if present, or NULL otherwise. | ||
*/ | ||
|
||
/* fpdef: NAME | '(' fplist ')' | ||
fplist: fpdef (',' fpdef)* [','] | ||
*/ | ||
i = 0; | ||
j = 0; /* index for defaults */ | ||
k = 0; /* index for args */ | ||
l = 0; /* index for type comments */ | ||
while (i < NCH(n)) { | ||
ch = CHILD(n, i); | ||
switch (TYPE(ch)) { | ||
|
@@ -834,7 +845,9 @@ ast_for_arguments(struct compiling *c, const node *n) | |
asdl_seq_SET(args, k++, name); | ||
|
||
} | ||
i += 2; /* the name and the comma */ | ||
i += 1; /* the name */ | ||
if (TYPE(CHILD(n, i)) == COMMA) | ||
i += 1; /* the comma, if present */ | ||
if (parenthesized && Py_Py3kWarningFlag && | ||
!ast_warn(c, ch, "parenthesized argument names " | ||
"are invalid in 3.x")) | ||
|
@@ -848,15 +861,36 @@ ast_for_arguments(struct compiling *c, const node *n) | |
vararg = NEW_IDENTIFIER(CHILD(n, i+1)); | ||
if (!vararg) | ||
return NULL; | ||
i += 3; | ||
i += 2; /* the star and the name */ | ||
if (TYPE(CHILD(n, i)) == COMMA) | ||
i += 1; /* the comma, if present */ | ||
break; | ||
case DOUBLESTAR: | ||
if (!forbidden_check(c, CHILD(n, i+1), STR(CHILD(n, i+1)))) | ||
return NULL; | ||
kwarg = NEW_IDENTIFIER(CHILD(n, i+1)); | ||
if (!kwarg) | ||
return NULL; | ||
i += 3; | ||
i += 2; /* the double star and the name */ | ||
if (TYPE(CHILD(n, i)) == COMMA) | ||
i += 1; /* the comma, if present */ | ||
break; | ||
case TYPE_COMMENT: | ||
assert(l < k + !!vararg + !!kwarg); | ||
|
||
if (!type_comments) { | ||
/* lazily allocate the type_comments seq for perf reasons */ | ||
type_comments = asdl_seq_new(n_all_args, c->c_arena); | ||
if (!type_comments) | ||
return NULL; | ||
} | ||
|
||
while (l < k + !!vararg + !!kwarg - 1) { | ||
asdl_seq_SET(type_comments, l++, NULL); | ||
} | ||
|
||
asdl_seq_SET(type_comments, l++, NEW_TYPE_COMMENT(ch)); | ||
i += 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All this logic looks sensible. I'd like to have a comment somewhere describing the intended semantics of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Added! |
||
break; | ||
default: | ||
PyErr_Format(PyExc_SystemError, | ||
|
@@ -866,7 +900,13 @@ ast_for_arguments(struct compiling *c, const node *n) | |
} | ||
} | ||
|
||
return arguments(args, vararg, kwarg, defaults, c->c_arena); | ||
if (type_comments) { | ||
while (l < n_all_args) { | ||
asdl_seq_SET(type_comments, l++, NULL); | ||
} | ||
} | ||
|
||
return arguments(args, vararg, kwarg, defaults, type_comments, c->c_arena); | ||
} | ||
|
||
static expr_ty | ||
|
@@ -1038,7 +1078,7 @@ ast_for_lambdef(struct compiling *c, const node *n) | |
expr_ty expression; | ||
|
||
if (NCH(n) == 3) { | ||
args = arguments(NULL, NULL, NULL, NULL, c->c_arena); | ||
args = arguments(NULL, NULL, NULL, NULL, NULL, c->c_arena); | ||
if (!args) | ||
return NULL; | ||
expression = ast_for_expr(c, CHILD(n, 2)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,9 +30,10 @@ async_funcdef: ASYNC funcdef | |
funcdef: 'def' NAME parameters ['->' test] ':' [TYPE_COMMENT] suite | ||
|
||
parameters: '(' [typedargslist] ')' | ||
typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' | ||
['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | ||
| '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef) | ||
typedargslist: (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* [',' [TYPE_COMMENT] | ||
['*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* [',' [TYPE_COMMENT] '**' tfpdef] | '**' tfpdef]] [TYPE_COMMENT] | ||
| '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* [',' [TYPE_COMMENT] '**' tfpdef] [TYPE_COMMENT] | ||
| '**' tfpdef [TYPE_COMMENT]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One consequence of this definition is that the type comment is required to come after the comma, if any, that follows the argument. This seems fine to me -- thanks to Python's graceful handling of a redundant trailing comma, there's rarely a good reason to want to put the comma on the next line, in a form like this:
such as might appear in other languages for the sake of uniformity between lines and avoiding unnecessary diff noise. It's not clearly specified by PEP 484, though: So we should say this clearly someplace like the README, and also update the PEP to clarify. (And once that's done, can take this point out of the README.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Looks like this and the other PEP clarification are still open.) |
||
tfpdef: NAME [':' test] | ||
varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' | ||
['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] | ||
|
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.
Cool. I think there's a version of this also that belongs in the ASDL file, which is generally the reference for people wanting to consume the AST. It's not totally obvious what the semantics of this sequence is, particularly as it's quite different from the other parallel-ish-to-args sequence,
defaults
.