From 4bcd04bcaddeeb53779f2c067a4d1b533c888f9d Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Wed, 24 Sep 2014 14:05:40 +0100
Subject: [PATCH] py: Tidy up exception matching; allow matching of tuple of
 exceptions.

Addresses issue #864.
---
 py/obj.h       |  2 +-
 py/objexcept.c | 14 +++++++++-----
 py/runtime.c   | 21 ++++++++++++++-------
 3 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/py/obj.h b/py/obj.h
index 9fee0413a..d96e4ec75 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -458,7 +458,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
 #define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
 bool mp_obj_is_exception_type(mp_obj_t self_in);
 bool mp_obj_is_exception_instance(mp_obj_t self_in);
-bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type);
+bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type);
 void mp_obj_exception_clear_traceback(mp_obj_t self_in);
 void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block);
 void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values);
diff --git a/py/objexcept.c b/py/objexcept.c
index 6cf9cbc4b..7f0736543 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -403,11 +403,15 @@ bool mp_obj_is_exception_instance(mp_obj_t self_in) {
     return mp_obj_is_exception_type(mp_obj_get_type(self_in));
 }
 
-// return true if exception (type or instance) is a subclass of given
-// exception type.
-bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type) {
-    // TODO: move implementation from RT_BINARY_OP_EXCEPTION_MATCH here.
-    return mp_binary_op(MP_BINARY_OP_EXCEPTION_MATCH, exc, (mp_obj_t)exc_type) == mp_const_true;
+// Return true if exception (type or instance) is a subclass of given
+// exception type.  Assumes exc_type is a subclass of BaseException, as
+// defined by mp_obj_is_exception_type(exc_type).
+bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type) {
+    // if exc is an instance of an exception, then extract and use its type
+    if (mp_obj_is_exception_instance(exc)) {
+        exc = mp_obj_get_type(exc);
+    }
+    return mp_obj_is_subclass_fast(exc, exc_type);
 }
 
 // traceback handling functions
diff --git a/py/runtime.c b/py/runtime.c
index 403e98c7c..1600caa06 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -263,18 +263,25 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
     if (op == MP_BINARY_OP_EXCEPTION_MATCH) {
         // rhs must be issubclass(rhs, BaseException)
         if (mp_obj_is_exception_type(rhs)) {
-            // if lhs is an instance of an exception, then extract and use its type
-            if (mp_obj_is_exception_instance(lhs)) {
-                lhs = mp_obj_get_type(lhs);
-            }
-            if (mp_obj_is_subclass_fast(lhs, rhs)) {
+            if (mp_obj_exception_match(lhs, rhs)) {
                 return mp_const_true;
             } else {
                 return mp_const_false;
             }
+        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_tuple)) {
+            mp_obj_tuple_t *tuple = rhs;
+            for (mp_uint_t i = 0; i < tuple->len; i++) {
+                rhs = tuple->items[i];
+                if (!mp_obj_is_exception_type(rhs)) {
+                    goto unsupported_op;
+                }
+                if (mp_obj_exception_match(lhs, rhs)) {
+                    return mp_const_true;
+                }
+            }
+            return mp_const_false;
         }
-        assert(0);
-        return mp_const_false;
+        goto unsupported_op;
     }
 
     if (MP_OBJ_IS_SMALL_INT(lhs)) {
-- 
GitLab