From 382e8eeea23db94f2b636d993c5a10467ea19643 Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Thu, 30 Jan 2014 13:49:18 +0200
Subject: [PATCH] vm: Add basic implementation of END_FINALLY opcode.

Allows to have nested try blocks with except filters.

TODO: Don't add END_FINALLY's exception re-raise points to traceback.
---
 py/vm.c              | 16 +++++++++++++---
 tests/basics/try2.py | 11 +++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/py/vm.c b/py/vm.c
index 8f5bb1ee5..d16d79d0b 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -325,12 +325,19 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
                         break;
 
                     case MP_BC_END_FINALLY:
-                        // not implemented
+                        // not fully implemented
                         // if TOS is an exception, reraises the exception (3 values on TOS)
-                        // if TOS is an integer, does something else
                         // if TOS is None, just pops it and continues
+                        // if TOS is an integer, does something else
                         // else error
-                        assert(0);
+                        if (MP_OBJ_IS_TYPE(TOP(), &exception_type)) {
+                            nlr_jump(TOP());
+                        }
+                        if (TOP() == mp_const_none) {
+                            sp--;
+                        } else {
+                            assert(0);
+                        }
                         break;
 
                     case MP_BC_GET_ITER:
@@ -361,6 +368,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
                         // TODO need to work out how blocks work etc
                         // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
                         assert(exc_sp >= &exc_stack[0]);
+                        assert(currently_in_except_block);
                         //sp = (mp_obj_t*)(*exc_sp--);
                         //exc_sp--; // discard ip
                         currently_in_except_block = (exc_sp[0] & 1); // restore previous state
@@ -517,6 +525,8 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
             // exception occurred
 
             // set file and line number that the exception occurred at
+            // TODO: don't set traceback for exceptions re-raised by END_FINALLY.
+            // But consider how to handle nested exceptions.
             if (MP_OBJ_IS_TYPE(nlr.ret_val, &exception_type)) {
                 machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24);
                 qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
diff --git a/tests/basics/try2.py b/tests/basics/try2.py
index 1cca9e039..5cd74bec4 100644
--- a/tests/basics/try2.py
+++ b/tests/basics/try2.py
@@ -10,3 +10,14 @@ try:
     bar()
 except:
     print("except 1")
+
+try:
+    print("try 1")
+    try:
+        print("try 2")
+        foo()
+    except TypeError:
+        print("except 2")
+    bar()
+except NameError:
+    print("except 1")
-- 
GitLab