Я поддержу точку зрения @EliBendersky относительно использования ast.parse вместо парсера (о котором я раньше не знал). Я также настоятельно рекомендую вам просмотреть его блог. Я использовал ast.parse для перевода Python-> JavaScript (@ https://bitbucket.org/amirouche/pythonium < / а>). Я придумал дизайн Pythonium, немного просмотрев другие реализации и попробовав их самостоятельно. Я раздвоил Pythonium из https://github.com/PythonJS/PythonJS, который я тоже начал. полный переписать. Общий дизайн вдохновлен PyPy и http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf документ.
Все, что я пробовал, от начала до лучшего решения, даже если это выглядит как маркетинг Pythonium, на самом деле это не так (не стесняйтесь сказать мне, если что-то не кажется правильным для сетевого этикета):
Реализуйте семантику Python в обычном старом JavaScript с использованием наследования прототипов: AFAIK невозможно реализовать множественное наследование Python с использованием объектной системы прототипов JS. Позже я попытался сделать это, используя другие приемы (см. Getattribute). Насколько я знаю, в JavaScript нет реализации множественного наследования Python, лучшее, что существует, - это одиночное наследование + миксины, и я не уверен, что они обрабатывают наследование алмаза. Вроде как Skulpt, но без закрытия Google.
Я пробовал использовать Google clojure, как и Skulpt (компилятор), вместо того, чтобы читать код Skulpt #fail. Во всяком случае, из-за объектной системы на основе прототипа JS все еще невозможно. Создание привязки было очень-очень сложным, вам нужно было написать JavaScript и много шаблонного кода (см. https://github.com/skulpt/skulpt/issues/50, где я призрак). В то время не было четкого способа интегрировать привязку в систему сборки. Я думаю, что Skulpt - это библиотека, и вам просто нужно включить свои файлы .py в html для выполнения, разработчик не требует выполнения этапа компиляции.
Пробовал pyjaco (компилятор), но создание привязок (вызов кода Javascript из кода Python) было очень сложно, слишком много шаблонного кода для создания каждый раз. Теперь я думаю, что pyjaco - это тот, который больше похож на Pythonium. pyjaco написан на Python (в том числе ast.parse), но многое написано на JavaScript и использует наследование прототипов.
На самом деле мне никогда не удавалось запустить Pyjamas #fail, и я никогда не пытался снова прочитать код #fail. Но на мой взгляд, пижама выполняла перевод API-> API (или фреймворк в фреймворк), а не перевод Python в JavaScript. Платформа JavaScript использует данные, которые уже есть на странице, или данные с сервера. Код Python - это всего лишь «сантехника». После этого я обнаружил, что pajamas на самом деле был настоящим переводчиком python-> js.
Тем не менее, я думаю, что можно сделать перевод API-> API (или framework-> framework), и это в основном то, что я делаю в Pythonium, но на более низком уровне. Вероятно, Pyjamas использует тот же алгоритм, что и Pythonium ...
Затем я обнаружил, что brython полностью написан на Javascript, например Skulpt, не требует компиляции и лишен всякой ерунды ... но написан на JavaScript.
С момента написания начальной строки в ходе этого проекта я знал о PyPy, даже о бэкэнде JavaScript для PyPy. Да, вы можете, если найдете, напрямую сгенерировать интерпретатор Python в JavaScript из PyPy. Говорят, это была катастрофа. Я не читал где почему. Но я думаю, причина в том, что промежуточный язык, который они используют для реализации интерпретатора, RPython, является подмножеством Python, адаптированным для перевода на C (и, возможно, asm). Ира Бакстер говорит, что вы всегда делаете предположения, когда создаете что-то, и, вероятно, вы точно настраиваете его, чтобы он был лучшим для того, что он должен делать в случае перевода PyPy: Python-> C. Эти предположения могут не иметь отношения к другому контексту, хуже того, что они могут привести к накладным расходам, в противном случае прямой перевод, скорее всего, всегда будет лучше.
Написание интерпретатора на Python звучало как (очень) хорошая идея. Но меня больше интересовал компилятор по соображениям производительности. К тому же, на самом деле, компилировать Python в JavaScript проще, чем интерпретировать его.
Я начал PythonJS с идеей собрать подмножество Python, которое я мог бы легко перевести на JavaScript. Сначала я даже не стал внедрять объектно-ориентированную систему из-за прошлого опыта. Подмножество Python, которое мне удалось перевести на JavaScript:
- функция с полной семантикой параметров как при определении, так и при вызове. Это та часть, которой я горжусь больше всего.
- а / если / элиф / еще
- Типы Python были преобразованы в типы JavaScript (никаких типов Python не существует)
- for может перебирать только массивы Javascript (для массива in)
- Прозрачный доступ к JavaScript: если вы напишете Array в коде Python, он будет переведен в Array в javascript. Это самое большое достижение с точки зрения удобства использования по сравнению с конкурентами.
- Вы можете передать функцию, определенную в исходном коде Python, в функции javascript. Аргументы по умолчанию будут приняты во внимание.
- В нем есть специальная функция под названием new, которая переводится в JavaScript new, например: new (Python) (1, 2, spam, «egg») переводится в «new Python (1, 2, spam,« egg »).
- "var" автоматически обрабатываются переводчиком. (очень хорошая находка от Бретта (участник PythonJS).
- глобальное ключевое слово
- закрытие
- лямбды
- понимание списка
- импорт поддерживается через requirejs
- наследование одного класса + миксин через classyjs
Это кажется большим, но на самом деле очень узким по сравнению с полноценной семантикой Python. Это действительно JavaScript с синтаксисом Python.
Сгенерированный JS идеален, т.е. нет накладных расходов, его нельзя улучшить по производительности дальнейшим редактированием. Если вы можете улучшить сгенерированный код, вы также можете сделать это из исходного файла Python. Кроме того, компилятор не полагался на какие-либо уловки JS, которые можно найти в .js, написанных http://superherojs.com/, поэтому он очень удобочитаемый.
Прямым потомком этой части PythonJS является режим Pythonium Veloce. Полную реализацию можно найти @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + около 100 SLOC общего кода с другим переводчиком.
Адаптированная версия pystones.py может быть переведена в режим Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master
После настройки базового перевода Python-> JavaScript я выбрал другой путь для перевода полного Python в JavaScript. Способ glib выполнения объектно-ориентированного кода на основе классов, за исключением того, что целевой язык - это JS, поэтому у вас есть доступ к массивам, объектам, подобным карте, и многим другим трюкам, и вся эта часть была написана на Python. IIRC нет кода javascript, написанного в переводчике Pythonium. Получить единичное наследование несложно, вот те сложные моменты, которые делают Pythonium полностью совместимым с Python:
spam.egg
в Python всегда переводится на getattribute(spam, "egg")
Я не профилировал это в частности, но я думаю, что там, где это теряет много времени, и я не уверен, что смогу улучшить его с помощью asm.js или чего-то еще.
- порядок разрешения методов: даже с алгоритмом, написанным на Python, перевод его в код, совместимый с Python Veloce, был большой задачей.
- getattributre: фактический алгоритм разрешения getattribute довольно сложен, и он по-прежнему не поддерживает дескрипторы данных.
- на основе класса метакласса: я знаю, где вставить код, но все же ...
- последнее бу не в последнюю очередь: some_callable (...) всегда переводится в "call (some_callable)". AFAIK переводчик вообще не использует логический вывод, поэтому каждый раз, когда вы выполняете вызов, вам нужно проверять, какой тип объекта должен называть его так, как он должен вызываться.
Эта часть учтена в https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Он написан на Python, совместимом с Python Veloce.
Фактический совместимый переводчик https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master не генерирует код JavaScript напрямую и, что наиболее важно, не выполняет преобразование ast-> ast. Я пробовал использовать ast-> ast, и ast, даже если он лучше, чем cst, нехорошо работать даже с ast.NodeTransformer и, что более важно, мне не нужно делать ast-> ast.
Выполнение python ast на python ast в моем случае, по крайней мере, может быть улучшением производительности, поскольку я иногда проверяю содержимое блока перед генерацией связанного с ним кода, например:
- var / global: чтобы иметь возможность что-то var, я должен знать, что мне нужно, а не var. Вместо того, чтобы генерировать блок, отслеживающий, какие переменные созданы в данном блоке, и вставляя их поверх сгенерированного функционального блока, я просто ищу удобное назначение переменных, когда я вхожу в блок, прежде чем фактически посещать дочерний узел для генерации связанного кода.
- yield, генераторы пока имеют специальный синтаксис в JS, поэтому мне нужно знать, какая функция Python является генератором, когда я хочу написать «var my_generator = function»
Поэтому я не посещаю каждый узел один раз на каждом этапе перевода.
Общий процесс можно описать как:
Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code
Встроенные функции Python написаны на коде Python (!), IIRC имеет несколько ограничений, связанных с типами начальной загрузки, но у вас есть доступ ко всему, что может переводить Pythonium в совместимый режим. Взгляните на https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master
Чтение JS-кода, сгенерированного из совместимого с pythonium, можно понять, но карты источников очень помогут.
Ценный совет, который я могу дать вам в свете этого опыта, - это старые добрые пердуны:
- Подробно изучите тему как в литературе, так и в существующих проектах с закрытым исходным кодом или бесплатно. Когда я просматривал различные существующие проекты, мне следовало уделить им больше времени и мотивации.
- задавать вопросы! Если бы я знал заранее, что бэкэнд PyPy бесполезен из-за накладных расходов из-за семантического несоответствия C / Javascript. У меня, возможно, была идея Pythonium раньше, чем 6 месяцев назад, может быть, 3 года назад.
- знайте, что вы хотите делать, имейте цель. В этом проекте у меня были другие цели: немного поработать JavaScript, узнать больше о Python и уметь писать код Python, который будет работать в браузере (подробнее об этом ниже).
- неудача - это опыт
- маленький шаг - это шаг
- начать с малого
- большая мечта
- делать демо
- повторять
Только с режимом Python Veloce, я очень счастлив! Но по пути я обнаружил, что то, что я действительно искал, - это освобождение меня и других от Javascript, но, что более важно, возможность создавать удобным способом. Это привело меня к схемам, DSL, моделям и, в конечном итоге, к моделям, специфичным для предметной области (см. http://dsmforum.org/ ).
О чем отзывается Ира Бакстер:
Оценки совершенно бесполезны. У меня ушло около 6 месяцев свободного времени как на PythonJS, так и на Pythonium. Так что я могу ожидать большего от 6 месяцев полной занятости. Я думаю, все мы знаем, что 100 человеко-лет в контексте предприятия могут означать и вовсе не означать ...
Когда кто-то говорит, что что-то сложно или чаще невозможно, я отвечаю, что «требуется только время, чтобы найти решение проблемы, которая невозможна», в противном случае сказал, что нет ничего невозможного, кроме случаев, когда это доказано в данном случае математическим доказательством ...
Если не доказано, что это невозможно, остается место для воображения:
- найти доказательство, доказывающее, что это невозможно
и
- Если это невозможно, может быть «неполная» проблема, у которой есть решение.
or
- если это не невозможно, найти решение
Это не просто оптимистическое мышление. Когда я начинал Python-> Javascript, все говорили, что это невозможно. PyPy невозможно. Метаклассы слишком сложные. и т. д. Я думаю, что единственная революция, которая привносит PyPy в бумагу Scheme-> C (которой 25 лет), - это автоматическая генерация JIT (на основе подсказок, написанных в интерпретаторе RPython, я думаю).
Большинство людей, которые говорят, что что-то «сложно» или «невозможно», не приводят причин. C ++ сложно разобрать? Я знаю, что это (бесплатный) синтаксический анализатор C ++. Зло в деталях? Я знаю это. Сказать, что это невозможно в одиночку, бесполезно. Это даже хуже, чем «бесполезно», это обескураживает, и некоторые люди хотят отговорить других. Я слышал об этом вопросе через https://stackoverflow.com/questions/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus.
Что было бы совершенством для вас? Так вы определяете следующую цель и, возможно, достигнете общей цели.
Мне больше интересно знать, какие типы шаблонов я могу применить к коду, чтобы упростить перевод (например, IoC, SOA?) Кода, чем то, как сделать перевод.
Я не вижу шаблонов, которые нельзя было бы перевести с одного языка на другой хотя бы неидеально. Поскольку перевод с языка на язык возможен, вам лучше сначала постараться. Поскольку, я думаю, согласно http://en.wikipedia.org/wiki/Graph_isomorphism_problem, перевод между двумя компьютерными языками - это дерево или изоморфизм DAG. Даже если мы уже знаем, что они оба завершены по Тьюрингу, так что ...
Framework-> Framework, который я лучше визуализирую как перевод API-> API, может быть тем, что вы могли бы иметь в виду как способ улучшить сгенерированный код. Например: Пролог как очень специфический синтаксис, но все же вы можете выполнять Пролог как вычисления, описывая тот же граф в Python ... Если бы мне пришлось реализовать переводчик Пролога в Python, я бы не реализовал унификацию в Python, а в библиотеке C и пришел с "синтаксисом Python", который очень хорошо читается питонистом. В конце концов, синтаксис - это всего лишь «картина», которой мы придаем смысл (поэтому я и начал схему). Зло в деталях языка, и я не говорю о синтаксисе. Концепции, которые используются в хуке языка getattribute (вы можете жить и без него), но с необходимыми функциями виртуальной машины, такими как оптимизация хвостовой рекурсии, может быть трудно справиться. Вам все равно, если исходная программа не использует хвостовую рекурсию, и даже если на целевом языке нет хвостовой рекурсии, вы можете эмулировать ее с помощью гринлетов / цикла событий.
Для целевого и исходного языков ищите:
- Большие и конкретные идеи
- Крошечные и общие идеи
Из этого выйдет:
- Вещи, которые легко перевести
- Вещи, которые сложно перевести
Вы также, вероятно, сможете узнать, что будет преобразовано в быстрый и медленный код.
Также есть вопрос о stdlib или любой другой библиотеке, но нет четкого ответа, это зависит от ваших целей.
Идиоматический код или читаемый сгенерированный код также имеют решения ...
Ориентация на такую платформу, как PHP, намного проще, чем на браузеры, поскольку вы можете обеспечить C-реализацию медленного и / или критического пути.
Учитывая, что ваш первый проект - это перевод Python на PHP, по крайней мере, для подмножества PHP3, о котором я знаю, настройка veloce.py - ваш лучший выбор. Если вы можете реализовать veloce.py для PHP, то, вероятно, вы сможете запустить соответствующий режим ... Также, если вы можете перевести PHP в подмножество PHP, которое вы можете сгенерировать с помощью php_veloce.py, это означает, что вы можете перевести PHP в подмножество Python, которое может использовать veloce.py, что означает, что вы можете перевести PHP в Javascript. Просто говорю...
Вы также можете взглянуть на эти библиотеки:
Также вас может заинтересовать это сообщение в блоге (и комментарии): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/.
person
amirouche
schedule
03.04.2014