183183#define TRACE_TICK (current_ip , current_sp , is_exception )
184184#endif // MICROPY_PY_SYS_SETTRACE
185185
186+ STATIC mp_obj_t get_active_exception (mp_exc_stack_t * exc_sp , mp_exc_stack_t * exc_stack ) {
187+ for (mp_exc_stack_t * e = exc_sp ; e >= exc_stack ; -- e ) {
188+ if (e -> prev_exc != NULL ) {
189+ return MP_OBJ_FROM_PTR (e -> prev_exc );
190+ }
191+ }
192+ return MP_OBJ_NULL ;
193+ }
194+
186195// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
187196// sp points to bottom of stack which grows up
188197// returns:
@@ -1129,13 +1138,7 @@ unwind_jump:;
11291138 ENTRY (MP_BC_RAISE_LAST ): {
11301139 MARK_EXC_IP_SELECTIVE ();
11311140 // search for the inner-most previous exception, to reraise it
1132- mp_obj_t obj = MP_OBJ_NULL ;
1133- for (mp_exc_stack_t * e = exc_sp ; e >= exc_stack ; -- e ) {
1134- if (e -> prev_exc != NULL ) {
1135- obj = MP_OBJ_FROM_PTR (e -> prev_exc );
1136- break ;
1137- }
1138- }
1141+ mp_obj_t obj = get_active_exception (exc_sp , exc_stack );
11391142 if (obj == MP_OBJ_NULL ) {
11401143 obj = mp_obj_new_exception_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("no active exception to reraise" ));
11411144 }
@@ -1145,14 +1148,30 @@ unwind_jump:;
11451148 ENTRY (MP_BC_RAISE_OBJ ): {
11461149 MARK_EXC_IP_SELECTIVE ();
11471150 mp_obj_t obj = mp_make_raise_obj (TOP ());
1151+ #if MICROPY_CPYTHON_EXCEPTION_CHAIN
1152+ mp_obj_t active_exception = get_active_exception (exc_sp , exc_stack );
1153+ if (active_exception != MP_OBJ_NULL ) {
1154+ mp_store_attr (obj , MP_QSTR___context__ , active_exception );
1155+ }
1156+ #endif
11481157 RAISE (obj );
11491158 }
11501159
11511160 ENTRY (MP_BC_RAISE_FROM ): {
11521161 MARK_EXC_IP_SELECTIVE ();
1153- mp_warning (NULL , "exception chaining not supported" );
1154- sp -- ; // ignore (pop) "from" argument
1162+ mp_obj_t cause = POP ();
11551163 mp_obj_t obj = mp_make_raise_obj (TOP ());
1164+ #if MICROPY_CPYTHON_EXCEPTION_CHAIN
1165+ // search for the inner-most previous exception, to chain it
1166+ mp_obj_t active_exception = get_active_exception (exc_sp , exc_stack );
1167+ if (active_exception != MP_OBJ_NULL ) {
1168+ mp_store_attr (obj , MP_QSTR___context__ , active_exception );
1169+ }
1170+ mp_store_attr (obj , MP_QSTR___cause__ , cause );
1171+ #else
1172+ (void )cause ;
1173+ mp_warning (NULL , "exception chaining not supported" );
1174+ #endif
11561175 RAISE (obj );
11571176 }
11581177
@@ -1391,7 +1410,10 @@ unwind_jump:;
13911410 // - constant GeneratorExit object, because it's const
13921411 // - exceptions re-raised by END_FINALLY
13931412 // - exceptions re-raised explicitly by "raise"
1394- if (nlr .ret_val != & mp_const_GeneratorExit_obj
1413+ if ( true
1414+ #if MICROPY_CONST_GENERATOREXIT_OBJ
1415+ && nlr .ret_val != & mp_static_GeneratorExit_obj
1416+ #endif
13951417 && * code_state -> ip != MP_BC_END_FINALLY
13961418 && * code_state -> ip != MP_BC_RAISE_LAST ) {
13971419 const byte * ip = code_state -> fun_bc -> bytecode ;
@@ -1434,10 +1456,19 @@ unwind_jump:;
14341456 // catch exception and pass to byte code
14351457 code_state -> ip = exc_sp -> handler ;
14361458 mp_obj_t * sp = MP_TAGPTR_PTR (exc_sp -> val_sp );
1459+ #if MICROPY_CPYTHON_EXCEPTION_CHAIN
1460+ mp_obj_t active_exception = get_active_exception (exc_sp , exc_stack );
1461+ #endif
14371462 // save this exception in the stack so it can be used in a reraise, if needed
14381463 exc_sp -> prev_exc = nlr .ret_val ;
1464+ mp_obj_t obj = MP_OBJ_FROM_PTR (nlr .ret_val );
1465+ #if MICROPY_CPYTHON_EXCEPTION_CHAIN
1466+ if (active_exception != MP_OBJ_NULL ) {
1467+ mp_store_attr (obj , MP_QSTR___context__ , active_exception );
1468+ }
1469+ #endif
14391470 // push exception object so it can be handled by bytecode
1440- PUSH (MP_OBJ_FROM_PTR ( nlr . ret_val ) );
1471+ PUSH (obj );
14411472 code_state -> sp = sp ;
14421473
14431474 #if MICROPY_STACKLESS
0 commit comments