@@ -243,7 +243,7 @@ pub enum ExecutionResult {
243243 Yield ( PyObjectRef ) ,
244244}
245245
246- // A valid execution result, or an exception
246+ /// A valid execution result, or an exception
247247pub type FrameResult = Result < Option < ExecutionResult > , PyObjectRef > ;
248248
249249impl Frame {
@@ -285,9 +285,11 @@ impl Frame {
285285 Ok ( Some ( value) ) => {
286286 break Ok ( value) ;
287287 }
288+ // Instruction raised an exception
288289 Err ( exception) => {
289- // unwind block stack on exception and find any handlers.
290- // Add an entry in the traceback:
290+ // 1. Extract traceback from exception's '__traceback__' attr.
291+ // 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
292+ // 3. Unwind block stack till appropriate handler is found.
291293 assert ! ( objtype:: isinstance(
292294 & exception,
293295 & vm. ctx. exceptions. base_exception_type
@@ -296,13 +298,12 @@ impl Frame {
296298 . get_attribute ( exception. clone ( ) , "__traceback__" )
297299 . unwrap ( ) ;
298300 trace ! ( "Adding to traceback: {:?} {:?}" , traceback, lineno) ;
299- let pos = vm. ctx . new_tuple ( vec ! [
301+ let raise_location = vm. ctx . new_tuple ( vec ! [
300302 vm. ctx. new_str( filename. clone( ) ) ,
301303 vm. ctx. new_int( lineno. get_row( ) ) ,
302304 vm. ctx. new_str( run_obj_name. clone( ) ) ,
303305 ] ) ;
304- objlist:: PyListRef :: try_from_object ( vm, traceback) ?. append ( pos, vm) ;
305- // exception.__trace
306+ objlist:: PyListRef :: try_from_object ( vm, traceback) ?. append ( raise_location, vm) ;
306307 match self . unwind_exception ( vm, exception) {
307308 None => { }
308309 Some ( exception) => {
@@ -333,7 +334,7 @@ impl Frame {
333334 ins2
334335 }
335336
336- // Execute a single instruction:
337+ /// Execute a single instruction.
337338 fn execute_instruction ( & self , vm : & VirtualMachine ) -> FrameResult {
338339 let instruction = self . fetch_instruction ( ) ;
339340 {
@@ -565,9 +566,7 @@ impl Frame {
565566 } = & block. typ
566567 {
567568 debug_assert ! ( end1 == end2) ;
568-
569- // call exit now with no exception:
570- self . with_exit ( vm, & context_manager, None ) ?;
569+ self . call_context_manager_exit_no_exception ( vm, & context_manager) ?;
571570 } else {
572571 unreachable ! ( "Block stack is incorrect, expected a with block" ) ;
573572 }
@@ -949,7 +948,7 @@ impl Frame {
949948 BlockType :: With {
950949 context_manager, ..
951950 } => {
952- match self . with_exit ( vm, & context_manager, None ) {
951+ match self . call_context_manager_exit_no_exception ( vm, & context_manager) {
953952 Ok ( ..) => { }
954953 Err ( exc) => {
955954 // __exit__ went wrong,
@@ -976,7 +975,7 @@ impl Frame {
976975 }
977976 BlockType :: With {
978977 context_manager, ..
979- } => match self . with_exit ( vm, & context_manager, None ) {
978+ } => match self . call_context_manager_exit_no_exception ( vm, & context_manager) {
980979 Ok ( ..) => { }
981980 Err ( exc) => {
982981 panic ! ( "Exception in with __exit__ {:?}" , exc) ;
@@ -1006,12 +1005,12 @@ impl Frame {
10061005 end,
10071006 context_manager,
10081007 } => {
1009- match self . with_exit ( vm, & context_manager, Some ( exc. clone ( ) ) ) {
1010- Ok ( exit_action ) => {
1011- match objbool:: boolval ( vm, exit_action ) {
1012- Ok ( handle_exception ) => {
1013- if handle_exception {
1014- // We handle the exception, so return!
1008+ match self . call_context_manager_exit ( vm, & context_manager, exc. clone ( ) ) {
1009+ Ok ( exit_result_obj ) => {
1010+ match objbool:: boolval ( vm, exit_result_obj ) {
1011+ // If __exit__ method returned True, suppress the exception and continue execution.
1012+ Ok ( suppress_exception ) => {
1013+ if suppress_exception {
10151014 self . jump ( end) ;
10161015 return None ;
10171016 } else {
@@ -1022,7 +1021,6 @@ impl Frame {
10221021 return Some ( exit_exc) ;
10231022 }
10241023 }
1025- // if objtype::isinstance
10261024 }
10271025 Err ( exit_exc) => {
10281026 // TODO: what about original exception?
@@ -1031,36 +1029,39 @@ impl Frame {
10311029 }
10321030 }
10331031 BlockType :: Loop { .. } => { }
1034- // Exception was already poped on Raised.
1032+ // Exception was already popped on Raised.
10351033 BlockType :: ExceptHandler => { }
10361034 }
10371035 }
10381036 Some ( exc)
10391037 }
10401038
1041- fn with_exit (
1039+ fn call_context_manager_exit_no_exception (
10421040 & self ,
10431041 vm : & VirtualMachine ,
10441042 context_manager : & PyObjectRef ,
1045- exc : Option < PyObjectRef > ,
10461043 ) -> PyResult {
1047- // Assume top of stack is __exit__ method:
10481044 // TODO: do we want to put the exit call on the stack?
1049- // let exit_method = self.pop_value();
1050- // let args = PyFuncArgs::default();
1051- // TODO: what happens when we got an error during handling exception?
1052- let args = if let Some ( exc) = exc {
1053- let exc_type = exc. class ( ) . into_object ( ) ;
1054- let exc_val = exc. clone ( ) ;
1055- let exc_tb = vm. ctx . none ( ) ; // TODO: retrieve traceback?
1056- vec ! [ exc_type, exc_val, exc_tb]
1057- } else {
1058- let exc_type = vm. ctx . none ( ) ;
1059- let exc_val = vm. ctx . none ( ) ;
1060- let exc_tb = vm. ctx . none ( ) ;
1061- vec ! [ exc_type, exc_val, exc_tb]
1062- } ;
1063- vm. call_method ( context_manager, "__exit__" , args)
1045+ // TODO: what happens when we got an error during execution of __exit__?
1046+ vm. call_method (
1047+ context_manager,
1048+ "__exit__" ,
1049+ vec ! [ vm. ctx. none( ) , vm. ctx. none( ) , vm. ctx. none( ) ] ,
1050+ )
1051+ }
1052+
1053+ fn call_context_manager_exit (
1054+ & self ,
1055+ vm : & VirtualMachine ,
1056+ context_manager : & PyObjectRef ,
1057+ exc : PyObjectRef ,
1058+ ) -> PyResult {
1059+ // TODO: do we want to put the exit call on the stack?
1060+ // TODO: what happens when we got an error during execution of __exit__?
1061+ let exc_type = exc. class ( ) . into_object ( ) ;
1062+ let exc_val = exc. clone ( ) ;
1063+ let exc_tb = vm. ctx . none ( ) ; // TODO: retrieve traceback?
1064+ vm. call_method ( context_manager, "__exit__" , vec ! [ exc_type, exc_val, exc_tb] )
10641065 }
10651066
10661067 fn store_name (
@@ -1131,7 +1132,7 @@ impl Frame {
11311132
11321133 fn jump ( & self , label : bytecode:: Label ) {
11331134 let target_pc = self . code . label_map [ & label] ;
1134- trace ! ( "program counter from {:?} to {:?}" , self . lasti, target_pc) ;
1135+ trace ! ( "jump from {:?} to {:?}" , self . lasti, target_pc) ;
11351136 * self . lasti . borrow_mut ( ) = target_pc;
11361137 }
11371138
0 commit comments