Как встроить такой язык, как JSX, в скрипт Python? - PullRequest
0 голосов
/ 12 июня 2019

В нашей компании нам нравится писать приложения на основе django, и мы также любим использовать реагировать. Недавно мы подумали о написании шаблонного движка на основе компонентов для python, где шаблоны могут быть написаны как реагирующие компоненты с использованием JSX.

В идеале должна быть возможность встроить JSX в код Python, чтобы вы могли писать такие компоненты:

В header.pyx:

import PyReact
from my_awsome_project.components import Logo, Link


def Header(context):
    page_title = context.get('page_title')
    links = context.get('links')

    return (
        <div>
            <Logo /> 
            {page_title}
            <ul>
                {[<Link href={link.url}>{link.title}</Link> for link in links]}
            </ul>
        </div>
    )

Это, конечно, потребует сначала перенести файл, чтобы получить правильный код Python. Это может привести к чему-то похожему:

import PyReact
from my_awsome_project.components import Logo, Link


def Header(context):
    page_title = context.get('page_title')
    links = context.get('links')

    return (
        PyReact.createComponent('div', context, [
            PyReact.createComponent(Logo),
            page_title,
            PyReact.createComponent('ul', context, [
                 [
                      PyReact.createComponent(Link, {'href': link.url}, link.title)
                      for link in links
                 ]
            ]),
        ])
    )

Вопрос: как бы я подошел к написанию такого транспилятора?

Также мы подумали, что вместо встраивания JSX напрямую в код Python мы можем вернуть строку, содержащую JSX, которая анализируется независимо. Это был бы лучший / более легкий подход?

1 Ответ

1 голос
/ 12 июня 2019

Я думаю, что это в основном слишком широкий вопрос для SO, и любой ответ будет кататься на краю руководящих принципов SO по поводу мнений. По сути, вы просите совета по проектированию по поводу сложной проблемы, и SO на самом деле не предназначен для этой цели.

Тем не менее, это интересный вопрос. Я попытаюсь решить проблемы, не углубляясь в самоуверенный дизайн (так как у меня есть мнения по этому вопросу).

  1. Транспилирование практично, по крайней мере, теоретически, и если вы сможете его осуществить, оно даст вам разумную производительность.

  2. Повторное повторение строк шаблона кажется мне неэффективным и сложным; Сложности связаны с оценкой встроенного кода Python, который вы захотите сделать внутри области, в которой определен строковый литерал, что, вероятно, не является областью, в которой он анализируется.

  3. Лексический анализ и синтаксический анализ в стиле JSX не особенно сложны, но ваш гипотетический переносчик также должен понимать лексический и синтаксический анализ Python. Стандартная библиотека Python включает в себя модули лексирования и синтаксического анализа Python, но на самом деле они не расширяемы, что может затруднить их использование для использования со встроенным языком. Вы можете написать свой собственный лексер и парсер, возможно, используя выбранные вами генераторы кода, или вы можете основывать свой лексер и парсер на какой-то реализации Python с открытым исходным кодом. В обоих случаях ваша задача сопровождения будет заключаться в синхронизации вашего пользовательского кода с будущими версиями Python.

  4. Основная проблема при внедрении псевдо-HTML в любой другой язык заключается в обнаружении, когда < является оператором сравнения и когда он запускает шаблон. Самое простое решение - разрешить шаблон только тогда, когда < анализируется лексически как полный токен (так что <= всегда является оператором), сопровождается идентификатором и встречается в синтаксической среде, в которой выражение ожидается.

  5. Последнее требование выше - убедиться, что 3 < count (например) не обманывает транспортер, заставляя его думать, что он собирается увидеть <count...> компонент. Я почти уверен, что в Python вы можете использовать простое лексическое правило, основанное на предыдущем токене, но полный синтаксический анализ был бы необходим для проверки того, что

  6. Как только вы запустите шаблон, он будет продолжаться, пока вы не достигнете соответствующего тега close; это очень просто, если для соответствия требуются теги. Но он лучше подходит для анализа сверху вниз, чем анализа снизу вверх, потому что сопоставление конечных тегов зависит от контекста. Это легко сделать, если вы тесно сотрудничаете между лексическим анализом и синтаксическим анализом, но это сотрудничество иногда осуждается: -)

  7. Поскольку код Python, встроенный в шаблон, сам может содержать встроенный шаблон, который, в свою очередь, может включать больше кода Python и т. Д., Ваш анализ должен быть рекурсивным. Ожидаемая глубина рекурсии не очень велика, поэтому с рекурсией нет никаких проблем per se , но многие генераторы синтаксического анализатора не справляются с такой рекурсией элегантно. Я бы предложил использовать (или реализовать) «push-parser» и структуру лексера, отделенную от обработчика буфера, чтобы вы могли легко изменить сканер в середине буфера.

  8. Работа с буфером может быть довольно простой; минимальное требование - это просто строка и индекс в этой строке. Если вы изолируете детали реализации внутри обработчика буфера, вы сможете позже перейти на другую реализацию, например, такую, которая не требует наличия полного ввода перед началом анализа. Возможно, вам на самом деле не нужна эта функция, но всегда полезно поддерживать независимые компоненты, на всякий случай

  9. Еще одной проблемой для вашего транспилятора будет интеграция его с модульной системой Python.Pythonic интеграция может предложить, что транспиляция должна выполняться при импорте модуля.С другой стороны, вы можете захотеть распространять предварительно транспортируемый пакет, который можно использовать без установки транспилятора и без зависимости от конкретной версии транспилятора.Если вы потратите некоторое время на обдумывание этого, вы можете избежать последующих проблем.(Например, проблема Ply, которая делает невозможным объединение проекта Ply в систему распространения одного файла.)

Надеюсь, что это немного поможет.

...