@@ -550,7 +550,7 @@ func do_UNPACK_EX(vm *Vm, counts int32) {
550
550
after := int (counts >> 8 )
551
551
totalargs := 1 + before + after
552
552
seq := vm .POP ()
553
- sp := len ( vm .frame . Stack )
553
+ sp := vm .STACK_LEVEL ( )
554
554
vm .EXTEND (make ([]py.Object , totalargs ))
555
555
unpack_iterable (vm , seq , before , after , sp + totalargs )
556
556
}
@@ -590,10 +590,6 @@ func do_MAP_ADD(vm *Vm, i int32) {
590
590
func do_RETURN_VALUE (vm * Vm , arg int32 ) {
591
591
defer vm .CheckException ()
592
592
vm .retval = vm .POP ()
593
- if len (vm .frame .Stack ) != 0 {
594
- debugf ("vmstack = %#v\n " , vm .frame .Stack )
595
- panic ("vm stack should be empty at this point" )
596
- }
597
593
vm .frame .Yielded = false
598
594
vm .why = whyReturn
599
595
}
@@ -747,7 +743,16 @@ func do_LOAD_BUILD_CLASS(vm *Vm, arg int32) {
747
743
// UNPACK_SEQUENCE).
748
744
func do_SETUP_WITH (vm * Vm , delta int32 ) {
749
745
defer vm .CheckException ()
750
- vm .NotImplemented ("SETUP_WITH" , delta )
746
+ mgr := vm .TOP ()
747
+ // exit := py.ObjectLookupSpecial(mgr, "__exit__")
748
+ exit := py .GetAttrString (mgr , "__exit__" )
749
+ vm .SET_TOP (exit )
750
+ // enter := py.ObjectLookupSpecial(mgr, "__enter__")
751
+ enter := py .GetAttrString (mgr , "__enter__" )
752
+ res := py .Call (enter , nil , nil ) // FIXME method for this?
753
+ // Setup the finally block before pushing the result of __enter__ on the stack.
754
+ vm .frame .PushBlock (py .TryBlockSetupFinally , vm .frame .Lasti + delta , vm .STACK_LEVEL ())
755
+ vm .PUSH (res )
751
756
}
752
757
753
758
// Cleans up the stack when a with statement block exits. On top of
@@ -770,7 +775,60 @@ func do_SETUP_WITH(vm *Vm, delta int32) {
770
775
// exception. (But non-local gotos should still be resumed.)
771
776
func do_WITH_CLEANUP (vm * Vm , arg int32 ) {
772
777
defer vm .CheckException ()
773
- vm .NotImplemented ("WITH_CLEANUP" , arg )
778
+ var exit_func py.Object
779
+
780
+ exc := vm .TOP ()
781
+ var val py.Object = py .None
782
+ var tb py.Object = py .None
783
+ if exc == py .None {
784
+ vm .DROP ()
785
+ exit_func = vm .TOP ()
786
+ vm .SET_TOP (exc )
787
+ } else if excInt , ok := exc .(py.Int ); ok {
788
+ vm .DROP ()
789
+ switch vmStatus (excInt ) {
790
+ case whyReturn , whyContinue :
791
+ /* Retval in TOP. */
792
+ exit_func = vm .SECOND ()
793
+ vm .SET_SECOND (vm .TOP ())
794
+ vm .SET_TOP (exc )
795
+ default :
796
+ exit_func = vm .TOP ()
797
+ vm .SET_TOP (exc )
798
+ }
799
+ exc = py .None
800
+ } else {
801
+ val = vm .SECOND ()
802
+ tb = vm .THIRD ()
803
+ tp2 := vm .FOURTH ()
804
+ exc2 := vm .PEEK (5 )
805
+ tb2 := vm .PEEK (6 )
806
+ exit_func = vm .PEEK (7 )
807
+ vm .SET_VALUE (7 , tb2 )
808
+ vm .SET_VALUE (6 , exc2 )
809
+ vm .SET_VALUE (5 , tp2 )
810
+ /* UNWIND_EXCEPT_HANDLER will pop this off. */
811
+ vm .SET_FOURTH (nil )
812
+ /* We just shifted the stack down, so we have
813
+ to tell the except handler block that the
814
+ values are lower than it expects. */
815
+ block := vm .frame .Block
816
+ if block .Type != py .TryBlockExceptHandler {
817
+ panic ("vm: WITH_CLEANUP expecting TryBlockExceptHandler" )
818
+ }
819
+ block .Level --
820
+ }
821
+ /* XXX Not the fastest way to call it... */
822
+ res := py .Call (exit_func , []py.Object {exc , val , tb }, nil )
823
+
824
+ err := false
825
+ if exc != py .None {
826
+ err = res == py .True
827
+ }
828
+ if err {
829
+ /* There was an exception and a True return */
830
+ vm .PUSH (py .Int (whySilenced ))
831
+ }
774
832
}
775
833
776
834
// All of the following opcodes expect arguments. An argument is two bytes, with the more significant byte last.
@@ -807,7 +865,7 @@ func do_UNPACK_SEQUENCE(vm *Vm, count int32) {
807
865
} else if list , ok := it .(* py.List ); ok && list .Len () == args {
808
866
vm .EXTEND_REVERSED (list .Items )
809
867
} else {
810
- sp := len ( vm .frame . Stack )
868
+ sp := vm .STACK_LEVEL ( )
811
869
vm .EXTEND (make ([]py.Object , args ))
812
870
unpack_iterable (vm , it , args , - 1 , sp + args )
813
871
}
@@ -1087,21 +1145,21 @@ func do_LOAD_GLOBAL(vm *Vm, namei int32) {
1087
1145
// from the current instruction with a size of delta bytes.
1088
1146
func do_SETUP_LOOP (vm * Vm , delta int32 ) {
1089
1147
defer vm .CheckException ()
1090
- vm .frame .PushBlock (py .TryBlockSetupLoop , vm .frame .Lasti + delta , len ( vm .frame . Stack ))
1148
+ vm .frame .PushBlock (py .TryBlockSetupLoop , vm .frame .Lasti + delta , vm .STACK_LEVEL ( ))
1091
1149
}
1092
1150
1093
1151
// Pushes a try block from a try-except clause onto the block
1094
1152
// stack. delta points to the first except block.
1095
1153
func do_SETUP_EXCEPT (vm * Vm , delta int32 ) {
1096
1154
defer vm .CheckException ()
1097
- vm .frame .PushBlock (py .TryBlockSetupExcept , vm .frame .Lasti + delta , len ( vm .frame . Stack ))
1155
+ vm .frame .PushBlock (py .TryBlockSetupExcept , vm .frame .Lasti + delta , vm .STACK_LEVEL ( ))
1098
1156
}
1099
1157
1100
1158
// Pushes a try block from a try-except clause onto the block
1101
1159
// stack. delta points to the finally block.
1102
1160
func do_SETUP_FINALLY (vm * Vm , delta int32 ) {
1103
1161
defer vm .CheckException ()
1104
- vm .frame .PushBlock (py .TryBlockSetupFinally , vm .frame .Lasti + delta , len ( vm .frame . Stack ))
1162
+ vm .frame .PushBlock (py .TryBlockSetupFinally , vm .frame .Lasti + delta , vm .STACK_LEVEL ( ))
1105
1163
}
1106
1164
1107
1165
// Store a key and value pair in a dictionary. Pops the key and value
0 commit comments