@@ -113,6 +113,24 @@ func (vm *Vm) CheckException() {
113113 }
114114}
115115
116+ // Checks if r is StopIteration and if so returns true
117+ //
118+ // Otherwise deals with the as per vm.CheckException and returns false
119+ func (vm * Vm ) catchStopIteration (r interface {}) bool {
120+ // FIXME match subclasses of StopIteration too?
121+ if ex , ok := r .(* py.Exception ); ok && ex .Type () == py .StopIteration {
122+ // StopIteration() raised
123+ return true
124+ } else if ex , ok := r .(* py.Type ); ok && ex == py .StopIteration {
125+ // StopIteration raised
126+ return true
127+ } else {
128+ // Deal with the exception as normal
129+ vm .CheckExceptionRecover (r )
130+ }
131+ return false
132+ }
133+
116134// Illegal instruction
117135func do_ILLEGAL (vm * Vm , arg int32 ) {
118136 defer vm .CheckException ()
@@ -519,8 +537,32 @@ func do_RETURN_VALUE(vm *Vm, arg int32) {
519537
520538// Pops TOS and delegates to it as a subiterator from a generator.
521539func do_YIELD_FROM (vm * Vm , arg int32 ) {
522- defer vm .CheckException ()
523- vm .NotImplemented ("YIELD_FROM" , arg )
540+ defer func () {
541+ if r := recover (); r != nil {
542+ if vm .catchStopIteration (r ) {
543+ // No extra action needed
544+ }
545+ }
546+ }()
547+
548+ var retval py.Object
549+ u := vm .POP ()
550+ x := vm .TOP ()
551+ // send u to x
552+ if u == py .None {
553+ retval = py .Next (x )
554+ } else {
555+ retval = py .Send (x , u )
556+ }
557+ // x remains on stack, retval is value to be yielded
558+ // FIXME vm.frame.Stacktop = stack_pointer
559+ //why = exitYield
560+ // and repeat...
561+ vm .frame .Lasti --
562+
563+ vm .result = retval
564+ vm .frame .Yielded = true
565+ vm .exit = exitYield
524566}
525567
526568// Pops TOS and yields it from a generator.
@@ -892,21 +934,12 @@ func do_JUMP_ABSOLUTE(vm *Vm, target int32) {
892934func do_FOR_ITER (vm * Vm , delta int32 ) {
893935 defer func () {
894936 if r := recover (); r != nil {
895- // FIXME match subclasses of StopIteration too?
896- if ex , ok := r .(* py.Exception ); ok && ex .Type () == py .StopIteration {
897- // StopIteration() raised
898- } else if ex , ok := r .(* py.Type ); ok && ex == py .StopIteration {
899- // StopIteration raised
900- } else {
901- // Deal with the exception as normal
902- vm .CheckExceptionRecover (r )
903- return
937+ if vm .catchStopIteration (r ) {
938+ vm .DROP ()
939+ vm .frame .Lasti += delta
904940 }
905- vm .DROP ()
906- vm .frame .Lasti += delta
907941 }
908942 }()
909- // FIXME should look in instance dictionary
910943 r := py .Next (vm .TOP ())
911944 vm .PUSH (r )
912945}
@@ -1307,7 +1340,7 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
13071340 fmt .Printf ("*** Unwinding %#v vm %#v\n " , b , vm )
13081341
13091342 if vm .exit == exitYield {
1310- panic ( "Unexpected exitYield" )
1343+ return vm . result , nil
13111344 }
13121345
13131346 // Now we have to pop the block.
@@ -1363,10 +1396,7 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
13631396 }
13641397 if b .Type == SETUP_FINALLY {
13651398 if vm .exit & (exitReturn | exitContinue ) != 0 {
1366- // vm.PUSH(retval)
1367- } else {
1368- // Discard the return value on the stack
1369- vm .POP ()
1399+ vm .PUSH (vm .result )
13701400 }
13711401 vm .PUSH (py .Int (vm .exit ))
13721402 vm .exit = exitNot
0 commit comments