8000 py: Implement keyword-only args. · micropython/micropython@2827d62 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2827d62

Browse files
committed
py: Implement keyword-only args.
Implements 'def f(*, a)' and 'def f(*a, b)', but not default keyword-only args, eg 'def f(*, a=1)'. Partially addresses issue #524.
1 parent 36cbd0d commit 2827d62

12 files changed

+198
-70
lines changed

py/compile.c

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,14 +2789,17 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
27892789

27902790
void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star, bool allow_annotations) {
27912791
// TODO verify that *k and **k are last etc
2792-
qstr param_name = 0;
2792+
qstr param_name = MP_QSTR_NULL;
2793+
uint param_flag = ID_FLAG_IS_PARAM;
27932794
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
27942795
if (MP_PARSE_NODE_IS_ID(pn)) {
27952796
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
27962797
if (comp->have_star) {
2797-
// comes after a bare star, so doesn't count as a parameter
2798+
// comes after a star, so counts as a keyword-only parameter
2799+
comp->scope_cur->num_kwonly_args += 1;
27982800
} else {
2799-
comp->scope_cur->num_params += 1;
2801+
// comes before a star, so counts as a positional parameter
2802+
comp->scope_cur->num_pos_args += 1;
28002803
}
28012804
} else {
28022805
assert(MP_PARSE_NODE_IS_STRUCT(pn));
@@ -2822,12 +2825,15 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
28222825
}
28232826
*/
28242827
if (comp->have_star) {
2825-
// comes after a bare star, so doesn't count as a parameter
2828+
// comes after a star, so counts as a keyword-only parameter
2829+
comp->scope_cur->num_kwonly_args += 1;
28262830
} else {
2827-
comp->scope_cur->num_params += 1;
2831+
// comes before a star, so counts as a positional parameter
2832+
comp->scope_cur->num_pos_args += 1;
28282833
}
2829 B422 2834
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {
28302835
comp->have_star = true;
2836+
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM;
28312837
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
28322838
// bare star
28332839
// TODO see http://www.python.org/dev/peps/pep-3102/
@@ -2848,6 +2854,7 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
28482854
}
28492855
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
28502856
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
2857+
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;
28512858
if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
28522859
// this parameter has an annotation
28532860
pn_annotation = pns->nodes[1];
@@ -2859,7 +2866,7 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
28592866
}
28602867
}
28612868

2862-
if (param_name != 0) {
2869+
if (param_name != MP_QSTR_NULL) {
28632870
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
28642871
// TODO this parameter has an annotation
28652872
}
@@ -2870,15 +2877,15 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
28702877
return;
28712878
}
28722879
id_info->kind = ID_INFO_KIND_LOCAL;
2873-
id_info->flags |= ID_FLAG_IS_PARAM;
2880+
id_info->flags = param_flag;
28742881
}
28752882
}
28762883

2877-
void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
2884+
STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
28782885
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
28792886
}
28802887

2881-
void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
2888+
STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
28822889
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
28832890
}
28842891

@@ -3051,7 +3058,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
30513058
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added);
30523059
assert(added);
30533060
id_info->kind = ID_INFO_KIND_LOCAL;
3054-
scope->num_params = 1;
3061+
scope->num_pos_args = 1;
30553062
}
30563063

30573064
if (scope->kind == SCOPE_LIST_COMP) {
@@ -3144,7 +3151,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
31443151
if (comp->pass == PASS_2) {
31453152
mp_parse_node_t *pn_params;
31463153
int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params);
3147-
scope->num_params = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);
3154+
scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);
31483155
}
31493156

31503157
assert(MP_PARSE_NODE_IS_NULL(pns->nodes[2])); // type
@@ -3235,6 +3242,25 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
32353242
#endif
32363243

32373244
STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
3245+
#if !MICROPY_EMIT_CPYTHON
3246+
// in Micro Python we put the *x parameter after all other parameters (except **y)
3247+
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
3248+
id_info_t *id_param = NULL;
3249+
for (int i = scope->id_info_len - 1; i >= 0; i--) {
3250+
id_info_t *id = &scope->id_info[i];
3251+
if (id->flags & ID_FLAG_IS_STAR_PARAM) {
3252+
if (id_param != NULL) {
3253+
// swap star param with last param
3254+
id_info_t temp = *id_param; *id_param = *id; *id = temp;
3255+
}
3256+
break;
3257+
} else if (id_param == NULL && id->flags == ID_FLAG_IS_PARAM) {
3258+
id_param = id;
3259+
}
3260+
}
3261+
}
3262+
#endif
3263+
32383264
// in functions, turn implicit globals into explicit globals
32393265
// compute the index of each local
32403266
scope->num_locals = 0;
@@ -3247,10 +3273,9 @@ STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
32473273
if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
32483274
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
32493275
}
3250-
// note: params always count for 1 local, even if they are a cell
3276+
// params always count for 1 local, even if they are a cell
32513277
if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) {
3252-
id->local_num = scope->num_locals;
3253-
scope->num_locals += 1;
3278+
id->local_num = scope->num_locals++;
32543279
}
32553280
}
32563281

@@ -3309,7 +3334,7 @@ STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
33093334
id->local_num += num_free;
33103335
}
33113336
}
3312-
scope->num_params += num_free; // free vars are counted as params for passing them into the function
3337+
scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function
33133338
scope->num_locals += num_free;
33143339
}
33153340
#endif

py/emitbc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,14 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
300300
emit->code_base = m_new0(byte, emit->code_info_size + emit->byte_code_size);
301301

302302
} else if (emit->pass == PASS_3) {
303-
qstr *arg_names = m_new(qstr, emit->scope->num_params);
304-
for (int i = 0; i < emit->scope->num_params; i++) {
303+
qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
304+
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
305305
arg_names[i] = emit->scope->id_info[i].qstr;
306306
}
307307
mp_emit_glue_assign_byte_code(emit->scope->raw_code, emit->code_base,
308308
emit->code_info_size + emit->byte_code_size,
309-
emit->scope->num_params, emit->scope->num_locals,
310-
emit->scope->scope_flags, arg_names);
309+
emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names,
310+
emit->scope->scope_flags);
311311
}
312312
}
313313

py/emitglue.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,22 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
4747
return rc;
4848
}
4949

50-
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) {
50+
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags) {
5151
rc->kind = MP_CODE_BYTE;
5252
rc->scope_flags = scope_flags;
53-
rc->n_args = n_args;
53+
rc->n_pos_args = n_pos_args;
54+
rc->n_kwonly_args = n_kwonly_args;
55+
rc->arg_names = arg_names;
5456
rc->u_byte.code = code;
5557
rc->u_byte.len = len;
56-
rc->arg_names = arg_names;
5758

5859
#ifdef DEBUG_PRINT
59-
DEBUG_printf("assign byte code: code=%p len=%u n_args=%d n_locals=%d\n", code, len, n_args, n_locals);
60+
DEBUG_printf("assign byte code: code=%p len=%u n_pos_args=%d n_kwonly_args=%d flags=%x\n", code, len, n_pos_args, n_kwonly_args, scope_flags);
61+
DEBUG_printf(" arg names:");
62+
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
63+
DEBUG_printf(" %s", qstr_str(arg_names[i]));
64+
}
65+
DEBUG_printf("\n");
6066
for (int i = 0; i < 128 && i < len; i++) {
6167
if (i > 0 && i % 16 == 0) {
6268
DEBUG_printf("\n");
@@ -73,7 +79,7 @@ void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, int
7379
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
7480
rc->kind = MP_CODE_NATIVE;
7581
rc->scope_flags = 0;
76-
rc->n_args = n_args;
82+
rc->n_pos_args = n_args;
7783
rc->u_native.fun = fun;
7884

7985
#ifdef DEBUG_PRINT
@@ -99,7 +105,7 @@ void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *fun, uint len, int
99105
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *fun, uint len, int n_args) {
100106
rc->kind = MP_CODE_INLINE_ASM;
101107
rc->scope_flags = 0;
102-
rc->n_args = n_args;
108+
rc->n_pos_args = n_args;
103109
rc->u_inline_asm.fun = fun;
104110

105111
#ifdef DEBUG_PRINT
@@ -136,13 +142,13 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
136142
mp_obj_t fun;
137143
switch (rc->kind) {
138144
case MP_CODE_BYTE:
139-
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_args, def_args, rc->u_byte.code);
145+
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, rc->u_byte.code);
140146
break;
141147
case MP_CODE_NATIVE:
142-
fun = mp_make_function_n(rc->n_args, rc->u_native.fun);
148+
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
143149
break;
144150
case MP_CODE_INLINE_ASM:
145-
fun = mp_obj_new_fun_asm(rc->n_args, rc->u_inline_asm.fun);
151+
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_inline_asm.fun);
146152
break;
147153
default:
148154
// raw code was never set (this should not happen)

py/emitglue.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ typedef enum {
99
} mp_raw_code_kind_t;
1010

1111
typedef struct _mp_code_t {
12-
mp_raw_code_kind_t kind : 8;
13-
uint scope_flags : 8;
14-
uint n_args : 16;
12+
mp_raw_code_kind_t kind : 3;
13+
uint scope_flags : 7;
14+
uint n_pos_args : 11;
15+
uint n_kwonly_args : 11;
16+
qstr *arg_names;
1517
union {
1618
struct {
1719
byte *code;
@@ -24,15 +26,14 @@ typedef struct _mp_code_t {
2426
void *fun;
2527
} u_inline_asm;
2628
};
27-
qstr *arg_names;
2829
} mp_raw_code_t;
2930

3031
void mp_emit_glue_init(void);
3132
void mp_emit_glue_deinit(void);
3233

3334
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
3435

35-
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names);
36+
void mp_emit_glue_assign_byte_code(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
3637
void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
3738
void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *f, uint len, int n_args);
3839

py/emitinlinethumb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
7373

7474
if (emit->pass == PASS_3) {
7575
void *f = asm_thumb_get_code(emit->as);
76-
mp_emit_glue_assign_inline_asm_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params);
76+
mp_emit_glue_assign_inline_asm_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
7777
}
7878

7979
return emit->success;

py/emitnative.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
230230

231231
// initialise locals from parameters
232232
#if N_X64
233-
for (int i = 0; i < scope->num_params; i++) {
233+
for (int i = 0; i < scope->num_pos_args; i++) {
234234
if (i == 0) {
235235
asm_x64_mov_r64_to_r64(emit->as, REG_ARG_1, REG_LOCAL_1);
236236
} else if (i == 1) {
@@ -243,7 +243,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
243243
}
244244
}
245245
#elif N_THUMB
246-
for (int i = 0; i < scope->num_params; i++) {
246+
for (int i = 0; i < scope->num_pos_args; i++) {
247247
if (i == 0) {
248248
asm_thumb_mov_reg_reg(emit->as, REG_LOCAL_1, REG_ARG_1);
249249
} else if (i == 1) {
@@ -283,10 +283,10 @@ STATIC void emit_native_end_pass(emit_t *emit) {
283283
if (emit->pass == PASS_3) {
284284
#if N_X64
285285
void *f = asm_x64_get_code(emit->as);
286-
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_x64_get_code_size(emit->as), emit->scope->num_params);
286+
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_x64_get_code_size(emit->as), emit->scope->num_pos_args);
287287
#elif N_THUMB
288288
void *f = asm_thumb_get_code(emit->as);
289-
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params);
289+
mp_emit_glue_assign_native_code(emit->scope->raw_code, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
290290
#endif
291291
}
292292
}

py/obj.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
356356
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
357357
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
358358
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
359-
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args, const byte *code);
359+
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, const byte *code);
360360
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
361361
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
362362
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);

0 commit comments

Comments
 (0)
0