@@ -550,7 +550,7 @@ func do_UNPACK_EX(vm *Vm, counts int32) {
550550 after := int (counts >> 8 )
551551 totalargs := 1 + before + after
552552 seq := vm .POP ()
553- sp := len ( vm .frame . Stack )
553+ sp := vm .STACK_LEVEL ( )
554554 vm .EXTEND (make ([]py.Object , totalargs ))
555555 unpack_iterable (vm , seq , before , after , sp + totalargs )
556556}
@@ -590,10 +590,6 @@ func do_MAP_ADD(vm *Vm, i int32) {
590590func do_RETURN_VALUE (vm * Vm , arg int32 ) {
591591 defer vm .CheckException ()
592592 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- }
597593 vm .frame .Yielded = false
598594 vm .why = whyReturn
599595}
@@ -747,7 +743,16 @@ func do_LOAD_BUILD_CLASS(vm *Vm, arg int32) {
747743// UNPACK_SEQUENCE).
748744func do_SETUP_WITH (vm * Vm , delta int32 ) {
749745 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 )
751756}
752757
753758// 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) {
770775// exception. (But non-local gotos should still be resumed.)
771776func do_WITH_CLEANUP (vm * Vm , arg int32 ) {
772777 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+ }
774832}
775833
776834// 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) {
807865 } else if list , ok := it .(* py.List ); ok && list .Len () == args {
808866 vm .EXTEND_REVERSED (list .Items )
809867 } else {
810- sp := len ( vm .frame . Stack )
868+ sp := vm .STACK_LEVEL ( )
811869 vm .EXTEND (make ([]py.Object , args ))
812870 unpack_iterable (vm , it , args , - 1 , sp + args )
813871 }
@@ -1087,21 +1145,21 @@ func do_LOAD_GLOBAL(vm *Vm, namei int32) {
10871145// from the current instruction with a size of delta bytes.
10881146func do_SETUP_LOOP (vm * Vm , delta int32 ) {
10891147 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 ( ))
10911149}
10921150
10931151// Pushes a try block from a try-except clause onto the block
10941152// stack. delta points to the first except block.
10951153func do_SETUP_EXCEPT (vm * Vm , delta int32 ) {
10961154 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 ( ))
10981156}
10991157
11001158// Pushes a try block from a try-except clause onto the block
11011159// stack. delta points to the finally block.
11021160func do_SETUP_FINALLY (vm * Vm , delta int32 ) {
11031161 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 ( ))
11051163}
11061164
11071165// Store a key and value pair in a dictionary. Pops the key and value
0 commit comments