Модуль Python 3.6 AST не распознает асинхронные методы

При реализации сопрограмм в компиляторе Transcrypt Python to JavaScript у меня возникает следующая странная проблема.

Transcrypt использует собственный синтаксический анализатор CPython 3.6 для генерации AST. Для асинхронной глобальной функции defs она генерирует узел AsyncFunctionDef. Но для асинхронных методов это не так! Тем не менее, кажется, что сам CPython правильно компилирует асинхронные методы.

Поэтому следующий фрагмент кода работает с CPython, но Transcrypt не может его запустить, потому что AST, сгенерированный модулем AST CPython, похоже, не имеет узла AsyncFunctionDef для методов (в отличие от глобальных функций).

Таким образом, следующий фрагмент кода НЕ генерирует узел AsyncFunctionDef:

class C:
    def __init__ (self):
        self.aTime = 2

    async def g (self, waw, asio):
        print ('g0')
        await waw (self.aTime, asio)
        print ('g1')

Что мне не хватает? Асинхронные методы официально поддерживаются, не так ли? Не удалось найти ничего конкретного в PEP 492.

Полный код примера:

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 ()

1 ответ

В конце концов я получил парсер для правильной работы. Я должен был заблокировать анализ где-то еще изначально. Наверное, я забыл позвонить visit от узла выше вверх по дереву. К сожалению, я больше не могу воспроизвести проблему.

Для тех, кто заинтересован, код парсера находится по адресу:

https://github.com/QQuick/Transcrypt/blob/master/transcrypt/modules/org/transcrypt/compiler.py

линия 2045

Самое важное: модуль Ast на Python работает нормально, хотя он может делать и с немного большим количеством документации.

Есть (довольно компактный, но полезный) сторонний документ по адресу:

https://greentreesnakes.readthedocs.io/en/latest/

Другие вопросы по тегам