py: Change compile order for default positional and keyword args.
This simplifies the compiler a little, since now it can do 1 pass over a function declaration, to determine default arguments. I would have done this originally, but CPython 3.3 somehow had the default keyword args compiled before the default position args (even though they appear in the other order in the text of the script), and I thought it was important to have the same order of execution when evaluating default arguments. CPython 3.4 has changed the order to the more obvious one, so we can also change.
This commit is contained in:
parent
0e3329a6b8
commit
69b89d21b2
69
py/compile.c
69
py/compile.c
@ -53,9 +53,8 @@ typedef struct _compiler_t {
|
|||||||
uint16_t n_arg_keyword;
|
uint16_t n_arg_keyword;
|
||||||
uint8_t star_flags;
|
uint8_t star_flags;
|
||||||
uint8_t have_bare_star;
|
uint8_t have_bare_star;
|
||||||
uint8_t param_pass;
|
uint16_t num_dict_params;
|
||||||
uint16_t param_pass_num_dict_params;
|
uint16_t num_default_params;
|
||||||
uint16_t param_pass_num_default_params;
|
|
||||||
|
|
||||||
scope_t *scope_head;
|
scope_t *scope_head;
|
||||||
scope_t *scope_cur;
|
scope_t *scope_cur;
|
||||||
@ -897,7 +896,7 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
|||||||
// this parameter does not have a default value
|
// this parameter does not have a default value
|
||||||
|
|
||||||
// check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid)
|
// check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid)
|
||||||
if (!comp->have_bare_star && comp->param_pass_num_default_params != 0) {
|
if (!comp->have_bare_star && comp->num_default_params != 0) {
|
||||||
compile_syntax_error(comp, pn, "non-default argument follows default argument");
|
compile_syntax_error(comp, pn, "non-default argument follows default argument");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -907,27 +906,23 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
|||||||
// in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
|
// in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
|
||||||
|
|
||||||
if (comp->have_bare_star) {
|
if (comp->have_bare_star) {
|
||||||
comp->param_pass_num_dict_params += 1;
|
comp->num_dict_params += 1;
|
||||||
if (comp->param_pass == 1) {
|
|
||||||
#if !MICROPY_EMIT_CPYTHON
|
#if !MICROPY_EMIT_CPYTHON
|
||||||
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
||||||
if (comp->param_pass_num_dict_params == 1) {
|
if (comp->num_dict_params == 1) {
|
||||||
// first default dict param, so make the map
|
// first default dict param, so make the map
|
||||||
EMIT_ARG(build_map, 0);
|
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
|
|
||||||
}
|
}
|
||||||
|
#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 {
|
} else {
|
||||||
comp->param_pass_num_default_params += 1;
|
comp->num_default_params += 1;
|
||||||
if (comp->param_pass == 2) {
|
compile_node(comp, pn_equal);
|
||||||
compile_node(comp, pn_equal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,34 +943,23 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint
|
|||||||
|
|
||||||
// save variables (probably don't need to do this, since we can't have nested definitions..?)
|
// save variables (probably don't need to do this, since we can't have nested definitions..?)
|
||||||
uint old_have_bare_star = comp->have_bare_star;
|
uint old_have_bare_star = comp->have_bare_star;
|
||||||
uint old_param_pass = comp->param_pass;
|
uint old_num_dict_params = comp->num_dict_params;
|
||||||
uint old_param_pass_num_dict_params = comp->param_pass_num_dict_params;
|
uint old_num_default_params = comp->num_default_params;
|
||||||
uint old_param_pass_num_default_params = comp->param_pass_num_default_params;
|
|
||||||
|
|
||||||
// compile default parameters
|
// compile default parameters
|
||||||
|
|
||||||
// pass 1 does any default parameters after bare star
|
|
||||||
comp->have_bare_star = false;
|
comp->have_bare_star = false;
|
||||||
comp->param_pass = 1;
|
comp->num_dict_params = 0;
|
||||||
comp->param_pass_num_dict_params = 0;
|
comp->num_default_params = 0;
|
||||||
comp->param_pass_num_default_params = 0;
|
|
||||||
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
|
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
|
||||||
|
|
||||||
if (comp->had_error) {
|
if (comp->had_error) {
|
||||||
return MP_QSTR_NULL;
|
return MP_QSTR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass 2 does any default parameters before bare star
|
|
||||||
comp->have_bare_star = false;
|
|
||||||
comp->param_pass = 2;
|
|
||||||
comp->param_pass_num_dict_params = 0;
|
|
||||||
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
|
#if !MICROPY_EMIT_CPYTHON
|
||||||
// in Micro Python we put the default positional parameters into a tuple using the bytecode
|
// in Micro Python we put the default positional parameters into a tuple using the bytecode
|
||||||
if (comp->param_pass_num_default_params > 0) {
|
if (comp->num_default_params > 0) {
|
||||||
EMIT_ARG(build_tuple, comp->param_pass_num_default_params);
|
EMIT_ARG(build_tuple, comp->num_default_params);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -983,13 +967,12 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint
|
|||||||
scope_t *fscope = (scope_t*)pns->nodes[4];
|
scope_t *fscope = (scope_t*)pns->nodes[4];
|
||||||
|
|
||||||
// make the function
|
// make the function
|
||||||
close_over_variables_etc(comp, fscope, comp->param_pass_num_default_params, comp->param_pass_num_dict_params);
|
close_over_variables_etc(comp, fscope, comp->num_default_params, comp->num_dict_params);
|
||||||
|
|
||||||
// restore variables
|
// restore variables
|
||||||
comp->have_bare_star = old_have_bare_star;
|
comp->have_bare_star = old_have_bare_star;
|
||||||
comp->param_pass = old_param_pass;
|
comp->num_dict_params = old_num_dict_params;
|
||||||
comp->param_pass_num_dict_params = old_param_pass_num_dict_params;
|
comp->num_default_params = old_num_default_params;
|
||||||
comp->param_pass_num_default_params = old_param_pass_num_default_params;
|
|
||||||
|
|
||||||
// return its name (the 'f' in "def f(...):")
|
// return its name (the 'f' in "def f(...):")
|
||||||
return fscope->simple_name;
|
return fscope->simple_name;
|
||||||
|
@ -744,10 +744,10 @@ STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defau
|
|||||||
if (n_pos_defaults == 0) {
|
if (n_pos_defaults == 0) {
|
||||||
// load dummy entry for non-existent positional default tuple
|
// load dummy entry for non-existent positional default tuple
|
||||||
emit_bc_load_null(emit);
|
emit_bc_load_null(emit);
|
||||||
|
emit_bc_rot_two(emit);
|
||||||
} else if (n_kw_defaults == 0) {
|
} else if (n_kw_defaults == 0) {
|
||||||
// load dummy entry for non-existent keyword default dict
|
// load dummy entry for non-existent keyword default dict
|
||||||
emit_bc_load_null(emit);
|
emit_bc_load_null(emit);
|
||||||
emit_bc_rot_two(emit);
|
|
||||||
}
|
}
|
||||||
emit_bc_pre(emit, -1);
|
emit_bc_pre(emit, -1);
|
||||||
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->unique_code_id);
|
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->unique_code_id);
|
||||||
@ -762,11 +762,11 @@ STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaul
|
|||||||
if (n_pos_defaults == 0) {
|
if (n_pos_defaults == 0) {
|
||||||
// load dummy entry for non-existent positional default tuple
|
// load dummy entry for non-existent positional default tuple
|
||||||
emit_bc_load_null(emit);
|
emit_bc_load_null(emit);
|
||||||
emit_bc_rot_two(emit);
|
emit_bc_rot_three(emit);
|
||||||
} else if (n_kw_defaults == 0) {
|
} else if (n_kw_defaults == 0) {
|
||||||
// load dummy entry for non-existent keyword default dict
|
// load dummy entry for non-existent keyword default dict
|
||||||
emit_bc_load_null(emit);
|
emit_bc_load_null(emit);
|
||||||
emit_bc_rot_three(emit);
|
emit_bc_rot_two(emit);
|
||||||
}
|
}
|
||||||
emit_bc_pre(emit, -2);
|
emit_bc_pre(emit, -2);
|
||||||
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->unique_code_id);
|
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->unique_code_id);
|
||||||
|
@ -197,6 +197,9 @@ mp_obj_t mp_make_function_from_id(uint unique_code_id, mp_obj_t def_args, mp_obj
|
|||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// def_args must be MP_OBJ_NULL or a tuple
|
||||||
|
assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
|
||||||
|
|
||||||
// TODO implement default kw args
|
// TODO implement default kw args
|
||||||
assert(def_kw_args == MP_OBJ_NULL);
|
assert(def_kw_args == MP_OBJ_NULL);
|
||||||
|
|
||||||
|
@ -361,6 +361,7 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t d
|
|||||||
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;
|
||||||
if (def_args != MP_OBJ_NULL) {
|
if (def_args != MP_OBJ_NULL) {
|
||||||
|
assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
|
||||||
n_def_args = def_args->len;
|
n_def_args = def_args->len;
|
||||||
n_extra_args = def_args->len;
|
n_extra_args = def_args->len;
|
||||||
}
|
}
|
||||||
|
8
py/vm.c
8
py/vm.c
@ -718,9 +718,9 @@ unwind_jump:
|
|||||||
|
|
||||||
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
// Stack layout: def_dict def_tuple <- TOS
|
// Stack layout: def_tuple def_dict <- TOS
|
||||||
obj1 = POP();
|
obj1 = POP();
|
||||||
SET_TOP(mp_make_function_from_id(unum, obj1, TOP()));
|
SET_TOP(mp_make_function_from_id(unum, TOP(), obj1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_MAKE_CLOSURE:
|
case MP_BC_MAKE_CLOSURE:
|
||||||
@ -731,10 +731,10 @@ unwind_jump:
|
|||||||
|
|
||||||
case MP_BC_MAKE_CLOSURE_DEFARGS:
|
case MP_BC_MAKE_CLOSURE_DEFARGS:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
// Stack layout: def_dict def_tuple closure_tuple <- TOS
|
// Stack layout: def_tuple def_dict closure_tuple <- TOS
|
||||||
obj1 = POP();
|
obj1 = POP();
|
||||||
obj2 = POP();
|
obj2 = POP();
|
||||||
SET_TOP(mp_make_closure_from_id(unum, obj1, obj2, TOP()));
|
SET_TOP(mp_make_closure_from_id(unum, obj1, TOP(), obj2));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_CALL_FUNCTION:
|
case MP_BC_CALL_FUNCTION:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user