|
9 | 9 | #include "runtime.h" |
10 | 10 | #include "bc0.h" |
11 | 11 | #include "bc.h" |
| 12 | +#include "objgenerator.h" |
12 | 13 |
|
13 | 14 | // Value stack grows up (this makes it incompatible with native C stack, but |
14 | 15 | // makes sure that arguments to functions are in natural order arg1..argN |
@@ -138,7 +139,9 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i |
138 | 139 | // If we have exception to inject, now that we finish setting up |
139 | 140 | // execution context, raise it. This works as if RAISE_VARARGS |
140 | 141 | // bytecode was executed. |
141 | | - if (inject_exc != MP_OBJ_NULL) { |
| 142 | + // Injecting exc into yield from generator is a special case, |
| 143 | + // handled by MP_BC_YIELD_FROM itself |
| 144 | + if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) { |
142 | 145 | mp_obj_t t = inject_exc; |
143 | 146 | inject_exc = MP_OBJ_NULL; |
144 | 147 | nlr_jump(rt_make_raise_obj(t)); |
@@ -631,12 +634,64 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i |
631 | 634 | nlr_jump(rt_make_raise_obj(obj1)); |
632 | 635 |
|
633 | 636 | case MP_BC_YIELD_VALUE: |
| 637 | +yield: |
634 | 638 | nlr_pop(); |
635 | 639 | *ip_in_out = ip; |
636 | 640 | *sp_in_out = sp; |
637 | 641 | *exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); |
638 | 642 | return MP_VM_RETURN_YIELD; |
639 | 643 |
|
| 644 | + case MP_BC_YIELD_FROM: |
| 645 | + { |
| 646 | +//#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) |
| 647 | +#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) |
| 648 | + mp_vm_return_kind_t ret_kind; |
| 649 | + obj1 = POP(); |
| 650 | + mp_obj_t t = MP_OBJ_NULL; |
| 651 | + if (inject_exc != MP_OBJ_NULL) { |
| 652 | + t = inject_exc; |
| 653 | + inject_exc = MP_OBJ_NULL; |
| 654 | + obj2 = mp_obj_gen_resume(TOP(), mp_const_none, t, &ret_kind); |
| 655 | + } else { |
| 656 | + obj2 = mp_obj_gen_resume(TOP(), obj1, MP_OBJ_NULL, &ret_kind); |
| 657 | + } |
| 658 | + |
| 659 | + if (ret_kind == MP_VM_RETURN_YIELD) { |
| 660 | + ip--; |
| 661 | + PUSH(obj2); |
| 662 | + goto yield; |
| 663 | + } |
| 664 | + if (ret_kind == MP_VM_RETURN_NORMAL) { |
| 665 | + // Pop exhausted gen |
| 666 | + sp--; |
| 667 | + if (obj2 == MP_OBJ_NULL) { |
| 668 | + // Optimize StopIteration |
| 669 | + // TODO: get StopIteration's value |
| 670 | + PUSH(mp_const_none); |
| 671 | + } else { |
| 672 | + PUSH(obj2); |
| 673 | + } |
| 674 | + |
| 675 | + // if it swallowed it, we re-raise GeneratorExit |
| 676 | + if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { |
| 677 | + nlr_jump(t); |
| 678 | + } |
| 679 | + |
| 680 | + break; |
| 681 | + } |
| 682 | + if (ret_kind == MP_VM_RETURN_EXCEPTION) { |
| 683 | + // Pop exhausted gen |
| 684 | + sp--; |
| 685 | + if (EXC_MATCH(obj2, &mp_type_StopIteration)) { |
| 686 | + printf("Generator explicitly raised StopIteration\n"); |
| 687 | + PUSH(mp_const_none); |
| 688 | + break; |
| 689 | + } else { |
| 690 | + nlr_jump(obj2); |
| 691 | + } |
| 692 | + } |
| 693 | + } |
| 694 | + |
640 | 695 | case MP_BC_IMPORT_NAME: |
641 | 696 | DECODE_QSTR; |
642 | 697 | obj1 = POP(); |
|
0 commit comments