@@ -113,6 +113,24 @@ func (vm *Vm) CheckException() {
113
113
}
114
114
}
115
115
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
+
116
134
// Illegal instruction
117
135
func do_ILLEGAL (vm * Vm , arg int32 ) {
118
136
defer vm .CheckException ()
@@ -519,8 +537,32 @@ func do_RETURN_VALUE(vm *Vm, arg int32) {
519
537
520
538
// Pops TOS and delegates to it as a subiterator from a generator.
521
539
func 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
524
566
}
525
567
526
568
// Pops TOS and yields it from a generator.
@@ -892,21 +934,12 @@ func do_JUMP_ABSOLUTE(vm *Vm, target int32) {
892
934
func do_FOR_ITER (vm * Vm , delta int32 ) {
893
935
defer func () {
894
936
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
904
940
}
905
- vm .DROP ()
906
- vm .frame .Lasti += delta
907
941
}
908
942
}()
909
- // FIXME should look in instance dictionary
910
943
r := py .Next (vm .TOP ())
911
944
vm .PUSH (r )
912
945
}
@@ -1307,7 +1340,7 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
1307
1340
fmt .Printf ("*** Unwinding %#v vm %#v\n " , b , vm )
1308
1341
1309
1342
if vm .exit == exitYield {
1310
- panic ( "Unexpected exitYield" )
1343
+ return vm . result , nil
1311
1344
}
1312
1345
1313
1346
// Now we have to pop the block.
@@ -1363,10 +1396,7 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
1363
1396
}
1364
1397
if b .Type == SETUP_FINALLY {
1365
1398
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 )
1370
1400
}
1371
1401
vm .PUSH (py .Int (vm .exit ))
1372
1402
vm .exit = exitNot
0 commit comments