@@ -65,9 +65,8 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
6565 // TODO: need predicate to check for int-like type (bools are such for example)
6666 // ["no", "yes"][1 == 2] is common idiom
6767 if (MP_OBJ_IS_SMALL_INT (rhs_in )) {
68- // TODO: This implements byte string access for single index so far
69- // TODO: Handle negative indexes.
70- return mp_obj_new_int (lhs_data [mp_obj_get_int (rhs_in )]);
68+ uint index = mp_get_index (lhs -> base .type , lhs_len , rhs_in );
69+ return mp_obj_new_str (qstr_from_strn ((const char * )lhs_data + index , 1 ));
7170#if MICROPY_ENABLE_SLICE
7271 } else if (MP_OBJ_IS_TYPE (rhs_in , & slice_type )) {
7372 machine_int_t start , stop , step ;
@@ -122,6 +121,16 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
122121 return mp_const_false ;
123122 }
124123 break ;
124+ case RT_BINARY_OP_MULTIPLY :
125+ {
126+ if (!MP_OBJ_IS_SMALL_INT (rhs_in )) {
127+ return NULL ;
128+ }
129+ int n = MP_OBJ_SMALL_INT_VALUE (rhs_in );
130+ char * s = m_new (char , lhs_len * n );
131+ mp_seq_multiply (lhs_data , sizeof (* lhs_data ), lhs_len , n , s );
132+ return MP_OBJ_NEW_QSTR (qstr_from_strn_take (s , lhs_len * n , lhs_len * n ));
133+ }
125134 }
126135
127136 return MP_OBJ_NULL ; // op not supported
@@ -184,6 +193,45 @@ mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
184193 nlr_jump (mp_obj_new_exception_msg (MP_QSTR_TypeError , "?str.join expecting a list of str's" ));
185194}
186195
196+ #define is_ws (c ) ((c) == ' ' || (c) == '\t')
197+
198+ static mp_obj_t str_split (uint n_args , const mp_obj_t * args ) {
199+ int splits = -1 ;
200+ mp_obj_t sep = mp_const_none ;
201+ if (n_args > 1 ) {
202+ sep = args [1 ];
203+ if (n_args > 2 ) {
204+ splits = MP_OBJ_SMALL_INT_VALUE (args [2 ]);
205+ }
206+ }
207+ assert (sep == mp_const_none );
208+ (void )sep ; // unused; to hush compiler warning
209+ mp_obj_t res = mp_obj_new_list (0 , NULL );
210+ const char * s = qstr_str (mp_obj_str_get (args [0 ]));
211+ const char * start ;
212+
213+ // Initial whitespace is not counted as split, so we pre-do it
214+ while (is_ws (* s )) s ++ ;
215+ while (* s && splits != 0 ) {
216+ start = s ;
217+ while (* s != 0 && !is_ws (* s )) s ++ ;
218+ rt_list_append (res , MP_OBJ_NEW_QSTR (qstr_from_strn (start , s - start )));
219+ if (* s == 0 ) {
220+ break ;
221+ }
222+ while (is_ws (* s )) s ++ ;
223+ if (splits > 0 ) {
224+ splits -- ;
225+ }
226+ }
227+
228+ if (* s != 0 ) {
229+ rt_list_append (res , MP_OBJ_NEW_QSTR (qstr_from_str (s )));
230+ }
231+
232+ return res ;
233+ }
234+
187235static bool chr_in_str (const char * const str , const size_t str_len , const char c ) {
188236 for (size_t i = 0 ; i < str_len ; i ++ ) {
189237 if (str [i ] == c ) {
@@ -195,16 +243,8 @@ static bool chr_in_str(const char* const str, const size_t str_len, const char c
195243
196244static mp_obj_t str_find (uint n_args , const mp_obj_t * args ) {
197245 assert (2 <= n_args && n_args <= 4 );
198- assert (MP_OBJ_IS_TYPE (args [0 ], & str_type ));
199- if (!MP_OBJ_IS_TYPE (args [1 ], & str_type )) {
200- nlr_jump (mp_obj_new_exception_msg_1_arg (
201- MP_QSTR_TypeError ,
202- "Can't convert '%s' object to str implicitly" ,
203- mp_obj_get_type_str (args [1 ])));
204- }
205-
206- const char * haystack = qstr_str (((mp_obj_str_t * )args [0 ])-> qstr );
207- const char * needle = qstr_str (((mp_obj_str_t * )args [1 ])-> qstr );
246+ const char * haystack = qstr_str (mp_obj_str_get (args [0 ]));
247+ const char * needle = qstr_str (mp_obj_str_get (args [1 ]));
208248
209249 size_t haystack_len = strlen (haystack );
210250 size_t needle_len = strlen (needle );
@@ -242,14 +282,11 @@ mp_obj_t str_strip(uint n_args, const mp_obj_t *args) {
242282 if (n_args == 1 ) {
243283 chars_to_del = whitespace ;
244284 } else {
245- assert (MP_OBJ_IS_TYPE (args [1 ], & str_type ));
246- mp_obj_str_t * chars_to_del_obj = args [1 ];
247- chars_to_del = qstr_str (chars_to_del_obj -> qstr );
285+ chars_to_del = qstr_str (mp_obj_str_get (args [1 ]));
248286 }
249287
250288 const size_t chars_to_del_len = strlen (chars_to_del );
251- mp_obj_str_t * self = args [0 ];
252- const char * orig_str = qstr_str (self -> qstr );
289+ const char * orig_str = qstr_str (mp_obj_str_get (args [0 ]));
253290 const size_t orig_str_len = strlen (orig_str );
254291
255292 size_t first_good_char_pos = 0 ;
@@ -307,12 +344,14 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) {
307344
308345static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_find_obj , 2 , 4 , str_find ) ;
309346static MP_DEFINE_CONST_FUN_OBJ_2 (str_join_obj , str_join ) ;
347+ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_split_obj , 1 , 3 , str_split ) ;
310348static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (str_strip_obj , 1 , 2 , str_strip ) ;
311349static MP_DEFINE_CONST_FUN_OBJ_VAR (str_format_obj , 1 , str_format ) ;
312350
313351static const mp_method_t str_type_methods [] = {
314352 { "find" , & str_find_obj },
315353 { "join" , & str_join_obj },
354+ { "split" , & str_split_obj },
316355 { "strip" , & str_strip_obj },
317356 { "format" , & str_format_obj },
318357 { NULL , NULL }, // end-of-list sentinel
@@ -335,9 +374,15 @@ mp_obj_t mp_obj_new_str(qstr qstr) {
335374}
336375
337376qstr mp_obj_str_get (mp_obj_t self_in ) {
338- assert (MP_OBJ_IS_TYPE (self_in , & str_type ));
339- mp_obj_str_t * self = self_in ;
340- return self -> qstr ;
377+ if (MP_OBJ_IS_QSTR (self_in )) {
378+ return MP_OBJ_QSTR_VALUE (self_in );
379+ }
380+ if (MP_OBJ_IS_TYPE (self_in , & str_type )) {
381+ mp_obj_str_t * self = self_in ;
382+ return self -> qstr ;
383+ }
384+ nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_TypeError , "Can't convert '%s' object to str implicitly" ,
385+ mp_obj_get_type_str (self_in )));
341386}
342387
343388/******************************************************************************/
0 commit comments