In implementing coroutines in the Transcrypt Python to JavaScript compiler, I have the following weird problem.
Transcrypt uses the native parser of CPython 3.6 to generate an AST. For async global function defs it generates an AsyncFunctionDef node. But for async methods it doesn't! Nevertheless CPython itself seems to compile async methods corrrectly.
So the following piece of code runs with CPython, but Transcrypt cannot run it because the AST generated by CPython's AST module seems to lack the AsyncFunctionDef node for methods (as opposed to global functions).
So the following piece of code does NOT generate an AsyncFunctionDef node:
class C:
def __init__ (self):
self.aTime = 2
async def g (self, waw, asio):
print ('g0')
await waw (self.aTime, asio)
print ('g1')
What am I missing? Async methods are officially supported, aren't they? Couldn't find anything specific in PEP 492.
The complete code of the example is:
from org.transcrypt.stubs.browser import __pragma__, __envir__
# Note that CPython will ignore all pragma's
# Provide waitAWhile for Transcrypt
__pragma__ ('js', '{}', '''
function waitAWhile (aTime, asio) {
return new Promise (resolve => {
setTimeout (() => {
resolve (aTime);
}, 1000 * aTime);
});
}
''')
# Provide waitAWhile for CPython
__pragma__ ('skip') # Compile time, needed because import is done compile time
import asyncio
def waitAWhile (aTime, asio):
return asio.sleep (aTime)
__pragma__ ('noskip')
# Actual code to be tested
async def f (waw, asio):
print ('f0')
await waw (2, asio)
print ('f1')
class C:
def __init__ (self):
self.aTime = 2
async def g (self, waw, asio):
print ('g0')
await waw (self.aTime, asio)
print ('g1')
c = C ()
# Just call async functions for Transcrypt, since in the browser JavaScript is event driven by default
if __envir__.executor_name == __envir__.transpiler_name:
f (waitAWhile, None)
c.g (waitAWhile, None)
c.g (waitAWhile, None)
f (waitAWhile, None)
# Create event loop and tasks for CPython, since it isn't event driven by default
else:
eventLoop = asyncio.get_event_loop ()
tasks = [
eventLoop.create_task (f (waitAWhile, asyncio)),
eventLoop.create_task (c.g (waitAWhile, asyncio)),
eventLoop.create_task (c.g (waitAWhile, asyncio)),
eventLoop.create_task (f (waitAWhile, asyncio)),
]
waitingTasks = asyncio.wait (tasks)
eventLoop.run_until_complete (waitingTasks)
eventLoop.close ()
Eventually I got the parser to work properly.
I must have blocked the parse somewhere else initially.
Probably I forgot to call visit
from a node higher up the tree.
Unfortunaly I can't reproduce the problem anymore.
For those interested, the parser code is at:
https://github.com/QQuick/Transcrypt/blob/master/transcrypt/modules/org/transcrypt/compiler.py
line 2045.
Most important: Python's ast module works fine, although it could do with a bit more documentation.
There's a (quite compact but useable) 3rd party doc at:
https://greentreesnakes.readthedocs.io/en/latest/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With