183
183
#define TRACE_TICK (current_ip , current_sp , is_exception )
184
184
#endif // MICROPY_PY_SYS_SETTRACE
185
185
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
+
186
195
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
187
196
// sp points to bottom of stack which grows up
188
197
// returns:
@@ -1129,13 +1138,7 @@ unwind_jump:;
1129
1138
ENTRY (MP_BC_RAISE_LAST ): {
1130
1139
MARK_EXC_IP_SELECTIVE ();
1131
1140
// 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 );
1139
1142
if (obj == MP_OBJ_NULL ) {
1140
1143
obj = mp_obj_new_exception_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("no active exception to reraise" ));
1141
1144
}
@@ -1145,14 +1148,30 @@ unwind_jump:;
1145
1148
ENTRY (MP_BC_RAISE_OBJ ): {
1146
1149
MARK_EXC_IP_SELECTIVE ();
1147
1150
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
1148
1157
RAISE (obj );
1149
1158
}
1150
1159
1151
1160
ENTRY (MP_BC_RAISE_FROM ): {
1152
1161
MARK_EXC_IP_SELECTIVE ();
1153
- mp_warning (NULL , "exception chaining not supported" );
1154
- sp -- ; // ignore (pop) "from" argument
1162
+ mp_obj_t cause = POP ();
1155
1163
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
1156
1175
RAISE (obj );
1157
1176
}
1158
1177
@@ -1391,7 +1410,10 @@ unwind_jump:;
1391
1410
// - constant GeneratorExit object, because it's const
1392
1411
// - exceptions re-raised by END_FINALLY
1393
1412
// - 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
1395
1417
&& * code_state -> ip != MP_BC_END_FINALLY
1396
1418
&& * code_state -> ip != MP_BC_RAISE_LAST ) {
1397
1419
const byte * ip = code_state -> fun_bc -> bytecode ;
@@ -1434,10 +1456,19 @@ unwind_jump:;
1434
1456
// catch exception and pass to byte code
1435
1457
code_state -> ip = exc_sp -> handler ;
1436
1458
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
1437
1462
// save this exception in the stack so it can be used in a reraise, if needed
1438
1463
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
1439
1470
// push exception object so it can be handled by bytecode
1440
- PUSH (MP_OBJ_FROM_PTR ( nlr . ret_val ) );
1471
+ PUSH (obj );
1441
1472
code_state -> sp = sp ;
1442
1473
1443
1474
#if MICROPY_STACKLESS
0 commit comments