Merge branch 'fun-defargs' of github.com:pfalcon/micropython into pfalcon-fun-defargs
This commit is contained in:
commit
87413a4d0c
2
py/bc0.h
2
py/bc0.h
|
@ -94,7 +94,9 @@
|
||||||
#define MP_BC_CALL_METHOD_VAR (0x97) // uint
|
#define MP_BC_CALL_METHOD_VAR (0x97) // uint
|
||||||
#define MP_BC_CALL_METHOD_KW (0x98) // uint
|
#define MP_BC_CALL_METHOD_KW (0x98) // uint
|
||||||
#define MP_BC_CALL_METHOD_VAR_KW (0x99) // uint
|
#define MP_BC_CALL_METHOD_VAR_KW (0x99) // uint
|
||||||
|
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x9a) // uint
|
||||||
|
|
||||||
#define MP_BC_IMPORT_NAME (0xe0) // qstr
|
#define MP_BC_IMPORT_NAME (0xe0) // qstr
|
||||||
#define MP_BC_IMPORT_FROM (0xe1) // qstr
|
#define MP_BC_IMPORT_FROM (0xe1) // qstr
|
||||||
#define MP_BC_IMPORT_STAR (0xe2)
|
#define MP_BC_IMPORT_STAR (0xe2)
|
||||||
|
|
||||||
|
|
|
@ -3212,7 +3212,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
#else
|
#else
|
||||||
// return function that executes the outer module
|
// return function that executes the outer module
|
||||||
return rt_make_function_from_id(unique_code_id);
|
return rt_make_function_from_id(unique_code_id, MP_OBJ_NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
py/emitbc.c
12
py/emitbc.c
|
@ -664,9 +664,15 @@ 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, int n_dict_params, int n_default_params) {
|
static void emit_bc_make_function(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) {
|
||||||
assert(n_default_params == 0 && n_dict_params == 0);
|
assert(n_dict_params == 0);
|
||||||
emit_pre(emit, 1);
|
if (n_default_params != 0) {
|
||||||
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION, scope->unique_code_id);
|
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);
|
||||||
|
} else {
|
||||||
|
emit_pre(emit, 1);
|
||||||
|
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION, scope->unique_code_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_bc_make_closure(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) {
|
static void emit_bc_make_closure(emit_t *emit, scope_t *scope, int n_dict_params, int n_default_params) {
|
||||||
|
|
2
py/obj.h
2
py/obj.h
|
@ -221,7 +221,7 @@ mp_obj_t mp_obj_new_exception_msg_2_args(qstr id, const char *fmt, const char *a
|
||||||
mp_obj_t mp_obj_new_exception_msg_varg(qstr id, 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(qstr id, 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_range(int start, int stop, int step);
|
mp_obj_t mp_obj_new_range(int start, int stop, int step);
|
||||||
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
|
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
|
||||||
mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code);
|
mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args, uint n_state, 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_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args);
|
mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args);
|
||||||
|
|
29
py/objfun.c
29
py/objfun.c
|
@ -8,6 +8,7 @@
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "qstr.h"
|
#include "qstr.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
#include "objtuple.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "bc.h"
|
#include "bc.h"
|
||||||
|
@ -136,21 +137,32 @@ mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var
|
||||||
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_map_t *globals; // the context within which this function was defined
|
mp_map_t *globals; // the context within which this function was defined
|
||||||
int n_args; // number of arguments this function takes
|
short n_args; // number of arguments this function takes
|
||||||
|
short n_def_args; // number of default arguments
|
||||||
uint n_state; // total state size for the executing function (incl args, locals, stack)
|
uint n_state; // total state size for the executing function (incl args, locals, stack)
|
||||||
const byte *bytecode; // bytecode for the function
|
const byte *bytecode; // bytecode for the function
|
||||||
|
mp_obj_t def_args[]; // values of default args, if any
|
||||||
} mp_obj_fun_bc_t;
|
} mp_obj_fun_bc_t;
|
||||||
|
|
||||||
mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||||
mp_obj_fun_bc_t *self = self_in;
|
mp_obj_fun_bc_t *self = self_in;
|
||||||
|
|
||||||
if (n_args != self->n_args) {
|
if (n_args < self->n_args - self->n_def_args || n_args > self->n_args) {
|
||||||
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args));
|
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args, (const char*)(machine_int_t)n_args));
|
||||||
}
|
}
|
||||||
if (n_kw != 0) {
|
if (n_kw != 0) {
|
||||||
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
|
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t full_args[n_args];
|
||||||
|
if (n_args < self->n_args) {
|
||||||
|
memcpy(full_args, args, n_args * sizeof(*args));
|
||||||
|
int use_def_args = self->n_args - n_args;
|
||||||
|
memcpy(full_args + n_args, self->def_args + self->n_def_args - use_def_args, use_def_args * sizeof(*args));
|
||||||
|
args = full_args;
|
||||||
|
n_args = self->n_args;
|
||||||
|
}
|
||||||
|
|
||||||
// optimisation: allow the compiler to optimise this tail call for
|
// optimisation: allow the compiler to optimise this tail call for
|
||||||
// the common case when the globals don't need to be changed
|
// the common case when the globals don't need to be changed
|
||||||
mp_map_t *old_globals = rt_globals_get();
|
mp_map_t *old_globals = rt_globals_get();
|
||||||
|
@ -170,13 +182,22 @@ const mp_obj_type_t fun_bc_type = {
|
||||||
.call = fun_bc_call,
|
.call = fun_bc_call,
|
||||||
};
|
};
|
||||||
|
|
||||||
mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code) {
|
mp_obj_t mp_obj_new_fun_bc(int n_args, mp_obj_t def_args_in, uint n_state, const byte *code) {
|
||||||
mp_obj_fun_bc_t *o = m_new_obj(mp_obj_fun_bc_t);
|
int n_def_args = 0;
|
||||||
|
mp_obj_tuple_t *def_args = def_args_in;
|
||||||
|
if (def_args != MP_OBJ_NULL) {
|
||||||
|
n_def_args = def_args->len;
|
||||||
|
}
|
||||||
|
mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_def_args);
|
||||||
o->base.type = &fun_bc_type;
|
o->base.type = &fun_bc_type;
|
||||||
o->globals = rt_globals_get();
|
o->globals = rt_globals_get();
|
||||||
o->n_args = n_args;
|
o->n_args = n_args;
|
||||||
|
o->n_def_args = n_def_args;
|
||||||
o->n_state = n_state;
|
o->n_state = n_state;
|
||||||
o->bytecode = code;
|
o->bytecode = code;
|
||||||
|
if (def_args != MP_OBJ_NULL) {
|
||||||
|
memcpy(o->def_args, def_args->items, n_def_args * sizeof(*o->def_args));
|
||||||
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -674,7 +674,7 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t rt_make_function_from_id(int unique_code_id) {
|
mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
|
||||||
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
|
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
|
||||||
if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) {
|
if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) {
|
||||||
// illegal code id
|
// illegal code id
|
||||||
|
@ -686,7 +686,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
|
||||||
mp_obj_t fun;
|
mp_obj_t fun;
|
||||||
switch (c->kind) {
|
switch (c->kind) {
|
||||||
case MP_CODE_BYTE:
|
case MP_CODE_BYTE:
|
||||||
fun = mp_obj_new_fun_bc(c->n_args, c->n_state, c->u_byte.code);
|
fun = mp_obj_new_fun_bc(c->n_args, def_args, c->n_state, c->u_byte.code);
|
||||||
break;
|
break;
|
||||||
case MP_CODE_NATIVE:
|
case MP_CODE_NATIVE:
|
||||||
fun = rt_make_function_n(c->n_args, c->u_native.fun);
|
fun = rt_make_function_n(c->n_args, c->u_native.fun);
|
||||||
|
@ -710,7 +710,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
|
||||||
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) {
|
||||||
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
|
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
|
||||||
// make function object
|
// make function object
|
||||||
mp_obj_t ffun = rt_make_function_from_id(unique_code_id);
|
mp_obj_t ffun = rt_make_function_from_id(unique_code_id, MP_OBJ_NULL);
|
||||||
// wrap function in closure object
|
// wrap function in closure object
|
||||||
return mp_obj_new_closure(ffun, closure_tuple);
|
return mp_obj_new_closure(ffun, closure_tuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ void rt_store_name(qstr qstr, mp_obj_t obj);
|
||||||
void rt_store_global(qstr qstr, mp_obj_t obj);
|
void rt_store_global(qstr qstr, mp_obj_t obj);
|
||||||
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
|
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
|
||||||
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
|
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
|
||||||
mp_obj_t rt_make_function_from_id(int unique_code_id);
|
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_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(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_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive
|
||||||
|
|
|
@ -339,6 +339,11 @@ void mp_byte_code_print(const byte *ip, int len) {
|
||||||
printf("MAKE_FUNCTION " UINT_FMT, unum);
|
printf("MAKE_FUNCTION " UINT_FMT, unum);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
||||||
|
DECODE_UINT;
|
||||||
|
printf("MAKE_FUNCTION_DEFARGS " UINT_FMT, unum);
|
||||||
|
break;
|
||||||
|
|
||||||
case MP_BC_MAKE_CLOSURE:
|
case MP_BC_MAKE_CLOSURE:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
printf("MAKE_CLOSURE " UINT_FMT, unum);
|
printf("MAKE_CLOSURE " UINT_FMT, unum);
|
||||||
|
|
7
py/vm.c
7
py/vm.c
|
@ -497,7 +497,12 @@ dispatch_loop:
|
||||||
|
|
||||||
case MP_BC_MAKE_FUNCTION:
|
case MP_BC_MAKE_FUNCTION:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
PUSH(rt_make_function_from_id(unum));
|
PUSH(rt_make_function_from_id(unum, MP_OBJ_NULL));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
||||||
|
DECODE_UINT;
|
||||||
|
SET_TOP(rt_make_function_from_id(unum, TOP()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_MAKE_CLOSURE:
|
case MP_BC_MAKE_CLOSURE:
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
def fun1(val=5):
|
||||||
|
print(5)
|
||||||
|
|
||||||
|
fun1()
|
||||||
|
fun1(10)
|
||||||
|
|
||||||
|
def fun2(p1, p2=100, p3="foo"):
|
||||||
|
print(p1, p2, p3)
|
||||||
|
|
||||||
|
fun2(1)
|
||||||
|
fun2(1, None)
|
||||||
|
fun2(0, "bar", 200)
|
||||||
|
try:
|
||||||
|
fun2()
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
try:
|
||||||
|
fun2(1, 2, 3, 4)
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
Loading…
Reference in New Issue