diff options
-rw-r--r-- | py/bc.h | 6 | ||||
-rw-r--r-- | py/obj.h | 3 | ||||
-rw-r--r-- | py/objarray.c | 1 | ||||
-rw-r--r-- | py/objdict.c | 2 | ||||
-rw-r--r-- | py/objgenerator.c | 9 | ||||
-rw-r--r-- | py/objgetitemiter.c | 1 | ||||
-rw-r--r-- | py/objlist.c | 1 | ||||
-rw-r--r-- | py/objrange.c | 1 | ||||
-rw-r--r-- | py/objset.c | 1 | ||||
-rw-r--r-- | py/objstr.c | 2 | ||||
-rw-r--r-- | py/objtuple.c | 5 | ||||
-rw-r--r-- | py/objzip.c | 6 | ||||
-rw-r--r-- | py/runtime.c | 200 | ||||
-rw-r--r-- | py/runtime.h | 8 | ||||
-rw-r--r-- | py/vm.c | 73 | ||||
-rw-r--r-- | tests/basics/fun-calldblstar.py | 17 | ||||
-rw-r--r-- | tests/basics/fun-callstar.py | 33 | ||||
-rw-r--r-- | tests/basics/fun-callstardblstar.py | 17 | ||||
-rw-r--r-- | tests/basics/gen-yield-from-ducktype.py | 44 | ||||
-rw-r--r-- | tests/basics/gen-yield-from-iter.py | 8 | ||||
-rw-r--r-- | tests/basics/iter-of-iter.py | 8 |
21 files changed, 429 insertions, 17 deletions
@@ -1,9 +1,3 @@ -typedef enum { - MP_VM_RETURN_NORMAL, - MP_VM_RETURN_YIELD, - MP_VM_RETURN_EXCEPTION, -} mp_vm_return_kind_t; - // Exception stack entry typedef struct _mp_exc_stack { const byte *handler; @@ -421,6 +421,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items); void mp_obj_tuple_del(mp_obj_t self_in); machine_int_t mp_obj_tuple_hash(mp_obj_t self_in); +mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args); // list mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); @@ -486,7 +487,7 @@ typedef struct _mp_obj_static_class_method_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_t) memcpy(dest, src, len * sizeof(item_t)) -#define m_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, len1 * sizeof(item_t)); memcpy(dest + len1, src2, len2 * sizeof(item_t)); } +#define m_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); } bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2); bool mp_seq_cmp_objs(int op, const mp_obj_t *items1, uint len1, const mp_obj_t *items2, uint len2); mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args); diff --git a/py/objarray.c b/py/objarray.c index ea8654b45..c91c553e3 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -219,6 +219,7 @@ STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t array_it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = array_it_iternext, }; diff --git a/py/objdict.c b/py/objdict.c index a9dbb76c4..01c7294a4 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -107,6 +107,7 @@ mp_obj_t dict_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t mp_type_dict_it = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = dict_it_iternext, }; @@ -336,6 +337,7 @@ STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t dict_view_it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = dict_view_it_iternext, }; diff --git a/py/objgenerator.c b/py/objgenerator.c index 0b342dc50..780c111bd 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -135,7 +135,14 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o return ret; case MP_VM_RETURN_EXCEPTION: - nlr_jump(ret); + // TODO: Optimization of returning MP_OBJ_NULL is really part + // of mp_iternext() protocol, but this function is called by other methods + // too, which may not handled MP_OBJ_NULL. + if (mp_obj_is_subclass_fast(mp_obj_get_type(ret), &mp_type_StopIteration)) { + return MP_OBJ_NULL; + } else { + nlr_jump(ret); + } default: assert(0); diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index 09235640a..da0e4760c 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -38,6 +38,7 @@ STATIC mp_obj_t it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = it_iternext }; diff --git a/py/objlist.c b/py/objlist.c index 1030a862a..244d4a596 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -408,6 +408,7 @@ mp_obj_t list_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t mp_type_list_it = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = list_it_iternext, }; diff --git a/py/objrange.c b/py/objrange.c index c527dfa89..64d92457b 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -63,6 +63,7 @@ STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) { STATIC const mp_obj_type_t range_it_type = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = range_it_iternext, }; diff --git a/py/objset.c b/py/objset.c index 2cabf6c50..439c6e96e 100644 --- a/py/objset.c +++ b/py/objset.c @@ -72,6 +72,7 @@ STATIC mp_obj_t set_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ const mp_obj_type_t mp_type_set_it = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = set_it_iternext, }; diff --git a/py/objstr.c b/py/objstr.c index 2dd7015c5..751f93afd 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -885,6 +885,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t mp_type_str_it = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = str_it_iternext, }; @@ -903,6 +904,7 @@ STATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t mp_type_bytes_it = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = bytes_it_iternext, }; diff --git a/py/objtuple.c b/py/objtuple.c index 618664060..d6a5bb3d0 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -30,7 +30,7 @@ void tuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_o print(env, ")"); } -STATIC mp_obj_t tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { +mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // TODO check n_kw == 0 switch (n_args) { @@ -175,7 +175,7 @@ const mp_obj_type_t mp_type_tuple = { { &mp_type_type }, .name = MP_QSTR_tuple, .print = tuple_print, - .make_new = tuple_make_new, + .make_new = mp_obj_tuple_make_new, .unary_op = tuple_unary_op, .binary_op = tuple_binary_op, .getiter = tuple_getiter, @@ -251,6 +251,7 @@ STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) { STATIC const mp_obj_type_t mp_type_tuple_it = { { &mp_type_type }, .name = MP_QSTR_iterator, + .getiter = mp_identity, .iternext = tuple_it_iternext, }; diff --git a/py/objzip.c b/py/objzip.c index d26b77d7a..9ed8b56f6 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -25,10 +25,6 @@ STATIC mp_obj_t zip_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ return o; } -STATIC mp_obj_t zip_getiter(mp_obj_t self_in) { - return self_in; -} - STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); mp_obj_zip_t *self = self_in; @@ -54,6 +50,6 @@ const mp_obj_type_t mp_type_zip = { { &mp_type_type }, .name = MP_QSTR_zip, .make_new = zip_make_new, - .getiter = zip_getiter, + .getiter = mp_identity, .iternext = zip_iternext, }; diff --git a/py/runtime.c b/py/runtime.c index ed01a5be0..489886496 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -7,6 +7,7 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objtuple.h" #include "objmodule.h" #include "parsenum.h" #include "runtime0.h" @@ -16,6 +17,7 @@ #include "builtintables.h" #include "bc.h" #include "intdivmod.h" +#include "objgenerator.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -503,6 +505,148 @@ mp_obj_t mp_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args) { return mp_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust); } +mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args, mp_obj_t pos_seq, mp_obj_t kw_dict) { + mp_obj_t fun = *args++; + mp_obj_t self = MP_OBJ_NULL; + if (have_self) { + self = *args++; // may be MP_OBJ_NULL + } + uint n_args = n_args_n_kw & 0xff; + uint n_kw = (n_args_n_kw >> 8) & 0xff; + + DEBUG_OP_printf("call method var (fun=%p, self=%p, n_args=%u, n_kw=%u, args=%p, seq=%p, dict=%p)\n", fun, self, n_args, n_kw, args, pos_seq, kw_dict); + + // We need to create the following array of objects: + // args[0 .. n_args] unpacked(pos_seq) args[n_args .. n_args + 2 * n_kw] unpacked(kw_dict) + // TODO: optimize one day to avoid constructing new arg array? Will be hard. + + // The new args array + mp_obj_t *args2; + uint args2_alloc; + uint args2_len = 0; + + // Try to get a hint for the size of the kw_dict + uint kw_dict_len = 0; + if (kw_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + kw_dict_len = mp_obj_dict_len(kw_dict); + } + + // Extract the pos_seq sequence to the new args array. + // Note that it can be arbitrary iterator. + if (pos_seq == MP_OBJ_NULL) { + // no sequence + + // allocate memory for the new array of args + args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len); + args2 = m_new(mp_obj_t, args2_alloc); + + // copy the self + if (self != MP_OBJ_NULL) { + args2[args2_len++] = self; + } + + // copy the fixed pos args + m_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); + args2_len += n_args; + + } else if (MP_OBJ_IS_TYPE(pos_seq, &mp_type_tuple) || MP_OBJ_IS_TYPE(pos_seq, &mp_type_list)) { + // optimise the case of a tuple and list + + // get the items + uint len; + mp_obj_t *items; + mp_obj_get_array(pos_seq, &len, &items); + + // allocate memory for the new array of args + args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len); + args2 = m_new(mp_obj_t, args2_alloc); + + // copy the self + if (self != MP_OBJ_NULL) { + args2[args2_len++] = self; + } + + // copy the fixed and variable position args + m_seq_cat(args2 + args2_len, args, n_args, items, len, mp_obj_t); + args2_len += n_args + len; + + } else { + // generic iterator + + // allocate memory for the new array of args + args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3; + args2 = m_new(mp_obj_t, args2_alloc); + + // copy the self + if (self != MP_OBJ_NULL) { + args2[args2_len++] = self; + } + + // copy the fixed position args + m_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); + + // extract the variable position args from the iterator + mp_obj_t iterable = mp_getiter(pos_seq); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) { + if (args2_len >= args2_alloc) { + args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2); + args2_alloc *= 2; + } + args2[args2_len++] = item; + } + } + + // The size of the args2 array now is the number of positional args. + uint pos_args_len = args2_len; + + // Copy the fixed kw args. + m_seq_copy(args2 + args2_len, args + n_args, 2 * n_kw, mp_obj_t); + args2_len += 2 * n_kw; + + // Extract (key,value) pairs from kw_dict dictionary and append to args2. + // Note that it can be arbitrary iterator. + if (kw_dict == MP_OBJ_NULL) { + // pass + } else if (MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + // dictionary + mp_map_t *map = mp_obj_dict_get_map(kw_dict); + assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above + for (uint i = 0; i < map->alloc; i++) { + if (map->table[i].key != MP_OBJ_NULL) { + args2[args2_len++] = map->table[i].key; + args2[args2_len++] = map->table[i].value; + } + } + } else { + // generic mapping + // TODO is calling 'items' on the mapping the correct thing to do here? + mp_obj_t dest[2]; + mp_load_method(kw_dict, MP_QSTR_items, dest); + mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest)); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) { + if (args2_len + 1 >= args2_alloc) { + uint new_alloc = args2_alloc * 2; + if (new_alloc < 4) { + new_alloc = 4; + } + args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); + args2_alloc = new_alloc; + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(item, 2, &items); + args2[args2_len++] = items[0]; + args2[args2_len++] = items[1]; + } + } + + mp_obj_t res = mp_call_function_n_kw(fun, pos_args_len, (args2_len - pos_args_len) / 2, args2); + m_del(mp_obj_t, args2, args2_alloc); + + return res; +} + mp_obj_t mp_build_tuple(int n_args, mp_obj_t *items) { return mp_obj_new_tuple(n_args, items); } @@ -760,6 +904,62 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { } } +// TODO: Unclear what to do with StopIterarion exception here. +mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + + if (type == &mp_type_gen_instance) { + return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val); + } + + if (type->iternext != NULL && send_value == mp_const_none) { + mp_obj_t ret = type->iternext(self_in); + if (ret != MP_OBJ_NULL) { + *ret_val = ret; + return MP_VM_RETURN_YIELD; + } else { + // Emulate raise StopIteration() + // Special case, handled in vm.c + *ret_val = MP_OBJ_NULL; + return MP_VM_RETURN_NORMAL; + } + } + + mp_obj_t dest[3]; // Reserve slot for send() arg + + if (send_value == mp_const_none) { + mp_load_method_maybe(self_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + *ret_val = mp_call_method_n_kw(0, 0, dest); + return MP_VM_RETURN_YIELD; + } + } + + if (send_value != MP_OBJ_NULL) { + mp_load_method(self_in, MP_QSTR_send, dest); + dest[2] = send_value; + *ret_val = mp_call_method_n_kw(1, 0, dest); + return MP_VM_RETURN_YIELD; + } + + if (throw_value != MP_OBJ_NULL) { + if (mp_obj_is_subclass_fast(mp_obj_get_type(throw_value), &mp_type_GeneratorExit)) { + mp_load_method_maybe(self_in, MP_QSTR_close, dest); + if (dest[0] != MP_OBJ_NULL) { + *ret_val = mp_call_method_n_kw(0, 0, dest); + // We assume one can't "yield" from close() + return MP_VM_RETURN_NORMAL; + } + } + mp_load_method(self_in, MP_QSTR_throw, dest); + *ret_val = mp_call_method_n_kw(1, 0, &throw_value); + return MP_VM_RETURN_YIELD; + } + + assert(0); + return MP_VM_RETURN_NORMAL; // Should be unreachable +} + mp_obj_t mp_make_raise_obj(mp_obj_t o) { DEBUG_printf("raise %p\n", o); if (mp_obj_is_exception_type(o)) { diff --git a/py/runtime.h b/py/runtime.h index b3d70d939..f79cb2e30 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -1,3 +1,9 @@ +typedef enum { + MP_VM_RETURN_NORMAL, + MP_VM_RETURN_YIELD, + MP_VM_RETURN_EXCEPTION, +} mp_vm_return_kind_t; + void mp_init(void); void mp_deinit(void); @@ -37,6 +43,7 @@ mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); mp_obj_t mp_call_function_n_kw_for_native(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args); mp_obj_t mp_call_function_n_kw(mp_obj_t fun, uint n_args, uint n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args); +mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args, mp_obj_t pos_seq, mp_obj_t kw_dict); mp_obj_t mp_build_tuple(int n_args, mp_obj_t *items); mp_obj_t mp_build_list(int n_args, mp_obj_t *items); @@ -54,6 +61,7 @@ void mp_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val); mp_obj_t mp_getiter(mp_obj_t o); mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_NULL instead of raising StopIteration() mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_NULL instead of raising StopIteration(...) +mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val); mp_obj_t mp_make_raise_obj(mp_obj_t o); @@ -1,4 +1,5 @@ #include <stdio.h> +#include <string.h> #include <assert.h> #include "nlr.h" @@ -670,6 +671,40 @@ unwind_jump: SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); break; + case MP_BC_CALL_FUNCTION_VAR: + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq <- TOS + obj1 = POP(); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); + SET_TOP(mp_call_method_n_kw_var(false, unum, sp, obj1, MP_OBJ_NULL)); + break; + + case MP_BC_CALL_FUNCTION_KW: + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun arg0 arg1 ... kw0 val0 kw1 val1 ... dict <- TOS + obj1 = POP(); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); + SET_TOP(mp_call_method_n_kw_var(false, unum, sp, MP_OBJ_NULL, obj1)); + break; + + case MP_BC_CALL_FUNCTION_VAR_KW: + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS + obj2 = POP(); + obj1 = POP(); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); + SET_TOP(mp_call_method_n_kw_var(false, unum, sp, obj1, obj2)); + break; + case MP_BC_CALL_METHOD: DECODE_UINT; // unum & 0xff == n_positional @@ -678,6 +713,40 @@ unwind_jump: SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); break; + case MP_BC_CALL_METHOD_VAR: + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq <- TOS + obj1 = POP(); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; + SET_TOP(mp_call_method_n_kw_var(true, unum, sp, obj1, MP_OBJ_NULL)); + break; + + case MP_BC_CALL_METHOD_KW: + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... dict <- TOS + obj1 = POP(); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; + SET_TOP(mp_call_method_n_kw_var(true, unum, sp, MP_OBJ_NULL, obj1)); + break; + + case MP_BC_CALL_METHOD_VAR_KW: + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS + obj2 = POP(); + obj1 = POP(); + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; + SET_TOP(mp_call_method_n_kw_var(true, unum, sp, obj1, obj2)); + break; + case MP_BC_RETURN_VALUE: unwind_return: while (exc_sp >= exc_stack) { @@ -739,9 +808,9 @@ yield: if (inject_exc != MP_OBJ_NULL) { t_exc = inject_exc; inject_exc = MP_OBJ_NULL; - ret_kind = mp_obj_gen_resume(TOP(), mp_const_none, t_exc, &obj2); + ret_kind = mp_resume(TOP(), mp_const_none, t_exc, &obj2); } else { - ret_kind = mp_obj_gen_resume(TOP(), obj1, MP_OBJ_NULL, &obj2); + ret_kind = mp_resume(TOP(), obj1, MP_OBJ_NULL, &obj2); } if (ret_kind == MP_VM_RETURN_YIELD) { diff --git a/tests/basics/fun-calldblstar.py b/tests/basics/fun-calldblstar.py new file mode 100644 index 000000000..aae9828cf --- /dev/null +++ b/tests/basics/fun-calldblstar.py @@ -0,0 +1,17 @@ +# test calling a function with keywords given by **dict + +def f(a, b): + print(a, b) + +f(1, **{'b':2}) +f(1, **{'b':val for val in range(1)}) + +# test calling a method with keywords given by **dict + +class A: + def f(self, a, b): + print(a, b) + +a = A() +a.f(1, **{'b':2}) +a.f(1, **{'b':val for val in range(1)}) diff --git a/tests/basics/fun-callstar.py b/tests/basics/fun-callstar.py new file mode 100644 index 000000000..255563b26 --- /dev/null +++ b/tests/basics/fun-callstar.py @@ -0,0 +1,33 @@ +# function calls with *pos + +def foo(a, b, c): + print(a, b, c) + +foo(*(1, 2, 3)) +foo(1, *(2, 3)) +foo(1, 2, *(3,)) +foo(1, 2, 3, *()) + +# Another sequence type +foo(1, 2, *[100]) + +# Iterator +foo(*range(3)) + +# method calls with *pos + +class A: + def foo(self, a, b, c): + print(a, b, c) + +a = A() +a.foo(*(1, 2, 3)) +a.foo(1, *(2, 3)) +a.foo(1, 2, *(3,)) +a.foo(1, 2, 3, *()) + +# Another sequence type +a.foo(1, 2, *[100]) + +# Iterator +a.foo(*range(3)) diff --git a/tests/basics/fun-callstardblstar.py b/tests/basics/fun-callstardblstar.py new file mode 100644 index 000000000..f2fd29107 --- /dev/null +++ b/tests/basics/fun-callstardblstar.py @@ -0,0 +1,17 @@ +# test calling a function with *tuple and **dict + +def f(a, b, c, d): + print(a, b, c, d) + +f(*(1, 2), **{'c':3, 'd':4}) +f(*(1, 2), **{['c', 'd'][i]:(3 + i) for i in range(2)}) + +# test calling a method with *tuple and **dict + +class A: + def f(self, a, b, c, d): + print(a, b, c, d) + +a = A() +a.f(*(1, 2), **{'c':3, 'd':4}) +a.f(*(1, 2), **{['c', 'd'][i]:(3 + i) for i in range(2)}) diff --git a/tests/basics/gen-yield-from-ducktype.py b/tests/basics/gen-yield-from-ducktype.py new file mode 100644 index 000000000..aa0109c91 --- /dev/null +++ b/tests/basics/gen-yield-from-ducktype.py @@ -0,0 +1,44 @@ +class MyGen: + + def __init__(self): + self.v = 0 + + def __iter__(self): + return self + + def __next__(self): + self.v += 1 + if self.v > 5: + raise StopIteration + return self.v + +def gen(): + yield from MyGen() + +def gen2(): + yield from gen() + +print(list(gen())) +print(list(gen2())) + + +class Incrementer: + + def __iter__(self): + return self + + def __next__(self): + return self.send(None) + + def send(self, val): + if val is None: + return "Incrementer initialized" + return val + 1 + +def gen3(): + yield from Incrementer() + +g = gen3() +print(next(g)) +print(g.send(5)) +print(g.send(100)) diff --git a/tests/basics/gen-yield-from-iter.py b/tests/basics/gen-yield-from-iter.py new file mode 100644 index 000000000..2d06328fb --- /dev/null +++ b/tests/basics/gen-yield-from-iter.py @@ -0,0 +1,8 @@ +def gen(): + yield from (1, 2, 3) + +def gen2(): + yield from gen() + +print(list(gen())) +print(list(gen2())) diff --git a/tests/basics/iter-of-iter.py b/tests/basics/iter-of-iter.py new file mode 100644 index 000000000..93368612b --- /dev/null +++ b/tests/basics/iter-of-iter.py @@ -0,0 +1,8 @@ +i = iter(iter((1, 2, 3))) +print(list(i)) +i = iter(iter([1, 2, 3])) +print(list(i)) +i = iter(iter({1:2, 3:4, 5:6})) +print(list(i)) +i = iter(iter({1, 2, 3})) +print(list(i)) |