@@ -23,7 +23,15 @@ use super::vm::VirtualMachine;
23
23
use num_bigint:: BigInt ;
24
24
25
25
#[ derive( Clone , Debug ) ]
26
- enum Block {
26
+ struct Block {
27
+ /// The type of block.
28
+ typ : BlockType ,
29
+ /// The level of the value stack when the block was entered.
30
+ level : usize ,
31
+ }
32
+
33
+ #[ derive( Clone , Debug ) ]
34
+ enum BlockType {
27
35
Loop {
28
36
start : bytecode:: Label ,
29
37
end : bytecode:: Label ,
@@ -357,21 +365,21 @@ impl Frame {
357
365
}
358
366
}
359
367
bytecode:: Instruction :: SetupLoop { start, end } => {
360
- self . push_block ( Block :: Loop {
368
+ self . push_block ( BlockType :: Loop {
361
369
start : * start,
362
370
end : * end,
363
371
} ) ;
364
372
Ok ( None )
365
373
}
366
374
bytecode:: Instruction :: SetupExcept { handler } => {
367
- self . push_block ( Block :: TryExcept { handler : * handler } ) ;
375
+ self . push_block ( BlockType :: TryExcept { handler : * handler } ) ;
368
376
Ok ( None )
369
377
}
370
378
bytecode:: Instruction :: SetupWith { end } => {
371
379
let context_manager = self . pop_value ( ) ;
372
380
// Call enter:
373
381
let obj = vm. call_method ( & context_manager, "__enter__" , vec ! [ ] ) ?;
374
- self . push_block ( Block :: With {
382
+ self . push_block ( BlockType :: With {
375
383
end : * end,
376
384
context_manager : context_manager. clone ( ) ,
377
385
} ) ;
@@ -380,22 +388,23 @@ impl Frame {
380
388
}
381
389
bytecode:: Instruction :: CleanupWith { end : end1 } => {
382
390
let block = self . pop_block ( ) . unwrap ( ) ;
383
- if let Block :: With {
391
+ if let BlockType :: With {
384
392
end : end2,
385
393
context_manager,
386
- } = & block
394
+ } = & block. typ
387
395
{
388
- assert ! ( end1 == end2) ;
396
+ debug_assert ! ( end1 == end2) ;
389
397
390
398
// call exit now with no exception:
391
- self . with_exit ( vm, context_manager, None ) ?;
392
- Ok ( None )
399
+ self . with_exit ( vm, & context_manager, None ) ?;
393
400
} else {
394
- panic ! ( "Block stack is incorrect, expected a with block" ) ;
401
+ unreachable ! ( "Block stack is incorrect, expected a with block" ) ;
395
402
}
403
+
404
+ Ok ( None )
396
405
}
397
406
bytecode:: Instruction :: PopBlock => {
398
- self . pop_block ( ) ;
407
+ self . pop_block ( ) . expect ( "no pop to block" ) ;
399
408
Ok ( None )
400
409
}
401
410
bytecode:: Instruction :: GetIter => {
@@ -532,7 +541,7 @@ impl Frame {
532
541
533
542
bytecode:: Instruction :: Break => {
534
543
let block = self . unwind_loop ( vm) ;
535
- if let Block :: Loop { end, .. } = block {
544
+ if let BlockType :: Loop { end, .. } = block. typ {
536
545
self . jump ( end) ;
537
546
}
538
547
Ok ( None )
@@ -543,7 +552,7 @@ impl Frame {
543
552
}
544
553
bytecode:: Instruction :: Continue => {
545
554
let block = self . unwind_loop ( vm) ;
546
- if let Block :: Loop { start, .. } = block {
555
+ if let BlockType :: Loop { start, .. } = block. typ {
547
556
self . jump ( start) ;
548
557
} else {
549
558
assert ! ( false ) ;
@@ -711,16 +720,15 @@ impl Frame {
711
720
712
721
// Unwind all blocks:
713
722
fn unwind_blocks ( & mut self , vm : & mut VirtualMachine ) -> Option < PyObjectRef > {
714
- loop {
715
- let block = self . pop_block ( ) ;
716
- match block {
717
- Some ( Block :: Loop { .. } ) => { }
718
- Some ( Block :: TryExcept { .. } ) => {
723
+ while let Some ( block) = self . pop_block ( ) {
724
+ match block. typ {
725
+ BlockType :: Loop { .. } => { }
726
+ BlockType :: TryExcept { .. } => {
719
727
// TODO: execute finally handler
720
728
}
721
- Some ( Block :: With {
729
+ BlockType :: With {
722
730
context_manager, ..
723
- } ) => {
731
+ } => {
724
732
match self . with_exit ( vm, & context_manager, None ) {
725
733
Ok ( ..) => { }
726
734
Err ( exc) => {
@@ -729,28 +737,28 @@ impl Frame {
729
737
}
730
738
}
731
739
}
732
- None => break None ,
733
740
}
734
741
}
742
+
743
+ None
735
744
}
736
745
737
746
fn unwind_loop ( & mut self , vm : & mut VirtualMachine ) -> Block {
738
747
loop {
739
- let block = self . pop_block ( ) ;
740
- match block {
741
- Some ( Block :: Loop { .. } ) => break block. unwrap ( ) ,
742
- Some ( Block :: TryExcept { .. } ) => {
748
+ let block = self . pop_block ( ) . expect ( "not in a loop" ) ;
749
+ match block. typ {
750
+ BlockType :: Loop { .. } => break block,
751
+ BlockType :: TryExcept { .. } => {
743
752
// TODO: execute finally handler
744
753
}
745
- Some ( Block :: With {
754
+ BlockType :: With {
746
755
context_manager, ..
747
- } ) => match self . with_exit ( vm, & context_manager, None ) {
756
+ } => match self . with_exit ( vm, & context_manager, None ) {
748
757
Ok ( ..) => { }
749
758
Err ( exc) => {
750
759
panic ! ( "Exception in with __exit__ {:?}" , exc) ;
751
760
}
752
761
} ,
753
- None => panic ! ( "No block to break / continue" ) ,
754
762
}
755
763
}
756
764
}
@@ -761,18 +769,17 @@ impl Frame {
761
769
exc : PyObjectRef ,
762
770
) -> Option < PyObjectRef > {
763
771
// unwind block stack on exception and find any handlers:
764
- loop {
765
- let block = self . pop_block ( ) ;
766
- match block {
767
- Some ( Block :: TryExcept { handler } ) => {
772
+ while let Some ( block) = self . pop_block ( ) {
773
+ match block. typ {
774
+ BlockType :: TryExcept { handler } => {
768
775
self . push_value ( exc) ;
769
776
self . jump ( handler) ;
770
777
return None ;
771
778
}
772
- Some ( Block :: With {
779
+ BlockType :: With {
773
780
end,
774
781
context_manager,
775
- } ) => {
782
+ } => {
776
783
match self . with_exit ( vm, & context_manager, Some ( exc. clone ( ) ) ) {
777
784
Ok ( exit_action) => {
778
785
match objbool:: boolval ( vm, exit_action) {
@@ -797,15 +804,14 @@ impl Frame {
797
804
}
798
805
}
799
806
}
800
- Some ( Block :: Loop { .. } ) => { }
801
- None => break ,
807
+ BlockType :: Loop { .. } => { }
802
808
}
803
809
}
804
810
Some ( exc)
805
811
}
806
812
807
813
fn with_exit (
808
- & mut self ,
814
+ & self ,
809
815
vm : & mut VirtualMachine ,
810
816
context_manager : & PyObjectRef ,
811
817
exc : Option < PyObjectRef > ,
@@ -1061,12 +1067,17 @@ impl Frame {
1061
1067
self . code . locations [ self . lasti ] . clone ( )
1062
1068
}
1063
1069
1064
- fn push_block ( & mut self , block : Block ) {
1065
- self . blocks . push ( block) ;
1070
+ fn push_block ( & mut self , typ : BlockType ) {
1071
+ self . blocks . push ( Block {
1072
+ typ,
1073
+ level : self . stack . len ( ) ,
1074
+ } ) ;
1066
1075
}
1067
1076
1068
1077
fn pop_block ( & mut self ) -> Option < Block > {
1069
- self . blocks . pop ( )
1078
+ let block = self . blocks . pop ( ) ?;
1079
+ self . stack . truncate ( block. level ) ;
1080
+ Some ( block)
1070
1081
}
1071
1082
1072
1083
pub fn push_value ( & mut self , obj : PyObjectRef ) {
0 commit comments