@@ -80,41 +80,38 @@ macro_rules! pop_stack {
80
80
}
81
81
}
82
82
83
- macro_rules! unwind {
84
- ( $call_stack: expr, $traceback: expr, $exception: expr, $exc_type: expr, $value: expr) => { {
85
- // Unwind call stack
86
- ' outer: loop {
87
- match $call_stack. pop( ) {
88
- None => panic!( "Exception reached bottom of call stack." ) ,
89
- Some ( mut frame) => {
90
- // Unwind block stack
91
- while let Some ( block) = frame. block_stack. pop( ) {
92
- match block {
93
- Block :: TryExcept ( begin, end) => {
94
- // Found a try…except block
95
- frame. block_stack. push( Block :: TryExcept ( begin, end) ) ; // Push it back, it will be poped by PopExcept.
96
- frame. program_counter = end;
97
- let traceback = $traceback;
98
- let exception = $exception;
99
- frame. var_stack. push( traceback. clone( ) ) ; // traceback
100
- frame. var_stack. push( exception. clone( ) ) ; // exception
101
- frame. var_stack. push( $exc_type) ; // exception type
83
+ /// Unwind call stack until a try…except is found.
84
+ fn unwind ( call_stack : & mut Vec < Frame > , traceback : ObjectRef , exception : ObjectRef , value : ObjectRef ) {
85
+ let exc_type = exception. clone ( ) ; // Looks like that's how CPython does things…
86
+ ' outer: loop {
87
+ match call_stack. pop ( ) {
88
+ None => panic ! ( "Exception reached bottom of call stack." ) ,
89
+ Some ( mut frame) => {
90
+ // Unwind block stack
91
+ while let Some ( block) = frame. block_stack . pop ( ) {
92
+ match block {
93
+ Block :: TryExcept ( begin, end) => {
94
+ // Found a try…except block
95
+ frame. block_stack . push ( Block :: TryExcept ( begin, end) ) ; // Push it back, it will be poped by PopExcept.
96
+ frame. program_counter = end;
97
+ frame. var_stack . push ( traceback. clone ( ) ) ;
98
+ frame. var_stack . push ( value. clone ( ) ) ;
99
+ frame. var_stack . push ( exc_type) ;
102
100
103
- frame. var_stack. push( traceback) ; // traceback
104
- frame. var_stack. push( $ value) ; // value
105
- frame. var_stack. push( exception) ; // exception
101
+ frame. var_stack . push ( traceback) ;
102
+ frame. var_stack . push ( value) ;
103
+ frame. var_stack . push ( exception) ;
106
104
107
- $call_stack. push( frame) ;
108
- break ' outer
109
- }
110
- _ => { // Non-try…except block, exit it.
111
- }
105
+ call_stack. push ( frame) ;
106
+ break ' outer
107
+ }
108
+ _ => { // Non-try…except block, exit it.
112
109
}
113
110
}
114
111
}
115
112
}
116
113
}
117
- } }
114
+ }
118
115
}
119
116
120
117
pub struct Processor < EP : EnvProxy > {
@@ -237,7 +234,7 @@ impl<EP: EnvProxy> Processor<EP> {
237
234
let res = function ( self , args) ; // Call the primitive
238
235
match res {
239
236
PyResult :: Return ( res) => call_stack. last_mut ( ) . unwrap ( ) . var_stack . push ( res) ,
240
- PyResult :: Raise ( exc, exc_type ) => unwind ! ( call_stack, self . primitive_objects. none. clone( ) , exc, exc_type , self . primitive_objects . none . clone ( ) ) ,
237
+ PyResult :: Raise ( exc, value ) => unwind ( call_stack, self . primitive_objects . none . clone ( ) , exc, value ) ,
241
238
PyResult :: Error ( err) => self . raise_runtime_error ( err) ,
242
239
} ;
243
240
}
@@ -306,13 +303,27 @@ impl<EP: EnvProxy> Processor<EP> {
306
303
pop_stack ! ( frame. block_stack) ;
307
304
}
308
305
Instruction :: EndFinally => {
309
- let frame = call_stack. last_mut ( ) . unwrap ( ) ;
310
- let status_ref = pop_stack ! ( frame. var_stack) ;
306
+ let status_ref = {
307
+ let frame = call_stack. last_mut ( ) . unwrap ( ) ;
308
+ pop_stack ! ( frame. var_stack)
309
+ } ;
311
310
let status = self . store . deref ( & status_ref) ;
312
311
match status. content {
313
312
ObjectContent :: Int ( i) => panic ! ( "TODO: finally int status" ) , // TODO
314
- ObjectContent :: OtherObject => { }
315
- _ => panic ! ( "Invalid finally status" )
313
+ ObjectContent :: OtherObject => {
314
+ let ( val, traceback) = {
315
+ let frame = call_stack. last_mut ( ) . unwrap ( ) ;
316
+ let val = pop_stack ! ( frame. var_stack) ; // Note: CPython calls this variable “exc”
317
+ let traceback = pop_stack ! ( frame. var_stack) ;
318
+ ( val, traceback)
319
+ } ;
320
+ let exc = status_ref;
321
+ call_stack. last_mut ( ) . unwrap ( ) . block_stack . pop ( ) . unwrap ( ) ; // Remove this try…except block
322
+ unwind ( call_stack, traceback, exc, val) ;
323
+ }
324
+ ObjectContent :: None => {
325
+ }
326
+ _ => panic ! ( format!( "Invalid finally status: {:?}" , status) )
316
327
}
317
328
}
318
329
Instruction :: PopExcept => {
@@ -402,8 +413,7 @@ impl<EP: EnvProxy> Processor<EP> {
402
413
}
403
414
Instruction :: RaiseVarargs ( 1 ) => {
404
415
let exception = pop_stack ! ( call_stack. last_mut( ) . unwrap( ) . var_stack) ;
405
- let exc_type = exception. clone ( ) ;
406
- unwind ! ( call_stack, self . primitive_objects. none. clone( ) , exception, exc_type, self . primitive_objects. none. clone( ) ) ;
416
+ unwind ( call_stack, self . primitive_objects . none . clone ( ) , exception, self . primitive_objects . none . clone ( ) ) ;
407
417
}
408
418
Instruction :: RaiseVarargs ( 2 ) => {
409
419
panic ! ( "RaiseVarargs(2) not implemented." )
0 commit comments