|
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 |
@@ -146,7 +147,9 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i |
146 | 147 | // If we have exception to inject, now that we finish setting up |
147 | 148 | // execution context, raise it. This works as if RAISE_VARARGS |
148 | 149 | // bytecode was executed. |
149 | | - if (inject_exc != MP_OBJ_NULL) { |
| 150 | + // Injecting exc into yield from generator is a special case, |
| 151 | + // handled by MP_BC_YIELD_FROM itself |
| 152 | + if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) { |
150 | 153 | mp_obj_t t = inject_exc; |
151 | 154 | inject_exc = MP_OBJ_NULL; |
152 | 155 | nlr_jump(rt_make_raise_obj(t)); |
@@ -634,12 +637,65 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i |
634 | 637 | nlr_jump(rt_make_raise_obj(obj1)); |
635 | 638 |
|
636 | 639 | case MP_BC_YIELD_VALUE: |
| 640 | +yield: |
637 | 641 | nlr_pop(); |
638 | 642 | *ip_in_out = ip; |
639 | 643 | *sp_in_out = sp; |
640 | 644 | *exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); |
641 | 645 | return MP_VM_RETURN_YIELD; |
642 | 646 |
|
| 647 | + case MP_BC_YIELD_FROM: |
| 648 | + { |
| 649 | +//#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) |
| 650 | +#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) |
| 651 | +#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { nlr_jump(t); } |
| 652 | + mp_vm_return_kind_t ret_kind; |
| 653 | + obj1 = POP(); |
| 654 | + mp_obj_t t_exc = MP_OBJ_NULL; |
| 655 | + if (inject_exc != MP_OBJ_NULL) { |
| 656 | + t_exc = inject_exc; |
| 657 | + inject_exc = MP_OBJ_NULL; |
| 658 | + ret_kind = mp_obj_gen_resume(TOP(), mp_const_none, t_exc, &obj2); |
| 659 | + } else { |
| 660 | + ret_kind = mp_obj_gen_resume(TOP(), obj1, MP_OBJ_NULL, &obj2); |
| 661 | + } |
| 662 | + |
| 663 | + if (ret_kind == MP_VM_RETURN_YIELD) { |
| 664 | + ip--; |
| 665 | + PUSH(obj2); |
| 666 | + goto yield; |
| 667 | + } |
| 668 | + if (ret_kind == MP_VM_RETURN_NORMAL) { |
| 669 | + // Pop exhausted gen |
| 670 | + sp--; |
| 671 | + if (obj2 == MP_OBJ_NULL) { |
| 672 | + // Optimize StopIteration |
| 673 | + // TODO: get StopIteration's value |
| 674 | + PUSH(mp_const_none); |
| 675 | + } else { |
| 676 | + PUSH(obj2); |
| 677 | + } |
| 678 | + |
| 679 | + // If we injected GeneratorExit downstream, then even |
| 680 | + // if it was swallowed, we re-raise GeneratorExit |
| 681 | + GENERATOR_EXIT_IF_NEEDED(t_exc); |
| 682 | + break; |
| 683 | + } |
| 684 | + if (ret_kind == MP_VM_RETURN_EXCEPTION) { |
| 685 | + // Pop exhausted gen |
| 686 | + sp--; |
| 687 | + if (EXC_MATCH(obj2, &mp_type_StopIteration)) { |
| 688 | + PUSH(mp_obj_exception_get_value(obj2)); |
| 689 | + // If we injected GeneratorExit downstream, then even |
| 690 | + // if it was swallowed, we re-raise GeneratorExit |
| 691 | + GENERATOR_EXIT_IF_NEEDED(t_exc); |
| 692 | + break; |
| 693 | + } else { |
| 694 | + nlr_jump(obj2); |
| 695 | + } |
| 696 | + } |
| 697 | + } |
| 698 | + |
643 | 699 | case MP_BC_IMPORT_NAME: |
644 | 700 | DECODE_QSTR; |
645 | 701 | obj1 = POP(); |
|
0 commit comments