@@ -40,11 +40,39 @@ void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj
4040 if (kind == PRINT_STR && !is_bytes ) {
4141 print (env , "%.*s" , str_len , str_data );
4242 } else {
43+ // this escapes characters, but it will be very slow to print (calling print many times)
44+ bool has_single_quote = false;
45+ bool has_double_quote = false;
46+ for (const byte * s = str_data , * top = str_data + str_len ; (!has_single_quote || !has_double_quote ) && s < top ; s ++ ) {
47+ if (* s == '\'' ) {
48+ has_single_quote = true;
49+ } else if (* s == '"' ) {
50+ has_double_quote = true;
51+ }
52+ }
4353 if (is_bytes ) {
4454 print (env , "b" );
4555 }
46- // TODO need to escape chars etc
47- print (env , "'%.*s'" , str_len , str_data );
56+ int quote_char = '\'' ;
57+ if (has_single_quote && !has_double_quote ) {
58+ quote_char = '"' ;
59+ }
60+ print (env , "%c" , quote_char );
61+ for (const byte * s = str_data , * top = str_data + str_len ; s < top ; s ++ ) {
62+ if (* s == quote_char ) {
63+ print (env , "\\%c" , quote_char );
64+ } else if (* s == '\\' ) {
65+ print (env , "\\\\" );
66+ } else if (32 <= * s && * s <= 126 ) {
67+ print (env , "%c" , * s );
68+ } else if (* s == '\n' ) {
69+ print (env , "\\n" );
70+ // TODO add more escape codes here if we want to match CPython
71+ } else {
72+ print (env , "\\x%02x" , * s );
73+ }
74+ }
75+ print (env , "%c" , quote_char );
4876 }
4977}
5078
@@ -474,13 +502,17 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
474502 }
475503}
476504
505+ void bad_implicit_conversion (mp_obj_t self_in ) __attribute__((noreturn ));
506+ void bad_implicit_conversion (mp_obj_t self_in ) {
507+ nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "Can't convert '%s' object to str implicitly" , mp_obj_get_type_str (self_in )));
508+ }
509+
477510uint mp_obj_str_get_hash (mp_obj_t self_in ) {
478511 if (MP_OBJ_IS_STR (self_in )) {
479512 GET_STR_HASH (self_in , h );
480513 return h ;
481514 } else {
482- nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "Can't convert '%s' object to str implicitly" ,
483- mp_obj_get_type_str (self_in )));
515+ bad_implicit_conversion (self_in );
484516 }
485517}
486518
@@ -489,8 +521,20 @@ uint mp_obj_str_get_len(mp_obj_t self_in) {
489521 GET_STR_LEN (self_in , l );
490522 return l ;
491523 } else {
492- nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "Can't convert '%s' object to str implicitly" ,
493- mp_obj_get_type_str (self_in )));
524+ bad_implicit_conversion (self_in );
525+ }
526+ }
527+
528+ // use this if you will anyway convert the string to a qstr
529+ // will be more efficient for the case where it's already a qstr
530+ qstr mp_obj_str_get_qstr (mp_obj_t self_in ) {
531+ if (MP_OBJ_IS_QSTR (self_in )) {
532+ return MP_OBJ_QSTR_VALUE (self_in );
533+ } else if (MP_OBJ_IS_TYPE (self_in , & str_type )) {
534+ mp_obj_str_t * self = self_in ;
535+ return qstr_from_strn ((char * )self -> data , self -> len );
536+ } else {
537+ bad_implicit_conversion (self_in );
494538 }
495539}
496540
@@ -502,8 +546,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) {
502546 (void )l ; // len unused
503547 return (const char * )s ;
504548 } else {
505- nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "Can't convert '%s' object to str implicitly" ,
506- mp_obj_get_type_str (self_in )));
549+ bad_implicit_conversion (self_in );
507550 }
508551}
509552
@@ -513,8 +556,7 @@ const byte *mp_obj_str_get_data(mp_obj_t self_in, uint *len) {
513556 * len = l ;
514557 return s ;
515558 } else {
516- nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "Can't convert '%s' object to str implicitly" ,
517- mp_obj_get_type_str (self_in )));
559+ bad_implicit_conversion (self_in );
518560 }
519561}
520562
0 commit comments