From e337f1ef5efda000f0517b3d5e7aec5ba4ed8b55 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 31 Mar 2014 15:18:37 +0100 Subject: [PATCH] py: Towards default keyword arguments. These are default arguments after a bare *. --- py/compile.c | 31 +++++++++++++++++++++++-------- py/emitbc.c | 27 +++++++++++++++++++++------ py/emitglue.c | 9 ++++++--- py/runtime.h | 4 ++-- py/vm.c | 13 +++++++++---- 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/py/compile.c b/py/compile.c index dc5a8b38a2..43253a926b 100644 --- a/py/compile.c +++ b/py/compile.c @@ -776,17 +776,14 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { } // stuff for lambda and comprehensions and generators +// if we are not in CPython compatibility mode then: +// if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults +// if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults +// if both exist, the tuple is above the dictionary (ie the first pop gets the tuple) void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) { assert(n_pos_defaults >= 0); assert(n_kw_defaults >= 0); -#if !MICROPY_EMIT_CPYTHON - // in Micro Python we put the default params into a tuple using the bytecode - if (n_pos_defaults) { - EMIT_ARG(build_tuple, n_pos_defaults); - } -#endif - // make closed over variables, if any // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython) int nfree = 0; @@ -870,8 +867,19 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) { if (comp->have_bare_star) { comp->param_pass_num_dict_params += 1; if (comp->param_pass == 1) { +#if !MICROPY_EMIT_CPYTHON + // in Micro Python we put the default dict parameters into a dictionary using the bytecode + if (comp->param_pass_num_dict_params == 1) { + // first default dict param, so make the map + EMIT_ARG(build_map, 0); + } +#endif EMIT_ARG(load_const_id, MP_PARSE_NODE_LEAF_ARG(pn_id)); compile_node(comp, pn_equal); +#if !MICROPY_EMIT_CPYTHON + // in Micro Python we put the default dict parameters into a dictionary using the bytecode + EMIT(store_map); +#endif } } else { comp->param_pass_num_default_params += 1; @@ -922,6 +930,13 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint comp->param_pass_num_default_params = 0; apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param); +#if !MICROPY_EMIT_CPYTHON + // in Micro Python we put the default positional parameters into a tuple using the bytecode + if (comp->param_pass_num_default_params > 0) { + EMIT_ARG(build_tuple, comp->param_pass_num_default_params); + } +#endif + // get the scope for this function scope_t *fscope = (scope_t*)pns->nodes[4]; @@ -3327,7 +3342,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) { #else // return function that executes the outer module // we can free the unique_code slot because no-one has reference to this unique_code_id anymore - return mp_make_function_from_id(unique_code_id, true, MP_OBJ_NULL); + return mp_make_function_from_id(unique_code_id, true, MP_OBJ_NULL, MP_OBJ_NULL); #endif } } diff --git a/py/emitbc.c b/py/emitbc.c index 595c7ac196..0a83448559 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -732,23 +732,38 @@ STATIC void emit_bc_unpack_ex(emit_t *emit, int n_left, int n_right) { } STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) { - assert(n_kw_defaults == 0); - if (n_pos_defaults == 0) { + if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_bc_pre(emit, 1); emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION, scope->unique_code_id); } else { - emit_bc_pre(emit, 0); + if (n_pos_defaults == 0) { + // load dummy entry for non-existent positional default tuple + emit_bc_load_null(emit); + } else if (n_kw_defaults == 0) { + // load dummy entry for non-existent keyword default dict + emit_bc_load_null(emit); + emit_bc_rot_two(emit); + } + emit_bc_pre(emit, -1); emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->unique_code_id); } } STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) { - assert(n_kw_defaults == 0); - if (n_pos_defaults == 0) { + if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_bc_pre(emit, 0); emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE, scope->unique_code_id); } else { - emit_bc_pre(emit, -1); + if (n_pos_defaults == 0) { + // load dummy entry for non-existent positional default tuple + emit_bc_load_null(emit); + emit_bc_rot_two(emit); + } else if (n_kw_defaults == 0) { + // load dummy entry for non-existent keyword default dict + emit_bc_load_null(emit); + emit_bc_rot_three(emit); + } + emit_bc_pre(emit, -2); emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->unique_code_id); } } diff --git a/py/emitglue.c b/py/emitglue.c index 73304de27a..dc084e159c 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -190,13 +190,16 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le #endif } -mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args) { +mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args, mp_obj_t def_kw_args) { DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id); if (unique_code_id >= unique_codes_total) { // illegal code id return mp_const_none; } + // TODO implement default kw args + assert(def_kw_args == MP_OBJ_NULL); + // make the function, depending on the code kind mp_code_t *c = &unique_codes[unique_code_id]; mp_obj_t fun; @@ -231,10 +234,10 @@ mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp return fun; } -mp_obj_t mp_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) { +mp_obj_t mp_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args) { DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id); // make function object - mp_obj_t ffun = mp_make_function_from_id(unique_code_id, false, def_args); + mp_obj_t ffun = mp_make_function_from_id(unique_code_id, false, def_args, def_kw_args); // wrap function in closure object return mp_obj_new_closure(ffun, closure_tuple); } diff --git a/py/runtime.h b/py/runtime.h index d71e045b01..78f572424a 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -31,11 +31,11 @@ mp_obj_t mp_load_const_bytes(qstr qstr); mp_obj_t mp_get_cell(mp_obj_t cell); void mp_set_cell(mp_obj_t cell, mp_obj_t val); -mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args); +mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args, mp_obj_t def_kw_args); mp_obj_t mp_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun); mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive -mp_obj_t mp_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args); +mp_obj_t mp_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args); mp_obj_t mp_call_function_0(mp_obj_t fun); mp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg); diff --git a/py/vm.c b/py/vm.c index 599a1d862e..20388ec9ad 100644 --- a/py/vm.c +++ b/py/vm.c @@ -648,23 +648,28 @@ unwind_jump: case MP_BC_MAKE_FUNCTION: DECODE_UINT; - PUSH(mp_make_function_from_id(unum, false, MP_OBJ_NULL)); + PUSH(mp_make_function_from_id(unum, false, MP_OBJ_NULL, MP_OBJ_NULL)); break; case MP_BC_MAKE_FUNCTION_DEFARGS: DECODE_UINT; - SET_TOP(mp_make_function_from_id(unum, false, TOP())); + // Stack layout: def_dict def_tuple <- TOS + obj1 = POP(); + SET_TOP(mp_make_function_from_id(unum, false, obj1, TOP())); break; case MP_BC_MAKE_CLOSURE: DECODE_UINT; - SET_TOP(mp_make_closure_from_id(unum, TOP(), MP_OBJ_NULL)); + // Stack layout: closure_tuple <- TOS + SET_TOP(mp_make_closure_from_id(unum, TOP(), MP_OBJ_NULL, MP_OBJ_NULL)); break; case MP_BC_MAKE_CLOSURE_DEFARGS: DECODE_UINT; + // Stack layout: def_dict def_tuple closure_tuple <- TOS obj1 = POP(); - SET_TOP(mp_make_closure_from_id(unum, obj1, TOP())); + obj2 = POP(); + SET_TOP(mp_make_closure_from_id(unum, obj1, obj2, TOP())); break; case MP_BC_CALL_FUNCTION: