From 3754c4a04035d18b0bbb780fa0aef273e1c8f033 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 18:20:57 +0200 Subject: mp_obj_get_qstr(): Handle MP_OBJ_QSTR. --- py/obj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'py') diff --git a/py/obj.c b/py/obj.c index 42f86cf17..dd081ee35 100644 --- a/py/obj.c +++ b/py/obj.c @@ -222,7 +222,9 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { #endif qstr mp_obj_get_qstr(mp_obj_t arg) { - if (MP_OBJ_IS_TYPE(arg, &str_type)) { + if (MP_OBJ_IS_QSTR(arg)) { + return MP_OBJ_QSTR_VALUE(arg); + } else if (MP_OBJ_IS_TYPE(arg, &str_type)) { return mp_obj_str_get(arg); } else { assert(0); -- cgit v1.2.3 From dff3f896d7f7ef20762f0be7c8d5aa457c04b71a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 18:37:30 +0200 Subject: mp_identity(): Add generic identity function. Useful as getiter method for objects which are their own iterators, etc. --- py/obj.c | 6 ++++++ py/obj.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'py') diff --git a/py/obj.c b/py/obj.c index dd081ee35..7dd9cc0a2 100644 --- a/py/obj.c +++ b/py/obj.c @@ -288,3 +288,9 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { } return MP_OBJ_NEW_SMALL_INT(len); } + +// Return input argument. Useful as .getiter for objects which are +// their own iterators, etc. +mp_obj_t mp_identity(mp_obj_t self) { + return self; +} diff --git a/py/obj.h b/py/obj.h index faf023147..d7154a743 100644 --- a/py/obj.h +++ b/py/obj.h @@ -351,6 +351,8 @@ extern const mp_obj_type_t fun_native_type; extern const mp_obj_type_t fun_bc_type; void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte **code); +mp_obj_t mp_identity(mp_obj_t self); + // generator extern const mp_obj_type_t gen_instance_type; -- cgit v1.2.3 From d54bef76921ae719bcbaf4ad7f9915da10f25574 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 18:35:32 +0200 Subject: stream: Add generic unbuffered iternext method. Uses stream_unbuffered_readline underline. --- py/stream.c | 11 ++++++++++- py/stream.h | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'py') diff --git a/py/stream.c b/py/stream.c index d3a11affb..3a87d0444 100644 --- a/py/stream.c +++ b/py/stream.c @@ -137,9 +137,18 @@ static mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { // TODO: \0 vstr_add_byte(vstr, 0); vstr_shrink(vstr); - return mp_obj_new_str(qstr_from_str_take(vstr_str(vstr), vstr_len(vstr))); + return MP_OBJ_NEW_QSTR(qstr_from_str_take(vstr_str(vstr), vstr_len(vstr))); } +mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { + mp_obj_t l_in = stream_unbuffered_readline(1, &self); + const char *l = qstr_str(MP_OBJ_QSTR_VALUE(l_in)); + // TODO: \0 + if (*l != 0) { + return l_in; + } + return mp_const_stop_iteration; +} MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read); MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_readall_obj, stream_readall); diff --git a/py/stream.h b/py/stream.h index 58e807254..a0cc34797 100644 --- a/py/stream.h +++ b/py/stream.h @@ -2,3 +2,6 @@ extern const mp_obj_fun_native_t mp_stream_read_obj; extern const mp_obj_fun_native_t mp_stream_readall_obj; extern const mp_obj_fun_native_t mp_stream_unbuffered_readline_obj; extern const mp_obj_fun_native_t mp_stream_write_obj; + +// Iterator which uses mp_stream_unbuffered_readline_obj +mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self); -- cgit v1.2.3 From ff3bdea49d10ea129fafb2e8be0cdaed172a036b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 19:40:46 +0200 Subject: stream_read(): Shrink memory block to actual read size. --- py/stream.c | 1 + 1 file changed, 1 insertion(+) (limited to 'py') diff --git a/py/stream.c b/py/stream.c index 3a87d0444..34bbea2e0 100644 --- a/py/stream.c +++ b/py/stream.c @@ -30,6 +30,7 @@ static mp_obj_t stream_read(uint n_args, const mp_obj_t *args) { if (out_sz == -1) { nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", error)); } else { + buf = m_realloc(buf, sz + 1, out_sz + 1); buf[out_sz] = 0; return mp_obj_new_str(qstr_from_str_take(buf, /*out_sz,*/ sz + 1)); } -- cgit v1.2.3 From a80ff04fe7458b8ed8e948619b3700b720832ec2 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 20:32:50 +0200 Subject: Add dummy bytes() constructor. Currently, MicroPython strings are mix between CPython byte and unicode strings. So, conversion is null so far. This dummy implementation is intended for compatibility with CPython (so, same code can run on both). --- py/builtin.c | 12 ++++++++++++ py/builtin.h | 1 + py/mpqstrraw.h | 1 + py/runtime.c | 1 + 4 files changed, 15 insertions(+) (limited to 'py') diff --git a/py/builtin.c b/py/builtin.c index f102aa588..13463ada6 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -347,3 +347,15 @@ static mp_obj_t mp_builtin_str(mp_obj_t o_in) { } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_str_obj, mp_builtin_str); + +// TODO: This should be type, this is just quick CPython compat hack +static mp_obj_t mp_builtin_bytes(uint n_args, const mp_obj_t *args) { + if (!MP_OBJ_IS_QSTR(args[0]) && !MP_OBJ_IS_TYPE(args[0], &str_type)) { + assert(0); + } + // Currently, MicroPython strings are mix between CPython byte and unicode + // strings. So, conversion is null so far. + return args[0]; +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_bytes_obj, 1, 3, mp_builtin_bytes); diff --git a/py/builtin.h b/py/builtin.h index 050a2161c..4257de5bd 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -5,6 +5,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bytes_obj); // Temporary hack MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj); MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj); diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h index 10b1fc0d3..9bc01c585 100644 --- a/py/mpqstrraw.h +++ b/py/mpqstrraw.h @@ -40,6 +40,7 @@ Q(any) Q(array) Q(bool) Q(bytearray) +Q(bytes) Q(callable) Q(chr) Q(complex) diff --git a/py/runtime.c b/py/runtime.c index d8fc3ff6e..72347aff8 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -130,6 +130,7 @@ void rt_init(void) { mp_map_add_qstr(&map_builtins, MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj); mp_map_add_qstr(&map_builtins, MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj); mp_map_add_qstr(&map_builtins, MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj); + mp_map_add_qstr(&map_builtins, MP_QSTR_bytes, (mp_obj_t)&mp_builtin_bytes_obj); mp_map_add_qstr(&map_builtins, MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj); mp_map_add_qstr(&map_builtins, MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj); mp_map_add_qstr(&map_builtins, MP_QSTR_divmod, (mp_obj_t)&mp_builtin_divmod_obj); -- cgit v1.2.3 From e6da0df6d100f726dcaf90e1552fa1628bb385c1 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 23:00:26 +0200 Subject: mp_obj_get_type_str(): Handle MP_OBJ_QSTR. --- py/obj.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'py') diff --git a/py/obj.c b/py/obj.c index 7dd9cc0a2..86429d03d 100644 --- a/py/obj.c +++ b/py/obj.c @@ -28,6 +28,8 @@ mp_obj_t mp_obj_get_type(mp_obj_t o_in) { const char *mp_obj_get_type_str(mp_obj_t o_in) { if (MP_OBJ_IS_SMALL_INT(o_in)) { return "int"; + } else if (MP_OBJ_IS_QSTR(o_in)) { + return "str"; } else { mp_obj_base_t *o = o_in; return o->type->name; -- cgit v1.2.3 From 8965a5eb1e9d7df9018fc9537169f7bb9a523d9c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 20 Jan 2014 23:33:19 +0200 Subject: objstr: More support for MP_OBJ_QSTR. --- py/objstr.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'py') diff --git a/py/objstr.c b/py/objstr.c index 5e87097a8..68fe7f0fc 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -175,16 +175,8 @@ static bool chr_in_str(const char* const str, const size_t str_len, const char c static mp_obj_t str_find(uint n_args, const mp_obj_t *args) { assert(2 <= n_args && n_args <= 4); - assert(MP_OBJ_IS_TYPE(args[0], &str_type)); - if (!MP_OBJ_IS_TYPE(args[1], &str_type)) { - nlr_jump(mp_obj_new_exception_msg_1_arg( - MP_QSTR_TypeError, - "Can't convert '%s' object to str implicitly", - mp_obj_get_type_str(args[1]))); - } - - const char* haystack = qstr_str(((mp_obj_str_t*)args[0])->qstr); - const char* needle = qstr_str(((mp_obj_str_t*)args[1])->qstr); + const char* haystack = qstr_str(mp_obj_str_get(args[0])); + const char* needle = qstr_str(mp_obj_str_get(args[1])); size_t haystack_len = strlen(haystack); size_t needle_len = strlen(needle); @@ -222,14 +214,11 @@ mp_obj_t str_strip(uint n_args, const mp_obj_t *args) { if (n_args == 1) { chars_to_del = whitespace; } else { - assert(MP_OBJ_IS_TYPE(args[1], &str_type)); - mp_obj_str_t *chars_to_del_obj = args[1]; - chars_to_del = qstr_str(chars_to_del_obj->qstr); + chars_to_del = qstr_str(mp_obj_str_get(args[1])); } const size_t chars_to_del_len = strlen(chars_to_del); - mp_obj_str_t *self = args[0]; - const char *orig_str = qstr_str(self->qstr); + const char *orig_str = qstr_str(mp_obj_str_get(args[0])); const size_t orig_str_len = strlen(orig_str); size_t first_good_char_pos = 0; @@ -321,9 +310,15 @@ mp_obj_t mp_obj_new_str(qstr qstr) { } qstr mp_obj_str_get(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &str_type)); - mp_obj_str_t *self = self_in; - return self->qstr; + if (MP_OBJ_IS_QSTR(self_in)) { + return MP_OBJ_QSTR_VALUE(self_in); + } + if (MP_OBJ_IS_TYPE(self_in, &str_type)) { + mp_obj_str_t *self = self_in; + return self->qstr; + } + 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))); } /******************************************************************************/ -- cgit v1.2.3 From 439542f70c4546568dca3f2539d503aa7a6ec05b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 21 Jan 2014 00:19:19 +0200 Subject: sequence.c: Start to refactor sequence operations for reuse among types. --- py/obj.h | 3 +++ py/objlist.c | 9 ++------- py/py.mk | 1 + py/sequence.c | 25 +++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 py/sequence.c (limited to 'py') diff --git a/py/obj.h b/py/obj.h index d7154a743..c2ce32588 100644 --- a/py/obj.h +++ b/py/obj.h @@ -376,3 +376,6 @@ typedef struct _mp_obj_classmethod_t { mp_obj_base_t base; mp_obj_t fun; } mp_obj_classmethod_t; + +// sequence helpers +void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest); diff --git a/py/objlist.c b/py/objlist.c index 0ad7b6879..804384222 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -153,13 +153,8 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return NULL; } int n = MP_OBJ_SMALL_INT_VALUE(rhs); - int len = o->len; - mp_obj_list_t *s = list_new(len * n); - mp_obj_t *dest = s->items; - for (int i = 0; i < n; i++) { - memcpy(dest, o->items, sizeof(mp_obj_t) * len); - dest += len; - } + mp_obj_list_t *s = list_new(o->len * n); + mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return s; } case RT_COMPARE_OP_EQUAL: diff --git a/py/py.mk b/py/py.mk index ce5169f77..6ab1ee305 100644 --- a/py/py.mk +++ b/py/py.mk @@ -97,6 +97,7 @@ PY_O_BASENAME = \ objstr.o \ objtuple.o \ objtype.o \ + sequence.o \ stream.o \ builtin.o \ builtinimport.o \ diff --git a/py/sequence.c b/py/sequence.c new file mode 100644 index 000000000..af3c61af6 --- /dev/null +++ b/py/sequence.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +#include "nlr.h" +#include "misc.h" +#include "mpconfig.h" +#include "mpqstr.h" +#include "obj.h" +#include "map.h" +#include "runtime0.h" +#include "runtime.h" + +// Helpers for sequence types + +// 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) { + for (int i = 0; i < times; i++) { + uint copy_sz = item_sz * len; + memcpy(dest, items, copy_sz); + dest = (char*)dest + copy_sz; + } +} -- cgit v1.2.3 From 545591a696bdff73f68573c54a05ca70eb58032d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 21 Jan 2014 00:27:33 +0200 Subject: Implement string multiplication. --- py/objstr.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'py') diff --git a/py/objstr.c b/py/objstr.c index 68fe7f0fc..01de5e367 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -102,6 +102,18 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (strstr(lhs_str, rhs_str) == NULL)); } break; + case RT_BINARY_OP_MULTIPLY: + { + if (!MP_OBJ_IS_SMALL_INT(rhs_in)) { + return NULL; + } + int n = MP_OBJ_SMALL_INT_VALUE(rhs_in); + size_t len = strlen(lhs_str); + char *s = m_new(char, len * n + 1); + s[len * n] = 0; + mp_seq_multiply(lhs_str, sizeof(*lhs_str), len, n, s); + return MP_OBJ_NEW_QSTR(qstr_from_str_take(s, len * n + 1)); + } } return MP_OBJ_NULL; // op not supported -- cgit v1.2.3 From 7380a837802b4630bdcef6e01cd5be32f92750ca Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 21 Jan 2014 02:22:02 +0200 Subject: str: Implement proper string (instead of byte string) indexing. Also, support negative indexes. --- py/objstr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'py') diff --git a/py/objstr.c b/py/objstr.c index 01de5e367..4adfef6f8 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -44,9 +44,8 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // TODO: need predicate to check for int-like type (bools are such for example) // ["no", "yes"][1 == 2] is common idiom if (MP_OBJ_IS_SMALL_INT(rhs_in)) { - // TODO: This implements byte string access for single index so far - // TODO: Handle negative indexes. - return mp_obj_new_int(lhs_str[mp_obj_get_int(rhs_in)]); + uint index = mp_get_index(lhs->base.type, strlen(lhs_str), rhs_in); + return mp_obj_new_str(qstr_from_strn_copy(lhs_str + index, 1)); #if MICROPY_ENABLE_SLICE } else if (MP_OBJ_IS_TYPE(rhs_in, &slice_type)) { machine_int_t start, stop, step; -- cgit v1.2.3 From 4c316552c16fa2bcb77e007d330dc32beaf6e652 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 21 Jan 2014 05:00:21 +0200 Subject: Implement str.split(None). Note that splitting by explicit string is not implemented so far. --- py/objstr.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'py') diff --git a/py/objstr.c b/py/objstr.c index 4adfef6f8..758e8c293 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -175,6 +175,44 @@ bad_arg: nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "?str.join expecting a list of str's")); } +#define is_ws(c) ((c) == ' ' || (c) == '\t') + +static mp_obj_t str_split(uint n_args, const mp_obj_t *args) { + int splits = -1; + mp_obj_t sep = mp_const_none; + if (n_args > 1) { + sep = args[1]; + if (n_args > 2) { + splits = MP_OBJ_SMALL_INT_VALUE(args[2]); + } + } + assert(sep == mp_const_none); + mp_obj_t res = mp_obj_new_list(0, NULL); + const char *s = qstr_str(mp_obj_str_get(args[0])); + const char *start; + + // Initial whitespace is not counted as split, so we pre-do it + while (is_ws(*s)) s++; + while (*s && splits != 0) { + start = s; + while (*s != 0 && !is_ws(*s)) s++; + rt_list_append(res, MP_OBJ_NEW_QSTR(qstr_from_strn_copy(start, s - start))); + if (*s == 0) { + break; + } + while (is_ws(*s)) s++; + if (splits > 0) { + splits--; + } + } + + if (*s != 0) { + rt_list_append(res, MP_OBJ_NEW_QSTR(qstr_from_strn_copy(s, strlen(s)))); + } + + return res; +} + static bool chr_in_str(const char* const str, const size_t str_len, const char c) { for (size_t i = 0; i < str_len; i++) { if (str[i] == c) { @@ -293,12 +331,14 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); static MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split); static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); static MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, str_format); static const mp_method_t str_type_methods[] = { { "find", &str_find_obj }, { "join", &str_join_obj }, + { "split", &str_split_obj }, { "strip", &str_strip_obj }, { "format", &str_format_obj }, { NULL, NULL }, // end-of-list sentinel -- cgit v1.2.3