py: Towards default keyword arguments.

These are default arguments after a bare *.
This commit is contained in:
Damien George 2014-03-31 15:18:37 +01:00
parent 1aa2c10263
commit e337f1ef5e
5 changed files with 61 additions and 23 deletions

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);

13
py/vm.c
View File

@ -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: