py/runtime: Allow multiple **args in a function call.

This is a partial implementation of PEP 448 to allow multiple ** unpackings
when calling a function or method.

The compiler is modified to encode the argument as a None: obj key-value
pair (similar to how regular keyword arguments are encoded as str: obj
pairs).  The extra object that was pushed on the stack to hold a single **
unpacking object is no longer used and is removed.

The runtime is modified to decode this new format.

Signed-off-by: David Lechner <david@pybricks.com>
This commit is contained in:
David Lechner
2020-03-24 21:39:46 -05:00
committed by Damien George
parent bb70874111
commit 1e99d29f36
9 changed files with 121 additions and 82 deletions

View File

@@ -2397,7 +2397,7 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
int n_positional = n_positional_extra;
uint n_keyword = 0;
uint star_flags = 0;
mp_parse_node_struct_t *star_args_node = NULL, *dblstar_args_node = NULL;
mp_parse_node_struct_t *star_args_node = NULL;
for (size_t i = 0; i < n_args; i++) {
if (MP_PARSE_NODE_IS_STRUCT(args[i])) {
mp_parse_node_struct_t *pns_arg = (mp_parse_node_struct_t *)args[i];
@@ -2409,12 +2409,11 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
star_flags |= MP_EMIT_STAR_FLAG_SINGLE;
star_args_node = pns_arg;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_dbl_star) {
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
compile_syntax_error(comp, (mp_parse_node_t)pns_arg, MP_ERROR_TEXT("can't have multiple **x"));
return;
}
star_flags |= MP_EMIT_STAR_FLAG_DOUBLE;
dblstar_args_node = pns_arg;
// double-star args are stored as kw arg with key of None
EMIT(load_null);
compile_node(comp, pns_arg->nodes[0]);
n_keyword++;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_argument) {
#if MICROPY_PY_ASSIGN_EXPR
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns_arg->nodes[1], PN_argument_3)) {
@@ -2429,7 +2428,7 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
}
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns_arg->nodes[0]));
compile_node(comp, pns_arg->nodes[1]);
n_keyword += 1;
n_keyword++;
} else {
compile_comprehension(comp, pns_arg, SCOPE_GEN_EXPR);
n_positional++;
@@ -2460,11 +2459,6 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
} else {
compile_node(comp, star_args_node->nodes[0]);
}
if (dblstar_args_node == NULL) {
EMIT(load_null);
} else {
compile_node(comp, dblstar_args_node->nodes[0]);
}
}
// emit the function/method call