diff --git a/py/bc.c b/py/bc.c index 2a21ffd4b7749..977cf3658eefa 100644 --- a/py/bc.c +++ b/py/bc.c @@ -123,7 +123,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // - code_state->fun_bc should contain a pointer to the function object // - code_state->ip should contain a pointer to the beginning of the prelude // - code_state->n_state should be the number of objects in the local state -void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { +void mp_setup_code_state(mp_code_state_t *code_state, size_t n_given_args, size_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. @@ -143,8 +143,8 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw size_t n_state = code_state->n_state; // Decode prelude - size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; - MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args); + size_t n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_posonly_args, n_kwonly_args, n_def_pos_args; + MP_BC_PRELUDE_SIG_DECODE_INTO(code_state->ip, n_state_unused, n_exc_stack_unused, scope_flags, n_pos_args, n_posonly_args, n_kwonly_args, n_def_pos_args); MP_BC_PRELUDE_SIZE_DECODE(code_state->ip); (void)n_state_unused; (void)n_exc_stack_unused; @@ -155,21 +155,23 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw // zero out the local stack to begin with memset(code_state->state, 0, n_state * sizeof(*code_state->state)); - const mp_obj_t *kwargs = args + n_args; + const mp_obj_t *kwargs = args + n_given_args; // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed) - mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args]; + uint32_t n_all_pos_args = n_pos_args + n_posonly_args; + uint32_t n_all_args = n_all_pos_args + n_kwonly_args; + mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_all_args]; // check positional arguments - if (n_args > n_pos_args) { + if (n_given_args > n_all_pos_args) { // given more than enough arguments if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) { - fun_pos_args_mismatch(self, n_pos_args, n_args); + fun_pos_args_mismatch(self, n_all_pos_args, n_given_args); } // put extra arguments in varargs tuple - *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args); - n_args = n_pos_args; + *var_pos_kw_args-- = mp_obj_new_tuple(n_given_args - n_all_pos_args, args + n_all_pos_args); + n_given_args = n_pos_args; } else { if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) { DEBUG_printf("passing empty tuple as *args\n"); @@ -178,19 +180,19 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw // Apply processing and check below only if we don't have kwargs, // otherwise, kw handling code below has own extensive checks. if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) { - if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) { + if (n_given_args >= (size_t)(n_all_pos_args - n_def_pos_args)) { // given enough arguments, but may need to use some default arguments - for (size_t i = n_args; i < n_pos_args; i++) { - code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)]; + for (size_t i = n_given_args; i < n_all_pos_args; i++) { + code_state->state[n_state - 1 - i] = self->extra_args[i - (n_all_pos_args - n_def_pos_args)]; } } else { - fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args); + fun_pos_args_mismatch(self, n_all_pos_args - n_def_pos_args, n_given_args); } } } // copy positional args into state - for (size_t i = 0; i < n_args; i++) { + for (size_t i = 0; i < n_given_args; i++) { code_state->state[n_state - 1 - i] = args[i]; } @@ -198,7 +200,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { DEBUG_printf("Initial args: "); - dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + dump_args(code_state->state + n_state - n_all_args, n_all_args); mp_obj_t dict = MP_OBJ_NULL; if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { @@ -214,7 +216,8 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw const uint8_t *arg_names = code_state->ip; arg_names = mp_decode_uint_skip(arg_names); - for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) { + // Iterating the function definition keywords + for (size_t j = n_posonly_args; j < n_all_args; j++) { qstr arg_qstr = mp_decode_uint(&arg_names); #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE arg_qstr = self->context->constants.qstr_table[arg_qstr]; @@ -242,10 +245,10 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw } DEBUG_printf("Args with kws flattened: "); - dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + dump_args(code_state->state + n_state - n_all_args, n_all_args); // fill in defaults for positional args - mp_obj_t *d = &code_state->state[n_state - n_pos_args]; + mp_obj_t *d = &code_state->state[n_state - n_all_pos_args]; mp_obj_t *s = &self->extra_args[n_def_pos_args - 1]; for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) { if (*d == MP_OBJ_NULL) { @@ -254,7 +257,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw } DEBUG_printf("Args after filling default positional: "); - dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + dump_args(code_state->state + n_state - n_all_args, n_all_args); // Check that all mandatory positional args are specified while (d < &code_state->state[n_state]) { @@ -275,13 +278,13 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE arg_qstr = self->context->constants.qstr_table[arg_qstr]; #endif - if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) { + if (code_state->state[n_state - 1 - n_all_pos_args - i] == MP_OBJ_NULL) { mp_map_elem_t *elem = NULL; if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { elem = mp_map_lookup(&((mp_obj_dict_t *)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, MP_OBJ_NEW_QSTR(arg_qstr), MP_MAP_LOOKUP); } if (elem != NULL) { - code_state->state[n_state - 1 - n_pos_args - i] = elem->value; + code_state->state[n_state - 1 - n_all_pos_args - i] = elem->value; } else { mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("function missing required keyword argument '%q'"), arg_qstr); @@ -312,8 +315,8 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw // now that we skipped over the prelude, set the ip for the VM code_state->ip = ip; - DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args); - dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + DEBUG_printf("Calling: n_pos_args=%d, n_posonly_args=%d, n_kwonly_args=%d\n", n_pos_args, n_posonly_args, n_kwonly_args); + dump_args(code_state->state + n_state - n_all_args, n_all_args); dump_args(code_state->state, n_state); } diff --git a/py/bc.h b/py/bc.h index 3b7b625fecfdb..33be92933ba98 100644 --- a/py/bc.h +++ b/py/bc.h @@ -32,12 +32,13 @@ // bytecode layout: // // func signature : var uint -// contains six values interleaved bit-wise as: xSSSSEAA [xFSSKAED repeated] +// contains six values interleaved bit-wise as: xSSSSEAA [xFSS(PorK)AED repeated] // x = extension another byte follows // S = n_state - 1 number of entries in Python value stack // E = n_exc_stack number of entries in exception stack // F = scope_flags four bits of flags, MP_SCOPE_FLAG_xxx // A = n_pos_args number of arguments this function takes +// P = n_posonly_args number of positional-only arguments this function takes // K = n_kwonly_args number of keyword-only arguments this function takes // D = n_def_pos_args number of default positional arguments // @@ -74,6 +75,7 @@ /*// Get values to store in prelude */ \ size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG; \ size_t A = scope->num_pos_args; \ + size_t P = scope->num_posonly_args; \ size_t K = scope->num_kwonly_args; \ size_t D = scope->num_def_pos_args; \ \ @@ -86,22 +88,30 @@ S >>= 4; \ E >>= 1; \ A >>= 2; \ - while (S | E | F | A | K | D) { \ + uint8_t n = 0; \ + while (S | E | F | A | P | K | D) { \ out_byte(out_env, 0x80 | z); \ - /* xFSSKAED */ \ - z = (F & 1) << 6 | (S & 3) << 4 | (K & 1) << 3 \ - | (A & 1) << 2 | (E & 1) << 1 | (D & 1); \ + uint16_t PorK = n % 2 == 0 ? P : K; \ + /* xFSS(PorK)AED */ \ + z = (F & 1) << 6 | (S & 3) << 4 | (PorK & 1) << 3 \ + | (A & 1) << 2 | (E & 1) << 1 \ + | (D & 1); \ S >>= 2; \ E >>= 1; \ F >>= 1; \ A >>= 1; \ - K >>= 1; \ + if (n % 2 == 0) { \ + P >>= 1; \ + } else { \ + K >>= 1; \ + } \ D >>= 1; \ + n++; \ } \ out_byte(out_env, z); \ } while (0) -#define MP_BC_PRELUDE_SIG_DECODE_INTO(ip, S, E, F, A, K, D) \ +#define MP_BC_PRELUDE_SIG_DECODE_INTO(ip, S, E, F, A, P, K, D) \ do { \ uint8_t z = *(ip)++; \ /* xSSSSEAA */ \ @@ -109,26 +119,31 @@ E = (z >> 2) & 0x1; \ F = 0; \ A = z & 0x3; \ + P = 0; \ K = 0; \ D = 0; \ for (unsigned n = 0; z & 0x80; ++n) { \ z = *(ip)++; \ - /* xFSSKAED */ \ - S |= (z & 0x30) << (2 * n); \ - E |= (z & 0x02) << n; \ + /* xFSS(PorK)AED */ \ F |= ((z & 0x40) >> 6) << n; \ + S |= (z & 0x30) << (2 * n); \ + if (n % 2 == 0) { \ + P |= ((z & 0x08) >> 3) << (n >> 1); \ + } else { \ + K |= ((z & 0x08) >> 3) << (n >> 1); \ + } \ A |= (z & 0x4) << n; \ - K |= ((z & 0x08) >> 3) << n; \ + E |= (z & 0x02) << n; \ D |= (z & 0x1) << n; \ } \ S += 1; \ } while (0) #define MP_BC_PRELUDE_SIG_DECODE(ip) \ - size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; \ - MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args); \ + size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_posonly_args, n_kwonly_args, n_def_pos_args; \ + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_posonly_args, n_kwonly_args, n_def_pos_args); \ (void)n_state; (void)n_exc_stack; (void)scope_flags; \ - (void)n_pos_args; (void)n_kwonly_args; (void)n_def_pos_args + (void)n_pos_args; (void)n_kwonly_args; (void)n_def_pos_args; (void)n_posonly_args #define MP_BC_PRELUDE_SIZE_ENCODE(I, C, out_byte, out_env) \ do { \ @@ -178,6 +193,7 @@ typedef struct _mp_bytecode_prelude_t { uint n_exc_stack; uint scope_flags; uint n_pos_args; + uint n_posonly_args; uint n_kwonly_args; uint n_def_pos_args; qstr qstr_block_name_idx; @@ -268,7 +284,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, #endif mp_obj_t inject_exc); mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); -void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_setup_code_state(mp_code_state_t *code_state, size_t n_given_args, size_t n_kw, const mp_obj_t *args); void mp_bytecode_print(const mp_print_t *print, const struct _mp_raw_code_t *rc, const mp_module_constants_t *cm); void mp_bytecode_print2(const mp_print_t *print, const byte *ip, size_t len, struct _mp_raw_code_t *const *child_table, const mp_module_constants_t *cm); const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip_start, const byte *ip, struct _mp_raw_code_t *const *child_table, const mp_module_constants_t *cm); diff --git a/py/compile.c b/py/compile.c index e4ead7f1ac2ac..4362511f14dc7 100644 --- a/py/compile.c +++ b/py/compile.c @@ -683,6 +683,12 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) int pn_kind; if (MP_PARSE_NODE_IS_ID(pn)) { pn_kind = -1; + } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_OP_SLASH)) { + if (comp->have_star) { + // Star cannot be in front of a positional only arguments. + compile_syntax_error(comp, pn, MP_ERROR_TEXT("invalid syntax")); + } + return; } else { assert(MP_PARSE_NODE_IS_STRUCT(pn)); pn_kind = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t *)pn); @@ -2864,6 +2870,20 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn comp->scope_cur->num_pos_args += 1; } mp_emit_common_use_qstr(&comp->emit_common, param_name); + } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_OP_SLASH)) { + // if slash was used, but no args were detected, that is invalid by spec. + if (comp->scope_cur->num_pos_args == 0) { + compile_syntax_error(comp, pn, MP_ERROR_TEXT("invalid syntax")); + return; + } + // slash may have appeared twice if posonly_args is already > 0, invalid by spec. + if (comp->scope_cur->num_posonly_args > 0) { + compile_syntax_error(comp, pn, MP_ERROR_TEXT("invalid syntax")); + return; + } + // comes before a slash, so counts as positional-only parameter + comp->scope_cur->num_posonly_args = comp->scope_cur->num_pos_args; + comp->scope_cur->num_pos_args = 0; } else { assert(MP_PARSE_NODE_IS_STRUCT(pn)); pns = (mp_parse_node_struct_t *)pn; diff --git a/py/emitbc.c b/py/emitbc.c index a9d5b3799e63e..f2302c60469c5 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -323,7 +323,9 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { // Note: there is some wasted RAM here for the case of storing a qstr // for each closed-over variable, and maybe there is a better way to do // it, but that would require changes to mp_setup_code_state. - for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) { + uint32_t num_args = scope->num_pos_args + scope->num_posonly_args + scope->num_kwonly_args; + assert(num_args < UINT16_MAX); + for (uint32_t i = scope->num_posonly_args; i < num_args; i++) { qstr qst = MP_QSTR__star_; for (int j = 0; j < scope->id_info_len; ++j) { id_info_t *id = &scope->id_info[j]; diff --git a/py/emitnative.c b/py/emitnative.c index 2863984047a15..39b99695edea9 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -375,7 +375,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } // set default type for arguments - mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args; + mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_posonly_args + emit->scope->num_kwonly_args; if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { num_args += 1; } @@ -669,7 +669,9 @@ STATIC bool emit_native_end_pass(emit_t *emit) { // bytecode prelude: source info (function and argument qstrs) size_t info_start = mp_asm_base_get_code_pos(&emit->as->base); emit_native_write_code_info_qstr(emit, emit->scope->simple_name); - for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) { + uint32_t num_args = emit->scope->num_pos_args + emit->scope->num_posonly_args + emit->scope->num_kwonly_args; + assert(num_args < UINT16_MAX); + for (uint32_t i = emit->scope->num_posonly_args; i < num_args; i++) { qstr qst = MP_QSTR__star_; for (int j = 0; j < emit->scope->id_info_len; ++j) { id_info_t *id = &emit->scope->id_info[j]; diff --git a/py/grammar.h b/py/grammar.h index 285fbded2fdae..808c6b97e4d72 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -75,14 +75,14 @@ DEF_RULE(funcdef, c(funcdef), and_blank(8), tok(KW_DEF), tok(NAME), tok(DEL_PARE DEF_RULE_NC(funcdefrettype, and_ident(2), tok(DEL_MINUS_MORE), rule(test)) // note: typedargslist lets through more than is allowed, compiler does further checks DEF_RULE_NC(typedargslist, list_with_end, rule(typedargslist_item), tok(DEL_COMMA)) -DEF_RULE_NC(typedargslist_item, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star)) +DEF_RULE_NC(typedargslist_item, or(4), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star), tok(OP_SLASH)) DEF_RULE_NC(typedargslist_name, and_ident(3), tok(NAME), opt_rule(generic_colon_test), opt_rule(generic_equal_test)) DEF_RULE_NC(typedargslist_star, and(2), tok(OP_STAR), opt_rule(tfpdef)) DEF_RULE_NC(typedargslist_dbl_star, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(generic_colon_test)) DEF_RULE_NC(tfpdef, and(2), tok(NAME), opt_rule(generic_colon_test)) // note: varargslist lets through more than is allowed, compiler does further checks DEF_RULE_NC(varargslist, list_with_end, rule(varargslist_item), tok(DEL_COMMA)) -DEF_RULE_NC(varargslist_item, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star)) +DEF_RULE_NC(varargslist_item, or(4), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star), tok(OP_SLASH)) DEF_RULE_NC(varargslist_name, and_ident(2), tok(NAME), opt_rule(generic_equal_test)) DEF_RULE_NC(varargslist_star, and(2), tok(OP_STAR), opt_rule(vfpdef)) DEF_RULE_NC(varargslist_dbl_star, and(2), tok(OP_DBL_STAR), tok(NAME)) diff --git a/py/objfun.c b/py/objfun.c index 3542cc0e3f0b8..190f4b460a9bc 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -198,9 +198,9 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { #define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \ { \ const uint8_t *ip = bytecode; \ - size_t n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args; \ - MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state_out_var, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_args); \ - (void)scope_flags; (void)n_pos_args; (void)n_kwonly_args; (void)n_def_args; \ + size_t n_exc_stack, scope_flags, n_pos_args, n_posonly_args, n_kwonly_args, n_def_args; \ + MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state_out_var, n_exc_stack, scope_flags, n_pos_args, n_posonly_args, n_kwonly_args, n_def_args); \ + (void)scope_flags; (void)n_pos_args; (void)n_kwonly_args; (void)n_def_args; (void)n_posonly_args; \ \ /* state size in bytes */ \ state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \ @@ -298,16 +298,16 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const } const byte *bytecode_ptr = self->bytecode; size_t n_state_unused, n_exc_stack_unused, scope_flags_unused; - size_t n_pos_args, n_kwonly_args, n_def_args_unused; + size_t n_pos_args, n_posonly_args, n_kwonly_args, n_def_args_unused; MP_BC_PRELUDE_SIG_DECODE_INTO(bytecode_ptr, n_state_unused, n_exc_stack_unused, - scope_flags_unused, n_pos_args, n_kwonly_args, n_def_args_unused); + scope_flags_unused, n_pos_args, n_posonly_args, n_kwonly_args, n_def_args_unused); // We can't check the case when an exception is returned in state[0] // and there are no arguments, because in this case our detection slot may have // been overwritten by the returned exception (which is allowed). - if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_pos_args + n_kwonly_args == 0)) { + if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_pos_args + n_posonly_args + n_kwonly_args == 0)) { // Just check to see that we have at least 1 null object left in the state. bool overflow = true; - for (size_t i = 0; i < n_state - n_pos_args - n_kwonly_args; ++i) { + for (size_t i = 0; i < n_state - n_pos_args - n_posonly_args - n_kwonly_args; ++i) { if (code_state->state[i] == MP_OBJ_NULL) { overflow = false; break; diff --git a/py/persistentcode.c b/py/persistentcode.c index f64e383a61690..9e6464b860d3f 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -53,6 +53,7 @@ typedef struct _bytecode_prelude_t { uint n_exc_stack; uint scope_flags; uint n_pos_args; + uint n_posonly_args; uint n_kwonly_args; uint n_def_pos_args; uint code_info_size; diff --git a/py/profile.c b/py/profile.c index 4e23e9eac43b5..724228125f044 100644 --- a/py/profile.c +++ b/py/profile.c @@ -47,6 +47,7 @@ void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelud prelude->n_exc_stack = n_exc_stack; prelude->scope_flags = scope_flags; prelude->n_pos_args = n_pos_args; + prelude->n_posonly_args = n_posonly_args; prelude->n_kwonly_args = n_kwonly_args; prelude->n_def_pos_args = n_def_pos_args; @@ -56,7 +57,7 @@ void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelud prelude->opcodes = ip + n_info + n_cell; prelude->qstr_block_name_idx = mp_decode_uint_value(ip); - for (size_t i = 0; i < 1 + n_pos_args + n_kwonly_args; ++i) { + for (size_t i = 0; i < 1 + n_pos_args + n_posonly_args + n_kwonly_args; ++i) { ip = mp_decode_uint_skip(ip); } prelude->line_info = ip; diff --git a/py/scope.h b/py/scope.h index 5006deadea830..5aab8862fc695 100644 --- a/py/scope.h +++ b/py/scope.h @@ -79,6 +79,7 @@ typedef struct _scope_t { uint16_t scope_flags; // see runtime0.h uint16_t emit_options; // see emitglue.h uint16_t num_pos_args; + uint16_t num_posonly_args; uint16_t num_kwonly_args; uint16_t num_def_pos_args; uint16_t num_locals; diff --git a/py/vm.c b/py/vm.c index 02f8bc88c953e..e100939cfb832 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1406,7 +1406,7 @@ unwind_jump:; const byte *bytecode_start = ip + n_info + n_cell; size_t bc = code_state->ip - bytecode_start; qstr block_name = mp_decode_uint_value(ip); - for (size_t i = 0; i < 1 + n_pos_args + n_kwonly_args; ++i) { + for (size_t i = 0; i < 1 + n_pos_args + n_posonly_args + n_kwonly_args; ++i) { ip = mp_decode_uint_skip(ip); } #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE diff --git a/tests/basics/fun_positional_args_only.py b/tests/basics/fun_positional_args_only.py new file mode 100644 index 0000000000000..e58a5dd578749 --- /dev/null +++ b/tests/basics/fun_positional_args_only.py @@ -0,0 +1,382 @@ +# positional_args_only tests + +# Tests sourced from +# https://github.com/python/cpython/blob/main/Lib/test/test_positional_only_arg.py + +# Not all tests were ported due to incompatibilities with +# MicroPython, such as required modules like pickle and dis +# not being implemented. + +def tryFunctionFail(s): + try: + eval(s) + print("FAILED: " + repr(s) + " did not throw syntax error.") + except Exception as e: + print("PASSED: " + repr(s) + " threw an error.") + +def tryFunctionPass(s): + try: + eval(s) + print("PASSED: " + repr(s) + " did not throw syntax error.") + except Exception as e: + print("FAILED: " + repr(s) + " incorrectly threw syntax error.") + +################################################## +# test_invalid_syntax_errors +# test_invalid_syntax_errors_async +invalid_tests = [ + "def f(a, b = 5, /, c): pass", + "def f(a = 5, b, /, c): pass", + "def f(a = 5, b=1, /, c, *, d=2): pass", + "def f(a = 5, b, /): pass", + "def f(*args, /): pass", + "def f(*args, a, /): pass", + "def f(**kwargs, /): pass", + "def f(/, a = 1): pass", + "def f(/, a): pass", + "def f(/): pass", + "def f(*, a, /): pass", + "def f(*, /, a): pass", + "def f(a, /, a): pass", + "def f(a, /, *, a): pass", + "def f(a, b/2, c): pass", + "def f(a, /, c, /): pass", + "def f(a, /, c, /, d): pass", + "def f(a, /, c, /, d, *, e): pass", + "def f(a, *, c, /, d, e): pass", + "async def f(a, b = 5, /, c): pass", + "async def f(a = 5, b, /, c): pass", + "async def f(a = 5, b=1, /, c, d=2): pass", + "async def f(a = 5, b, /): pass", + "async def f(*args, /): pass", + "async def f(*args, a, /): pass", + "async def f(**kwargs, /): pass", + "async def f(/, a = 1): pass", + "async def f(/, a): pass", + "async def f(/): pass", + "async def f(*, a, /): pass", + "async def f(*, /, a): pass", + "async def f(a, /, a): pass", + "async def f(a, /, *, a): pass", + "async def f(a, b/2, c): pass", + "async def f(a, /, c, /): pass", + "async def f(a, /, c, /, d): pass", + "async def f(a, /, c, /, d, *, e): pass", + "async def f(a, *, c, /, d, e): pass" +] +for s in invalid_tests: + tryFunctionFail(s) + +################################################## +# test_optional_positional_only_args +print("\ntest_optional_positional_only_args") +def assertEqual(f, res): + assert(f == res) + print("PASSED: Assertion check") + +def f(a, b=10, /, c=100): + return a + b + c + +assertEqual(f(1, 2, 3), 6) +assertEqual(f(1, 2, c=3), 6) +tryFunctionFail("f(1, b=2, c=3)") + +assertEqual(f(1, 2), 103) +tryFunctionFail("f(1, b=2)") +assertEqual(f(1, c=2), 13) + +def f(a=1, b=10, /, c=100): + return a + b + c + +assertEqual(f(1, 2, 3), 6) +assertEqual(f(1, 2, c=3), 6) +tryFunctionFail("f(1, b=2, c=3)") + +assertEqual(f(1, 2), 103) +tryFunctionFail("f(1, b=2)") +assertEqual(f(1, c=2), 13) + +################################################## +# test_pos_only_call_via_unpacking +print("\ntest_pos_only_call_via_unpacking") +def f(a, b, /): + return a + b +assertEqual(f(*[1, 2]), 3) + +################################################## +# test_use_positional_as_keyword +print("\ntest_use_positional_as_keyword") +def f(a, /): + pass +expected = r"f() got some positional-only arguments passed as keyword arguments: 'a'" +tryFunctionFail("f(a=1)") + +def f(a, /, b): + pass +expected = r"f() got some positional-only arguments passed as keyword arguments: 'a'" +tryFunctionFail("f(a=1, b=2)") + +def f(a, b, /): + pass +expected = r"f() got some positional-only arguments passed as keyword arguments: 'a, b'" +tryFunctionFail("f(a=1, b=2)") + +################################################## +# test_positional_only_and_arg_invalid_calls +print("\ntest_positional_only_and_arg_invalid_calls") + +def f(a, b, /, c): + pass +# r"f() missing 1 required positional argument: 'c'" +tryFunctionFail("f(1, 2)") +# r"f() missing 2 required positional arguments: 'b' and 'c'" +tryFunctionFail("f(1)") +# r"f() missing 3 required positional arguments: 'a', 'b', and 'c'" +tryFunctionFail("f()") +# r"f() takes 3 positional arguments but 4 were given" +tryFunctionFail("f(1, 2, 3, 4)") + +################################################## +# test_positional_only_and_optional_arg_invalid_calls +print("\ntest_positional_only_and_optional_arg_invalid_calls") +def f(a, b, /, c=3): + pass +tryFunctionPass("f(1, 2)") +# "f() missing 1 required positional argument: 'b'" +tryFunctionFail("f(1)") +# "f() missing 2 required positional arguments: 'a' and 'b'" +tryFunctionFail("f()") +# "f() takes from 2 to 3 positional arguments but 4 were given" +tryFunctionFail("f(1, 2, 3, 4)") + +################################################## +# test_positional_only_and_kwonlyargs_invalid_calls +def f(a, b, /, c, *, d, e): + pass +tryFunctionPass("f(1, 2, 3, d=1, e=2)") +# r"missing 1 required keyword-only argument: 'd'" +tryFunctionFail("f(1, 2, 3, e=2)") +# r"missing 2 required keyword-only arguments: 'd' and 'e'" +tryFunctionFail("f(1, 2, 3)") +# r"f() missing 1 required positional argument: 'c'" +tryFunctionFail("f(1, 2)") +# r"f() missing 2 required positional arguments: 'b' and 'c'" +tryFunctionFail("f(1)") +# r" missing 3 required positional arguments: 'a', 'b', and 'c'" +tryFunctionFail("f()") +# r"f() takes 3 positional arguments but 6 positional arguments \(and 2 keyword-only arguments\) were given" +tryFunctionFail("f(1, 2, 3, 4, 5, 6, d=7, e=8)") +# r"f() got an unexpected keyword argument 'f'" +tryFunctionFail("f(1, 2, 3, d=1, e=4, f=56)") + +################################################## +# test_positional_only_invalid_calls +def f(a, b, /): + pass +tryFunctionPass("f(1, 2)") +# f() missing 1 required positional argument: 'b'" +tryFunctionFail("f(1)") +# f() missing 2 required positional arguments: 'a' and 'b'" +tryFunctionFail("f()") +# f() takes 2 positional arguments but 3 were given" +tryFunctionFail("f(1, 2, 3)") + +################################################## +# test_positional_only_with_optional_invalid_calls +def f(a, b=2, /): + pass +tryFunctionPass("f(1)") +# "f() missing 1 required positional argument: 'a'" +tryFunctionFail("f()") +# "f() takes from 1 to 2 positional arguments but 3 were given" +tryFunctionFail("f(1, 2, 3)") + +################################################## +# test_no_standard_args_usage +print("\ntest_no_standard_args_usage") +def f(a, b, /, *, c): + pass + +tryFunctionPass("f(1, 2, c=3)") +# TypeError +tryFunctionFail("f(1, b=2, c=3)") + +################################################## +# test_lambdas +print("\ntest_lambdas") +try: + x = lambda a, /, b: a + b + assertEqual(x(1,2), 3) + assertEqual(x(1,b=2), 3) + + x = lambda a, /, b=2: a + b + assertEqual(x(1), 3) + + x = lambda a, b, /: a + b + assertEqual(x(1, 2), 3) + + x = lambda a, b, /, : a + b + assertEqual(x(1, 2), 3) +except: + print("FAILED: test_lambdas not working") + +################################################## +# test_invalid_syntax_lambda +try: + tryFunctionFail("lambda a, b = 5, /, c: None") + tryFunctionFail("lambda a = 5, b, /, c: None") + tryFunctionFail("lambda a = 5, b, /: None") + tryFunctionFail("lambda *args, /: None") + tryFunctionFail("lambda *args, a, /: None") + tryFunctionFail("lambda **kwargs, /: None") + tryFunctionFail("lambda /, a = 1: None") + tryFunctionFail("lambda /, a: None") + tryFunctionFail("lambda /: None") + tryFunctionFail("lambda *, a, /: None") + tryFunctionFail("lambda *, /, a: None") + tryFunctionFail("lambda a, /, a: None") + tryFunctionFail("lambda a, /, *, a: None") + tryFunctionFail("lambda a, /, b, /: None") + tryFunctionFail("lambda a, /, b, /, c: None") + tryFunctionFail("lambda a, /, b, /, c, *, d: None") + tryFunctionFail("lambda a, *, b, /, c: None") +except: + print("FAILED: test_invalid_syntax_lambda not working") + +################################################## +# test_posonly_methods +print("\ntest_posonly_methods") +class Example: + def f(self, a, b, /): + return a, b + +assertEqual(Example().f(1, 2), (1, 2)) +assertEqual(Example.f(Example(), 1, 2), (1, 2)) +tryFunctionFail("Example.f(1,2)") +# f() got some positional-only arguments passed as keyword arguments: 'b' +tryFunctionFail("Example().f(1, b=2)") + +################################################## +# test_module_function +print("\ntest_module_function") +def f(a, b, /): + pass +tryFunctionFail("f()") + +################################################## +# test_closures +print("\ntest_closures") +def f(x,y): + def g(x2,/,y2): + return x + y + x2 + y2 + return g + +assertEqual(f(1,2)(3,4), 10) +tryFunctionFail("f(1,2)(3)") +tryFunctionFail("f(1,2)(3,4,5)") + +def f(x,/,y): + def g(x2,y2): + return x + y + x2 + y2 + return g +assertEqual(f(1,2)(3,4), 10) + +def f(x,/,y): + def g(x2,/,y2): + return x + y + x2 + y2 + return g +assertEqual(f(1,2)(3,4), 10) +tryFunctionFail("f(1,2)(3)") +tryFunctionFail("f(1,2)(3,4,5)") + + +################################################## +# test_same_keyword_as_positional_with_kwargs +print("\ntest_same_keyword_as_positional_with_kwargs") +def f(something,/,**kwargs): + return (something, kwargs) + +assertEqual(f(42, something=42), (42, {'something': 42})) +tryFunctionFail("f(something=42)") +assertEqual(f(42), (42, {})) + + +################################################## +# test_mangling +print("\ntest_mangling") +class X: + def f(self, __a=42, /): + return __a + + def f2(self, __a=42, /, __b=43): + return (__a, __b) + + def f3(self, __a=42, /, __b=43, *, __c=44): + return (__a, __b, __c) + +assertEqual(X().f(), 42) +assertEqual(X().f2(), (42, 43)) +assertEqual(X().f3(), (42, 43, 44)) + +################################################## +# test_too_many_arguments +# Ignored due to bug with compile function in micropython-minimal +# print("\ntest_too_many_arguments") +# fundef = "def f(" + ', '.join('i' + str(i) for i in range(300)) + ", /):\n pass\n" +# compile(fundef, "", "single") +# print("PASSED: > 255 arg check") + +################################################## +# test_async +print("\ntest_async") +async def f(a=1, /, b=2): + return a, b + +tryFunctionFail("f(a=1, b=2)") + +def _check_call(*args, **kwargs): + try: + coro = f(*args, **kwargs) + coro.send(None) + except StopIteration as e: + result = e.value + assertEqual(result, (1, 2)) + +_check_call(1, 2) +_check_call(1, b=2) +_check_call(1) +_check_call() + + +################################################## +# test_generator +print("\ntest_generator") +def f(a=1, /, b=2): + yield a, b + +tryFunctionFail("f(a=1, b=2)") + +gen = f(1, 2) +assertEqual(next(gen), (1, 2)) +gen = f(1, b=2) +assertEqual(next(gen), (1, 2)) +gen = f(1) +assertEqual(next(gen), (1, 2)) +gen = f() +assertEqual(next(gen), (1, 2)) + + +################################################## +# test_super +print("\ntest_super") +sentinel = object() + +class A: + def method(self): + return sentinel + +class C(A): + def method(self, /): + return super().method() + +assertEqual(C().method(), sentinel) \ No newline at end of file diff --git a/tests/basics/fun_positional_args_only.py.exp b/tests/basics/fun_positional_args_only.py.exp new file mode 100644 index 0000000000000..fff7557d5e71c --- /dev/null +++ b/tests/basics/fun_positional_args_only.py.exp @@ -0,0 +1,160 @@ +PASSED: 'def f(a, b = 5, /, c): pass' threw an error. +PASSED: 'def f(a = 5, b, /, c): pass' threw an error. +PASSED: 'def f(a = 5, b=1, /, c, *, d=2): pass' threw an error. +PASSED: 'def f(a = 5, b, /): pass' threw an error. +PASSED: 'def f(*args, /): pass' threw an error. +PASSED: 'def f(*args, a, /): pass' threw an error. +PASSED: 'def f(**kwargs, /): pass' threw an error. +PASSED: 'def f(/, a = 1): pass' threw an error. +PASSED: 'def f(/, a): pass' threw an error. +PASSED: 'def f(/): pass' threw an error. +PASSED: 'def f(*, a, /): pass' threw an error. +PASSED: 'def f(*, /, a): pass' threw an error. +PASSED: 'def f(a, /, a): pass' threw an error. +PASSED: 'def f(a, /, *, a): pass' threw an error. +PASSED: 'def f(a, b/2, c): pass' threw an error. +PASSED: 'def f(a, /, c, /): pass' threw an error. +PASSED: 'def f(a, /, c, /, d): pass' threw an error. +PASSED: 'def f(a, /, c, /, d, *, e): pass' threw an error. +PASSED: 'def f(a, *, c, /, d, e): pass' threw an error. +PASSED: 'async def f(a, b = 5, /, c): pass' threw an error. +PASSED: 'async def f(a = 5, b, /, c): pass' threw an error. +PASSED: 'async def f(a = 5, b=1, /, c, d=2): pass' threw an error. +PASSED: 'async def f(a = 5, b, /): pass' threw an error. +PASSED: 'async def f(*args, /): pass' threw an error. +PASSED: 'async def f(*args, a, /): pass' threw an error. +PASSED: 'async def f(**kwargs, /): pass' threw an error. +PASSED: 'async def f(/, a = 1): pass' threw an error. +PASSED: 'async def f(/, a): pass' threw an error. +PASSED: 'async def f(/): pass' threw an error. +PASSED: 'async def f(*, a, /): pass' threw an error. +PASSED: 'async def f(*, /, a): pass' threw an error. +PASSED: 'async def f(a, /, a): pass' threw an error. +PASSED: 'async def f(a, /, *, a): pass' threw an error. +PASSED: 'async def f(a, b/2, c): pass' threw an error. +PASSED: 'async def f(a, /, c, /): pass' threw an error. +PASSED: 'async def f(a, /, c, /, d): pass' threw an error. +PASSED: 'async def f(a, /, c, /, d, *, e): pass' threw an error. +PASSED: 'async def f(a, *, c, /, d, e): pass' threw an error. + +test_optional_positional_only_args +PASSED: Assertion check +PASSED: Assertion check +PASSED: 'f(1, b=2, c=3)' threw an error. +PASSED: Assertion check +PASSED: 'f(1, b=2)' threw an error. +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check +PASSED: 'f(1, b=2, c=3)' threw an error. +PASSED: Assertion check +PASSED: 'f(1, b=2)' threw an error. +PASSED: Assertion check + +test_pos_only_call_via_unpacking +PASSED: Assertion check + +test_use_positional_as_keyword +PASSED: 'f(a=1)' threw an error. +PASSED: 'f(a=1, b=2)' threw an error. +PASSED: 'f(a=1, b=2)' threw an error. + +test_positional_only_and_arg_invalid_calls +PASSED: 'f(1, 2)' threw an error. +PASSED: 'f(1)' threw an error. +PASSED: 'f()' threw an error. +PASSED: 'f(1, 2, 3, 4)' threw an error. + +test_positional_only_and_optional_arg_invalid_calls +PASSED: 'f(1, 2)' did not throw syntax error. +PASSED: 'f(1)' threw an error. +PASSED: 'f()' threw an error. +PASSED: 'f(1, 2, 3, 4)' threw an error. +PASSED: 'f(1, 2, 3, d=1, e=2)' did not throw syntax error. +PASSED: 'f(1, 2, 3, e=2)' threw an error. +PASSED: 'f(1, 2, 3)' threw an error. +PASSED: 'f(1, 2)' threw an error. +PASSED: 'f(1)' threw an error. +PASSED: 'f()' threw an error. +PASSED: 'f(1, 2, 3, 4, 5, 6, d=7, e=8)' threw an error. +PASSED: 'f(1, 2, 3, d=1, e=4, f=56)' threw an error. +PASSED: 'f(1, 2)' did not throw syntax error. +PASSED: 'f(1)' threw an error. +PASSED: 'f()' threw an error. +PASSED: 'f(1, 2, 3)' threw an error. +PASSED: 'f(1)' did not throw syntax error. +PASSED: 'f()' threw an error. +PASSED: 'f(1, 2, 3)' threw an error. + +test_no_standard_args_usage +PASSED: 'f(1, 2, c=3)' did not throw syntax error. +PASSED: 'f(1, b=2, c=3)' threw an error. + +test_lambdas +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check +PASSED: 'lambda a, b = 5, /, c: None' threw an error. +PASSED: 'lambda a = 5, b, /, c: None' threw an error. +PASSED: 'lambda a = 5, b, /: None' threw an error. +PASSED: 'lambda *args, /: None' threw an error. +PASSED: 'lambda *args, a, /: None' threw an error. +PASSED: 'lambda **kwargs, /: None' threw an error. +PASSED: 'lambda /, a = 1: None' threw an error. +PASSED: 'lambda /, a: None' threw an error. +PASSED: 'lambda /: None' threw an error. +PASSED: 'lambda *, a, /: None' threw an error. +PASSED: 'lambda *, /, a: None' threw an error. +PASSED: 'lambda a, /, a: None' threw an error. +PASSED: 'lambda a, /, *, a: None' threw an error. +PASSED: 'lambda a, /, b, /: None' threw an error. +PASSED: 'lambda a, /, b, /, c: None' threw an error. +PASSED: 'lambda a, /, b, /, c, *, d: None' threw an error. +PASSED: 'lambda a, *, b, /, c: None' threw an error. + +test_posonly_methods +PASSED: Assertion check +PASSED: Assertion check +PASSED: 'Example.f(1,2)' threw an error. +PASSED: 'Example().f(1, b=2)' threw an error. + +test_module_function +PASSED: 'f()' threw an error. + +test_closures +PASSED: Assertion check +PASSED: 'f(1,2)(3)' threw an error. +PASSED: 'f(1,2)(3,4,5)' threw an error. +PASSED: Assertion check +PASSED: Assertion check +PASSED: 'f(1,2)(3)' threw an error. +PASSED: 'f(1,2)(3,4,5)' threw an error. + +test_same_keyword_as_positional_with_kwargs +PASSED: Assertion check +PASSED: 'f(something=42)' threw an error. +PASSED: Assertion check + +test_mangling +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check + +test_async +PASSED: 'f(a=1, b=2)' threw an error. +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check + +test_generator +PASSED: 'f(a=1, b=2)' threw an error. +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check +PASSED: Assertion check + +test_super +PASSED: Assertion check diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index 6ee96b7caf293..96dfe8ab01c6d 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -32,11 +32,11 @@ id(h) [ 13] \(rule\|atom_expr_normal\)(44) (n=2) [ 13] literal const(\.\+) -[ 13] \(rule\|atom_expr_trailers\)(142) (n=2) +[ 13] atom_expr_trailers(142) (n=2) [ 13] \(rule\|trailer_period\)(50) (n=1) id(format) [ 13] \(rule\|trailer_paren\)(48) (n=1) -[ 13] \(rule\|arglist\)(164) (n=1) +[ 13] arglist(164) (n=1) id(b) ---------------- File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ 62 bytes) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 84c09a0c688d2..2736c0074d455 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -374,21 +374,25 @@ def read_prelude_sig(read_byte): E = (z >> 2) & 0x1 F = 0 A = z & 0x3 + P = 0 K = 0 D = 0 n = 0 while z & 0x80: z = read_byte() - # xFSSKAED + # xFSS(PorK)AED S |= (z & 0x30) << (2 * n) E |= (z & 0x02) << n F |= ((z & 0x40) >> 6) << n A |= (z & 0x4) << n - K |= ((z & 0x08) >> 3) << n + if n % 2 == 0: + P |= ((z & 0x08) >> 3) << (n >> 1) + else: + P |= ((z & 0x08) >> 3) << (n >> 1) D |= (z & 0x1) << n n += 1 S += 1 - return S, E, F, A, K, D + return S, E, F, A, P, K, D def read_prelude_size(read_byte): @@ -418,6 +422,7 @@ def local_read_byte(): n_exc_stack, scope_flags, n_pos_args, + n_posonly_args, n_kwonly_args, n_def_pos_args, ) = read_prelude_sig(local_read_byte) @@ -432,7 +437,7 @@ def local_read_byte(): # Extract simple_name and argument qstrs (var uints). args = [] - for arg_num in range(1 + n_pos_args + n_kwonly_args): + for arg_num in range(1 + n_pos_args + n_posonly_args + n_kwonly_args): value = 0 while True: b = local_read_byte() @@ -445,7 +450,15 @@ def local_read_byte(): ip2, ip, ip_ref[0], - (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args), + ( + n_state, + n_exc_stack, + scope_flags, + n_pos_args, + n_posonly_args, + n_kwonly_args, + n_def_pos_args, + ), args, ) @@ -791,8 +804,9 @@ def freeze_raw_code(self, qstr_links=(), type_sig=0): print(" .n_exc_stack = %u," % self.prelude[1]) print(" .scope_flags = %u," % self.prelude[2]) print(" .n_pos_args = %u," % self.prelude[3]) - print(" .n_kwonly_args = %u," % self.prelude[4]) - print(" .n_def_pos_args = %u," % self.prelude[5]) + print(" .n_posonly_args = %u," % self.prelude[4]) + print(" .n_kwonly_args = %u," % self.prelude[5]) + print(" .n_def_pos_args = %u," % self.prelude[6]) print(" .qstr_block_name_idx = %u," % self.names[0]) print( " .line_info = fun_data_%s + %u," pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy