Quels types de modèles pourrais-je appliquer sur le code pour faciliter la traduction vers un autre langage de programmation? [fermé]

95

Je me propose de faire un projet parallèle qui a pour objectif de traduire du code d'un langage de programmation à un autre. Les langages avec lesquels je commence sont PHP et Python (Python à PHP devrait être plus facile pour commencer), mais idéalement, je serais capable d'ajouter d'autres langages avec (relative) facilité. Le plan est:

  • Ceci est orienté vers le développement Web. Le code original et cible sera assis sur des frameworks (que je devrai également écrire). Ces frameworks adopteront un modèle de conception MVC et suivront des conventions de codage strictes. Cela devrait rendre la traduction un peu plus facile.

  • J'examine également l'IOC et l'injection de dépendances, car ils pourraient rendre le processus de traduction plus facile et moins sujet aux erreurs.

  • Je vais utiliser le module analyseur de Python , qui me permet de jouer avec l'arbre de syntaxe abstraite. Apparemment, le plus proche que je puisse obtenir avec PHP est token_get_all () , ce qui est un début.

  • À partir de là, je peux construire l'AST, les tables de symboles et contrôler le flux.

Ensuite, je crois que je peux commencer à produire du code. Je n'ai pas besoin d'une traduction parfaite . Je vais encore devoir revoir le code généré et résoudre les problèmes. Idéalement, le traducteur devrait signaler les traductions problématiques.

Avant de demander "Qu'est-ce que c'est que ça?" La réponse est ... Ce sera une expérience d'apprentissage intéressante. Si vous avez des idées sur la façon de rendre cela moins intimidant, veuillez me le faire savoir.


ÉDITER:

Je suis plus intéressé à savoir quels types de modèles je pourrais appliquer sur le code pour faciliter la traduction (ie: IoC, SOA?) Le code que comment faire la traduction.

NullUserException
la source
6
Avez-vous examiné des systèmes comme le .NET CLR ou le Parrot de Perl6? Ils compilent un ensemble de langages jusqu'à une représentation intermédiaire qui peut être exécutée par un interpréteur commun. Si vous pouvez remonter de la représentation intermédiaire à une langue, vous avez un traducteur.
Borealid
1
@Borealid le CIL .NET AFAIK est (relativement) facile à compiler dans , mais bonne chance pour revenir de code lisible à partir de cela. En regardant Parrot maintenant.
NullUserException
Il existe des projets similaires pour d'autres langues; Je ne suis pas sûr de la richesse de leurs auteurs. Et je me retiens beaucoup ici, en ayant besoin d'un cadre et en adhérant à des conventions de codage strictes.
NullUserException
2
Je ne peux pas ajouter de connaissances spécifiques, mais avez-vous regardé pyjamas ( pyjs.org ), en particulier Translator.py? Ceci est un compilateur python vers javascript.
stephan
3
Re EDIT: Si vous avez le contrôle sur le code qui sera traduit, la chose la plus évidente à faire est d'éviter les constructions difficiles à traduire! Par exemple, C est beaucoup plus facile à traduire en Java s'il n'y a pas d'arithmétique de pointeur. Pour Python, je resterais probablement à l'écart des fermetures. L'autre chose que vous pouvez faire est d'écrire le code source de manière à ce que les parties les plus difficiles à traduire soient toujours codées de manière idiomatique, ce qui les rend plus faciles à reconnaître et à gérer des cas particuliers.
Ira Baxter

Réponses:

122

Je construis des outils (DMS Software Reengineering Toolkit) pour faire des manipulations de programmes à usage général (la traduction de langue étant un cas particulier) depuis 1995, soutenu par une solide équipe d'informaticiens. DMS fournit l'analyse générique, la construction AST, les tables de symboles, l'analyse de contrôle et de flux de données, l'application de règles de traduction, la régénération du texte source avec des commentaires, etc., le tout paramétré par des définitions explicites de langages informatiques.

La quantité de machines que vous devez faire ce bien est vaste (surtout si vous voulez être en mesure de le faire pour plusieurs langues d'une manière générale), et vous avez besoin parseurs fiables pour les langues avec des définitions peu fiables (PHP est parfait exemple ).

Il n'y a rien de mal à penser à créer un traducteur de langue à langue ou à l'essayer, mais je pense que vous trouverez que c'est une tâche beaucoup plus importante pour les vraies langues que ce à quoi vous vous attendez. Nous avons investi quelque 100 années-homme uniquement dans le DMS, et encore 6 à 12 mois dans chaque définition de langage "fiable" (y compris celle que nous avons péniblement construite pour PHP), beaucoup plus pour des langages désagréables tels que C ++. Ce sera une «expérience d'apprentissage d'enfer»; cela a été pour nous. (Vous pourriez trouver la section des documents techniques sur le site Web ci-dessus intéressante pour démarrer cet apprentissage).

Les gens essaient souvent de construire une sorte de machinerie généralisée en commençant par une technologie avec laquelle ils sont familiers, qui fait une partie du travail. (Les AST Python sont un excellent exemple). La bonne nouvelle, c'est qu'une partie du travail est faite. La mauvaise nouvelle est que la machinerie a des millions d'hypothèses intégrées, dont la plupart ne seront pas découvertes tant que vous n'essayerez pas de faire autre chose. À ce stade, vous découvrez que la machine est câblée pour faire ce qu'elle fait à l'origine et qu'elle résistera vraiment, vraiment à votre tentative de lui faire faire autre chose. (Je pense qu'essayer de faire en sorte que Python AST modélise PHP va être très amusant).

La raison pour laquelle j'ai commencé à construire DMS à l'origine était de construire des fondations qui avaient très peu d'hypothèses intégrées. Certaines d'entre elles nous donnent des maux de tête. Jusqu'à présent, pas de trous noirs. (La partie la plus difficile de mon travail au cours des 15 dernières années est d'essayer d'empêcher de telles hypothèses de s'infiltrer).

Beaucoup de gens font également l'erreur de supposer que s'ils peuvent analyser (et peut-être obtenir un AST), ils sont sur la bonne voie pour faire quelque chose de compliqué. L'une des leçons difficiles est que vous avez besoin de tables de symboles et d'une analyse de flux pour effectuer une bonne analyse ou transformation de programme. Les AST sont nécessaires mais pas suffisants. C'est la raison pour laquelle le livre du compilateur d'Aho & Ullman ne s'arrête pas au chapitre 2. (L'OP a ce droit dans la mesure où il prévoit de construire des machines supplémentaires au-delà de l'AST). Pour plus d'informations sur ce sujet, consultez Life After Parsing .

La remarque "Je n'ai pas besoin d'une traduction parfaite" est gênante. Ce que font les traducteurs faibles, c'est convertir les 80% "faciles" du code, laissant les 20% difficiles à faire à la main. Si l'application que vous avez l'intention de convertir est assez petite et que vous avez seulement l'intention de la convertir une fois correctement, alors ce 20% est OK. Si vous souhaitez convertir de nombreuses applications (ou même la même avec des modifications mineures au fil du temps), ce n'est pas bien. Si vous essayez de convertir 100K SLOC, 20% correspondent à 20 000 lignes de code originales difficiles à traduire, à comprendre et à modifier dans le contexte de 80 000 autres lignes de programme traduit que vous ne comprenez pas déjà. Cela demande énormément d'efforts. Au niveau du million de lignes, c'est tout simplement impossible dans la pratique.plus difficile et ils découvrent normalement douloureusement avec de longs délais, des coûts élevés et souvent un échec pur et simple.)

Ce que vous devez viser pour traduire des systèmes à grande échelle, ce sont des taux de conversion élevés des années 90, ou il est probable que vous ne puissiez pas terminer la partie manuelle de l'activité de traduction.

Une autre considération clé est la taille du code à traduire. Il faut beaucoup d'énergie pour construire un traducteur efficace et robuste, même avec de bons outils. Bien qu'il semble sexy et cool de construire un traducteur au lieu de simplement faire une conversion manuelle, pour les petites bases de code (par exemple, jusqu'à environ 100K SLOC dans notre expérience), les aspects économiques ne le justifient tout simplement pas. Personne n'aime cette réponse, mais si vous devez vraiment traduire seulement 10K SLOC de code, vous feriez probablement mieux de simplement mordre la balle et de le faire. Et oui, c'est douloureux.

Je considère que nos outils sont extrêmement bons (mais alors, je suis assez partial). Et il est encore très difficile de construire un bon traducteur; cela nous prend environ 1,5 à 2 années-homme et nous savons comment utiliser nos outils. La différence est qu'avec autant de machines, nous réussissons beaucoup plus souvent que nous échouons.

Ira Baxter
la source
8
Avez-vous déjà envisagé de renvoyer votre définition PHP «douloureusement construite» à la communauté PHP dans son ensemble, ou est-elle trop étroitement associée à votre propre flux de revenus pour que cela soit possible?
TML
53
Beaucoup de gens qui ne voulaient pas contribuer à une source de revenus et qui n'avaient pas l'énergie pour faire le travail et l'open source m'ont demandé de rendre tout ce que nous faisons "open source". Si vous ne contribuez qu'une petite partie à un très gros projet et / ou que vous avez une autre source de revenus, «open source» semble bien. Si vous avez fait tout le travail vous-même et que c'est votre seule source de revenus, c'est beaucoup moins attrayant. [Je ne veux pas entrer dans une discussion sur les mérites relatifs de la philosophie du «logiciel libre», je ne participerai donc à aucun autre commentaire dans ce sens]
Ira Baxter
9
Je suis d'accord avec ce que vous avez dit ici, c'est pourquoi j'ai formulé la question comme je l'ai fait. Je suppose que nous devons comprendre à partir de cette réponse que vous estimez que c'est trop étroitement lié à vos revenus, et il n'y a absolument rien de mal à cela - j'ai simplement pensé que cela valait la peine de le demander.
TML
3
@IraBaxter Vous venez de dire des idiomes courants sur les pratiques liées à l'informatique qui peuvent s'appliquer à beaucoup d'autres pratiques. La seule chose intéressante dans tout ce que vous avez écrit sont les liens vers semanticdesigns.com (qui se trouve être votre entreprise)
amirouche
1
Vous fournissez souvent des liens vers des pages liées à Clang dans vos réponses. Cela prouve seulement que quelqu'un d'autre peut créer une page Web. La plupart d'entre nous supposent qu'une page Web bien écrite implique qu'il y a un travail sérieux et réel derrière et pas seulement une tentative frauduleuse de tromper le lecteur comme vous semblez le laisser entendre dans votre réponse. Pensez-vous réellement que cette page Web est frauduleuse? La page contient des informations de référence à la source «pertinente»; il est anonomisé parce que le contrat pour les travaux l'exigeait. Que je ne peux pas aider.
Ira Baxter
13

Ma réponse abordera la tâche spécifique d'analyse de Python afin de le traduire dans une autre langue, et non les aspects de niveau supérieur que Ira a bien abordés dans sa réponse.

Bref: n'utilisez pas le module parser, il existe un moyen plus simple.

Le astmodule, disponible depuis Python 2.6, est beaucoup plus adapté à vos besoins, car il vous donne un AST prêt à l'emploi avec lequel travailler. J'ai écrit un article à ce sujet l'année dernière, mais en bref, utilisez la parseméthode de astpour analyser le code source Python dans un AST. Le parsermodule vous donnera un arbre d'analyse, pas un AST. Méfiez-vous de la différence .

Maintenant, comme les AST de Python sont assez détaillés, étant donné un AST, le travail frontal n'est pas terriblement difficile. Je suppose que vous pouvez avoir un prototype simple pour certaines parties de la fonctionnalité prêt assez rapidement. Cependant, parvenir à une solution complète prendra plus de temps, principalement parce que la sémantique des langages est différente. Un sous-ensemble simple du langage (fonctions, types de base, etc.) peut être facilement traduit, mais une fois que vous entrez dans les couches les plus complexes, vous aurez besoin de machines lourdes pour émuler le noyau d'un langage dans un autre. Par exemple, considérons les générateurs de Python et les listes de compréhension qui n'existent pas en PHP (à ma connaissance, ce qui est certes médiocre lorsque PHP est impliqué).

Pour vous donner un dernier conseil, considérez l' 2to3outil créé par les développeurs Python pour traduire le code Python 2 en code Python 3. En ce qui concerne le front-end, il contient la plupart des éléments dont vous avez besoin pour traduire Python en quelque chose . Cependant, comme les cœurs de Python 2 et 3 sont similaires, aucune machine d'émulation n'y est nécessaire.

Eli Bendersky
la source
Weeeell. 2to3est juste AST à AST. Il ne prend pas en charge tout ce qui dépasse les capacités du astmodule. Notez que toutes les traductions vont de la syntaxe prise en charge par le processus python hôte à la syntaxe prise en charge par le processus python hôte. Il n'y a pas de traducteur qui ajoute, disons, des annotations de fonction, car 2.6 ne le prend pas en charge.
habnabit
... et la question du PO pourrait être cadrée, à court terme, comment passer de Python 2.6 AST à ... quelque chose en PHP. Le module ast ne voudra probablement pas bien représenter la syntaxe PHP, donc ce n'est même pas astucieux.
Ira Baxter
2
@Aaron: 2to3peut être vu comme un exemple d'utilisation de l'AST généré à partir de ast.
Eli Bendersky
AFAIK, 2to3 est sans doute une traduction plus facile que Python en PHP (après tout, son Python en Python, non)? Et même cela ne fonctionne pas particulièrement bien. Notez la grande quantité de Python 2.6 qui n'a pas encore été poussée par 2to3 ... car il y a apparemment un tas de correctifs manuels post-traduction qui doivent encore être faits. S'il était 100% automatisé, Python 2.6 serait mort.
Ira Baxter
5

Écrire un traducteur n'est pas impossible, d'autant plus que le stagiaire de Joel l'a fait pendant un été.

Si vous voulez faire une langue, c'est facile. Si vous voulez en faire plus, c'est un peu plus difficile, mais pas trop. Le plus difficile est que, bien que n'importe quel langage complet turing puisse faire ce qu'un autre langage complet turing fait, les types de données intégrés peuvent changer de façon phénoménale ce qu'un langage fait.

Par exemple:

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

prend beaucoup de code C ++ à dupliquer (ok, vous pouvez le faire assez court avec des constructions en boucle, mais quand même).

C'est un peu un aparté, je suppose.

Avez-vous déjà écrit un tokenizer / analyseur basé sur une grammaire de langue? Vous voudrez probablement apprendre comment faire cela si vous ne l'avez pas fait, car c'est la partie principale de ce projet. Ce que je ferais, c'est proposer une syntaxe complète de base de Turing - quelque chose d'assez similaire au bytecode Python . Ensuite, vous créez un lexer / analyseur qui prend une grammaire de langue (peut-être en utilisant BNF ), et basé sur la grammaire, compile la langue dans votre langue intermédiaire. Ensuite, ce que vous voudrez faire est de faire l'inverse - créer un analyseur de votre langue dans les langues cibles en fonction de la grammaire.

Le problème le plus évident que je vois est qu'au début, vous allez probablement créer du code horriblement inefficace, en particulier dans des langages plus puissants * comme Python.

Mais si vous le faites de cette façon, vous serez probablement en mesure de trouver des moyens d'optimiser la sortie au fur et à mesure. Résumer:

  • lire la grammaire fournie
  • compiler le programme en syntaxe intermédiaire (mais aussi complète de Turing)
  • compiler le programme intermédiaire dans la langue finale (basé sur la grammaire fournie)
  • ...?
  • Profit!(?)

* par puissant, je veux dire que cela prend 4 lignes:

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

Montrez-moi un autre langage qui peut faire quelque chose comme ça en 4 lignes, et je vais vous montrer un langage aussi puissant que Python.

Wayne Werner
la source
"Avez-vous déjà écrit un tokenizer / analyseur basé sur une grammaire de langage?" Je l'ai fait en utilisant JavaCC.
NullUserException
2
Le stagiaire de Joel a fait un travail partiel pendant un été. Sa langue source était un sous-ensemble d'une langue existante, et vraisemblablement ce sous-ensemble pourrait être quelque peu ajusté. Cela rend le travail beaucoup plus facile. De même, NullPointerException voudra peut-être commencer par les parties les plus faciles de Python, peut-être en passant par les choses les plus difficiles pour la conversion manuelle (comme indiqué dans les questions).
David Thornley
@NullUserException: Vous aurez une certaine exposition, mais vous ferez essentiellement une réimplémentation de JavaCC, mais au lieu de Java comme langage de sortie, vous ferez <insert langauge here>. @David, tout à fait. Même Thistle a besoin d'aide sur certaines constructions de langage. Si j'étais l'OP, je choisirais d'abord le fonctionnel, puis l'optimiser, sinon je serais coincé pour toujours en essayant d'obtenir du C ++ pour faire du tranchage de chaîne (avec étapes): p
Wayne Werner
@WayneWerner Pour mémoire, les langages comme C # ne nécessitent pas du tout de nouvelles lignes. (Du moins, pas après avoir supprimé les commentaires sur une seule ligne.) Vous pouvez donc écrire n'importe quel programme C # sur une seule ligne. Mais bien sûr, je comprends ce que vous voulez en venir.
leviathanbadger
@ aboveyou00: Je ne pense pas que ce soit juste. Si vous interdisez les conditions de préprocesseur, vous avez peut-être raison.
Ira Baxter
3

Il y a quelques réponses qui vous disent de ne pas vous embêter. Eh bien, à quel point est-ce utile? Tu veux apprendre? Tu peux apprendre. C'est une compilation. Il se trouve que votre langage cible n'est pas du code machine, mais un autre langage de haut niveau. Cela se fait tout le temps.

Il existe un moyen relativement simple de commencer. Tout d'abord, allez chercher http://sourceforge.net/projects/lime-php/ (si vous voulez travailler en PHP) ou quelque chose du genre et parcourez l'exemple de code. Ensuite, vous pouvez écrire un analyseur lexical à l'aide d'une séquence d'expressions régulières et de jetons de flux vers l'analyseur que vous générez. Vos actions sémantiques peuvent soit générer du code directement dans un autre langage, soit créer une structure de données (pensez aux objets, à l'homme) que vous pouvez masser et parcourir pour générer du code de sortie.

Vous avez de la chance avec PHP et Python, car à bien des égards, ils sont dans le même langage, mais avec une syntaxe différente. Le plus dur est de surmonter les différences sémantiques entre les formes grammaticales et les structures de données. Par exemple, Python a des listes et des dictionnaires, tandis que PHP n'a que des tableaux d'assoc.

L'approche «apprenant» consiste à créer quelque chose qui fonctionne bien pour un sous-ensemble restreint du langage (comme uniquement les instructions d'impression, les mathématiques simples et l'affectation de variables), puis de supprimer progressivement les limitations. C'est essentiellement ce que les «gros» gars du terrain ont tous fait.

Oh, et comme vous n'avez pas de types statiques en Python, il peut être préférable d'écrire et de s'appuyer sur des fonctions PHP comme "python_add" qui ajoute des nombres, des chaînes ou des objets selon la façon dont Python le fait.

De toute évidence, cela peut devenir beaucoup plus important si vous le laissez.

Ian
la source
3
En fait, je n'ai pas dit "pas la peine". Ce que j'ai dit, c'est que "traduire les langues de manière générale est très difficile". Si l'OP poursuit sa voie originale d'utilisation des arbres Python pour essayer de générer du PHP, il apprendra beaucoup et je suis tout à fait en faveur de l'expérience d'apprentissage; J'ai commencé là aussi. Il ne pourra pas ajouter de nouvelles langues facilement.
Ira Baxter
@IraBaxter Je ne peux pas supporter votre déclaration, faire Python-> PHP et PHP-> Javascript serait assez simple. cf. dernière partie de stackoverflow.com/a/22850139/140837 au milieu de la réponse je traite aussi de votre "argumentation"
amirouche
2

Je vais seconder le point de vue de @EliBendersky concernant l'utilisation d'ast.parse au lieu de parser (que je ne connaissais pas auparavant). Je vous recommande également vivement de consulter son blog. J'ai utilisé ast.parse pour faire le traducteur Python-> JavaScript (@ https://bitbucket.org/amirouche/pythonium ). J'ai inventé la conception de Pythonium en examinant quelque peu d' autres implémentations et en les essayant moi-même. J'ai forké Pythonium de https://github.com/PythonJS/PythonJS que j'ai également commencé, c'est en fait une réécriture complète. La conception générale est inspirée du papier PyPy et http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf .

Tout ce que j'ai essayé, du début à la meilleure solution, même si cela ressemble à du marketing Pythonium, ce n'est vraiment pas le cas (n'hésitez pas à me dire si quelque chose ne semble pas correct à la nétiquette):

  • Implémentation de la sémantique Python dans Plain Old JavaScript en utilisant l'héritage prototype: AFAIK, il est impossible d'implémenter l'héritage multiple Python en utilisant le système d'objet prototype JS. J'ai essayé de le faire en utilisant d'autres astuces plus tard (cf. getattribute). Autant que je sache, il n'y a pas d'implémentation de l'héritage multiple Python en JavaScript, le meilleur qui existe est l'héritage unique + mixins et je ne suis pas sûr qu'ils gèrent l'héritage de diamant. Un peu similaire à Skulpt mais sans Google Clojure.

  • J'ai essayé avec Google clojure, tout comme Skulpt (compilateur) au lieu de lire le code Skulpt #fail. Quoi qu'il en soit à cause du système d'objet basé sur un prototype JS encore impossible. Créer une reliure a été très très difficile, il faut écrire du JavaScript et beaucoup de code passe-partout (cf. https://github.com/skulpt/skulpt/issues/50 où je suis le fantôme). À cette époque, il n'y avait pas de moyen clair d'intégrer la liaison dans le système de construction. Je pense que Skulpt est une bibliothèque et il suffit d'inclure vos fichiers .py dans le html à exécuter, aucune phase de compilation n'est requise par le développeur.

  • J'ai essayé pyjaco (compilateur) mais créer des liaisons (appeler du code Javascript à partir de code Python) était très difficile, il y avait trop de code standard à créer à chaque fois. Maintenant je pense que pyjaco est celui qui est le plus proche de Pythonium. pyjaco est écrit en Python (ast.parse aussi) mais beaucoup est écrit en JavaScript et utilise l'héritage de prototype.

Je n'ai jamais réussi à exécuter Pyjamas #fail et je n'ai jamais essayé de relire le code #fail. Mais dans mon esprit, pyjamas faisait de la traduction API-> API (ou framework vers framework) et non de la traduction Python vers JavaScript. Le framework JavaScript consomme des données qui se trouvent déjà dans la page ou des données du serveur. Le code Python n'est que de la "plomberie". Après cela, j'ai découvert que pyjamas était en fait un véritable traducteur python-> js.

Pourtant, je pense qu'il est possible de faire de la traduction API-> API (ou framework-> framework) et c'est essentiellement ce que je fais dans Pythonium mais à un niveau inférieur. Pyjama utilise probablement le même algorithme que Pythonium ...

Puis j'ai découvert brython entièrement écrit en Javascript comme Skulpt, pas besoin de compilation et beaucoup de fluff ... mais écrit en JavaScript.

Depuis la ligne initiale écrite au cours de ce projet, je connaissais PyPy, même le backend JavaScript pour PyPy. Oui, vous pouvez, si vous le trouvez, générer directement un interpréteur Python en JavaScript depuis PyPy. Les gens disent que c'était une catastrophe. Je n'ai lu nulle part pourquoi. Mais je pense que la raison est que le langage intermédiaire qu'ils utilisent pour implémenter l'interpréteur, RPython, est un sous-ensemble de Python conçu pour être traduit en C (et peut-être asm). Ira Baxter dit que vous faites toujours des hypothèses lorsque vous construisez quelque chose et que vous l'ajustez probablement pour qu'il soit le meilleur dans ce qu'il est censé faire dans le cas de la traduction PyPy: Python-> C. Ces hypothèses pourraient ne pas être pertinentes dans un autre contexte, pires qu'elles peuvent entraîner des frais généraux, sinon la traduction directe sera probablement toujours meilleure.

Avoir l'interpréteur écrit en Python semblait être une (très) bonne idée. Mais j'étais plus intéressé par un compilateur pour des raisons de performances.Il est en fait plus facile de compiler Python en JavaScript que de l'interpréter.

J'ai commencé PythonJS avec l'idée de créer un sous-ensemble de Python que je pourrais facilement traduire en JavaScript. Au début, je n'ai même pas pris la peine de mettre en œuvre le système OO en raison de l'expérience passée. Le sous-ensemble de Python que j'ai réussi à traduire en JavaScript est:

  • fonction avec des paramètres sémantiques complets à la fois dans la définition et l'appel. C'est la partie dont je suis le plus fier.
  • while / if / elif / else
  • Les types Python ont été convertis en types JavaScript (il n'y a aucun type Python d'aucune sorte)
  • pour pourrait itérer sur des tableaux Javascript uniquement (pour un tableau in)
  • Accès transparent à JavaScript: si vous écrivez Array dans le code Python, il sera traduit en Array en javascript. C'est la plus grande réussite en termes de convivialité par rapport à ses concurrents.
  • Vous pouvez passer la fonction définie dans la source Python aux fonctions javascript. Les arguments par défaut seront pris en compte.
  • Il ajoute une fonction spéciale appelée new qui est traduite en JavaScript new par exemple: new (Python) (1, 2, spam, "egg") est traduit en "new Python (1, 2, spam," egg ").
  • "var" sont automatiquement gérés par le traducteur. (très belle découverte de Brett (contributeur PythonJS).
  • mot-clé global
  • fermetures
  • lambdas
  • compréhension de liste
  • les importations sont prises en charge via requirejs
  • héritage de classe unique + mixin via classyjs

Cela semble beaucoup mais en fait très restreint par rapport à la sémantique complète de Python. C'est vraiment du JavaScript avec une syntaxe Python.

Le JS généré est parfait ie. il n'y a pas de surcharge, il ne peut pas être amélioré en termes de performances en l'éditant davantage. Si vous pouvez améliorer le code généré, vous pouvez également le faire à partir du fichier source Python. De plus, le compilateur ne s'appuyait sur aucune astuce JS que vous pouvez trouver dans .js écrit par http://superherojs.com/ , donc c'est très lisible.

Le descendant direct de cette partie de PythonJS est le mode Pythonium Veloce. L'implémentation complète peut être trouvée @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + environ 100 SLOC de code partagé avec l'autre traducteur.

Une version adaptée de pystones.py peut être traduite en mode Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Après avoir configuré la traduction de base de Python-> JavaScript, j'ai choisi un autre chemin pour traduire Python complet en JavaScript. La manière de glib de faire du code basé sur une classe orientée objet, sauf le langage cible, est JS, vous avez donc accès à des tableaux, des objets de type carte et de nombreuses autres astuces et toute cette partie a été écrite en Python. IIRC il n'y a pas de code javascript écrit par dans le traducteur Pythonium. Obtenir un héritage unique n'est pas difficile, voici les parties difficiles qui rendent Pythonium entièrement compatible avec Python:

  • spam.eggen Python est toujours traduit en getattribute(spam, "egg")Je n'ai pas profilé cela en particulier, mais je pense que là où cela perd beaucoup de temps et je ne suis pas sûr de pouvoir l'améliorer avec asm.js ou autre chose.
  • ordre de résolution des méthodes: même avec l'algorithme écrit en Python, le traduire en code compatible Python Veloce était un gros effort.
  • getattributre : l'algorithme de résolution réel de getattribute est assez délicat et il ne prend toujours pas en charge les descripteurs de données
  • basé sur la classe métaclasse: je sais où brancher le code, mais quand même ...
  • last but not least: some_callable (...) est toujours transalté en "call (some_callable)". AFAIK le traducteur n'utilise pas du tout l'inférence, donc chaque fois que vous effectuez un appel, vous devez vérifier de quel type d'objet il s'agit de l'appeler comme il est censé être appelé.

Cette partie est prise en compte dans https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Il est écrit en Python compatible avec Python Veloce.

Le traducteur conforme actuel https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master ne génère pas de code JavaScript directement et, surtout, n'effectue pas de transformation ast-> ast . J'ai essayé la chose ast-> ast et même si plus agréable que cst n'est pas agréable de travailler même avec ast.NodeTransformer et surtout je n'ai pas besoin de faire ast-> ast.

Faire de python ast à python ast dans mon cas au moins serait peut-être une amélioration des performances puisque j'inspecte parfois le contenu d'un bloc avant de générer le code qui lui est associé, par exemple:

  • var / global: pour pouvoir var quelque chose, je dois savoir ce dont j'ai besoin et non pas var. Au lieu de générer un bloc de suivi des variables créées dans un bloc donné et de l'insérer au-dessus du bloc de fonction généré, je recherche simplement une attribution de variable révélatrice lorsque j'entre dans le bloc avant de visiter réellement le nœud enfant pour générer le code associé.
  • rendement, les générateurs ont, pour le moment, une syntaxe spéciale dans JS, donc j'ai besoin de savoir quelle fonction Python est un générateur lorsque je veux écrire le "var my_generator = function"

Je ne visite donc pas vraiment chaque nœud une fois pour chaque phase de la traduction.

Le processus global peut être décrit comme:

Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code

Les buildins Python sont écrits en code Python (!), IIRC il y a quelques restrictions liées aux types de bootstraping, mais vous avez accès à tout ce qui peut traduire Pythonium en mode conforme. Jetez un œil à https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

La lecture du code JS généré à partir de la compatibilité pythonium peut être comprise, mais les cartes sources seront grandement utiles.

Les précieux conseils que je peux vous donner à la lumière de cette expérience sont de bons vieux pets:

  • faire une revue approfondie du sujet à la fois dans la littérature et dans les projets existants en source fermée ou gratuite. Quand j'ai passé en revue les différents projets existants, j'aurais dû lui donner beaucoup plus de temps et de motivation.
  • poser des questions! Si je savais à l'avance que le backend PyPy était inutile à cause de la surcharge due à l'incompatibilité sémantique C / Javascript. J'aurais peut-être eu une idée de Pythonium bien avant il y a 6 mois peut-être 3 ans.
  • savoir ce que vous voulez faire, avoir une cible. Pour ce projet j'avais différents objectifs: pratiquer un peu le javascript, en savoir plus sur Python et être capable d'écrire du code Python qui fonctionnerait dans le navigateur (plus et cela ci-dessous).
  • l'échec est l'expérience
  • un petit pas est un pas
  • commencer petit
  • rêve grand
  • faire des démos
  • répéter

Avec le mode Python Veloce uniquement, je suis très content! Mais en cours de route, j'ai découvert que ce que je cherchais vraiment était de me libérer, moi et les autres, de Javascript, mais surtout de pouvoir créer de manière confortable. Cela m'a conduit à Scheme, DSL, Models et éventuellement à des modèles spécifiques au domaine (cf. http://dsmforum.org/ ).

À propos de la réponse d'Ira Baxter:

Les estimations ne sont pas du tout utiles. J'ai pris plus ou moins 6 mois de temps libre pour PythonJS et Pythonium. Je peux donc m'attendre à plus de 6 mois à temps plein. Je pense que nous savons tous ce que 100 années-homme dans un contexte d'entreprise peuvent signifier et ne pas signifier du tout ...

Quand quelqu'un dit que quelque chose est difficile ou plus souvent impossible, je réponds que "cela ne prend que du temps pour trouver une solution à un problème qui est impossible" autrement dit que rien n'est impossible sauf s'il s'avère impossible dans ce cas une preuve mathématique ...

Si cela n'est pas impossible, cela laisse place à l'imagination:

  • trouver une preuve prouvant que c'est impossible

et

  • Si c'est impossible, il peut y avoir un problème «inférieur» qui peut avoir une solution.

ou

  • si ce n'est pas impossible, trouver une solution

Ce n'est pas seulement une pensée optimiste. Quand j'ai commencé Python-> Javascript, tout le monde disait que c'était impossible. PyPy impossible. Métaclasses trop difficiles. etc ... Je pense que la seule révolution qui apporte PyPy sur le papier Scheme-> C (qui a 25 ans) est une génération automatique de JIT (basée sur des indices écrits dans l'interpréteur RPython je pense).

La plupart des gens qui disent qu'une chose est «difficile» ou «impossible» n'en donnent pas les raisons. C ++ est difficile à analyser? Je sais que, ils sont toujours des analyseurs C ++ (gratuits). Le mal est dans le détail? Je le sais. Dire que c'est impossible à lui seul n'est pas utile, c'est encore pire que «pas utile», c'est décourageant, et certaines personnes veulent en décourager les autres. J'ai entendu parler de cette question via /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

Quelle serait la perfection pour vous ? C'est ainsi que vous définissez le prochain objectif et que vous atteignez peut-être l'objectif global.

Je suis plus intéressé à savoir quels types de modèles je pourrais appliquer sur le code pour faciliter la traduction (ie: IoC, SOA?) Le code que comment faire la traduction.

Je ne vois aucun modèle qui ne puisse pas être traduit d'une langue à une autre au moins d'une manière moins que parfaite. Étant donné que la traduction d'une langue à une autre est possible, vous feriez mieux de viser cette première. Depuis, je pense que selon http://en.wikipedia.org/wiki/Graph_isomorphism_problem , la traduction entre deux langages informatiques est un isomorphisme arborescent ou DAG. Même si nous savons déjà qu'ils sont tous les deux terminés, alors ...

Framework-> Framework que je visualise mieux comme API-> La traduction d'API pourrait encore être quelque chose que vous pourriez garder à l'esprit comme moyen d'améliorer le code généré. Par exemple: Prolog comme syntaxe très spécifique mais vous pouvez quand même faire Prolog comme le calcul en décrivant le même graphe en Python ... Si je devais implémenter un traducteur Prolog en Python, je n'implémenterais pas l'unification en Python mais dans une bibliothèque C et je viendrais avec une "syntaxe Python" qui est très lisible pour un pythoniste. Au final, la syntaxe n'est que "peinture" pour laquelle on donne un sens (c'est pour cela que j'ai commencé le schéma). Le mal est dans le détail du langage et je ne parle pas de la syntaxe. Les concepts utilisés dans le langage getattributehook (vous pouvez vous en passer) mais les fonctionnalités VM requises telles que l'optimisation de la récursivité de la queue peuvent être difficiles à gérer. Vous ne vous souciez pas si le programme initial n'utilise pas la récursivité de queue et même s'il n'y a pas de récursivité de queue dans la langue cible, vous pouvez l'émuler en utilisant des greenlets / boucle d'événement.

Pour les langues cible et source, recherchez:

  • Des idées grandes et spécifiques
  • Idées partagées minuscules et communes

De cela émergera:

  • Des choses faciles à traduire
  • Des choses difficiles à traduire

Vous pourrez également probablement savoir ce qui sera traduit en code rapide et lent.

Il y a aussi la question du stdlib ou de n'importe quelle bibliothèque mais il n'y a pas de réponse claire, cela dépend de vos objectifs.

Le code idiomatique ou le code généré lisible ont aussi des solutions ...

Cibler une plate-forme comme PHP est beaucoup plus facile que de cibler les navigateurs puisque vous pouvez fournir une implémentation en C d'un chemin lent et / ou critique.

Étant donné que votre premier projet consiste à traduire Python en PHP, au moins pour le sous-ensemble PHP3 que je connais, la personnalisation de veloce.py est votre meilleur pari. Si vous pouvez implémenter veloce.py pour PHP, vous pourrez probablement exécuter le mode conforme ... De plus, si vous pouvez traduire PHP dans le sous-ensemble de PHP, vous pouvez générer avec php_veloce.py cela signifie que vous pouvez traduire PHP en sous-ensemble de Python que veloce.py peut consommer, ce qui signifie que vous pouvez traduire PHP en Javascript. Juste en disant ...

Vous pouvez également jeter un œil à ces bibliothèques:

Cet article de blog (et commentaires) pourrait également vous intéresser: https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/

Amirouche
la source
La seule chose qui reste passionnante pour moi à propos de la traduction du langage informatique en langage informatique est décrite dans stackoverflow.com/questions/22621164/…
amirouche
Je seconde l'autre réponse sur les types de données. Dans Pythonium, je n'avais même pas l'intention de prendre en charge un type entier et flottant correct dans le mode conforme sans asm.js.
amirouche
OK, donc si je vous donne un package Python de 100K SLOC, et que vous l'exécutez via votre "traducteur", est-ce que j'obtiens un programme fonctionnel? Combien de travail manuel après la traduction faut-il pour résoudre ce problème? Ce que vous avez dit ici, c'est: "étant donné un bon analyseur pour Python déjà existant qui construit des AST, je peux construire un traducteur partiel en 6 mois". Personne n'est surpris. 6 mois n'est pas, selon les normes de la plupart des gens, «assez facile» (citant un autre de vos commentaires). La résolution des problèmes restants exigera plus d'efforts. Ma réponse a dit, fondamentalement, "faire ceci n'est pas facile", et "le faire d'une manière générale est difficile".
Ira Baxter
... ce dernier point en réponse au désir originel d'OP: «idéalement, je pourrais ajouter d'autres langues avec une (relative) facilité», ce que ma réponse aborde spécifiquement.
Ira Baxter
Je ne suis pas d'accord, surtout quand vous savez ce que vous faites, c'est facile et ce qui suit n'est pas difficile, c'est juste une question de faire avancer les choses. Je ne sais pas trop où vous parlez de quelque chose de spécifique à la question. Vous dites en 4 ou 5 paragraphes que votre entreprise le fait, et c'est difficile. Mais sinon, vous diffusez FUD sur le sujet, tout en étant un peu hors sujet comme vous l'êtes dans stackoverflow.com/questions/22621164/… . A plein temps 6 mois j'aurais écrit un traducteur complet.
amirouche
0

Vous pouvez jeter un œil au compilateur Vala , qui traduit Vala (un langage de type C #) en C.

ptomate
la source
C'était un objectif de conception de Vala d'être traduit en C et de faciliter le développement avec les bibliothèques gnome.
amirouche