Skip to content

Commit d269d78

Browse files
committed
fix trampoline stripping to (appropriately) isomorphic with that in fasttco.py; fix handling of generator return values in gtco
1 parent b824de4 commit d269d78

File tree

1 file changed

+17
-19
lines changed

1 file changed

+17
-19
lines changed

unpythonic/gtco.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from functools import wraps
88
from inspect import isgenerator
99

10-
from unpythonic.dynscope import dyn
11-
1210
def gtco(generator):
1311
"""Low-level function: run a generator with TCO enabled.
1412
@@ -23,15 +21,19 @@ def gen():
2321
assert tuple(take(6, gtco(gen()))) == (1, 2, 1, 2, 1, 2)
2422
last(take(10000, gtco(gen()))) # no crash
2523
"""
26-
with dyn.let(_gtrampoline_active=True):
27-
while True: # trampoline
28-
x = yield from generator # yield stuff, get final result (return ...)
29-
if isgenerator(x) or isinstance(x, _TrampolinedGenerator):
30-
generator = x
31-
else:
32-
if x: # usually this is None, but allow for an iterable
33-
yield from x # the last batch!
34-
break
24+
while True: # trampoline
25+
x = yield from generator # yield stuff, get final result (return ...)
26+
# don't let the TCO jump target bring along its trampoline if it has one
27+
if isinstance(x, _TrampolinedGenerator):
28+
x = x.g
29+
if isgenerator(x):
30+
generator = x
31+
else:
32+
# usually the return value is None, but allow for an iterable
33+
try:
34+
yield from x # the last batch!
35+
except TypeError:
36+
return x # passthrough
3537

3638
def gtrampolined(gfunc):
3739
"""Decorator for generator functions (i.e. definitions of generators).
@@ -48,21 +50,17 @@ def ones():
4850
last(take(10000, ones())) # no crash
4951
"""
5052
@wraps(gfunc)
51-
def decorated(*args, **kwargs):
53+
def trampolining_gfunc(*args, **kwargs):
5254
generator = gfunc(*args, **kwargs)
53-
if "_gtrampoline_active" not in dyn: # start up the trampoline
54-
return _TrampolinedGenerator(generator)
55-
else: # avoid stacking when already running in the trampoline
56-
# and a generator calls a gtrampolined gfunc (incl. its own!)
57-
return generator
58-
return decorated
55+
return _TrampolinedGenerator(generator) # inject a trampoline
56+
return trampolining_gfunc
5957

6058
class _TrampolinedGenerator:
6159
"""Wrapper to inject the gtco() call to the generator g returned by gfunc."""
6260
def __init__(self, g):
6361
self.g = g
6462
def __iter__(self):
65-
return gtco(iter(self.g))
63+
return gtco(iter(self.g)) # start the trampoline
6664
# no __next__, because __iter__ redirects;
6765
# this wrapper is never actually iterated over.
6866

0 commit comments

Comments
 (0)