Я підтримаю точку зору @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 clojure.
Я пробував із 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, і він використовує успадкування прототипів.
Насправді мені ніколи не вдається запустити піжаму # fail і ніколи більше не намагався прочитати код # fail. Але, на мою думку, піжама робила трансляцію API-> API (або фреймворк в фреймворк), а не переклад Python в JavaScript. Структура JavaScript використовує дані, які вже є на сторінці, або дані із сервера. Код Python - це лише "сантехніка". Після цього я виявив, що піжама насправді була справжнім перекладачем python-> js.
Тим не менш, я думаю, що можна зробити переклад API-> API (або фреймворк-> фреймворк), і це в основному те, що я роблю в Pythonium, але на нижчому рівні. Ймовірно, піжами використовують той самий алгоритм, що і 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, є:
- функція з повними семантичними параметрами як у визначенні, так і у виклику. Це та частина, якою я пишаюся найбільше.
- while / if / elif / else
- Типи Python були перетворені в типи JavaScript (жодного типу типів python не існує)
- бо міг перебирати лише масиви Javascript (для масиву in 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
- успадкування одного класу + mixin через 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 пор. 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. Замість того, щоб генерувати блок відстеження, яка змінна створена в даному блоці, і вставляти його поверх згенерованого функціонального блоку, я просто шукаю присвоєння змінної змінної, коли я ввожу блок перед тим, як фактично відвідати дочірній вузол, щоб сформувати відповідний код.
- 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 людських років у контексті підприємства ...
Коли хтось каже, що щось важке або частіше неможливе, я відповідаю, що "потрібен час, щоб знайти рішення неможливої проблеми", інакше кажуть, що нічого неможливого є, крім випадків, коли це доведено неможливим у цьому випадку математичним підтвердженням ...
Якщо це не доведено неможливим, це залишає простір для фантазії:
- знайти доказ, що доводить, що це неможливо
і
- Якщо це неможливо, може виникнути "неповноцінна" проблема, яка може мати рішення.
або
- якщо це неможливо, пошук рішення
Це не просто оптимістичне мислення. Коли я запустив Python-> Javascript, усі говорили, що це неможливо. PyPy неможливо. Метакласи занадто важкі. і т.д. ... Я думаю, що єдиною революцією, яка приводить PyPy до паперу Scheme-> C (якому 25 років), є деяке автоматичне генерування JIT (на мої підказки, написані в інтерпретаторі RPython).
Більшість людей, які кажуть, що річ "важка" або "неможлива", не вказують причин. C ++ важко проаналізувати? Я це знаю, все ж вони є (безкоштовними) парсерами C ++. Зло в деталях? Я це знаю. Сказати, що це неможливо поодинці, не корисно, це навіть гірше, ніж "не корисно", це знеохочує, і деякі люди хочуть знеохотити інших. Я чув про це запитання за допомогою /programming/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. Навіть якщо ми вже знаємо, що вони обидва тверді, цілі ...
Фреймворк-> Фреймворк, який я краще візуалізую як API-> Переклад API, все-таки може бути тим, що ви можете мати на увазі як спосіб поліпшити згенерований код. Наприклад: Пролог як дуже конкретний синтаксис, але все одно Ви можете робити Пролог, як обчислення, описуючи той самий графік в Python ... Якби я мав реалізувати перекладач Пролог на Python, я б не реалізував уніфікацію в Python, а в бібліотеці C і прийшов з "синтаксисом Python", який дуже читається для Pythonist. Врешті-решт, синтаксис - це лише «живопис», якому ми надаємо значення (саме тому я розпочав схему). Зло в деталях мови, і я не кажу про синтаксис. Поняття, які використовуються в мові гетатрибутіхук (ви можете жити без нього), але з такими необхідними функціями віртуальної машини, як оптимізація хвостової рекурсії, може бути важко впоратися. Вам байдуже, чи в початковій програмі не використовується рекурсія хвоста, і навіть якщо у цільовій мові немає рекурсії хвоста, ви можете емулювати її, використовуючи цикл greenlets / event.
Для цільової та вихідної мов шукайте:
- Великі та конкретні ідеї
- Крихітні спільні ідеї
З цього вийде:
- Речі, які легко перекласти
- Речі, які важко перекласти
Ви також, мабуть, зможете знати, що буде перекладено на швидкий і повільний код.
Існує також питання про 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/