summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/bc.h6
-rw-r--r--py/obj.h3
-rw-r--r--py/objarray.c1
-rw-r--r--py/objdict.c2
-rw-r--r--py/objgenerator.c9
-rw-r--r--py/objgetitemiter.c1
-rw-r--r--py/objlist.c1
-rw-r--r--py/objrange.c1
-rw-r--r--py/objset.c1
-rw-r--r--py/objstr.c2
-rw-r--r--py/objtuple.c5
-rw-r--r--py/objzip.c6
-rw-r--r--py/runtime.c200
-rw-r--r--py/runtime.h8
-rw-r--r--py/vm.c73
-rw-r--r--tests/basics/fun-calldblstar.py17
-rw-r--r--tests/basics/fun-callstar.py33
-rw-r--r--tests/basics/fun-callstardblstar.py17
-rw-r--r--tests/basics/gen-yield-from-ducktype.py44
-rw-r--r--tests/basics/gen-yield-from-iter.py8
-rw-r--r--tests/basics/iter-of-iter.py8
21 files changed, 429 insertions, 17 deletions
diff --git a/py/bc.h b/py/bc.h
index 62151a3d3..fb672ea03 100644
--- a/py/bc.h
+++ b/py/bc.h
@@ -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;
diff --git a/py/obj.h b/py/obj.h
index 20e2e5eee..a34d5407a 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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);
diff --git a/py/vm.c b/py/vm.c
index 8e16c12ff..edcad3956 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -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))