void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_uint_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { mp_uint_t pos_found = 0, kws_found = 0; for (mp_uint_t i = 0; i < n_allowed; i++) { mp_obj_t given_arg; if (i < n_pos) { if (allowed[i].flags & MP_ARG_KW_ONLY) { goto extra_positional; } pos_found++; given_arg = pos[i]; } else { mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP); if (kw == NULL) { if (allowed[i].flags & MP_ARG_REQUIRED) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' argument required", qstr_str(allowed[i].qst))); } } out_vals[i] = allowed[i].defval; continue; } else { kws_found++; given_arg = kw->value; } } if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_BOOL) { out_vals[i].u_bool = mp_obj_is_true(given_arg); } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) { out_vals[i].u_int = mp_obj_get_int(given_arg); } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ) { out_vals[i].u_obj = given_arg; } else { assert(0); } } if (pos_found < n_pos) { extra_positional: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { // TODO better error message nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "extra positional arguments given")); } } if (kws_found < kws->used) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { // TODO better error message nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "extra keyword arguments given")); } } }
STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t*)type_in; size_t num_fields = type->n_fields; if (n_args + n_kw != num_fields) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", num_fields, n_args + n_kw)); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", type->base.name, num_fields, n_args + n_kw)); } } mp_obj_t *arg_objects; if (n_args == num_fields) { arg_objects = (mp_obj_t*)args; } else { size_t alloc_size = sizeof(mp_obj_t) * num_fields; arg_objects = alloca(alloc_size); memset(arg_objects, 0, alloc_size); for (mp_uint_t i = 0; i < n_args; i++) { arg_objects[i] = args[i]; } for (mp_uint_t i = n_args; i < n_args + 2 * n_kw; i += 2) { qstr kw = mp_obj_str_get_qstr(args[i]); int id = namedtuple_find_field(type, kw); if (id == -1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected keyword argument '%q'", kw)); } } if (arg_objects[id] != MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%q'", kw)); } } arg_objects[id] = args[i + 1]; } } mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_fields, arg_objects)); tuple->base.type = type_in; return MP_OBJ_FROM_PTR(tuple); }
STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t*)type_in; size_t num_fields = type->n_fields; if (n_args + n_kw != num_fields) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", num_fields, n_args + n_kw)); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", type->base.name, num_fields, n_args + n_kw)); } } // Create a tuple and set the type to this namedtuple mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_fields, NULL)); tuple->base.type = type_in; // Copy the positional args into the first slots of the namedtuple memcpy(&tuple->items[0], args, sizeof(mp_obj_t) * n_args); // Fill in the remaining slots with the keyword args memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw); for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) { qstr kw = mp_obj_str_get_qstr(args[i]); size_t id = mp_obj_namedtuple_find_field(type, kw); if (id == (size_t)-1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected keyword argument '%q'", kw)); } } if (tuple->items[id] != MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%q'", kw)); } } tuple->items[id] = args[i + 1]; } return MP_OBJ_FROM_PTR(tuple); }
void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp_uint_t n_args_max, bool takes_kw) { // TODO maybe take the function name as an argument so we can print nicer error messages if (n_kw && !takes_kw) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); } } if (n_args_min == n_args_max) { if (n_args != n_args_min) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", n_args_min, n_args)); } } } else { if (n_args < n_args_min) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing %d required positional arguments", n_args_min - n_args)); } } else if (n_args > n_args_max) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function expected at most %d arguments, got %d", n_args_max, n_args)); } } } }
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues mp_arg_error_terse_mismatch(); #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", expected, given)); #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q() takes %d positional arguments but %d were given", mp_obj_fun_get_name(f), expected, given)); #endif }