From 5e34a113eaaf736fb4f703a3ee0892e1705d0a63 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 24 Nov 2017 13:04:24 +1100 Subject: py/runtime: Add MP_BINARY_OP_CONTAINS as reverse of MP_BINARY_OP_IN. Before this patch MP_BINARY_OP_IN had two meanings: coming from bytecode it meant that the args needed to be swapped, but coming from within the runtime meant that the args were already in the correct order. This lead to some confusion in the code and comments stating how args were reversed. It also lead to 2 bugs: 1) containment for a subclass of a native type didn't work; 2) the expression "{True} in True" would illegally succeed and return True. In both of these cases it was because the args to MP_BINARY_OP_IN ended up being reversed twice. To fix these things this patch introduces MP_BINARY_OP_CONTAINS which corresponds exactly to the __contains__ special method, and this is the operator that built-in types should implement. MP_BINARY_OP_IN is now only emitted by the compiler and is converted to MP_BINARY_OP_CONTAINS by swapping the arguments. --- tests/micropython/viper_error.py.exp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/micropython') diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index 96be5a590..a44fb3ff0 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -18,7 +18,7 @@ ViperTypeError('must raise an object',) ViperTypeError('unary op __pos__ not implemented',) ViperTypeError('unary op __neg__ not implemented',) ViperTypeError('unary op __invert__ not implemented',) -ViperTypeError('binary op __contains__ not implemented',) +ViperTypeError('binary op not implemented',) NotImplementedError('native yield',) NotImplementedError('native yield from',) NotImplementedError('conversion to object',) -- cgit v1.2.3 From e02cb9ec318580497dbb17f369a61d9e932094e5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 11:56:20 +0200 Subject: tests/heapalloc_*: Refactor some tests to work in strict stackless mode. In strict stackless mode, it's not possible to make a function call with heap locked (because function activation record aka frame is allocated on heap). So, if the only purpose of function is to introduce local variable scope, move heap lock/unlock calls inside the function. --- tests/micropython/heapalloc_exc_raise.py | 4 ++-- tests/micropython/heapalloc_iter.py | 4 ++-- tests/micropython/heapalloc_traceback.py | 4 ++-- tests/micropython/heapalloc_traceback.py.exp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'tests/micropython') diff --git a/tests/micropython/heapalloc_exc_raise.py b/tests/micropython/heapalloc_exc_raise.py index d60e14ce5..fb63a84bf 100644 --- a/tests/micropython/heapalloc_exc_raise.py +++ b/tests/micropython/heapalloc_exc_raise.py @@ -5,6 +5,7 @@ import micropython e = ValueError("error") def func(): + micropython.heap_lock() try: # This works as is because traceback is not allocated # if not possible (heap is locked, no memory). If heap @@ -16,8 +17,7 @@ def func(): raise e except Exception as e2: print(e2) + micropython.heap_unlock() -micropython.heap_lock() func() print("ok") -micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_iter.py b/tests/micropython/heapalloc_iter.py index 79461f999..30ac82e14 100644 --- a/tests/micropython/heapalloc_iter.py +++ b/tests/micropython/heapalloc_iter.py @@ -11,8 +11,10 @@ except (ImportError, AttributeError): heap_lock = heap_unlock = lambda:0 def do_iter(l): + heap_lock() for i in l: print(i) + heap_unlock() def gen_func(): yield 1 @@ -55,7 +57,6 @@ print(sum(t)) heap_unlock() # test iterating over collections with the heap locked -heap_lock() do_iter(b'123') do_iter(ba) do_iter(ar) @@ -66,4 +67,3 @@ do_iter(s) do_iter(fs) do_iter(g1) do_iter(g2) -heap_unlock() diff --git a/tests/micropython/heapalloc_traceback.py b/tests/micropython/heapalloc_traceback.py index f4212b6ce..813dea4b2 100644 --- a/tests/micropython/heapalloc_traceback.py +++ b/tests/micropython/heapalloc_traceback.py @@ -16,17 +16,17 @@ except: pass def test(): + micropython.heap_lock() global global_exc global_exc.__traceback__ = None try: raise global_exc except StopIteration: print('StopIteration') + micropython.heap_unlock() # call test() with heap allocation disabled -micropython.heap_lock() test() -micropython.heap_unlock() # print the exception that was raised buf = uio.StringIO() diff --git a/tests/micropython/heapalloc_traceback.py.exp b/tests/micropython/heapalloc_traceback.py.exp index 291bbd697..facd0af13 100644 --- a/tests/micropython/heapalloc_traceback.py.exp +++ b/tests/micropython/heapalloc_traceback.py.exp @@ -1,5 +1,5 @@ StopIteration Traceback (most recent call last): - File , line 22, in test + File , line 23, in test StopIteration: -- cgit v1.2.3 From 016f83053669ee56561bebd8e9b65dac77b670ac Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 11:58:44 +0200 Subject: tests/heapalloc, heapalloc_super: Skip in strict stackless mode. These tests involves testing allocation-free function calling, and in strict stackless mode, it's not possible to make a function call with heap locked (because function activation record aka frame is allocated on the heap). --- tests/micropython/heapalloc.py | 9 +++++++++ tests/micropython/heapalloc_super.py | 9 +++++++++ 2 files changed, 18 insertions(+) (limited to 'tests/micropython') diff --git a/tests/micropython/heapalloc.py b/tests/micropython/heapalloc.py index 62f26df6a..f74bb92c8 100644 --- a/tests/micropython/heapalloc.py +++ b/tests/micropython/heapalloc.py @@ -2,6 +2,15 @@ import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + def f1(a): print(a) diff --git a/tests/micropython/heapalloc_super.py b/tests/micropython/heapalloc_super.py index 1cf5293d2..a8c23393e 100644 --- a/tests/micropython/heapalloc_super.py +++ b/tests/micropython/heapalloc_super.py @@ -1,6 +1,15 @@ # test super() operations which don't require allocation import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + class A: def foo(self): print('A foo') -- cgit v1.2.3 From 6031957473a15f62ecbe59b9d27e58e9d06a4d8a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 14 Feb 2018 16:46:44 +1100 Subject: tests: Automatically skip tests that require eval, exec or frozenset. --- tests/basics/builtin_eval.py | 6 ++++++ tests/basics/builtin_eval_error.py | 6 ++++++ tests/basics/builtin_exec.py | 8 ++++++++ tests/basics/fun_calldblstar2.py | 6 ++++++ tests/basics/lexer.py | 7 +++++++ tests/basics/python34.py | 6 ++++++ tests/basics/syntaxerror.py | 6 ++++++ tests/micropython/heapalloc_iter.py | 3 ++- 8 files changed, 47 insertions(+), 1 deletion(-) (limited to 'tests/micropython') diff --git a/tests/basics/builtin_eval.py b/tests/basics/builtin_eval.py index 8b9d02e61..9b49a2015 100644 --- a/tests/basics/builtin_eval.py +++ b/tests/basics/builtin_eval.py @@ -1,5 +1,11 @@ # builtin eval +try: + eval +except NameError: + print("SKIP") + raise SystemExit + eval('1 + 2') eval('1 + 2\n') eval('1 + 2\n\n#comment\n') diff --git a/tests/basics/builtin_eval_error.py b/tests/basics/builtin_eval_error.py index 671eedab6..ef0a32da0 100644 --- a/tests/basics/builtin_eval_error.py +++ b/tests/basics/builtin_eval_error.py @@ -1,5 +1,11 @@ # test if eval raises SyntaxError +try: + eval +except NameError: + print("SKIP") + raise SystemExit + try: print(eval("[1,,]")) except SyntaxError: diff --git a/tests/basics/builtin_exec.py b/tests/basics/builtin_exec.py index fd4e65c53..2e417a43a 100644 --- a/tests/basics/builtin_exec.py +++ b/tests/basics/builtin_exec.py @@ -1,3 +1,11 @@ +# test builtin exec + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + print(exec("def foo(): return 42")) print(foo()) diff --git a/tests/basics/fun_calldblstar2.py b/tests/basics/fun_calldblstar2.py index cf982ef5b..8795eaf15 100644 --- a/tests/basics/fun_calldblstar2.py +++ b/tests/basics/fun_calldblstar2.py @@ -1,5 +1,11 @@ # test passing a string object as the key for a keyword argument +try: + exec +except NameError: + print("SKIP") + raise SystemExit + # they key in this dict is a string object and is not interned args = {'thisisaverylongargumentname': 123} diff --git a/tests/basics/lexer.py b/tests/basics/lexer.py index 244de8cb9..181d62db1 100644 --- a/tests/basics/lexer.py +++ b/tests/basics/lexer.py @@ -1,5 +1,12 @@ # test the lexer +try: + eval + exec +except NameError: + print("SKIP") + raise SystemExit + # __debug__ is a special symbol print(type(__debug__)) diff --git a/tests/basics/python34.py b/tests/basics/python34.py index d5cc59ad6..36531f11c 100644 --- a/tests/basics/python34.py +++ b/tests/basics/python34.py @@ -1,5 +1,11 @@ # tests that differ when running under Python 3.4 vs 3.5/3.6 +try: + exec +except NameError: + print("SKIP") + raise SystemExit + # from basics/fun_kwvarargs.py # test evaluation order of arguments (in 3.4 it's backwards, 3.5 it's fixed) def f4(*vargs, **kwargs): diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index 843459f0b..8e706c6e2 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -1,5 +1,11 @@ # test syntax errors +try: + exec +except NameError: + print("SKIP") + raise SystemExit + def test_syntax(code): try: exec(code) diff --git a/tests/micropython/heapalloc_iter.py b/tests/micropython/heapalloc_iter.py index 30ac82e14..163e17211 100644 --- a/tests/micropython/heapalloc_iter.py +++ b/tests/micropython/heapalloc_iter.py @@ -1,7 +1,8 @@ # test that iterating doesn't use the heap try: + frozenset import array -except ImportError: +except (NameError, ImportError): print("SKIP") raise SystemExit -- cgit v1.2.3 From c607b58efe9333ab92e1b721dcd974e35a9d393e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 10:59:09 +1100 Subject: tests: Move heap-realloc-while-locked test from C to Python. This test for calling gc_realloc() while the GC is locked can be done in pure Python, so better to do it that way since it can then be tested on more ports. --- ports/unix/coverage.c | 8 +------- tests/micropython/heap_lock.py | 11 +++++++++++ tests/micropython/heap_lock.py.exp | 1 + tests/unix/extra_coverage.py.exp | 1 - 4 files changed, 13 insertions(+), 8 deletions(-) (limited to 'tests/micropython') diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index db97f4f77..33533ad86 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -169,14 +169,8 @@ STATIC mp_obj_t extra_coverage(void) { gc_free(NULL); gc_unlock(); - // calling gc_realloc while GC is locked - void *p = gc_alloc(4, false); - gc_lock(); - mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 8, true)); - gc_unlock(); - // using gc_realloc to resize to 0, which means free the memory - p = gc_alloc(4, false); + void *p = gc_alloc(4, false); mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); // calling gc_nbytes with a non-heap pointer diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py index 0f0a70eff..ca3f5806a 100644 --- a/tests/micropython/heap_lock.py +++ b/tests/micropython/heap_lock.py @@ -2,13 +2,24 @@ import micropython +l = [] +l2 = list(range(100)) + micropython.heap_lock() +# general allocation on the heap try: print([]) except MemoryError: print('MemoryError') +# expansion of a heap block +try: + l.extend(l2) +except MemoryError: + print('MemoryError') + micropython.heap_unlock() +# check that allocation works after an unlock print([]) diff --git a/tests/micropython/heap_lock.py.exp b/tests/micropython/heap_lock.py.exp index 67b208cfc..819c32663 100644 --- a/tests/micropython/heap_lock.py.exp +++ b/tests/micropython/heap_lock.py.exp @@ -1,2 +1,3 @@ MemoryError +MemoryError [] diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index a686e7161..d2e557fdc 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -16,7 +16,6 @@ abc # GC 0 0 -0 # vstr tests sts -- cgit v1.2.3 From 5995a199a327b81553189d53035c586d7b0249dc Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 01:06:40 +1000 Subject: tests/micropython: Add set of tests for extreme cases of raising exc's. --- tests/micropython/extreme_exc.py | 75 ++++++++++++++++++++++++++++++++++++ tests/micropython/extreme_exc.py.exp | 5 +++ 2 files changed, 80 insertions(+) create mode 100644 tests/micropython/extreme_exc.py create mode 100644 tests/micropython/extreme_exc.py.exp (limited to 'tests/micropython') diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py new file mode 100644 index 000000000..c180f7cc1 --- /dev/null +++ b/tests/micropython/extreme_exc.py @@ -0,0 +1,75 @@ +# test some extreme cases of allocating exceptions and tracebacks + +import micropython + +# some ports need to allocate heap for the emergency exception +try: + micropython.alloc_emergency_exception_buf(256) +except AttributeError: + pass + +def main(): + # create an exception with many args while heap is locked + # should revert to empty tuple for args + micropython.heap_lock() + e = Exception(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + micropython.heap_unlock() + print(repr(e)) + + # create an exception with a long formatted error message while heap is locked + # should use emergency exception buffer and truncate the message + def f(): + pass + micropython.heap_lock() + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)[:50]) + + # create an exception with a long formatted error message while heap is low + # should use the heap and truncate the message + lst = [] + while 1: + try: + lst = [lst] + except MemoryError: + break + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + lst = None + print(repr(e)) + + # raise a deep exception with the heap locked + # should use emergency exception and be unable to resize traceback array + def g(): + g() + micropython.heap_lock() + try: + g() + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)) + + # create an exception on the heap with some traceback on the heap, but then + # raise it with the heap locked so it can't allocate any more traceback + exc = Exception('my exception') + try: + raise exc + except: + pass + def h(e): + raise e + micropython.heap_lock() + try: + h(exc) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)) + +main() diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp new file mode 100644 index 000000000..d7d65e03f --- /dev/null +++ b/tests/micropython/extreme_exc.py.exp @@ -0,0 +1,5 @@ +Exception() +TypeError("unexpected keyword argument 'abcdefghij +TypeError("unexpected keyword argument 'abc",) +RuntimeError('maximum recursion depth exceeded',) +Exception('my exception',) -- cgit v1.2.3 From 4caadc3c013a24af8eaaad846a8eca931cd5653e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 02:33:48 +1000 Subject: tests/micropython/extreme_exc.py: Fix test to run on more ports/configs. --- tests/micropython/extreme_exc.py | 12 +++++++++++- tests/micropython/extreme_exc.py.exp | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'tests/micropython') diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py index c180f7cc1..86c5fed19 100644 --- a/tests/micropython/extreme_exc.py +++ b/tests/micropython/extreme_exc.py @@ -2,6 +2,15 @@ import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on the heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + # some ports need to allocate heap for the emergency exception try: micropython.alloc_emergency_exception_buf(256) @@ -40,8 +49,9 @@ def main(): f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) except Exception as er: e = er + lst[0] = None lst = None - print(repr(e)) + print(repr(e)[:43]) # raise a deep exception with the heap locked # should use emergency exception and be unable to resize traceback array diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp index d7d65e03f..33f942cbc 100644 --- a/tests/micropython/extreme_exc.py.exp +++ b/tests/micropython/extreme_exc.py.exp @@ -1,5 +1,5 @@ Exception() TypeError("unexpected keyword argument 'abcdefghij -TypeError("unexpected keyword argument 'abc",) +TypeError("unexpected keyword argument 'abc RuntimeError('maximum recursion depth exceeded',) Exception('my exception',) -- cgit v1.2.3 From b9c78425a66234c45ac5c0b159773363d185d914 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 5 Apr 2018 03:03:16 +1000 Subject: tests/micropython/extreme_exc.py: Allow to run without any emg exc buf. --- tests/micropython/extreme_exc.py | 6 +++--- tests/micropython/extreme_exc.py.exp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tests/micropython') diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py index 86c5fed19..b9db96406 100644 --- a/tests/micropython/extreme_exc.py +++ b/tests/micropython/extreme_exc.py @@ -35,7 +35,7 @@ def main(): except Exception as er: e = er micropython.heap_unlock() - print(repr(e)[:50]) + print(repr(e)[:10]) # create an exception with a long formatted error message while heap is low # should use the heap and truncate the message @@ -51,7 +51,7 @@ def main(): e = er lst[0] = None lst = None - print(repr(e)[:43]) + print(repr(e)[:10]) # raise a deep exception with the heap locked # should use emergency exception and be unable to resize traceback array @@ -63,7 +63,7 @@ def main(): except Exception as er: e = er micropython.heap_unlock() - print(repr(e)) + print(repr(e)[:13]) # create an exception on the heap with some traceback on the heap, but then # raise it with the heap locked so it can't allocate any more traceback diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp index 33f942cbc..956257e4c 100644 --- a/tests/micropython/extreme_exc.py.exp +++ b/tests/micropython/extreme_exc.py.exp @@ -1,5 +1,5 @@ Exception() -TypeError("unexpected keyword argument 'abcdefghij -TypeError("unexpected keyword argument 'abc -RuntimeError('maximum recursion depth exceeded',) +TypeError( +TypeError( +RuntimeError( Exception('my exception',) -- cgit v1.2.3 From e686c940525c5b87d02e3dd7bfcdec23cfa996dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 19 May 2018 00:30:42 +1000 Subject: py/emit: Combine yield value and yield-from emit funcs into one. Reduces code size by: bare-arm: -24 minimal x86: -72 unix x64: -200 unix nanbox: -72 stm32: -52 cc3200: -32 esp8266: -84 esp32: -24 --- py/compile.c | 8 ++++---- py/emit.h | 10 ++++++---- py/emitbc.c | 16 +++++----------- py/emitnative.c | 11 +++-------- tests/micropython/viper_error.py.exp | 2 +- 5 files changed, 19 insertions(+), 28 deletions(-) (limited to 'tests/micropython') diff --git a/py/compile.c b/py/compile.c index 4d985a07f..743034e57 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1699,7 +1699,7 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_yield_from(compiler_t *comp) { EMIT_ARG(get_iter, false); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_from); + EMIT_ARG(yield, MP_EMIT_YIELD_FROM); } #if MICROPY_PY_ASYNC_AWAIT @@ -2621,14 +2621,14 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; compile_node(comp, pns->nodes[0]); compile_yield_from(comp); } else { compile_node(comp, pns->nodes[0]); - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } } @@ -2862,7 +2862,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn // no more nested if/for; compile inner expression compile_node(comp, pn_inner_expr); if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); EMIT(pop_top); } else { EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5); diff --git a/py/emit.h b/py/emit.h index 5fe3c3d1f..c85df0a67 100644 --- a/py/emit.h +++ b/py/emit.h @@ -59,6 +59,10 @@ typedef enum { #define MP_EMIT_IDOP_LOCAL_FAST (0) #define MP_EMIT_IDOP_LOCAL_DEREF (1) +// Kind for emit->yield() +#define MP_EMIT_YIELD_VALUE (0) +#define MP_EMIT_YIELD_FROM (1) + typedef struct _emit_t emit_t; typedef struct _mp_emit_method_table_id_ops_t { @@ -137,8 +141,7 @@ typedef struct _emit_method_table_t { void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void (*return_value)(emit_t *emit); void (*raise_varargs)(emit_t *emit, mp_uint_t n_args); - void (*yield_value)(emit_t *emit); - void (*yield_from)(emit_t *emit); + void (*yield)(emit_t *emit, int kind); // these methods are used to control entry to/exit from an exception handler // they may or may not emit code @@ -252,8 +255,7 @@ void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_ void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void mp_emit_bc_return_value(emit_t *emit); void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_yield_value(emit_t *emit); -void mp_emit_bc_yield_from(emit_t *emit); +void mp_emit_bc_yield(emit_t *emit, int kind); void mp_emit_bc_start_except_handler(emit_t *emit); void mp_emit_bc_end_except_handler(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 28d32d4ea..bff2c5a4c 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -931,16 +931,11 @@ void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); } -void mp_emit_bc_yield_value(emit_t *emit) { - emit_bc_pre(emit, 0); - emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE); -} - -void mp_emit_bc_yield_from(emit_t *emit) { - emit_bc_pre(emit, -1); +void mp_emit_bc_yield(emit_t *emit, int kind) { + MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM); + emit_bc_pre(emit, -kind); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM); + emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind); } void mp_emit_bc_start_except_handler(emit_t *emit) { @@ -1034,8 +1029,7 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_call_method, mp_emit_bc_return_value, mp_emit_bc_raise_varargs, - mp_emit_bc_yield_value, - mp_emit_bc_yield_from, + mp_emit_bc_yield, mp_emit_bc_start_except_handler, mp_emit_bc_end_except_handler, diff --git a/py/emitnative.c b/py/emitnative.c index 9e16ef4bd..26bcebfcb 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -2170,16 +2170,12 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { emit_call(emit, MP_F_NATIVE_RAISE); } -STATIC void emit_native_yield_value(emit_t *emit) { +STATIC void emit_native_yield(emit_t *emit, int kind) { // not supported (for now) (void)emit; + (void)kind; mp_raise_NotImplementedError("native yield"); } -STATIC void emit_native_yield_from(emit_t *emit) { - // not supported (for now) - (void)emit; - mp_raise_NotImplementedError("native yield from"); -} STATIC void emit_native_start_except_handler(emit_t *emit) { // This instruction follows an nlr_pop, so the stack counter is back to zero, when really @@ -2278,8 +2274,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_call_method, emit_native_return_value, emit_native_raise_varargs, - emit_native_yield_value, - emit_native_yield_from, + emit_native_yield, emit_native_start_except_handler, emit_native_end_except_handler, diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index a44fb3ff0..3a8cb0299 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -20,6 +20,6 @@ ViperTypeError('unary op __neg__ not implemented',) ViperTypeError('unary op __invert__ not implemented',) ViperTypeError('binary op not implemented',) NotImplementedError('native yield',) -NotImplementedError('native yield from',) +NotImplementedError('native yield',) NotImplementedError('conversion to object',) NotImplementedError('casting',) -- cgit v1.2.3