From edbdf71f5c810b0fb2d00c05c752fe25ecb3e832 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 2 Feb 2014 00:54:06 +0200 Subject: rt_unpack_sequence(): Support generic iterables. --- py/runtime.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'py') diff --git a/py/runtime.c b/py/runtime.c index 6f6e3c903..a3970fe3d 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -769,8 +769,8 @@ mp_obj_t rt_store_set(mp_obj_t set, mp_obj_t item) { // unpacked items are stored in reverse order into the array pointed to by items void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) { + uint seq_len; if (MP_OBJ_IS_TYPE(seq_in, &tuple_type) || MP_OBJ_IS_TYPE(seq_in, &list_type)) { - uint seq_len; mp_obj_t *seq_items; if (MP_OBJ_IS_TYPE(seq_in, &tuple_type)) { mp_obj_tuple_get(seq_in, &seq_len, &seq_items); @@ -778,17 +778,33 @@ void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) { mp_obj_list_get(seq_in, &seq_len, &seq_items); } if (seq_len < num) { - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", (void*)(machine_uint_t)seq_len)); + goto too_short; } else if (seq_len > num) { - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", (void*)(machine_uint_t)num)); + goto too_long; } for (uint i = 0; i < num; i++) { items[i] = seq_items[num - 1 - i]; } } else { - // TODO call rt_getiter and extract via rt_iternext - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(seq_in))); + mp_obj_t iterable = rt_getiter(seq_in); + + for (seq_len = 0; seq_len < num; seq_len++) { + mp_obj_t el = rt_iternext(iterable); + if (el == mp_const_stop_iteration) { + goto too_short; + } + items[num - 1 - seq_len] = el; + } + if (rt_iternext(iterable) != mp_const_stop_iteration) { + goto too_long; + } } + return; + +too_short: + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "need more than %d values to unpack", seq_len)); +too_long: + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "too many values to unpack (expected %d)", num)); } mp_obj_t rt_build_map(int n_args) { -- cgit v1.2.3 From 7364af2d8cd72467bbb3bf135b29fae47105b232 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 2 Feb 2014 02:38:22 +0200 Subject: Factor out m_seq_get_fast_slice_indexes() fucntions as sequence helper. Takes slice object and sequence length and computes subsequence indexes for case of slice step=1. --- py/obj.h | 1 + py/objstr.c | 22 ++-------------------- py/sequence.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 20 deletions(-) (limited to 'py') diff --git a/py/obj.h b/py/obj.h index 0680e6fb1..45430d4a1 100644 --- a/py/obj.h +++ b/py/obj.h @@ -395,3 +395,4 @@ typedef struct _mp_obj_classmethod_t { // sequence helpers void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest); +bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end); diff --git a/py/objstr.c b/py/objstr.c index 3f6aa483e..92bd71f3d 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -115,26 +115,8 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } #if MICROPY_ENABLE_SLICE } else if (MP_OBJ_IS_TYPE(rhs_in, &slice_type)) { - machine_int_t start, stop, step; - mp_obj_slice_get(rhs_in, &start, &stop, &step); - assert(step == 1); - if (start < 0) { - start = lhs_len + start; - if (start < 0) { - start = 0; - } - } else if (start > lhs_len) { - start = lhs_len; - } - if (stop <= 0) { - stop = lhs_len + stop; - // CPython returns empty string in such case - if (stop < 0) { - stop = start; - } - } else if (stop > lhs_len) { - stop = lhs_len; - } + machine_uint_t start, stop; + assert(m_seq_get_fast_slice_indexes(lhs_len, rhs_in, &start, &stop)); return mp_obj_new_str(lhs_data + start, stop - start, false); #endif } else { diff --git a/py/sequence.c b/py/sequence.c index 56718c6f8..1e851a9f8 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -23,3 +23,33 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void dest = (char*)dest + copy_sz; } } + +bool m_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) { + return false; + } + + // Unlike subscription, out-of-bounds slice indexes are never error + if (start < 0) { + start = len + start; + if (start < 0) { + start = 0; + } + } else if (start > len) { + start = len; + } + if (stop <= 0) { + stop = len + stop; + // CPython returns empty sequence in such case + if (stop < 0) { + stop = start; + } + } else if (stop > len) { + stop = len; + } + *begin = start; + *end = stop; + return true; +} -- cgit v1.2.3 From 13cfabd1b265d974e53e03d1d77eac7dc1d000e5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 2 Feb 2014 03:32:55 +0200 Subject: Implement slicing for lists. --- py/obj.h | 1 + py/objlist.c | 10 +++++++++- tests/basics/list1.py | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'py') diff --git a/py/obj.h b/py/obj.h index 45430d4a1..bed5103db 100644 --- a/py/obj.h +++ b/py/obj.h @@ -396,3 +396,4 @@ typedef struct _mp_obj_classmethod_t { // sequence helpers void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest); bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end); +#define m_seq_copy(dest, src, len, item_sz) memcpy(dest, src, len * sizeof(item_sz)) diff --git a/py/objlist.c b/py/objlist.c index b28ca8127..f3db99a63 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -136,7 +136,15 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case RT_BINARY_OP_SUBSCR: { - // list load +#if MICROPY_ENABLE_SLICE + if (MP_OBJ_IS_TYPE(rhs, &slice_type)) { + machine_uint_t start, stop; + assert(m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)); + mp_obj_list_t *res = list_new(stop - start); + m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); + return res; + } +#endif uint index = mp_get_index(o->base.type, o->len, rhs); return o->items[index]; } diff --git a/tests/basics/list1.py b/tests/basics/list1.py index 250a12b70..8dc3939dd 100644 --- a/tests/basics/list1.py +++ b/tests/basics/list1.py @@ -16,3 +16,7 @@ print(x) x += [2, 1] print(x) + +print(x[1:]) +print(x[:-1]) +print(x[2:3]) -- cgit v1.2.3 From 9ed5435061cc6ae85cd9d8556d934c0e638ffadd Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 2 Feb 2014 03:42:07 +0200 Subject: Implement slicing for tuples. --- py/objtuple.c | 11 ++++++++++- tests/basics/tuple1.py | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/basics/tuple1.py (limited to 'py') diff --git a/py/objtuple.c b/py/objtuple.c index 5f1744ea3..da714e08a 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -87,7 +88,15 @@ static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { switch (op) { case RT_BINARY_OP_SUBSCR: { - // tuple load +#if MICROPY_ENABLE_SLICE + if (MP_OBJ_IS_TYPE(rhs, &slice_type)) { + machine_uint_t start, stop; + assert(m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)); + mp_obj_tuple_t *res = mp_obj_new_tuple(stop - start, NULL); + m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); + return res; + } +#endif uint index = mp_get_index(o->base.type, o->len, rhs); return o->items[index]; } diff --git a/tests/basics/tuple1.py b/tests/basics/tuple1.py new file mode 100644 index 000000000..b64720b3e --- /dev/null +++ b/tests/basics/tuple1.py @@ -0,0 +1,16 @@ +# basic tuple functionality +x = (1, 2, 3 * 4) +print(x) +try: + x[0] = 4 +except TypeError: + print("TypeError") +print(x) +try: + x.append(5) +except AttributeError: + print("AttributeError") + +print(x[1:]) +print(x[:-1]) +print(x[2:3]) -- cgit v1.2.3 From 87e85b7dc7753bde510ec37db321574a1cc0cc47 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 2 Feb 2014 08:24:07 +0200 Subject: Implement str/bytes rich comparisons. --- py/obj.h | 1 + py/objstr.c | 12 ++++++++++ py/sequence.c | 38 ++++++++++++++++++++++++++++++++ tests/basics/string-compare.py | 50 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 tests/basics/string-compare.py (limited to 'py') diff --git a/py/obj.h b/py/obj.h index bed5103db..ca3ab1af6 100644 --- a/py/obj.h +++ b/py/obj.h @@ -397,3 +397,4 @@ typedef struct _mp_obj_classmethod_t { void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest); bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end); #define m_seq_copy(dest, src, len, item_sz) memcpy(dest, src, len * sizeof(item_sz)) +bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2); diff --git a/py/objstr.c b/py/objstr.c index 92bd71f3d..50cd31d54 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -169,6 +169,18 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data); return mp_obj_str_builder_end(s); } + + // These 2 are never passed here, dealt with as a special case in rt_binary_op(). + //case RT_BINARY_OP_EQUAL: + //case RT_BINARY_OP_NOT_EQUAL: + case RT_BINARY_OP_LESS: + case RT_BINARY_OP_LESS_EQUAL: + case RT_BINARY_OP_MORE: + case RT_BINARY_OP_MORE_EQUAL: + if (MP_OBJ_IS_STR(rhs_in)) { + GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); + return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len)); + } } return MP_OBJ_NULL; // op not supported diff --git a/py/sequence.c b/py/sequence.c index 1e851a9f8..74b4fcfdf 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -14,6 +14,8 @@ // Helpers for sequence types +#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; } + // Implements backend of sequence * integer operation. Assumes elements are // memory-adjacent in sequence. void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest) { @@ -53,3 +55,39 @@ bool m_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_ui *end = stop; return true; } + +// Special-case comparison function for sequences of bytes +// Don't pass RT_BINARY_OP_NOT_EQUAL here +bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) { + // Let's deal only with > & >= + if (op == RT_BINARY_OP_LESS || op == RT_BINARY_OP_LESS_EQUAL) { + SWAP(const byte*, data1, data2); + SWAP(uint, len1, len2); + if (op == RT_BINARY_OP_LESS) { + op = RT_BINARY_OP_MORE; + } else { + op = RT_BINARY_OP_MORE_EQUAL; + } + } + uint min_len = len1 < len2 ? len1 : len2; + int res = memcmp(data1, data2, min_len); + if (res < 0) { + return false; + } + if (res > 0) { + return true; + } + + // If we had tie in the last element... + // ... and we have lists of different lengths... + if (len1 != len2) { + if (len1 < len2) { + // ... then longer list length wins (we deal only with >) + return false; + } + } else if (op == RT_BINARY_OP_MORE) { + // Otherwise, if we have strict relation, equality means failure + return false; + } + return true; +} diff --git a/tests/basics/string-compare.py b/tests/basics/string-compare.py new file mode 100644 index 000000000..740e1959c --- /dev/null +++ b/tests/basics/string-compare.py @@ -0,0 +1,50 @@ +print("" == "") +print("" > "") +print("" < "") +print("" == "1") +print("1" == "") +print("" > "1") +print("1" > "") +print("" < "1") +print("1" < "") +print("" >= "1") +print("1" >= "") +print("" <= "1") +print("1" <= "") + +print("1" == "1") +print("1" != "1") +print("1" == "2") +print("1" == "10") + +print("1" > "1") +print("1" > "2") +print("2" > "1") +print("10" > "1") +print("1/" > "1") +print("1" > "10") +print("1" > "1/") + +print("1" < "1") +print("2" < "1") +print("1" < "2") +print("1" < "10") +print("1" < "1/") +print("10" < "1") +print("1/" < "1") + +print("1" >= "1") +print("1" >= "2") +print("2" >= "1") +print("10" >= "1") +print("1/" >= "1") +print("1" >= "10") +print("1" >= "1/") + +print("1" <= "1") +print("2" <= "1") +print("1" <= "2") +print("1" <= "10") +print("1" <= "1/") +print("10" <= "1") +print("1/" <= "1") -- cgit v1.2.3 From ea2509d92cbb222854ceb0b323b616b807dd221b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 2 Feb 2014 08:57:05 +0200 Subject: Fix assert() usage. --- py/objlist.c | 4 +++- py/objstr.c | 4 +++- py/objtuple.c | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'py') diff --git a/py/objlist.c b/py/objlist.c index f3db99a63..59a4ad6b1 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -139,7 +139,9 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { #if MICROPY_ENABLE_SLICE if (MP_OBJ_IS_TYPE(rhs, &slice_type)) { machine_uint_t start, stop; - assert(m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)); + if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) { + assert(0); + } mp_obj_list_t *res = list_new(stop - start); m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); return res; diff --git a/py/objstr.c b/py/objstr.c index 50cd31d54..03602b6ec 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -116,7 +116,9 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { #if MICROPY_ENABLE_SLICE } else if (MP_OBJ_IS_TYPE(rhs_in, &slice_type)) { machine_uint_t start, stop; - assert(m_seq_get_fast_slice_indexes(lhs_len, rhs_in, &start, &stop)); + if (!m_seq_get_fast_slice_indexes(lhs_len, rhs_in, &start, &stop)) { + assert(0); + } return mp_obj_new_str(lhs_data + start, stop - start, false); #endif } else { diff --git a/py/objtuple.c b/py/objtuple.c index da714e08a..3e5041c9d 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -91,7 +91,9 @@ static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { #if MICROPY_ENABLE_SLICE if (MP_OBJ_IS_TYPE(rhs, &slice_type)) { machine_uint_t start, stop; - assert(m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)); + if (!m_seq_get_fast_slice_indexes(o->len, rhs, &start, &stop)) { + assert(0); + } mp_obj_tuple_t *res = mp_obj_new_tuple(stop - start, NULL); m_seq_copy(res->items, o->items + start, res->len, mp_obj_t); return res; -- cgit v1.2.3