Skip to content

Commit 6c2401e

Browse files
committed
Merge pull request adafruit#165 from chipaca/builtins
added zip()
2 parents 8bc9647 + 9345100 commit 6c2401e

14 files changed

Lines changed: 155 additions & 26 deletions

File tree

py/builtin.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,5 +324,23 @@ static mp_obj_t mp_builtin_sum(int n_args, const mp_obj_t *args) {
324324
}
325325
return value;
326326
}
327-
328327
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);
328+
329+
static mp_obj_t mp_builtin_sorted(mp_obj_t args, mp_map_t *kwargs) {
330+
mp_obj_t *args_items = NULL;
331+
uint args_len = 0;
332+
333+
assert(MP_OBJ_IS_TYPE(args, &tuple_type));
334+
mp_obj_tuple_get(args, &args_len, &args_items);
335+
assert(args_len >= 1);
336+
if (args_len > 1) {
337+
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
338+
"must use keyword argument for key function"));
339+
}
340+
mp_obj_t self = list_type.make_new((mp_obj_t)&list_type, 1, args_items);
341+
mp_obj_t new_args = rt_build_tuple(1, &self);
342+
list_sort(new_args, kwargs);
343+
344+
return self;
345+
}
346+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);

py/builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_ord_obj);
2121
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_pow_obj);
2222
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_print_obj);
2323
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_range_obj);
24+
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj);
2425
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj);

py/misc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ typedef unsigned int uint;
2121
#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
2222
#define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))
2323
#define m_del_obj(type, ptr) (m_del(type, ptr, 1))
24+
#define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
2425

2526
void *m_malloc(int num_bytes);
2627
void *m_malloc0(int num_bytes);

py/mpqstrraw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@ Q(pow)
5757
Q(print)
5858
Q(range)
5959
Q(set)
60+
Q(sorted)
6061
Q(sum)
6162
Q(tuple)
6263
Q(type)
64+
Q(zip)
6365

6466
Q(append)
6567
Q(pop)

py/obj.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
5959
#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 3, 3, (mp_fun_3_t)fun_name)
6060
#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, (~((machine_uint_t)0)), (mp_fun_var_t)fun_name)
6161
#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, n_args_max, (mp_fun_var_t)fun_name)
62-
#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, 0, (~((machine_uint_t)0)), (mp_fun_kw_t)fun_name)
62+
#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, n_args_min, (~((machine_uint_t)0)), (mp_fun_kw_t)fun_name)
6363

6464
// These macros are used to declare and define constant staticmethond and classmethod objects
6565
// You can put "static" in front of the definitions to make them local
@@ -285,12 +285,14 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
285285
// tuple
286286
extern const mp_obj_type_t tuple_type;
287287
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
288+
void mp_obj_tuple_del(mp_obj_t self_in);
288289

289290
// list
290291
extern const mp_obj_type_t list_type;
291292
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
292293
void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
293294
void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
295+
mp_obj_t list_sort(mp_obj_t args, struct _mp_map_t *kwargs);
294296

295297
// dict
296298
extern const mp_obj_type_t dict_type;
@@ -306,6 +308,10 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
306308
extern const mp_obj_type_t slice_type;
307309
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step);
308310

311+
// zip
312+
extern const mp_obj_type_t zip_type;
313+
314+
309315
// functions
310316
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
311317
mp_obj_base_t base;

py/objfun.c

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,44 @@
1717

1818
// mp_obj_fun_native_t defined in obj.h
1919

20+
void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) {
21+
if (n_kw && !self->is_kw) {
22+
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
23+
"function does not take keyword arguments"));
24+
}
25+
26+
if (self->n_args_min == self->n_args_max) {
27+
if (n_args != self->n_args_min) {
28+
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
29+
"function takes %d positional arguments but %d were given",
30+
(const char*)(machine_int_t)self->n_args_min,
31+
(const char*)(machine_int_t)n_args));
32+
}
33+
} else {
34+
if (n_args < self->n_args_min) {
35+
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError,
36+
"<fun name>() missing %d required positional arguments: <list of names of params>",
37+
(const char*)(machine_int_t)(self->n_args_min - n_args)));
38+
} else if (n_args > self->n_args_max) {
39+
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError,
40+
"<fun name> expected at most %d arguments, got %d",
41+
(void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
42+
}
43+
}
44+
}
45+
2046
mp_obj_t fun_native_call_n_kw(mp_obj_t self_in, int n_args, int n_kw, const mp_obj_t *args);
2147
// args are in reverse order in the array
2248
mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
2349
mp_obj_fun_native_t *self = self_in;
50+
// check number of arguments
51+
check_nargs(self, n_args, 0);
2452
if (self->is_kw) {
2553
return fun_native_call_n_kw(self_in, n_args, 0, args);
2654
}
2755
if (self->n_args_min == self->n_args_max) {
2856
// function requires a fixed number of arguments
2957

30-
// check number of arguments
31-
if (n_args != self->n_args_min) {
32-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "function takes %d positional arguments but %d were given", (const char*)(machine_int_t)self->n_args_min, (const char*)(machine_int_t)n_args));
33-
}
34-
3558
// dispatch function call
3659
switch (self->n_args_min) {
3760
case 0:
@@ -54,12 +77,6 @@ mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
5477
} else {
5578
// function takes a variable number of arguments
5679

57-
if (n_args < self->n_args_min) {
58-
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "<fun name>() missing %d required positional arguments: <list of names of params>", (const char*)(machine_int_t)(self->n_args_min - n_args)));
59-
} else if (n_args > self->n_args_max) {
60-
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_TypeError, "<fun name> expected at most %d arguments, got %d", (void*)(machine_int_t)self->n_args_max, (void*)(machine_int_t)n_args));
61-
}
62-
6380
// TODO really the args need to be passed in as a Python tuple, as the form f(*[1,2]) can be used to pass var args
6481
mp_obj_t *args_ordered = m_new(mp_obj_t, n_args);
6582
for (int i = 0; i < n_args; i++) {
@@ -76,9 +93,7 @@ mp_obj_t fun_native_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
7693
mp_obj_t fun_native_call_n_kw(mp_obj_t self_in, int n_args, int n_kw, const mp_obj_t *args) {
7794
mp_obj_fun_native_t *self = self_in;
7895

79-
if (!self->is_kw) {
80-
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
81-
}
96+
check_nargs(self, n_args, n_kw);
8297

8398
mp_obj_t *vargs = mp_obj_new_tuple_reverse(n_args, args + 2*n_kw);
8499
mp_map_t *kw_args = mp_map_new(n_kw);

py/objlist.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,14 @@ static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, bool r
248248
}
249249
}
250250

251-
static mp_obj_t list_sort(mp_obj_t args, mp_map_t *kwargs) {
251+
mp_obj_t list_sort(mp_obj_t args, mp_map_t *kwargs) {
252252
mp_obj_t *args_items = NULL;
253253
uint args_len = 0;
254254

255255
assert(MP_OBJ_IS_TYPE(args, &tuple_type));
256256
mp_obj_tuple_get(args, &args_len, &args_items);
257257
assert(args_len >= 1);
258+
assert(MP_OBJ_IS_TYPE(args_items[0], &list_type));
258259
if (args_len > 1) {
259260
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError,
260261
"list.sort takes no positional arguments"));
@@ -380,7 +381,7 @@ static MP_DEFINE_CONST_FUN_OBJ_3(list_insert_obj, list_insert);
380381
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_pop_obj, 1, 2, list_pop);
381382
static MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, list_remove);
382383
static MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse);
383-
static MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, list_sort);
384+
static MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 0, list_sort);
384385

385386
static const mp_method_t list_type_methods[] = {
386387
{ "append", &list_append_obj },

py/objtuple.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,10 @@ mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items) {
111111
mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n);
112112
o->base.type = &tuple_type;
113113
o->len = n;
114-
for (int i = 0; i < n; i++) {
115-
o->items[i] = items[i];
114+
if (items) {
115+
for (int i = 0; i < n; i++) {
116+
o->items[i] = items[i];
117+
}
116118
}
117119
return o;
118120
}
@@ -133,8 +135,18 @@ mp_obj_t mp_obj_new_tuple_reverse(uint n, const mp_obj_t *items) {
133135
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items) {
134136
assert(MP_OBJ_IS_TYPE(self_in, &tuple_type));
135137
mp_obj_tuple_t *self = self_in;
136-
*len = self->len;
137-
*items = &self->items[0];
138+
if (len) {
139+
*len = self->len;
140+
}
141+
if (items) {
142+
*items = &self->items[0];
143+
}
144+
}
145+
146+
void mp_obj_tuple_del(mp_obj_t self_in) {
147+
assert(MP_OBJ_IS_TYPE(self_in, &tuple_type));
148+
mp_obj_tuple_t *self = self_in;
149+
m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self);
138150
}
139151

140152
/******************************************************************************/

py/objzip.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include <stdlib.h>
2+
#include <assert.h>
3+
4+
#include "misc.h"
5+
#include "mpconfig.h"
6+
#include "obj.h"
7+
#include "runtime.h"
8+
9+
typedef struct _mp_obj_zip_t {
10+
mp_obj_base_t base;
11+
int n_iters;
12+
mp_obj_t iters[];
13+
} mp_obj_zip_t;
14+
15+
static mp_obj_t zip_getiter(mp_obj_t self_in) {
16+
return self_in;
17+
}
18+
19+
static mp_obj_t zip_iternext(mp_obj_t self_in);
20+
21+
static mp_obj_t zip_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args) {
22+
/* NOTE: args are backwards */
23+
mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args);
24+
o->base.type = &zip_type;
25+
o->n_iters = n_args;
26+
for (int i = 0; i < n_args; i++) {
27+
o->iters[i] = rt_getiter(args[n_args-i-1]);
28+
}
29+
return o;
30+
}
31+
32+
const mp_obj_type_t zip_type = {
33+
{ &mp_const_type },
34+
"zip",
35+
.make_new = zip_make_new,
36+
.iternext = zip_iternext,
37+
.getiter = zip_getiter,
38+
};
39+
40+
static mp_obj_t zip_iternext(mp_obj_t self_in) {
41+
assert(MP_OBJ_IS_TYPE(self_in, &zip_type));
42+
mp_obj_zip_t *self = self_in;
43+
mp_obj_t *items;
44+
if (self->n_iters == 0) {
45+
return mp_const_stop_iteration;
46+
}
47+
mp_obj_t o = mp_obj_new_tuple(self->n_iters, NULL);
48+
mp_obj_tuple_get(o, NULL, &items);
49+
50+
for (int i = 0; i < self->n_iters; i++) {
51+
mp_obj_t next = rt_iternext(self->iters[i]);
52+
if (next == mp_const_stop_iteration) {
53+
mp_obj_tuple_del(o);
54+
return mp_const_stop_iteration;
55+
}
56+
items[i] = next;
57+
}
58+
return o;
59+
}

py/py.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ PY_O_BASENAME = \
9797
vm.o \
9898
showbc.o \
9999
repl.o \
100+
objzip.o \
100101

101102
# prepend the build destination prefix to the py object files
102103

0 commit comments

Comments
 (0)