From 9daa78943e58602f74c89a2b5b1ed225f4ccf6cc Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Tue, 14 Jan 2014 23:55:01 +0000 Subject: [PATCH 1/3] added enumerate() --- py/mpqstrraw.h | 1 + py/obj.h | 3 ++ py/objenumerate.c | 53 +++++++++++++++++++++++++++++++++ py/py.mk | 1 + py/runtime.c | 1 + tests/basics/tests/enumerate.py | 6 ++++ 6 files changed, 65 insertions(+) create mode 100644 py/objenumerate.c create mode 100644 tests/basics/tests/enumerate.py diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h index c3cda84b4..8d681c9a4 100644 --- a/py/mpqstrraw.h +++ b/py/mpqstrraw.h @@ -41,6 +41,7 @@ Q(chr) Q(complex) Q(dict) Q(divmod) +Q(enumerate) Q(float) Q(hash) Q(int) diff --git a/py/obj.h b/py/obj.h index dbf9efe20..6a6f98d0c 100644 --- a/py/obj.h +++ b/py/obj.h @@ -294,6 +294,9 @@ void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items); void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); mp_obj_t list_sort(mp_obj_t args, struct _mp_map_t *kwargs); +// enumerate +extern const mp_obj_type_t enumerate_type; + // dict extern const mp_obj_type_t dict_type; uint mp_obj_dict_len(mp_obj_t self_in); diff --git a/py/objenumerate.c b/py/objenumerate.c new file mode 100644 index 000000000..5bfd8a337 --- /dev/null +++ b/py/objenumerate.c @@ -0,0 +1,53 @@ +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "obj.h" +#include "runtime.h" + +typedef struct _mp_obj_enumerate_t { + mp_obj_base_t base; + mp_obj_t iter; + machine_int_t cur; +} mp_obj_enumerate_t; + +static mp_obj_t enumerate_getiter(mp_obj_t self_in) { + return self_in; +} + +static mp_obj_t enumerate_iternext(mp_obj_t self_in); + +/* TODO: enumerate is one of the ones that can take args or kwargs. + Sticking to args for now */ +static mp_obj_t enumerate_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) { + /* NOTE: args are backwards */ + assert(n_args > 0); + args += n_args - 1; + mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); + o->base.type = &enumerate_type; + o->iter = rt_getiter(args[0]); + o->cur = n_args > 1 ? mp_obj_get_int(args[-1]) : 0; + + return o; +} + +const mp_obj_type_t enumerate_type = { + { &mp_const_type }, + "enumerate", + .make_new = enumerate_make_new, + .iternext = enumerate_iternext, + .getiter = enumerate_getiter, +}; + +static mp_obj_t enumerate_iternext(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &enumerate_type)); + mp_obj_enumerate_t *self = self_in; + mp_obj_t next = rt_iternext(self->iter); + if (next == mp_const_stop_iteration) { + return mp_const_stop_iteration; + } else { + mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next}; + return mp_obj_new_tuple(2, items); + } +} diff --git a/py/py.mk b/py/py.mk index 95f9c0767..275c92d12 100644 --- a/py/py.mk +++ b/py/py.mk @@ -77,6 +77,7 @@ PY_O_BASENAME = \ objclosure.o \ objcomplex.o \ objdict.o \ + objenumerate.o \ objexcept.o \ objfloat.o \ objfun.o \ diff --git a/py/runtime.c b/py/runtime.c index dc3d15657..6047b90b4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -105,6 +105,7 @@ void rt_init(void) { mp_map_add_qstr(&map_builtins, MP_QSTR_complex, (mp_obj_t)&complex_type); #endif mp_map_add_qstr(&map_builtins, MP_QSTR_dict, (mp_obj_t)&dict_type); + mp_map_add_qstr(&map_builtins, MP_QSTR_enumerate, (mp_obj_t)&enumerate_type); #if MICROPY_ENABLE_FLOAT mp_map_add_qstr(&map_builtins, MP_QSTR_float, (mp_obj_t)&float_type); #endif diff --git a/tests/basics/tests/enumerate.py b/tests/basics/tests/enumerate.py new file mode 100644 index 000000000..f2bdf4f32 --- /dev/null +++ b/tests/basics/tests/enumerate.py @@ -0,0 +1,6 @@ +print(list(enumerate([]))) +print(list(enumerate([1, 2, 3]))) +print(list(enumerate([1, 2, 3], 5))) +print(list(enumerate([1, 2, 3], -5))) +print(list(enumerate(range(10000)))) + From 39b174e00a05dfaf4ac6f2e17cee4892a60e92c3 Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Wed, 15 Jan 2014 01:10:09 +0000 Subject: [PATCH 2/3] Added map --- py/mpqstrraw.h | 1 + py/obj.h | 3 +++ py/objmap.c | 55 +++++++++++++++++++++++++++++++++++++++ py/py.mk | 1 + py/runtime.c | 1 + tests/basics/tests/map.py | 4 +++ 6 files changed, 65 insertions(+) create mode 100644 py/objmap.c create mode 100644 tests/basics/tests/map.py diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h index 8d681c9a4..bbca1bb43 100644 --- a/py/mpqstrraw.h +++ b/py/mpqstrraw.h @@ -50,6 +50,7 @@ Q(issubclass) Q(iter) Q(len) Q(list) +Q(map) Q(max) Q(min) Q(next) diff --git a/py/obj.h b/py/obj.h index 00d152ec4..7779c4710 100644 --- a/py/obj.h +++ b/py/obj.h @@ -294,6 +294,9 @@ void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items); void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_list_sort(mp_obj_t args, struct _mp_map_t *kwargs); +// map (the python builtin, not the dict implementation detail) +extern const mp_obj_type_t map_type; + // enumerate extern const mp_obj_type_t enumerate_type; diff --git a/py/objmap.c b/py/objmap.c new file mode 100644 index 000000000..2e07d76b7 --- /dev/null +++ b/py/objmap.c @@ -0,0 +1,55 @@ +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "obj.h" +#include "runtime.h" + +typedef struct _mp_obj_map_t { + mp_obj_base_t base; + machine_uint_t n_iters; + mp_obj_t fun; + mp_obj_t iters[]; +} mp_obj_map_t; + +static mp_obj_t map_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) { + /* NOTE: args are backwards */ + mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1); + assert(n_args >= 2); + o->base.type = &map_type; + o->n_iters = n_args - 1; + o->fun = args[n_args - 1]; + for (int i = 0; i < n_args - 1; i++) { + o->iters[i] = rt_getiter(args[n_args-i-2]); + } + return o; +} + +static mp_obj_t map_getiter(mp_obj_t self_in) { + return self_in; +} + +static mp_obj_t map_iternext(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &map_type)); + mp_obj_map_t *self = self_in; + mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); + + for (int i = 0; i < self->n_iters; i++) { + mp_obj_t next = rt_iternext(self->iters[i]); + if (next == mp_const_stop_iteration) { + m_del(mp_obj_t, nextses, self->n_iters); + return mp_const_stop_iteration; + } + nextses[i] = next; + } + return rt_call_function_n(self->fun, self->n_iters, nextses); +} + +const mp_obj_type_t map_type = { + { &mp_const_type }, + "map", + .make_new = map_make_new, + .getiter = map_getiter, + .iternext = map_iternext, +}; diff --git a/py/py.mk b/py/py.mk index 275c92d12..ba26fc029 100644 --- a/py/py.mk +++ b/py/py.mk @@ -84,6 +84,7 @@ PY_O_BASENAME = \ objgenerator.o \ objint.o \ objlist.o \ + objmap.o \ objmodule.o \ objnone.o \ objrange.o \ diff --git a/py/runtime.c b/py/runtime.c index a76af3db7..c5292dc26 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -111,6 +111,7 @@ void rt_init(void) { #endif mp_map_add_qstr(&map_builtins, MP_QSTR_int, (mp_obj_t)&int_type); mp_map_add_qstr(&map_builtins, MP_QSTR_list, (mp_obj_t)&list_type); + mp_map_add_qstr(&map_builtins, MP_QSTR_map, (mp_obj_t)&map_type); mp_map_add_qstr(&map_builtins, MP_QSTR_set, (mp_obj_t)&set_type); mp_map_add_qstr(&map_builtins, MP_QSTR_tuple, (mp_obj_t)&tuple_type); mp_map_add_qstr(&map_builtins, MP_QSTR_type, (mp_obj_t)&mp_const_type); diff --git a/tests/basics/tests/map.py b/tests/basics/tests/map.py new file mode 100644 index 000000000..62dca44ed --- /dev/null +++ b/tests/basics/tests/map.py @@ -0,0 +1,4 @@ +print(list(map(lambda x: x & 1, range(-3, 4)))) +print(list(map(abs, range(-3, 4)))) +print(list(map(set, [[i] for i in range(-3, 4)]))) +print(list(map(pow, range(4), range(4)))) From fca456bc3c0e3c43b2ef598ba1b352e0c27a2778 Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Wed, 15 Jan 2014 01:37:08 +0000 Subject: [PATCH 3/3] added filter() --- py/mpqstrraw.h | 1 + py/obj.h | 3 ++ py/objfilter.c | 53 ++++++++++++++++++++++++++++++++++++ py/py.mk | 1 + py/runtime.c | 1 + tests/basics/tests/filter.py | 2 ++ 6 files changed, 61 insertions(+) create mode 100644 py/objfilter.c create mode 100644 tests/basics/tests/filter.py diff --git a/py/mpqstrraw.h b/py/mpqstrraw.h index bbca1bb43..f6b4444a7 100644 --- a/py/mpqstrraw.h +++ b/py/mpqstrraw.h @@ -42,6 +42,7 @@ Q(complex) Q(dict) Q(divmod) Q(enumerate) +Q(filter) Q(float) Q(hash) Q(int) diff --git a/py/obj.h b/py/obj.h index 7779c4710..c2182863a 100644 --- a/py/obj.h +++ b/py/obj.h @@ -300,6 +300,9 @@ extern const mp_obj_type_t map_type; // enumerate extern const mp_obj_type_t enumerate_type; +// filter +extern const mp_obj_type_t filter_type; + // dict extern const mp_obj_type_t dict_type; uint mp_obj_dict_len(mp_obj_t self_in); diff --git a/py/objfilter.c b/py/objfilter.c new file mode 100644 index 000000000..6696ffe32 --- /dev/null +++ b/py/objfilter.c @@ -0,0 +1,53 @@ +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "obj.h" +#include "runtime.h" + +typedef struct _mp_obj_filter_t { + mp_obj_base_t base; + mp_obj_t fun; + mp_obj_t iter; +} mp_obj_filter_t; + +static mp_obj_t filter_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) { + /* NOTE: args are backwards */ + mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t); + assert(n_args == 2); + o->base.type = &filter_type; + o->fun = args[1]; + o->iter = rt_getiter(args[0]); + return o; +} + +static mp_obj_t filter_getiter(mp_obj_t self_in) { + return self_in; +} + +static mp_obj_t filter_iternext(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &filter_type)); + mp_obj_filter_t *self = self_in; + mp_obj_t next; + while ((next = rt_iternext(self->iter)) != mp_const_stop_iteration) { + mp_obj_t val; + if (self->fun != mp_const_none) { + val = rt_call_function_n(self->fun, 1, &next); + } else { + val = next; + } + if (rt_is_true(val)) { + return next; + } + } + return mp_const_stop_iteration; +} + +const mp_obj_type_t filter_type = { + { &mp_const_type }, + "filter", + .make_new = filter_make_new, + .getiter = filter_getiter, + .iternext = filter_iternext, +}; diff --git a/py/py.mk b/py/py.mk index ba26fc029..daf2f5934 100644 --- a/py/py.mk +++ b/py/py.mk @@ -79,6 +79,7 @@ PY_O_BASENAME = \ objdict.o \ objenumerate.o \ objexcept.o \ + objfilter.o \ objfloat.o \ objfun.o \ objgenerator.o \ diff --git a/py/runtime.c b/py/runtime.c index c5292dc26..04c098de3 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -106,6 +106,7 @@ void rt_init(void) { #endif mp_map_add_qstr(&map_builtins, MP_QSTR_dict, (mp_obj_t)&dict_type); mp_map_add_qstr(&map_builtins, MP_QSTR_enumerate, (mp_obj_t)&enumerate_type); + mp_map_add_qstr(&map_builtins, MP_QSTR_filter, (mp_obj_t)&filter_type); #if MICROPY_ENABLE_FLOAT mp_map_add_qstr(&map_builtins, MP_QSTR_float, (mp_obj_t)&float_type); #endif diff --git a/tests/basics/tests/filter.py b/tests/basics/tests/filter.py new file mode 100644 index 000000000..5883e3d00 --- /dev/null +++ b/tests/basics/tests/filter.py @@ -0,0 +1,2 @@ +print(list(filter(lambda x: x & 1, range(-3, 4)))) +print(list(filter(None, range(-3, 4))))