From 79d996a57b351e0ef354eb1e2f644b194433cc73 Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Tue, 15 Nov 2016 01:10:34 +0300
Subject: [PATCH] py/runtime: mp_resume: Handle exceptions in Python
 __next__().

This includes StopIteration and thus are important to make Python-coded
iterables work with yield from/await.

Exceptions in Python send() are still not handled and left for future
consideration and optimization.
---
 py/runtime.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/py/runtime.c b/py/runtime.c
index c25557464..4bab03b80 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1191,17 +1191,31 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
 
     mp_obj_t dest[3]; // Reserve slot for send() arg
 
+    // Python instance iterator protocol
     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;
+            nlr_buf_t nlr;
+            if (nlr_push(&nlr) == 0) {
+                *ret_val = mp_call_method_n_kw(0, 0, dest);
+                nlr_pop();
+                return MP_VM_RETURN_YIELD;
+            } else {
+                *ret_val = nlr.ret_val;
+                return MP_VM_RETURN_EXCEPTION;
+            }
         }
     }
 
+    // Either python instance generator protocol, or native object
+    // generator protocol.
     if (send_value != MP_OBJ_NULL) {
         mp_load_method(self_in, MP_QSTR_send, dest);
         dest[2] = send_value;
+        // TODO: This should have exception wrapping like __next__ case
+        // above. Not done right away to think how to optimize native
+        // generators better, see:
+        // https://github.com/micropython/micropython/issues/2628
         *ret_val = mp_call_method_n_kw(1, 0, dest);
         return MP_VM_RETURN_YIELD;
     }
-- 
GitLab