@@ -383,46 +383,52 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) {
383383}
384384MP_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}
0 commit comments