Skip to content

Commit ef89736

Browse files
committed
Implement generator send() and stub out throw() and close()
1 parent e1f0bbd commit ef89736

File tree

1 file changed

+37
-16
lines changed

1 file changed

+37
-16
lines changed

py/generator.go

+37-16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ type Generator struct {
1919

2020
var GeneratorType = NewType("generator", "generator object")
2121

22+
func init() {
23+
// FIXME would like to do this with introspection
24+
GeneratorType.Dict["send"] = NewMethod("send", func(self Object, value Object) Object {
25+
return self.(*Generator).Send(value)
26+
}, 0, "send(arg) -> send 'arg' into generator,\nreturn next yielded value or raise StopIteration.")
27+
GeneratorType.Dict["throw"] = NewMethod("throw", func(self Object, args Tuple, kwargs StringDict) Object {
28+
return self.(*Generator).Throw(args, kwargs)
29+
}, 0, "throw(typ[,val[,tb]]) -> raise exception in generator,\nreturn next yielded value or raise StopIteration.")
30+
GeneratorType.Dict["close"] = NewMethod("close", func(self Object) Object {
31+
return self.(*Generator).Close()
32+
}, 0, "close() -> raise GeneratorExit inside generator.")
33+
}
34+
2235
// Type of this object
2336
func (o *Generator) Type() *Type {
2437
return GeneratorType
@@ -51,20 +64,7 @@ func (it *Generator) M__iter__() Object {
5164
//
5265
// This method is normally called implicitly, e.g. by a for loop, or by the built-in next() function.
5366
func (it *Generator) M__next__() Object {
54-
it.Running = true
55-
res, err := RunFrame(it.Frame)
56-
it.Running = false
57-
// Push a None on the stack for next time
58-
// FIXME this value is the one sent by Send
59-
it.Frame.Stack = append(it.Frame.Stack, None)
60-
if err != nil {
61-
// Propagate the error
62-
panic(err)
63-
}
64-
if it.Frame.Yielded {
65-
return res
66-
}
67-
panic(StopIteration)
67+
return it.Send(None)
6868
}
6969

7070
// generator.send(value)
@@ -76,8 +76,29 @@ func (it *Generator) M__next__() Object {
7676
// without yielding another value. When send() is called to start the
7777
// generator, it must be called with None as the argument, because
7878
// there is no yield expression that could receive the value.
79-
func (it *Generator) Send(value Object) Object {
80-
panic("generator send not implemented")
79+
func (it *Generator) Send(arg Object) Object {
80+
if it.Running {
81+
panic(ExceptionNewf(ValueError, "generator already executing"))
82+
}
83+
if it.Frame.Lasti == 0 {
84+
if arg != None {
85+
panic(ExceptionNewf(TypeError, "can't send non-None value to a just-started generator"))
86+
}
87+
} else {
88+
// Push arg onto the frame's value stack
89+
it.Frame.Stack = append(it.Frame.Stack, arg)
90+
}
91+
it.Running = true
92+
res, err := RunFrame(it.Frame)
93+
it.Running = false
94+
if err != nil {
95+
// Propagate the error
96+
panic(err)
97+
}
98+
if it.Frame.Yielded {
99+
return res
100+
}
101+
panic(StopIteration)
81102
}
82103

83104
// generator.throw(type[, value[, traceback]])

0 commit comments

Comments
 (0)