py: Implement keyword-only args.
Implements 'def f(*, a)' and 'def f(*a, b)', but not default keyword-only args, eg 'def f(*, a=1)'. Partially addresses issue #524.
This commit is contained in:
parent
36cbd0db7e
commit
2827d62e8b
55
py/compile.c
55
py/compile.c
@ -2789,14 +2789,17 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
|||||||
|
|
||||||
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, bool allow_annotations) {
|
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, bool allow_annotations) {
|
||||||
// TODO verify that *k and **k are last etc
|
// TODO verify that *k and **k are last etc
|
||||||
qstr param_name = 0;
|
qstr param_name = MP_QSTR_NULL;
|
||||||
|
uint param_flag = ID_FLAG_IS_PARAM;
|
||||||
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
|
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
|
||||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||||
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
|
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||||
if (comp->have_star) {
|
if (comp->have_star) {
|
||||||
// comes after a bare star, so doesn't count as a parameter
|
// comes after a star, so counts as a keyword-only parameter
|
||||||
|
comp->scope_cur->num_kwonly_args += 1;
|
||||||
} else {
|
} else {
|
||||||
comp->scope_cur->num_params += 1;
|
// comes before a star, so counts as a positional parameter
|
||||||
|
comp->scope_cur->num_pos_args += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(MP_PARSE_NODE_IS_STRUCT(pn));
|
assert(MP_PARSE_NODE_IS_STRUCT(pn));
|
||||||
@ -2822,12 +2825,15 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (comp->have_star) {
|
if (comp->have_star) {
|
||||||
// comes after a bare star, so doesn't count as a parameter
|
// comes after a star, so counts as a keyword-only parameter
|
||||||
|
comp->scope_cur->num_kwonly_args += 1;
|
||||||
} else {
|
} else {
|
||||||
comp->scope_cur->num_params += 1;
|
// comes before a star, so counts as a positional parameter
|
||||||
|
comp->scope_cur->num_pos_args += 1;
|
||||||
}
|
}
|
||||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {
|
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {
|
||||||
comp->have_star = true;
|
comp->have_star = true;
|
||||||
|
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM;
|
||||||
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
|
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
|
||||||
// bare star
|
// bare star
|
||||||
// TODO see http://www.python.org/dev/peps/pep-3102/
|
// TODO see http://www.python.org/dev/peps/pep-3102/
|
||||||
@ -2848,6 +2854,7 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
|||||||
}
|
}
|
||||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
|
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
|
||||||
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
|
||||||
|
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;
|
||||||
if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
||||||
// this parameter has an annotation
|
// this parameter has an annotation
|
||||||
pn_annotation = pns->nodes[1];
|
pn_annotation = pns->nodes[1];
|
||||||
@ -2859,7 +2866,7 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param_name != 0) {
|
if (param_name != MP_QSTR_NULL) {
|
||||||
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
|
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
|
||||||
// TODO this parameter has an annotation
|
// TODO this parameter has an annotation
|
||||||
}
|
}
|
||||||
@ -2870,15 +2877,15 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
id_info->kind = ID_INFO_KIND_LOCAL;
|
id_info->kind = ID_INFO_KIND_LOCAL;
|
||||||
id_info->flags |= ID_FLAG_IS_PARAM;
|
id_info->flags = param_flag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
|
STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||||
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
|
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
|
STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||||
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
|
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3051,7 +3058,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
|||||||
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added);
|
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added);
|
||||||
assert(added);
|
assert(added);
|
||||||
id_info->kind = ID_INFO_KIND_LOCAL;
|
id_info->kind = ID_INFO_KIND_LOCAL;
|
||||||
scope->num_params = 1;
|
scope->num_pos_args = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope->kind == SCOPE_LIST_COMP) {
|
if (scope->kind == SCOPE_LIST_COMP) {
|
||||||
@ -3144,7 +3151,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
|||||||
if (comp->pass == PASS_2) {
|
if (comp->pass == PASS_2) {
|
||||||
mp_parse_node_t *pn_params;
|
mp_parse_node_t *pn_params;
|
||||||
int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params);
|
int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params);
|
||||||
scope->num_params = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);
|
scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(MP_PARSE_NODE_IS_NULL(pns->nodes[2])); // type
|
assert(MP_PARSE_NODE_IS_NULL(pns->nodes[2])); // type
|
||||||
@ -3235,6 +3242,25 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
|
STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
|
||||||
|
#if !MICROPY_EMIT_CPYTHON
|
||||||
|
// in Micro Python we put the *x parameter after all other parameters (except **y)
|
||||||
|
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
|
||||||
|
id_info_t *id_param = NULL;
|
||||||
|
for (int i = scope->id_info_len - 1; i >= 0; i--) {
|
||||||
|
id_info_t *id = &scope->id_info[i];
|
||||||
|
if (id->flags & ID_FLAG_IS_STAR_PARAM) {
|
||||||
|
if (id_param != NULL) {
|
||||||
|
// swap star param with last param
|
||||||
|
id_info_t temp = *id_param; *id_param = *id; *id = temp;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else if (id_param == NULL && id->flags == ID_FLAG_IS_PARAM) {
|
||||||
|
id_param = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// in functions, turn implicit globals into explicit globals
|
// in functions, turn implicit globals into explicit globals
|
||||||
// compute the index of each local
|
// compute the index of each local
|
||||||
scope->num_locals = 0;
|
scope->num_locals = 0;
|
||||||
@ -3247,10 +3273,9 @@ STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
|
|||||||
if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
|
if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
|
||||||
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
|
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
|
||||||
}
|
}
|
||||||
// note: params always count for 1 local, even if they are a cell
|
// params always count for 1 local, even if they are a cell
|
||||||
if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) {
|
if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) {
|
||||||
id->local_num = scope->num_locals;
|
id->local_num = scope->num_locals++;
|
||||||
scope->num_locals += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3309,7 +3334,7 @@ STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
|
|||||||
id->local_num += num_free;
|
id->local_num += num_free;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope->num_params += num_free; // free vars are counted as params for passing them into the function
|
scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function
|
||||||
scope->num_locals += num_free;
|
scope->num_locals += num_free;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -300,14 +300,14 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
|
|||||||
emit->code_base = m_new0(byte, emit->code_info_size + emit->byte_code_size);
|
emit->code_base = m_new0(byte, emit->code_info_size + emit->byte_code_size);
|
||||||
|
|
||||||
} else if (emit->pass == PASS_3) {
|
} else if (emit->pass == PASS_3) {
|
||||||
qstr *arg_names = m_new(qstr, emit->scope->num_params);
|
qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||||
for (int i = 0; i < emit->scope->num_params; i++) {
|
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
|
||||||
arg_names[i] = emit->scope->id_info[i].qstr;
|
arg_names[i] = emit->scope->id_info[i].qstr;
|
||||||
}
|
}
|
||||||
mp_emit_glue_assign_byte_code(emit->scope->raw_code, emit->code_base,
|
mp_emit_glue_assign_byte_code(emit->scope->raw_code, emit->code_base,
|
||||||
emit->code_info_size + emit->byte_code_size,
|
emit->code_info_size + emit->byte_code_size,
|
||||||
emit->scope->num_params, emit->scope->num_locals,
|
emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names,
|
||||||
emit->scope->scope_flags, arg_names);
|
emit->scope->scope_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,16 +47,22 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) {
|
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags) {
|
||||||
rc->kind = MP_CODE_BYTE;
|
rc->kind = MP_CODE_BYTE;
|
||||||
rc->scope_flags = scope_flags;
|
rc->scope_flags = scope_flags;
|
||||||
rc->n_args = n_args;
|
rc->n_pos_args = n_pos_args;
|
||||||
|
rc->n_kwonly_args = n_kwonly_args;
|
||||||
|
rc->arg_names = arg_names;
|
||||||
rc->u_byte.code = code;
|
rc->u_byte.code = code;
|
||||||
rc->u_byte.len = len;
|
rc->u_byte.len = len;
|
||||||
rc->arg_names = arg_names;
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRINT
|
#ifdef DEBUG_PRINT
|
||||||
DEBUG_printf("assign byte code: code=%p len=%u n_args=%d n_locals=%d\n", code, len, n_args, n_locals);
|
DEBUG_printf("assign byte code: code=%p len=%u n_pos_args=%d n_kwonly_args=%d flags=%x\n", code, len, n_pos_args, n_kwonly_args, scope_flags);
|
||||||
|
DEBUG_printf(" arg names:");
|
||||||
|
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
|
||||||
|
DEBUG_printf(" %s", qstr_str(arg_names[i]));
|
||||||
|
}
|
||||||
|
DEBUG_printf("\n");
|
||||||
for (int i = 0; i < 128 && i < len; i++) {
|
for (int i = 0; i < 128 && i < len; i++) {
|
||||||
if (i > 0 && i % 16 == 0) {
|
if (i > 0 && i % 16 == 0) {
|
||||||
DEBUG_printf("\n");
|
DEBUG_printf("\n");
|
||||||
@ -73,7 +79,7 @@ void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, int
|
|||||||
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
|
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
|
||||||
rc->kind = MP_CODE_NATIVE;
|
rc->kind = MP_CODE_NATIVE;
|
||||||
rc->scope_flags = 0;
|
rc->scope_flags = 0;
|
||||||
rc->n_args = n_args;
|
rc->n_pos_args = n_args;
|
||||||
rc->u_native.fun = fun;
|
rc->u_native.fun = fun;
|
||||||
|
|
||||||
#ifdef DEBUG_PRINT
|
#ifdef DEBUG_PRINT
|
||||||
@ -99,7 +105,7 @@ void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *fun, uint len, int
|
|||||||
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
|
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
|
||||||
rc->kind = MP_CODE_INLINE_ASM;
|
rc->kind = MP_CODE_INLINE_ASM;
|
||||||
rc->scope_flags = 0;
|
rc->scope_flags = 0;
|
||||||
rc->n_args = n_args;
|
rc->n_pos_args = n_args;
|
||||||
rc->u_inline_asm.fun = fun;
|
rc->u_inline_asm.fun = fun;
|
||||||
|
|
||||||
#ifdef DEBUG_PRINT
|
#ifdef DEBUG_PRINT
|
||||||
@ -136,13 +142,13 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
|||||||
mp_obj_t fun;
|
mp_obj_t fun;
|
||||||
switch (rc->kind) {
|
switch (rc->kind) {
|
||||||
case MP_CODE_BYTE:
|
case MP_CODE_BYTE:
|
||||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_args, def_args, rc->u_byte.code);
|
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, rc->u_byte.code);
|
||||||
break;
|
break;
|
||||||
case MP_CODE_NATIVE:
|
case MP_CODE_NATIVE:
|
||||||
fun = mp_make_function_n(rc->n_args, rc->u_native.fun);
|
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
|
||||||
break;
|
break;
|
||||||
case MP_CODE_INLINE_ASM:
|
case MP_CODE_INLINE_ASM:
|
||||||
fun = mp_obj_new_fun_asm(rc->n_args, rc->u_inline_asm.fun);
|
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_inline_asm.fun);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// raw code was never set (this should not happen)
|
// raw code was never set (this should not happen)
|
||||||
|
@ -9,9 +9,11 @@ typedef enum {
|
|||||||
} mp_raw_code_kind_t;
|
} mp_raw_code_kind_t;
|
||||||
|
|
||||||
typedef struct _mp_code_t {
|
typedef struct _mp_code_t {
|
||||||
mp_raw_code_kind_t kind : 8;
|
mp_raw_code_kind_t kind : 3;
|
||||||
uint scope_flags : 8;
|
uint scope_flags : 7;
|
||||||
uint n_args : 16;
|
uint n_pos_args : 11;
|
||||||
|
uint n_kwonly_args : 11;
|
||||||
|
qstr *arg_names;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
byte *code;
|
byte *code;
|
||||||
@ -24,7 +26,6 @@ typedef struct _mp_code_t {
|
|||||||
void *fun;
|
void *fun;
|
||||||
} u_inline_asm;
|
} u_inline_asm;
|
||||||
};
|
};
|
||||||
qstr *arg_names;
|
|
||||||
} mp_raw_code_t;
|
} mp_raw_code_t;
|
||||||
|
|
||||||
void mp_emit_glue_init(void);
|
void mp_emit_glue_init(void);
|
||||||
@ -32,7 +33,7 @@ void mp_emit_glue_deinit(void);
|
|||||||
|
|
||||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
|
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
|
||||||
|
|
||||||
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names);
|
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
|
||||||
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
|
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
|
||||||
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
|
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
|
|||||||
|
|
||||||
if (emit->pass == PASS_3) {
|
if (emit->pass == PASS_3) {
|
||||||
void *f = asm_thumb_get_code(emit->as);
|
void *f = asm_thumb_get_code(emit->as);
|
||||||
mp_emit_glue_assign_inline_asm_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params);
|
mp_emit_glue_assign_inline_asm_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return emit->success;
|
return emit->success;
|
||||||
|
@ -230,7 +230,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||||||
|
|
||||||
// initialise locals from parameters
|
// initialise locals from parameters
|
||||||
#if N_X64
|
#if N_X64
|
||||||
for (int i = 0; i < scope->num_params; i++) {
|
for (int i = 0; i < scope->num_pos_args; i++) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
asm_x64_mov_r64_to_r64(emit->as, REG_ARG_1, REG_LOCAL_1);
|
asm_x64_mov_r64_to_r64(emit->as, REG_ARG_1, REG_LOCAL_1);
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
@ -243,7 +243,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif N_THUMB
|
#elif N_THUMB
|
||||||
for (int i = 0; i < scope->num_params; i++) {
|
for (int i = 0; i < scope->num_pos_args; i++) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
asm_thumb_mov_reg_reg(emit->as, REG_LOCAL_1, REG_ARG_1);
|
asm_thumb_mov_reg_reg(emit->as, REG_LOCAL_1, REG_ARG_1);
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
@ -283,10 +283,10 @@ STATIC void emit_native_end_pass(emit_t *emit) {
|
|||||||
if (emit->pass == PASS_3) {
|
if (emit->pass == PASS_3) {
|
||||||
#if N_X64
|
#if N_X64
|
||||||
void *f = asm_x64_get_code(emit->as);
|
void *f = asm_x64_get_code(emit->as);
|
||||||
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_x64_get_code_size(emit->as), emit->scope->num_params);
|
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_x64_get_code_size(emit->as), emit->scope->num_pos_args);
|
||||||
#elif N_THUMB
|
#elif N_THUMB
|
||||||
void *f = asm_thumb_get_code(emit->as);
|
void *f = asm_thumb_get_code(emit->as);
|
||||||
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params);
|
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
py/obj.h
2
py/obj.h
@ -356,7 +356,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
|||||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
|
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
|
||||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
|
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
|
||||||
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||||
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args, const byte *code);
|
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, const byte *code);
|
||||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
||||||
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
|
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
|
||||||
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
|
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
|
||||||
|
77
py/objfun.c
77
py/objfun.c
@ -152,17 +152,18 @@ bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, co
|
|||||||
mp_obj_fun_bc_t *self = self_in;
|
mp_obj_fun_bc_t *self = self_in;
|
||||||
|
|
||||||
assert(n_kw == 0);
|
assert(n_kw == 0);
|
||||||
|
assert(self->n_kwonly_args == 0);
|
||||||
assert(self->takes_var_args == 0);
|
assert(self->takes_var_args == 0);
|
||||||
assert(self->takes_kw_args == 0);
|
assert(self->takes_kw_args == 0);
|
||||||
|
|
||||||
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
|
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
|
||||||
uint n_extra_args = 0;
|
uint n_extra_args = 0;
|
||||||
|
|
||||||
if (n_args > self->n_args) {
|
if (n_args > self->n_pos_args) {
|
||||||
goto arg_error;
|
goto arg_error;
|
||||||
} else {
|
} else {
|
||||||
extra_args -= self->n_args - n_args;
|
extra_args -= self->n_pos_args - n_args;
|
||||||
n_extra_args += self->n_args - n_args;
|
n_extra_args += self->n_pos_args - n_args;
|
||||||
}
|
}
|
||||||
*out_args1 = args;
|
*out_args1 = args;
|
||||||
*out_args1_len = n_args;
|
*out_args1_len = n_args;
|
||||||
@ -171,10 +172,15 @@ bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, co
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
arg_error:
|
arg_error:
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args));
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_pos_args, n_args));
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||||
|
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
|
||||||
|
// usage for the common case of positional only args.
|
||||||
|
//
|
||||||
|
// extra_args layout: def_args, var_arg tuple, kwonly args, var_kw dict
|
||||||
|
|
||||||
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
|
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
|
||||||
DEBUG_printf("Input pos args: ");
|
DEBUG_printf("Input pos args: ");
|
||||||
dump_args(args, n_args);
|
dump_args(args, n_args);
|
||||||
@ -187,19 +193,18 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
|||||||
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
|
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
|
||||||
uint n_extra_args = 0;
|
uint n_extra_args = 0;
|
||||||
|
|
||||||
|
|
||||||
// check positional arguments
|
// check positional arguments
|
||||||
|
|
||||||
if (n_args > self->n_args) {
|
if (n_args > self->n_pos_args) {
|
||||||
// given more than enough arguments
|
// given more than enough arguments
|
||||||
if (!self->takes_var_args) {
|
if (!self->takes_var_args) {
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||||
"function takes %d positional arguments but %d were given", self->n_args, n_args));
|
"function takes %d positional arguments but %d were given", self->n_pos_args, n_args));
|
||||||
}
|
}
|
||||||
// put extra arguments in varargs tuple
|
// put extra arguments in varargs tuple
|
||||||
*extra_args = mp_obj_new_tuple(n_args - self->n_args, args + self->n_args);
|
*extra_args = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
|
||||||
n_extra_args = 1;
|
n_extra_args = 1;
|
||||||
n_args = self->n_args;
|
n_args = self->n_pos_args;
|
||||||
} else {
|
} else {
|
||||||
if (self->takes_var_args) {
|
if (self->takes_var_args) {
|
||||||
DEBUG_printf("passing empty tuple as *args\n");
|
DEBUG_printf("passing empty tuple as *args\n");
|
||||||
@ -209,14 +214,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
|||||||
// Apply processing and check below only if we don't have kwargs,
|
// Apply processing and check below only if we don't have kwargs,
|
||||||
// otherwise, kw handling code below has own extensive checks.
|
// otherwise, kw handling code below has own extensive checks.
|
||||||
if (n_kw == 0) {
|
if (n_kw == 0) {
|
||||||
if (n_args >= self->n_args - self->n_def_args) {
|
if (n_args >= self->n_pos_args - self->n_def_args) {
|
||||||
// given enough arguments, but may need to use some default arguments
|
// given enough arguments, but may need to use some default arguments
|
||||||
extra_args -= self->n_args - n_args;
|
extra_args -= self->n_pos_args - n_args;
|
||||||
n_extra_args += self->n_args - n_args;
|
n_extra_args += self->n_pos_args - n_args;
|
||||||
} else {
|
} else {
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||||
"function takes at least %d positional arguments but %d were given",
|
"function takes at least %d positional arguments but %d were given",
|
||||||
self->n_args - self->n_def_args, n_args));
|
self->n_pos_args - self->n_def_args, n_args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,13 +234,13 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
|||||||
// So, we have 2 choices: allocate it unconditionally at the top of function
|
// So, we have 2 choices: allocate it unconditionally at the top of function
|
||||||
// (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
|
// (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
|
||||||
//mp_obj_t flat_args[self->n_args];
|
//mp_obj_t flat_args[self->n_args];
|
||||||
mp_obj_t *flat_args = alloca(self->n_args * sizeof(mp_obj_t));
|
mp_obj_t *flat_args = alloca((self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t));
|
||||||
for (int i = self->n_args - 1; i >= 0; i--) {
|
for (int i = self->n_pos_args + self->n_kwonly_args - 1; i >= 0; i--) {
|
||||||
flat_args[i] = MP_OBJ_NULL;
|
flat_args[i] = MP_OBJ_NULL;
|
||||||
}
|
}
|
||||||
memcpy(flat_args, args, sizeof(*args) * n_args);
|
memcpy(flat_args, args, sizeof(*args) * n_args);
|
||||||
DEBUG_printf("Initial args: ");
|
DEBUG_printf("Initial args: ");
|
||||||
dump_args(flat_args, self->n_args);
|
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
|
||||||
|
|
||||||
mp_obj_t dict = MP_OBJ_NULL;
|
mp_obj_t dict = MP_OBJ_NULL;
|
||||||
if (self->takes_kw_args) {
|
if (self->takes_kw_args) {
|
||||||
@ -243,7 +248,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
|||||||
}
|
}
|
||||||
for (uint i = 0; i < n_kw; i++) {
|
for (uint i = 0; i < n_kw; i++) {
|
||||||
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
||||||
for (uint j = 0; j < self->n_args; j++) {
|
for (uint j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||||
if (arg_name == self->args[j]) {
|
if (arg_name == self->args[j]) {
|
||||||
if (flat_args[j] != MP_OBJ_NULL) {
|
if (flat_args[j] != MP_OBJ_NULL) {
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||||
@ -261,10 +266,10 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
|
|||||||
continue2:;
|
continue2:;
|
||||||
}
|
}
|
||||||
DEBUG_printf("Args with kws flattened: ");
|
DEBUG_printf("Args with kws flattened: ");
|
||||||
dump_args(flat_args, self->n_args);
|
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
|
||||||
|
|
||||||
// Now fill in defaults
|
// Now fill in defaults for positional args
|
||||||
mp_obj_t *d = &flat_args[self->n_args - 1];
|
mp_obj_t *d = &flat_args[self->n_pos_args - 1];
|
||||||
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
|
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
|
||||||
for (int i = self->n_def_args; i > 0; i--, d--, s--) {
|
for (int i = self->n_def_args; i > 0; i--, d--, s--) {
|
||||||
if (*d == MP_OBJ_NULL) {
|
if (*d == MP_OBJ_NULL) {
|
||||||
@ -272,9 +277,9 @@ continue2:;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_printf("Args after filling defaults: ");
|
DEBUG_printf("Args after filling defaults: ");
|
||||||
dump_args(flat_args, self->n_args);
|
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
|
||||||
|
|
||||||
// Now check that all mandatory args specified
|
// Check that all mandatory positional args are specified
|
||||||
while (d >= flat_args) {
|
while (d >= flat_args) {
|
||||||
if (*d-- == MP_OBJ_NULL) {
|
if (*d-- == MP_OBJ_NULL) {
|
||||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||||
@ -282,8 +287,16 @@ continue2:;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that all mandatory keyword args are specified
|
||||||
|
for (int i = 0; i < self->n_kwonly_args; i++) {
|
||||||
|
if (flat_args[self->n_pos_args + i] == MP_OBJ_NULL) {
|
||||||
|
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||||
|
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
args = flat_args;
|
args = flat_args;
|
||||||
n_args = self->n_args;
|
n_args = self->n_pos_args + self->n_kwonly_args;
|
||||||
|
|
||||||
if (self->takes_kw_args) {
|
if (self->takes_kw_args) {
|
||||||
extra_args[n_extra_args] = dict;
|
extra_args[n_extra_args] = dict;
|
||||||
@ -291,6 +304,10 @@ continue2:;
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no keyword arguments given
|
// no keyword arguments given
|
||||||
|
if (self->n_kwonly_args != 0) {
|
||||||
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||||
|
"function missing keyword-only argument"));
|
||||||
|
}
|
||||||
if (self->takes_kw_args) {
|
if (self->takes_kw_args) {
|
||||||
extra_args[n_extra_args] = mp_obj_new_dict(0);
|
extra_args[n_extra_args] = mp_obj_new_dict(0);
|
||||||
n_extra_args += 1;
|
n_extra_args += 1;
|
||||||
@ -320,7 +337,7 @@ const mp_obj_type_t mp_type_fun_bc = {
|
|||||||
.binary_op = fun_binary_op,
|
.binary_op = fun_binary_op,
|
||||||
};
|
};
|
||||||
|
|
||||||
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args_in, const byte *code) {
|
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, const byte *code) {
|
||||||
uint n_def_args = 0;
|
uint n_def_args = 0;
|
||||||
uint n_extra_args = 0;
|
uint n_extra_args = 0;
|
||||||
mp_obj_tuple_t *def_args = def_args_in;
|
mp_obj_tuple_t *def_args = def_args_in;
|
||||||
@ -339,14 +356,22 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t d
|
|||||||
o->base.type = &mp_type_fun_bc;
|
o->base.type = &mp_type_fun_bc;
|
||||||
o->globals = mp_globals_get();
|
o->globals = mp_globals_get();
|
||||||
o->args = args;
|
o->args = args;
|
||||||
o->n_args = n_args;
|
o->n_pos_args = n_pos_args;
|
||||||
|
o->n_kwonly_args = n_kwonly_args;
|
||||||
o->n_def_args = n_def_args;
|
o->n_def_args = n_def_args;
|
||||||
o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
|
o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
|
||||||
o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
|
o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
|
||||||
o->bytecode = code;
|
o->bytecode = code;
|
||||||
|
memset(o->extra_args, 0, n_extra_args * sizeof(mp_obj_t));
|
||||||
if (def_args != MP_OBJ_NULL) {
|
if (def_args != MP_OBJ_NULL) {
|
||||||
memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
|
memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
|
||||||
}
|
}
|
||||||
|
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
|
||||||
|
o->extra_args[n_def_args] = MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
|
||||||
|
o->extra_args[n_extra_args - 1] = MP_OBJ_NULL;
|
||||||
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
typedef struct _mp_obj_fun_bc_t {
|
typedef struct _mp_obj_fun_bc_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_obj_dict_t *globals; // the context within which this function was defined
|
mp_obj_dict_t *globals; // the context within which this function was defined
|
||||||
machine_uint_t n_args : 15; // number of arguments this function takes
|
machine_uint_t n_pos_args : 16; // number of arguments this function takes
|
||||||
machine_uint_t n_def_args : 15; // number of default arguments
|
machine_uint_t n_kwonly_args : 16; // number of arguments this function takes
|
||||||
|
machine_uint_t n_def_args : 16; // number of default arguments
|
||||||
machine_uint_t takes_var_args : 1; // set if this function takes variable args
|
machine_uint_t takes_var_args : 1; // set if this function takes variable args
|
||||||
machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
|
machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
|
||||||
const byte *bytecode; // bytecode for the function
|
const byte *bytecode; // bytecode for the function
|
||||||
|
@ -236,7 +236,7 @@ void scope_print_info(scope_t *s) {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
*/
|
*/
|
||||||
printf(" flags %04x\n", s->scope_flags);
|
printf(" flags %04x\n", s->scope_flags);
|
||||||
printf(" argcount %d\n", s->num_params);
|
printf(" argcount %d\n", s->num_pos_args);
|
||||||
printf(" nlocals %d\n", s->num_locals);
|
printf(" nlocals %d\n", s->num_locals);
|
||||||
printf(" stacksize %d\n", s->stack_size);
|
printf(" stacksize %d\n", s->stack_size);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@ enum {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
ID_FLAG_IS_PARAM = 0x01,
|
ID_FLAG_IS_PARAM = 0x01,
|
||||||
ID_FLAG_IS_DELETED = 0x02,
|
ID_FLAG_IS_STAR_PARAM = 0x02,
|
||||||
|
ID_FLAG_IS_DBL_STAR_PARAM = 0x04,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _id_info_t {
|
typedef struct _id_info_t {
|
||||||
@ -32,7 +33,8 @@ typedef struct _scope_t {
|
|||||||
mp_raw_code_t *raw_code;
|
mp_raw_code_t *raw_code;
|
||||||
uint8_t scope_flags; // see runtime0.h
|
uint8_t scope_flags; // see runtime0.h
|
||||||
uint8_t emit_options; // see compile.h
|
uint8_t emit_options; // see compile.h
|
||||||
uint16_t num_params;
|
uint16_t num_pos_args;
|
||||||
|
uint16_t num_kwonly_args;
|
||||||
uint16_t num_locals;
|
uint16_t num_locals;
|
||||||
uint16_t stack_size; // maximum size of the locals stack
|
uint16_t stack_size; // maximum size of the locals stack
|
||||||
uint16_t exc_stack_size; // maximum size of the exception stack
|
uint16_t exc_stack_size; // maximum size of the exception stack
|
||||||
|
68
tests/basics/fun-kwonly.py
Normal file
68
tests/basics/fun-kwonly.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# to test keyword-only arguments
|
||||||
|
|
||||||
|
# simplest case
|
||||||
|
def f(*, a):
|
||||||
|
print(a)
|
||||||
|
|
||||||
|
f(a=1)
|
||||||
|
|
||||||
|
# with 2 keyword-only args
|
||||||
|
def f(*, a, b):
|
||||||
|
print(a, b)
|
||||||
|
|
||||||
|
f(a=1, b=2)
|
||||||
|
f(b=1, a=2)
|
||||||
|
|
||||||
|
# positional followed by bare star
|
||||||
|
def f(a, *, b, c):
|
||||||
|
print(a, b, c)
|
||||||
|
|
||||||
|
f(1, b=3, c=4)
|
||||||
|
f(1, c=3, b=4)
|
||||||
|
f(1, **{'b':'3', 'c':4})
|
||||||
|
|
||||||
|
try:
|
||||||
|
f(1)
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
|
||||||
|
try:
|
||||||
|
f(1, b=2)
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
|
||||||
|
try:
|
||||||
|
f(1, c=2)
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
|
||||||
|
# with **kw
|
||||||
|
def f(a, *, b, **kw):
|
||||||
|
print(a, b, kw)
|
||||||
|
|
||||||
|
f(1, b=2)
|
||||||
|
f(1, b=2, c=3)
|
||||||
|
|
||||||
|
## with a default value; not currently working
|
||||||
|
#def g(a, *, b=2, c):
|
||||||
|
# print(a, b, c)
|
||||||
|
#
|
||||||
|
#g(1, c=3)
|
||||||
|
#g(1, b=3, c=4)
|
||||||
|
#g(1, **{'c':3})
|
||||||
|
#g(1, **{'b':'3', 'c':4})
|
||||||
|
|
||||||
|
# with named star
|
||||||
|
def f(*a, b, c):
|
||||||
|
print(a, b, c)
|
||||||
|
|
||||||
|
f(b=1, c=2)
|
||||||
|
f(c=1, b=2)
|
||||||
|
|
||||||
|
# with positional and named star
|
||||||
|
def f(a, *b, c):
|
||||||
|
print(a, b, c)
|
||||||
|
|
||||||
|
f(1, c=2)
|
||||||
|
f(1, 2, c=3)
|
||||||
|
f(a=1, c=3)
|
Loading…
x
Reference in New Issue
Block a user