diff --git a/py/obj.h b/py/obj.h index 2a9ed3acd3..5f2b9d3bef 100644 --- a/py/obj.h +++ b/py/obj.h @@ -517,7 +517,7 @@ mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in); void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); // slice -void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step); +void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); // array uint mp_obj_array_len(mp_obj_t self_in); diff --git a/py/objslice.c b/py/objslice.c index 8fe65de1f8..dfd070f8d0 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -62,13 +62,20 @@ const mp_obj_ellipsis_t mp_const_ellipsis_obj = {{&mp_type_ellipsis}}; // CPython supports 3rd arg (step), plus args can be arbitrary Python objects. typedef struct _mp_obj_slice_t { mp_obj_base_t base; - machine_int_t start; - machine_int_t stop; + mp_obj_t start; + mp_obj_t stop; + mp_obj_t step; } mp_obj_slice_t; void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_slice_t *o = o_in; - print(env, "slice(" INT_FMT ", " INT_FMT ")", o->start, o->stop); + print(env, "slice("); + mp_obj_print_helper(print, env, o->start, PRINT_REPR); + print(env, ", "); + mp_obj_print_helper(print, env, o->stop, PRINT_REPR); + print(env, ", "); + mp_obj_print_helper(print, env, o->step, PRINT_REPR); + print(env, ")"); } const mp_obj_type_t mp_type_slice = { @@ -77,39 +84,21 @@ const mp_obj_type_t mp_type_slice = { .print = slice_print, }; -// TODO: Make sure to handle "empty" values, which are signified by None in CPython mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { - assert(ostep == NULL); - machine_int_t start = 0, stop = 0; - if (ostart != mp_const_none) { - start = mp_obj_get_int(ostart); - } - if (ostop != mp_const_none) { - stop = mp_obj_get_int(ostop); - if (stop == 0) { - // [x:0] is a special case - in our slice object, stop = 0 means - // "end of sequence". Fortunately, [x:0] is an empty seqence for - // any x (including negative). [x:x] is also always empty sequence. - // but x also can be 0. But note that b""[x:x] is b"" for any x (i.e. - // no IndexError, at least in Python 3.3.3). So, we just use -1's to - // signify that. -1 is catchy "special" number in case someone will - // try to print [x:0] slice ever. - start = stop = -1; - } - } - mp_obj_slice_t *o = m_new(mp_obj_slice_t, 1); + mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t); o->base.type = &mp_type_slice; - o->start = start; - o->stop = stop; - return (mp_obj_t)o; + o->start = ostart; + o->stop = ostop; + o->step = ostep; + return o; } -void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step) { +void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice)); mp_obj_slice_t *self = self_in; *start = self->start; *stop = self->stop; - *step = 1; + *step = self->step; } #endif diff --git a/py/objstr.c b/py/objstr.c index 4ec1034e1e..67de2ce804 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -355,6 +355,9 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (!mp_seq_get_fast_slice_indexes(self_len, index, &start, &stop)) { assert(0); } + if (start >= stop) { + return MP_OBJ_NEW_QSTR(MP_QSTR_); + } return str_new(type, self_data + start, stop - start); } #endif diff --git a/py/sequence.c b/py/sequence.c index 966adaac03..2c1f6a836c 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -52,12 +52,24 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void } bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) { - machine_int_t start, stop, step; - mp_obj_slice_get(slice, &start, &stop, &step); - if (step != 1) { + mp_obj_t ostart, ostop, ostep; + machine_int_t start, stop; + mp_obj_slice_get(slice, &ostart, &ostop, &ostep); + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { return false; } + if (ostart == mp_const_none) { + start = 0; + } else { + start = MP_OBJ_SMALL_INT_VALUE(ostart); + } + if (ostop == mp_const_none) { + stop = len; + } else { + stop = MP_OBJ_SMALL_INT_VALUE(ostop); + } + // Unlike subscription, out-of-bounds slice indexes are never error if (start < 0) { start = len + start; @@ -67,7 +79,7 @@ bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_u } else if (start > len) { start = len; } - if (stop <= 0) { + if (stop < 0) { stop = len + stop; // CPython returns empty sequence in such case if (stop < 0) { diff --git a/py/vm.c b/py/vm.c index 1f3f693c97..608c9096d9 100644 --- a/py/vm.c +++ b/py/vm.c @@ -768,12 +768,12 @@ unwind_jump: if (unum == 2) { obj2 = POP(); obj1 = TOP(); - SET_TOP(mp_obj_new_slice(obj1, obj2, NULL)); + SET_TOP(mp_obj_new_slice(obj1, obj2, mp_const_none)); } else { - obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported"); - nlr_pop(); - fastn[0] = obj1; - return MP_VM_RETURN_EXCEPTION; + mp_obj_t obj3 = POP(); + obj2 = POP(); + obj1 = TOP(); + SET_TOP(mp_obj_new_slice(obj1, obj2, obj3)); } DISPATCH(); #endif