Skip to content

Commit 9a56912

Browse files
committed
py/compile: Do proper checking of * and ** in function definition.
This patch checks that there is only one *, and that ** is last in the arg list.
1 parent 0e3f29c commit 9a56912

File tree

3 files changed

+21
-3
lines changed

3 files changed

+21
-3
lines changed

py/compile.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2505,7 +2505,12 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
25052505
}
25062506

25072507
STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) {
2508-
// TODO verify that *k and **k are last etc
2508+
// check that **kw is last
2509+
if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
2510+
compile_syntax_error(comp, pn, "invalid syntax");
2511+
return;
2512+
}
2513+
25092514
qstr param_name = MP_QSTR_NULL;
25102515
uint param_flag = ID_FLAG_IS_PARAM;
25112516
if (MP_PARSE_NODE_IS_ID(pn)) {
@@ -2530,6 +2535,11 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
25302535
comp->scope_cur->num_pos_args += 1;
25312536
}
25322537
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {
2538+
if (comp->have_star) {
2539+
// more than one star
2540+
compile_syntax_error(comp, pn, "invalid syntax");
2541+
return;
2542+
}
25332543
comp->have_star = true;
25342544
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM;
25352545
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {

py/grammar.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ DEF_RULE(decorated, c(decorated), and(2), rule(decorators), rule(decorated_body)
6060
DEF_RULE(decorated_body, nc, or(2), rule(classdef), rule(funcdef))
6161
DEF_RULE(funcdef, c(funcdef), blank | and(8), tok(KW_DEF), tok(NAME), tok(DEL_PAREN_OPEN), opt_rule(typedargslist), tok(DEL_PAREN_CLOSE), opt_rule(funcdefrettype), tok(DEL_COLON), rule(suite))
6262
DEF_RULE(funcdefrettype, nc, ident | and(2), tok(DEL_MINUS_MORE), rule(test))
63-
// TODO typedargslist lets through more than is allowed
63+
// note: typedargslist lets through more than is allowed, compiler does further checks
6464
DEF_RULE(typedargslist, nc, list_with_end, rule(typedargslist_item), tok(DEL_COMMA))
6565
DEF_RULE(typedargslist_item, nc, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star))
6666
DEF_RULE(typedargslist_name, nc, ident | and(3), tok(NAME), opt_rule(typedargslist_colon), opt_rule(typedargslist_equal))
@@ -69,7 +69,7 @@ DEF_RULE(typedargslist_dbl_star, nc, and(3), tok(OP_DBL_STAR), tok(NAME), opt_ru
6969
DEF_RULE(typedargslist_colon, nc, ident | and(2), tok(DEL_COLON), rule(test))
7070
DEF_RULE(typedargslist_equal, nc, ident | and(2), tok(DEL_EQUAL), rule(test))
7171
DEF_RULE(tfpdef, nc, and(2), tok(NAME), opt_rule(typedargslist_colon))
72-
// TODO varargslist lets through more than is allowed
72+
// note: varargslist lets through more than is allowed, compiler does further checks
7373
DEF_RULE(varargslist, nc, list_with_end, rule(varargslist_item), tok(DEL_COMMA))
7474
DEF_RULE(varargslist_item, nc, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star))
7575
DEF_RULE(varargslist_name, nc, ident | and(2), tok(NAME), opt_rule(varargslist_equal))

tests/basics/syntaxerror.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,11 @@ def test_syntax(code):
113113

114114
# can define variable to be both nonlocal and global
115115
test_syntax('def f():\n nonlocal x\n global x')
116+
117+
# can't have multiple *'s
118+
test_syntax('def f(x, *a, *):\n pass')
119+
test_syntax('lambda x, *a, *: 1')
120+
121+
# **kw must be last
122+
test_syntax('def f(x, *a, **kw, r):\n pass')
123+
test_syntax('lambda x, *a, **kw, r: 1')

0 commit comments

Comments
 (0)