Commit 626f79ae authored by Stefan Behnel's avatar Stefan Behnel

initial attempt to evaluate "@coroutine" at compile time by making the resulting coroutine iterable

Signed-off-by: default avatarStefan Behnel <stefan_ml@behnel.de>
parent fc6d44b9
...@@ -4054,6 +4054,7 @@ class GeneratorDefNode(DefNode): ...@@ -4054,6 +4054,7 @@ class GeneratorDefNode(DefNode):
is_generator = True is_generator = True
is_coroutine = False is_coroutine = False
is_iterable_coroutine = False
is_asyncgen = False is_asyncgen = False
gen_type_name = 'Generator' gen_type_name = 'Generator'
needs_closure = True needs_closure = True
...@@ -4106,6 +4107,11 @@ class AsyncDefNode(GeneratorDefNode): ...@@ -4106,6 +4107,11 @@ class AsyncDefNode(GeneratorDefNode):
is_coroutine = True is_coroutine = True
class IterableAsyncDefNode(AsyncDefNode):
gen_type_name = 'IterableCoroutine'
is_iterable_coroutine = True
class AsyncGenNode(AsyncDefNode): class AsyncGenNode(AsyncDefNode):
gen_type_name = 'AsyncGen' gen_type_name = 'AsyncGen'
is_asyncgen = True is_asyncgen = True
......
...@@ -2593,10 +2593,27 @@ class MarkClosureVisitor(CythonTransform): ...@@ -2593,10 +2593,27 @@ class MarkClosureVisitor(CythonTransform):
collector.visitchildren(node) collector.visitchildren(node)
if node.is_async_def: if node.is_async_def:
coroutine_type = Nodes.AsyncGenNode if collector.has_yield else Nodes.AsyncDefNode coroutine_type = Nodes.AsyncDefNode
if collector.has_yield: if collector.has_yield:
coroutine_type = Nodes.AsyncGenNode
for yield_expr in collector.yields + collector.returns: for yield_expr in collector.yields + collector.returns:
yield_expr.in_async_gen = True yield_expr.in_async_gen = True
elif node.decorators:
# evaluate @asyncio.coroutine() decorator at compile time if it's the inner-most one
# TODO: better decorator validation: should come from imported module
decorator = node.decorators[-1].decorator
if decorator.is_name and decorator.name == 'coroutine':
pass
elif decorator.is_attribute and decorator.attribute == 'coroutine':
if decorator.obj.is_name and decorator.obj.name in ('types', 'asyncio'):
pass
else:
decorator = None
else:
decorator = None
if decorator is not None:
node.decorators.pop()
coroutine_type = Nodes.IterableAsyncDefNode
elif collector.has_await: elif collector.has_await:
found = next(y for y in collector.yields if y.is_await) found = next(y for y in collector.yields if y.is_await)
error(found.pos, "'await' not allowed in generators (use 'yield')") error(found.pos, "'await' not allowed in generators (use 'yield')")
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment