Какие шаблоны я могу применить к коду, чтобы упростить перевод на другой язык программирования? [закрыто]

95

Я собираюсь выполнить побочный проект, целью которого является перевод кода с одного языка программирования на другой. Языки, с которых я начинаю, - это PHP и Python (с Python на PHP должно быть легче начать), но в идеале я мог бы добавить другие языки с (относительной) легкостью. План такой:

  • Это ориентировано на веб-разработку. Исходный и целевой код будут находиться поверх фреймворков (которые мне также придется написать). Эти платформы будут охватывать шаблон проектирования MVC и следовать строгим соглашениям о кодировании. Это должно несколько упростить перевод.

  • Я также смотрю на IOC и внедрение зависимостей, так как они могут упростить процесс перевода и уменьшить вероятность ошибок.

  • Я буду использовать модуль синтаксического анализатора Python , который позволяет мне возиться с абстрактным синтаксическим деревом. По-видимому, самое близкое, что я могу найти с PHP, - это token_get_all () , что является началом.

  • С этого момента я могу создавать AST, таблицы символов и поток управления.

Тогда я думаю, что могу начать выводить код. Мне не нужен идеальный перевод . Мне все равно придется просмотреть сгенерированный код и исправить проблемы. В идеале переводчик должен отмечать проблемные переводы.

Прежде чем вы спросите: "Какой в ​​этом черт смысл?" Ответ ... Это будет интересный опыт обучения. Если у вас есть идеи, как сделать это менее пугающим, дайте мне знать.


РЕДАКТИРОВАТЬ:

Меня больше интересует, какие типы шаблонов я могу применить к коду, чтобы упростить перевод (например, IoC, SOA?) Кода, чем то, как сделать перевод.

NullUserException
источник
6
Вы смотрели на такие системы, как .NET CLR или Perl6's Parrot? Они компилируют набор языков до промежуточного представления, которое может выполняться обычным интерпретатором. Если вы можете вернуться от промежуточного представления к языку, у вас есть переводчик.
Borealid
1
@Borealid AFAIK в .NET КСС является (относительно) легко собрать в , но удача получать читаемый код обратно от этого. Сейчас смотрю на Попугая.
NullUserException
Есть аналогичные проекты для других языков; Я не уверен, насколько богаты их авторы. И я на самом деле очень сдерживаюсь здесь, потому что нуждаюсь в структуре и придерживаюсь строгих соглашений о кодировании.
NullUserException
2
Я не могу добавить каких-либо конкретных знаний, но вы смотрели пижамы ( pyjs.org ), в частности translator.py? Это компилятор python для javascript.
Стефан
3
Повторное РЕДАКТИРОВАНИЕ: если у вас есть контроль над кодом, который будет переведен, самое очевидное, что нужно сделать, - это избегать конструкций, которые трудно переводить! Например, C намного проще перевести на Java, если нет арифметики с указателями. Для Python я бы, вероятно, держался подальше от замыканий. Другая вещь, которую вы можете сделать, - это написать исходный код таким образом, чтобы более сложные для перевода части всегда кодировались идиоматически, что упростило их распознавание и обработку особых случаев.
Ира Бакстер

Ответы:

122

Я занимаюсь созданием инструментов (DMS Software Reengineering Toolkit) для манипуляций с программами общего назначения (особый случай - языковой перевод) с 1995 года при поддержке сильной команды компьютерных ученых. DMS обеспечивает общий синтаксический анализ, построение AST, таблицы символов, управление и анализ потока данных, применение правил перевода, регенерацию исходного текста с комментариями и т. Д., Все параметризованные явными определениями компьютерных языков.

Количество оборудования, которое вам нужно для этого хорошо , огромно (особенно если вы хотите иметь возможность делать это для нескольких языков в общем виде), и тогда вам нужны надежные парсеры для языков с ненадежными определениями (PHP - прекрасный пример этого. ).

Нет ничего плохого в том, что вы думаете о создании переводчика с одного языка на другой или пытаетесь это сделать, но я думаю, что для реальных языков это будет гораздо более сложной задачей, чем вы ожидаете. Мы потратили около 100 человеко-лет только на DMS и еще 6–12 месяцев на каждое «надежное» определение языка (включая то, которое мы с трудом создали для PHP), и намного больше для неприятных языков, таких как C ++. Это будет «адский опыт обучения»; это было для нас. (Возможно, вам будет интересен раздел технических статей на указанном выше веб-сайте, чтобы начать это обучение).

Люди часто пытаются создать какой-то универсальный механизм, начиная с некоторой части технологии, с которой они знакомы и которая выполняет часть работы. (Python AST - отличный пример). Хорошая новость в том, что часть работы сделана. Плохая новость заключается в том, что в механизм встроен миллион предположений, большинство из которых вы не обнаружите, пока не попытаетесь заставить его делать что-то еще. В этот момент вы обнаруживаете, что механизм настроен на то, что он делает изначально, и действительно, действительно сопротивляется вашей попытке заставить его делать что-то еще. (Я подозреваю, что попытка заставить Python AST моделировать PHP будет очень весело).

Причина, по которой я начал создавать DMS изначально, заключалась в том, чтобы построить фундамент, в котором было очень мало таких допущений. Некоторые из них доставляют нам головную боль. Пока нет черных дыр. (Самая сложная часть моей работы за последние 15 лет - попытаться предотвратить появление таких предположений).

Многие люди также ошибаются, полагая, что, если они могут анализировать (и, возможно, получить AST), они хорошо на пути к выполнению чего-то сложного. Один из трудных уроков состоит в том, что вам нужны таблицы символов и анализ потока, чтобы проводить хороший анализ или преобразование программы. AST необходимы, но недостаточны. Это причина того, что книга компиляторов Ахо и Ульмана не ограничивается главой 2. (ОП имеет на это право в том смысле, что он планирует построить дополнительные механизмы помимо AST). Для получения дополнительной информации по этой теме см. Жизнь после анализа. .

Замечание о том, что «мне не нужен идеальный перевод», вызывает беспокойство. Что делают слабые переводчики, так это конвертируют «простые» 80% кода, оставляя сложные 20% делать вручную. Если приложение, которое вы собираетесь преобразовать, довольно маленькое, и вы собираетесь преобразовать его только один раз, то эти 20% в порядке. Если вы хотите преобразовать много приложений (или даже одно и то же с небольшими изменениями со временем), это нехорошо. Если вы попытаетесь преобразовать 100K SLOC, то 20% - это 20 000 исходных строк кода, которые трудно перевести, понять и изменить в контексте еще 80 000 строк переведенной программы, которую вы уже не понимаете. Это требует огромных усилий. На уровне миллиона строк это просто невозможно на практике.сложнее, и обычно они выясняют это болезненно, с длительными задержками, высокими затратами и часто откровенными неудачами.)

Для перевода крупномасштабных систем вам нужно стремиться к высокому проценту конверсии в девяностые годы, иначе вы, вероятно, не сможете выполнить ручную часть переводческой деятельности.

Еще одно важное соображение - это размер транслируемого кода. Даже с хорошими инструментами для создания работающего надежного переводчика требуется много энергии. Хотя создание переводчика вместо простого ручного преобразования кажется привлекательным и крутым, для небольших баз кода (например, примерно до 100 тыс. SLOC по нашему опыту) экономия просто не оправдывает этого. Никому не нравится этот ответ, но если вам действительно нужно перевести всего 10K SLOC кода, вам, вероятно, лучше просто укусить пулю и сделать это. И да, это больно.

Я считаю наши инструменты очень хорошими (но тогда я довольно пристрастен). А создать хорошего переводчика по-прежнему очень сложно; на это у нас уходит 1,5–2 человеко-года, и мы знаем, как использовать наши инструменты. Разница в том, что с таким большим количеством машин мы добиваемся успеха гораздо чаще, чем терпим поражение.

Ира Бакстер
источник
8
Вы когда-нибудь задумывались о том, чтобы передать свое «мучительно созданное» определение PHP обратно сообществу PHP в целом, или оно слишком тесно связано с вашим собственным потоком доходов, чтобы сделать это возможным?
TML
53
Меня просили сделать все, что мы делаем, «с открытым исходным кодом» многие люди, которые не хотели вносить свой вклад в поток доходов, и у которых не было энергии, чтобы делать работу и открывать исходный код самостоятельно. Если вы вносите лишь небольшую часть в очень большой проект и / или у вас есть другой источник дохода, «открытый исходный код» кажется прекрасным. Если вы сделали всю работу сами и это ваш единственный источник дохода, это намного менее привлекательно. [Я не хочу вдаваться в дискуссию об относительных достоинствах философии «свободных программ», поэтому я не буду участвовать в каких-либо дальнейших комментариях по этому поводу]
Ира Бакстер
9
Я согласен с тем, что вы здесь сказали, поэтому я сформулировал вопрос именно так. Я думаю, мы должны интуитивно понять из этого ответа, что вы чувствуете, что он слишком тесно связан с вашим доходом, и в этом нет абсолютно ничего плохого - я просто подумал, что стоит спросить.
TML
3
@IraBaxter Вы просто говорите общие идиомы о практиках, связанных с компьютером, которые можно применить ко многим другим практикам. Единственное, что вас интересует во всем, что вы написали, - это ссылки на semanticdesigns.com (это ваша компания)
amirouche
1
В ответах вы часто указываете ссылки на страницы, связанные с Clang. Это только доказывает, что кто-то другой может создать веб-страницу. Большинство из нас полагает, что хорошо написанная веб-страница подразумевает серьезную реальную работу, а не просто мошенническую попытку обмануть читателя, как вы, кажется, подразумеваете в своем ответе. Вы действительно верите, что веб-страница является мошеннической? На странице есть ссылка на «соответствующий» источник; он анономизирован, потому что этого требует контракт на выполнение работ. Я ничего не могу поделать.
Ира Бакстер,
13

Мой ответ будет касаться конкретной задачи синтаксического анализа Python, чтобы перевести его на другой язык, а не аспектов более высокого уровня, которые Ира хорошо рассмотрел в своем ответе.

Вкратце: не используйте модуль парсера, есть способ попроще.

astМодуль доступен с Python 2.6 гораздо больше подходит для ваших нужд, так как она дает готовый AST для работы с. Я написал статью об этом в прошлом году, но, короче говоря, используйте parseметод astдля синтаксического анализа исходного кода Python в AST. parserМодуль даст вам дерево разбора, не является AST. Остерегайтесь разницы .

Теперь, поскольку AST Python довольно подробны, с учетом AST работа с интерфейсом не так уж и сложна. Я полагаю, у вас может быть простой прототип для некоторых частей функциональности, готовый довольно быстро. Однако получение полного решения займет больше времени, в основном из-за разницы в семантике языков. Простое подмножество языка (функции, базовые типы и т. Д.) Можно легко перевести, но как только вы перейдете на более сложные уровни, вам понадобится тяжелая техника для эмуляции ядра одного языка в другом. Например, рассмотрим генераторы Python и списки, которых нет в PHP (насколько мне известно, что, по общему признанию, плохо, когда задействован PHP).

Чтобы дать вам последний совет, рассмотрим 2to3инструмент, созданный разработчиками Python для перевода кода Python 2 в код Python 3. Что касается внешнего интерфейса, в нем есть большинство элементов, необходимых для перевода Python во что-то . Однако, поскольку ядра Python 2 и 3 схожи, никаких механизмов эмуляции там не требуется.

Эли Бендерский
источник
Weeeell. 2to3это просто AST для AST. Он не поддерживает выполнение каких-либо действий, выходящих за рамки возможностей astмодуля. Обратите внимание, что все переводы идут от синтаксиса, поддерживаемого хост-процессом python, до синтаксиса, поддерживаемого хост-процессом python. Нет переводчика, который бы добавил, скажем, аннотации функций, потому что 2.6 не поддерживает его.
habnabit
... и вопрос OP может быть сформулирован, в краткосрочной перспективе, как перейти от Python 2.6 AST к ... чему-то в PHP. Модуль ast, скорее всего, не захочет хорошо представлять синтаксис PHP, так что это даже не удивительно.
Ира Бакстер,
2
@Aaron: 2to3можно рассматривать как пример использования AST, созданного из ast.
Эли Бендерски
AFAIK, 2to3, возможно, является более простым переводом, чем Python на PHP (в конце концов, его Python на Python, верно)? И даже не особо хорошо работает. Обратите внимание на большое количество Python 2.6, которое еще не было пропущено через 2to3 ... потому что, по всей видимости, есть много исправлений, которые все еще нужно сделать вручную. Если бы он был на 100% автоматизирован, Python 2.6 был бы мертв.
Ира Бакстер,
5

Написать переводчика не невозможно, особенно учитывая, что стажер Джоэла сделал это за лето.

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

Например:

word = 'This is not a word'
print word[::-2]

требует много кода C ++ для дублирования (хорошо, ну, вы можете сделать это довольно быстро с некоторыми конструкциями цикла, но все же).

Думаю, это немного отступление.

Вы когда-нибудь писали токенизатор / парсер на основе языковой грамматики? Вы, вероятно, захотите узнать, как это сделать, если вы этого не сделали, потому что это основная часть этого проекта. Что бы я сделал, так это придумал базовый полный синтаксис Тьюринга - что-то очень похожее на байт-код Python . Затем вы создаете лексический анализатор / анализатор, который принимает грамматику языка (возможно, используя BNF ) и на основе грамматики компилирует язык в ваш промежуточный язык. Затем вам нужно сделать обратное - создать синтаксический анализатор вашего языка на целевые языки на основе грамматики.

Самая очевидная проблема, которую я вижу, заключается в том, что сначала вы, вероятно, создадите ужасно неэффективный код, особенно на более мощных * языках, таких как Python.

Но если вы сделаете это таким образом, вы, вероятно, сможете найти способы оптимизации вывода по мере продвижения. Подвести итоги:

  • прочитать предоставленную грамматику
  • компилировать программу в промежуточный (но также полный по Тьюрингу) синтаксис
  • компилировать промежуточную программу в окончательный язык (на основе предоставленной грамматики)
  • ...?
  • Прибыль! (?)

* под мощным я подразумеваю, что это занимает 4 строки:

myinput = raw_input("Enter something: ")
print myinput.replace('a', 'A')
print sum(ord(c) for c in myinput)
print myinput[::-1]

Покажите мне другой язык, который может делать что-то подобное, в 4 строки, и я покажу вам язык, столь же мощный, как Python.

Уэйн Вернер
источник
«Вы когда-нибудь писали токенизатор / парсер на основе языковой грамматики?» Я сделал это с помощью JavaCC.
NullUserException
2
Стажер Джоэла за лето выполнял частичную работу. Его исходный язык был подмножеством существующего языка, и, по-видимому, это подмножество можно было несколько скорректировать. Это значительно упрощает работу. Точно так же NullPointerException может захотеть начать с более простых частей Python, возможно, пройдя через более сложные вещи для ручного преобразования (как указано в вопросах).
Дэвид Торнли
@NullUserException: у вас будет некоторая информация, но в основном вы будете выполнять повторную реализацию JavaCC, только вместо Java в качестве языка вывода вы будете использовать <insert langauge here>. @ Дэвид, именно так. Даже Thistle нуждается в помощи по некоторым языковым конструкциям. Если бы я был ОП, я бы сначала занялся функционалом, а затем оптимизировал, иначе я бы навсегда застрял, пытаясь заставить C ++ выполнять нарезку строк (с шагами): p
Уэйн Вернер
@WayneWerner Для записи такие языки, как C #, вообще не требуют перевода строки. (По крайней мере, не после того, как вы удалили однострочные комментарии.) Таким образом, вы можете написать любую программу на C # в одну строку. Но, конечно, я понимаю, к чему вы клоните.
левиафан
@ aboveyou00: Не думаю, что это правильно. Если вы запрещаете условные выражения препроцессора, возможно, вы правы.
Ира Бакстер
3

Есть пара ответов, которые говорят вам не беспокоиться. Насколько это полезно? Ты хочешь учиться? Ты можешь выучить. Это компиляция. Так уж случилось, что ваш целевой язык - это не машинный код, а другой язык высокого уровня. Это происходит постоянно.

Есть относительно простой способ начать. Сначала перейдите по адресу http://sourceforge.net/projects/lime-php/ (если вы хотите работать на PHP) или что-то подобное и просмотрите пример кода. Затем вы можете написать лексический анализатор, используя последовательность регулярных выражений, и передать токены в сгенерированный вами синтаксический анализатор. Ваши семантические действия могут либо выводить код непосредственно на другом языке, либо создавать некоторую структуру данных (мыслить объекты, человек), которые вы можете массировать и перемещаться для генерации кода вывода.

Вам повезло с PHP и Python, потому что во многих отношениях это один и тот же язык, но с другим синтаксисом. Труднее всего преодолеть семантические различия между грамматическими формами и структурами данных. Например, в Python есть списки и словари, а в PHP - только ассоциативные массивы.

Подход «учащийся» состоит в том, чтобы создать что-то, что работает нормально для ограниченного подмножества языка (например, только операторы печати, простую математику и присвоение переменных), а затем постепенно снимать ограничения. Это в основном то, что делали все «большие» ребята в этой области.

Да, и поскольку у вас нет статических типов в Python, возможно, лучше написать и полагаться на функции PHP, такие как «python_add», которые добавляют числа, строки или объекты в соответствии с тем, как это делает Python.

Очевидно, это может стать намного больше, если вы позволите этому.

Ян
источник
3
На самом деле я не сказал «не беспокойся». Я сказал, что «переводить языки в целом очень сложно». Если ОП продолжит свой первоначальный путь использования деревьев Python, чтобы попытаться сгенерировать PHP, он многому научится, и я полностью поддерживаю опыт обучения; Я тоже там начал. Он не сможет легко добавлять новые языки.
Ира Бакстер
@IraBaxter Я не могу поддержать ваше утверждение, сделать Python-> PHP и PHP-> Javascript было бы довольно легко. ср. последняя часть stackoverflow.com/a/22850139/140837 в середине ответа Я также имею дело с вашей «аргументацией»
amirouche
2

Я поддержу точку зрения @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, но, что более важно, возможность создавать комфортным способом. Это привело меня к Scheme, DSL, Models и, в конечном итоге, к моделям, специфичным для предметной области (см. 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. Даже если мы уже знаем, что они оба завершены по Тьюрингу, так что ...

Framework-> Framework, который я лучше визуализирую как перевод API-> API, может быть тем, что вы могли бы иметь в виду как способ улучшить сгенерированный код. Например: Пролог как очень специфический синтаксис, но все же вы можете выполнять Пролог как вычисление, описывая тот же граф в Python ... Если бы я должен был реализовать переводчик Пролога в Python, я бы не реализовал унификацию в Python, а в библиотеке C и пришел с "синтаксисом Python", который очень удобен для чтения Pythonist. В конце концов, синтаксис - это всего лишь «картина», которой мы придаем смысл (поэтому я и начал схему). Зло в деталях языка, и я не говорю о синтаксисе. Понятия, которые используются в языке 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/

амируш
источник
Единственное, что меня по-
прежнему волнует в
Второй ответ о типах данных. В Pythonium я даже не планировал поддерживать правильный тип целого числа и числа с плавающей запятой в совместимом режиме без asm.js.
amirouche
Итак, если я дам вам пакет Python из 100K SLOC, и вы запустите его через свой «переводчик», получу ли я работающую программу? Сколько потребуется ручной работы после перевода, чтобы это исправить? Вы сказали, что «с учетом уже существующего хорошего парсера для Python, который строит AST, я могу построить частичный переводчик за 6 месяцев». Никто не удивлен. 6 месяцев по стандартам большинства людей - это не «легко» (цитата из другого вашего комментария). Решение оставшихся проблем потребует дополнительных усилий. В моем ответе говорилось, что в основном «делать это непросто» и «делать это в общих чертах сложно».
Ира Бакстер
... этот последний пункт в ответ на первоначальное желание OP: «в идеале я мог бы добавить другие языки с (относительной) легкостью», к которому мой ответ обращается конкретно.
Ира Бакстер
Я прошу не согласиться, особенно когда вы знаете, что делаете, это легко, а то, что будет дальше, не сложно, это просто вопрос выполнения работы. Я не уверен, где вы имеете дело с конкретным вопросом. В 4 или 5 абзацах вы говорите, что это делает ваша компания, и это сложно. Но в противном случае вы распространяете FUD на эту тему, будучи добрыми не по теме, как в stackoverflow.com/questions/22621164/… . За полные 6 месяцев я бы написал полноценного переводчика.
amirouche
0

Вы можете взглянуть на компилятор Vala , который переводит Vala (язык, подобный C #) на C.

Помидор
источник
Целью разработки Vala было перевести ее на C и упростить разработку с использованием библиотек gnome.
amirouche