Skip to content

pep 570 positional only parameters. #8480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 26 additions & 23 deletions py/bc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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;
Expand All @@ -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");
Expand All @@ -178,27 +180,27 @@ 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];
}

// check keyword arguments

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) {
Expand All @@ -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];
Expand Down Expand Up @@ -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) {
Expand All @@ -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]) {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
46 changes: 31 additions & 15 deletions py/bc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down Expand Up @@ -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; \
\
Expand All @@ -86,49 +88,62 @@
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 */ \
S = (z >> 3) & 0xf; \
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 { \
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
20 changes: 20 additions & 0 deletions py/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion py/emitbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
6 changes: 4 additions & 2 deletions py/emitnative.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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];
Expand Down
Loading
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