Skip to content

Commit 58f00d7

Browse files
committed
py/modbuiltins: Use standard arg-parsing helper func for builtin print.
This allows the function to raise an exception when unknown keyword args are passed in. This patch also reduces code size by (in bytes): bare-arm: -24 minimal x86: -76 unix x64: -56 unix nanbox: -84 stm32: -40 esp8266: -68 cc3200: -48 Furthermore, this patch adds space (" ") to the set of ROM qstrs which means it doesn't need to be put in RAM if it's ever used.
1 parent e104e24 commit 58f00d7

2 files changed

Lines changed: 33 additions & 26 deletions

File tree

py/modbuiltins.c

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -383,46 +383,52 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) {
383383
}
384384
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);
385385

386-
STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
387-
mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP);
388-
mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP);
389-
const char *sep_data = " ";
390-
size_t sep_len = 1;
391-
const char *end_data = "\n";
392-
size_t end_len = 1;
393-
if (sep_elem != NULL && sep_elem->value != mp_const_none) {
394-
sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len);
395-
}
396-
if (end_elem != NULL && end_elem->value != mp_const_none) {
397-
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
398-
}
399-
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
400-
void *stream_obj = &mp_sys_stdout_obj;
401-
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
402-
if (file_elem != NULL && file_elem->value != mp_const_none) {
403-
stream_obj = MP_OBJ_TO_PTR(file_elem->value); // XXX may not be a concrete object
404-
}
386+
STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
387+
enum { ARG_sep, ARG_end, ARG_file };
388+
static const mp_arg_t allowed_args[] = {
389+
{ MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} },
390+
{ MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} },
391+
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
392+
{ MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} },
393+
#endif
394+
};
395+
396+
// parse args (a union is used to reduce the amount of C stack that is needed)
397+
union {
398+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
399+
size_t len[2];
400+
} u;
401+
mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args);
405402

406-
mp_print_t print = {stream_obj, mp_stream_write_adaptor};
403+
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
404+
// TODO file may not be a concrete object (eg it could be a small-int)
405+
mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor};
407406
#endif
407+
408+
// extract the objects first because we are going to use the other part of the union
409+
mp_obj_t sep = u.args[ARG_sep].u_obj;
410+
mp_obj_t end = u.args[ARG_end].u_obj;
411+
const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]);
412+
const char *end_data = mp_obj_str_get_data(end, &u.len[1]);
413+
408414
for (size_t i = 0; i < n_args; i++) {
409415
if (i > 0) {
410416
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
411-
mp_stream_write_adaptor(stream_obj, sep_data, sep_len);
417+
mp_stream_write_adaptor(print.data, sep_data, u.len[0]);
412418
#else
413-
mp_print_strn(&mp_plat_print, sep_data, sep_len, 0, 0, 0);
419+
mp_print_strn(&mp_plat_print, sep_data, u.len[0], 0, 0, 0);
414420
#endif
415421
}
416422
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
417-
mp_obj_print_helper(&print, args[i], PRINT_STR);
423+
mp_obj_print_helper(&print, pos_args[i], PRINT_STR);
418424
#else
419-
mp_obj_print_helper(&mp_plat_print, args[i], PRINT_STR);
425+
mp_obj_print_helper(&mp_plat_print, pos_args[i], PRINT_STR);
420426
#endif
421427
}
422428
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
423-
mp_stream_write_adaptor(stream_obj, end_data, end_len);
429+
mp_stream_write_adaptor(print.data, end_data, u.len[1]);
424430
#else
425-
mp_print_strn(&mp_plat_print, end_data, end_len, 0, 0, 0);
431+
mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0);
426432
#endif
427433
return mp_const_none;
428434
}

py/qstrdefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Q(/)
4040
Q(%#o)
4141
Q(%#x)
4242
Q({:#b})
43+
Q( )
4344
Q(\n)
4445
Q(maximum recursion depth exceeded)
4546
Q(<module>)

0 commit comments

Comments
 (0)