// args are in reverse order in the array mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) { mp_obj_fun_native_t *self = self_in; if (self->is_kw) { return fun_native_call_n_kw(self_in, n_args, 0, args); } if (self->n_args_min == self->n_args_max) { // function requires a fixed number of arguments // check number of arguments if (n_args != self->n_args_min) { 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_min, (const char*)(machine_int_t)n_args)); } // dispatch function call switch (self->n_args_min) { case 0: return ((mp_fun_0_t)self->fun)(); case 1: return ((mp_fun_1_t)self->fun)(args[0]); case 2: return ((mp_fun_2_t)self->fun)(args[1], args[0]); case 3: return ((mp_fun_3_t)self->fun)(args[2], args[1], args[0]); default: assert(0); return mp_const_none; } } else { // function takes a variable number of arguments if (n_args < self->n_args_min) { nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "<fun name>() missing %d required positional arguments: <list of names of params>", (const char*)(machine_int_t)(self->n_args_min - n_args))); } else if (n_args > self->n_args_max) { nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "<fun name> expected at most %d arguments, got %d", (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args)); } // TODO really the args need to be passed in as a Python tuple, as the form f(*[1,2]) can be used to pass var args mp_obj_t *args_ordered = m_new(mp_obj_t, n_args); for (int i = 0; i < n_args; i++) { args_ordered[i] = args[n_args - i - 1]; } mp_obj_t res = ((mp_fun_var_t)self->fun)(n_args, args_ordered); m_del(mp_obj_t, args_ordered, n_args); return res; } }
// args are in reverse order in the array mp_obj_t gen_wrap_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) { mp_obj_gen_wrap_t *self = self_in; mp_obj_t self_fun = self->fun; assert(MP_OBJ_IS_TYPE(self_fun, &fun_bc_type)); int bc_n_args; uint bc_n_state; const byte *bc_code; mp_obj_fun_bc_get(self_fun, &bc_n_args, &bc_n_state, &bc_code); if (n_args != bc_n_args) { nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)bc_n_args, (const char*)(machine_int_t)n_args)); } return mp_obj_new_gen_instance(bc_code, self->n_state, n_args, args); }
// args are in reverse order in the array mp_obj_t fun_bc_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) { mp_obj_fun_bc_t *self = self_in; if (n_args != self->n_args) { nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_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)); } // optimisation: allow the compiler to optimise this tail call for // the common case when the globals don't need to be changed mp_map_t *old_globals = rt_globals_get(); if (self->globals == old_globals) { return mp_execute_byte_code(self->bytecode, args, n_args, self->n_state); } else { rt_globals_set(self->globals); mp_obj_t result = mp_execute_byte_code(self->bytecode, args, n_args, self->n_state); rt_globals_set(old_globals); return result; } }
mp_obj_t mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr) { // logic: look in obj members then class locals (TODO check this against CPython) mp_obj_instance_t *self = self_in; mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false); if (elem != NULL) { // object member, always treated as a value return elem->value; } elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false); if (elem != NULL) { if (mp_obj_is_callable(elem->value)) { // class member is callable so build a bound method return mp_obj_new_bound_meth(self_in, elem->value); } else { // class member is a value, so just return that value return elem->value; } } nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(self_in), qstr_str(attr))); }
// args are in reverse order in the array mp_obj_t fun_asm_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) { mp_obj_fun_asm_t *self = self_in; if (n_args != self->n_args) { nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_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)); } machine_uint_t ret; if (n_args == 0) { ret = ((inline_asm_fun_0_t)self->fun)(); } else if (n_args == 1) { ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0])); } else if (n_args == 2) { ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[0])); } else if (n_args == 3) { ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[2]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[0])); } else { assert(0); ret = 0; } return convert_val_from_inline_asm(ret); }