Skip to content

Commit 84c03fa

Browse files
committed
Implement YIELD_FROM and fix YIELD
1 parent 9c120e6 commit 84c03fa

File tree

1 file changed

+49
-19
lines changed

1 file changed

+49
-19
lines changed

vm/eval.go

+49-19
Original file line numberDiff line numberDiff line change
@@ -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
117135
func 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.
521539
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
524566
}
525567

526568
// Pops TOS and yields it from a generator.
@@ -892,21 +934,12 @@ func do_JUMP_ABSOLUTE(vm *Vm, target int32) {
892934
func 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

Comments
 (0)