From 2447a5b582503b70936681702062704e2e9f44d3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 26 Mar 2014 23:14:59 +0200 Subject: [PATCH] py: Support closures with default args. --- py/bc0.h | 1 + py/compile.c | 3 +++ py/emitbc.c | 12 ++++++++---- py/runtime.c | 4 ++-- py/runtime.h | 2 +- py/showbc.c | 5 +++++ py/vm.c | 8 +++++++- tests/basics/closure-defargs.py | 8 ++++++++ 8 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 tests/basics/closure-defargs.py diff --git a/py/bc0.h b/py/bc0.h index 2c8c47bd2e..3d4b106d32 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -95,6 +95,7 @@ #define MP_BC_CALL_METHOD_KW (0x98) // uint #define MP_BC_CALL_METHOD_VAR_KW (0x99) // uint #define MP_BC_MAKE_FUNCTION_DEFARGS (0x9a) // uint +#define MP_BC_MAKE_CLOSURE_DEFARGS (0x9b) // uint #define MP_BC_IMPORT_NAME (0xe0) // qstr #define MP_BC_IMPORT_FROM (0xe1) // qstr diff --git a/py/compile.c b/py/compile.c index 0a10b81768..dc001cd88f 100644 --- a/py/compile.c +++ b/py/compile.c @@ -766,6 +766,9 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { // stuff for lambda and comprehensions and generators void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_dict_params, int n_default_params) { + if (n_default_params) { + EMIT_ARG(build_tuple, n_default_params); + } // 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; diff --git a/py/emitbc.c b/py/emitbc.c index ef5da3a622..653b144875 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -722,16 +722,20 @@ STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, int n_dict_param emit_pre(emit, 1); emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION, scope->unique_code_id); } else { - emit_bc_build_tuple(emit, n_default_params); emit_pre(emit, 0); 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, int n_dict_params, int n_default_params) { - assert(n_default_params == 0 && n_dict_params == 0); - emit_pre(emit, 0); - emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE, scope->unique_code_id); + assert(n_dict_params == 0); + if (n_default_params == 0) { + emit_pre(emit, 0); + emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE, scope->unique_code_id); + } else { + emit_pre(emit, -1); + emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->unique_code_id); + } } STATIC void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { diff --git a/py/runtime.c b/py/runtime.c index 247a78fe1a..eab414c9ee 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -683,10 +683,10 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) { return fun; } -mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple) { +mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) { DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id); // make function object - mp_obj_t ffun = rt_make_function_from_id(unique_code_id, MP_OBJ_NULL); + mp_obj_t ffun = rt_make_function_from_id(unique_code_id, def_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 f5e4a49cf8..553a834689 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -19,7 +19,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args); mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun); mp_obj_t rt_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 rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple); +mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args); mp_obj_t rt_call_function_0(mp_obj_t fun); mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg); mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); diff --git a/py/showbc.c b/py/showbc.c index 9bdf811d9a..eb743bd29e 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -371,6 +371,11 @@ void mp_byte_code_print(const byte *ip, int len) { printf("MAKE_CLOSURE " UINT_FMT, unum); break; + case MP_BC_MAKE_CLOSURE_DEFARGS: + DECODE_UINT; + printf("MAKE_CLOSURE_DEFARGS " UINT_FMT, unum); + break; + case MP_BC_CALL_FUNCTION: DECODE_UINT; printf("CALL_FUNCTION n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); diff --git a/py/vm.c b/py/vm.c index e34acb488b..b98781c761 100644 --- a/py/vm.c +++ b/py/vm.c @@ -561,7 +561,13 @@ unwind_jump: case MP_BC_MAKE_CLOSURE: DECODE_UINT; - SET_TOP(rt_make_closure_from_id(unum, TOP())); + SET_TOP(rt_make_closure_from_id(unum, TOP(), MP_OBJ_NULL)); + break; + + case MP_BC_MAKE_CLOSURE_DEFARGS: + DECODE_UINT; + obj1 = POP(); + SET_TOP(rt_make_closure_from_id(unum, obj1, TOP())); break; case MP_BC_CALL_FUNCTION: diff --git a/tests/basics/closure-defargs.py b/tests/basics/closure-defargs.py new file mode 100644 index 0000000000..ff8ada0414 --- /dev/null +++ b/tests/basics/closure-defargs.py @@ -0,0 +1,8 @@ +def f(): + a = 1 + def bar(b = 10, c = 20): + print(a + b + c) + bar() + +print(f()) +