98 Stimmen

Welche Arten von Mustern könnte ich dem Code aufzwingen, um ihn leichter in eine andere Programmiersprache übersetzen zu können?

Ich bin dabei, ein Nebenprojekt zu starten, dessen Ziel es ist, Code von einer Programmiersprache in eine andere zu übersetzen. Die Sprachen, mit denen ich anfange, sind PHP und Python (Python zu PHP sollte am Anfang einfacher sein), aber idealerweise wäre ich in der Lage, andere Sprachen mit (relativer) Leichtigkeit hinzuzufügen. Der Plan ist:

  • Dies ist auf die Webentwicklung ausgerichtet. Der ursprüngliche und der Zielcode werden auf Frameworks aufsetzen (die ich ebenfalls schreiben muss). Diese Frameworks werden ein MVC-Entwurfsmuster verwenden und strengen Kodierungskonventionen folgen. Das sollte die Übersetzung etwas einfacher machen.

  • Ich beschäftige mich auch mit IOC und Dependency Injection, da sie den Übersetzungsprozess einfacher und weniger fehleranfällig machen könnten.

  • Ich benutze Pythons Parser-Modul die es mir ermöglicht, mit dem abstrakten Syntaxbaum zu spielen. Das, was ich mit PHP am ehesten erreichen kann, ist anscheinend token_get_all() Das ist ein Anfang.

  • Von da an kann ich die AST, die Symboltabellen und den Kontrollfluss erstellen.

Dann glaube ich, dass ich mit der Ausgabe von Code beginnen kann. Ich brauche keine perfekte Übersetzung . Ich werde den generierten Code noch überprüfen und Probleme beheben müssen. Idealerweise sollte der Übersetzer problematische Übersetzungen kennzeichnen.

Bevor Sie fragen: "Was zum Teufel soll das?" Die Antwort ist... Es wird eine interessante Lernerfahrung sein. Wenn Sie wissen, wie man das Ganze weniger entmutigend gestalten kann, lassen Sie es mich bitte wissen.


EDITAR:

Ich bin mehr daran interessiert zu wissen, welche Arten von Mustern ich dem Code aufzwingen könnte, um die Übersetzung zu erleichtern (z. B. IoC, SOA ?), als daran, wie ich die Übersetzung durchführe.

6 Stimmen

Haben Sie sich Systeme wie die .NET CLR oder Parrot von Perl6 angesehen? Sie kompilieren eine Reihe von Sprachen in eine Zwischendarstellung, die von einem gemeinsamen Interpreter ausgeführt werden kann. Wenn man von der Zwischendarstellung zurück zu einer Sprache gehen kann, hat man einen Übersetzer.

1 Stimmen

@Borealid AFAIK ist die .NET CIL (relativ) einfach zu kompilieren in aber viel Glück dabei, lesbaren Code zurückzubekommen. Ich schaue mir jetzt Parrot an.

0 Stimmen

Es gibt ähnliche Projekte für andere Sprachen; ich bin nicht sicher, wie reich deren Autoren sind. Und ich schränke mich hier tatsächlich sehr ein, indem ich ein Gerüst brauche und mich an strenge Programmierkonventionen halte.

130voto

Ira Baxter Punkte 91118

Ich habe Erstellungswerkzeuge (DMS Software Reengineering Toolkit) zur allgemeinen Programmmanipulation (wobei die Sprachübersetzung einen Sonderfall darstellt) seit 1995, unterstützt von einem starken Team von Informatikern. DMS bietet generisches Parsing, AST-Erstellung, Symboltabellen, Kontroll- und Datenflussanalyse, Anwendung von Übersetzungsregeln, Regeneration von Quelltext mit Kommentaren usw., alles parametrisiert durch explizite Definitionen von Computersprachen.

Die Menge an Maschinen, die Sie für diese Aufgabe benötigen gut ist sehr umfangreich (vor allem, wenn man dies allgemein für mehrere Sprachen tun möchte), und dann braucht man zuverlässige Parser für Sprachen mit unzuverlässigen Definitionen (PHP ist das perfekte Beispiel dafür).

Es ist nichts dagegen einzuwenden, wenn Sie darüber nachdenken, einen Übersetzer von Sprache zu Sprache zu bauen oder es zu versuchen, aber ich denke, Sie werden feststellen, dass dies für echte Sprachen eine viel größere Aufgabe ist, als Sie erwarten. Wir haben etwa 100 Mannjahre allein in DMS investiert, und weitere 6-12 Monate in jede "zuverlässige" Sprachdefinition (einschließlich der, die wir mühsam für PHP erstellt haben), und noch viel mehr für unangenehme Sprachen wie C++. Es wird eine "höllische Lernerfahrung" sein; das war es auch für uns. (Vielleicht finden Sie den Abschnitt "Technical Papers" auf der oben genannten Website interessant, um mit dem Lernen zu beginnen).

Die Menschen versuchen oft, eine Art verallgemeinerte Maschine zu bauen, indem sie mit einem Stück Technologie beginnen, mit dem sie vertraut sind und das einen Teil der Aufgabe erfüllt. (Python ASTs sind ein gutes Beispiel). Die gute Nachricht ist, dass damit ein Teil der Aufgabe erledigt ist. Die schlechte Nachricht ist, dass diese Maschinen eine Vielzahl von Annahmen enthalten, von denen man die meisten erst entdeckt, wenn man versucht, sie dazu zu bringen, etwas anderes zu tun. Dann stellt man fest, dass die Maschine so verdrahtet ist, dass sie das tut, was sie ursprünglich getan hat, und sich dem Versuch, sie zu etwas anderem zu bewegen, sehr widersetzen wird. (Ich vermute, dass der Versuch, den Python AST dazu zu bringen, PHP zu modellieren, eine Menge Spaß machen wird).

Der Grund, warum ich ursprünglich mit dem Aufbau von DMS begonnen habe, war, Grundlagen zu schaffen, die nur wenige solcher Annahmen enthalten. Es gibt einige, die uns Kopfschmerzen bereiten. Bis jetzt aber keine schwarzen Löcher. (Der schwierigste Teil meiner Arbeit in den letzten 15 Jahren besteht darin, zu verhindern, dass sich solche Annahmen einschleichen).

Viele Leute machen auch den Fehler, anzunehmen, dass sie, wenn sie parsen können (und vielleicht einen AST erhalten), auf dem besten Weg sind, etwas Kompliziertes zu tun. Eine der harten Lektionen ist, dass man Symboltabellen und Flussanalysen braucht, um eine gute Programmanalyse oder -transformation durchzuführen. ASTs sind notwendig, aber nicht ausreichend. Das ist der Grund, warum Aho&Ullmans Compiler-Buch nicht bei Kapitel 2 aufhört (der OP hat insofern Recht, als er plant, über den AST hinaus zusätzliche Maschinen zu bauen). Für mehr zu diesem Thema, siehe Leben nach dem Parsen .

Die Bemerkung "Ich brauche keine perfekte Übersetzung" ist problematisch. Schwache Übersetzer konvertieren die "einfachen" 80 % des Codes und überlassen die schwierigen 20 % der Handarbeit. Wenn die Anwendungen, die Sie konvertieren wollen, ziemlich klein sind und Sie sie nur einmal konvertieren wollen, dann sind diese 20% in Ordnung. Wenn Sie viele Anwendungen konvertieren wollen (oder sogar dieselbe Anwendung mit kleinen Änderungen im Laufe der Zeit), ist das nicht schön. Wenn Sie versuchen, 100K SLOC zu konvertieren, dann sind 20% 20.000 ursprüngliche Codezeilen, die schwer zu übersetzen, zu verstehen und zu ändern sind, und das im Kontext von weiteren 80.000 Zeilen übersetzten Programms, das Sie ohnehin nicht verstehen. Das bedeutet einen enormen Aufwand. Bei einer Million Zeilen ist dies in der Praxis einfach unmöglich. (Erstaunlicherweise gibt es Leute, die automatisierten Tools misstrauen und darauf bestehen, millionenzeilige Systeme von Hand zu übersetzen; das ist sogar härter und sie finden es in der Regel schmerzlich heraus, mit langen Zeitverzögerungen, hohen Kosten und oft einem völligen Scheitern).

Bei der Übersetzung von Großsystemen müssen Sie hohe Konversionsraten in den 90er Jahren anstreben, sonst können Sie den manuellen Teil der Übersetzungsarbeit wahrscheinlich nicht erledigen.

Ein weiterer wichtiger Aspekt ist der Umfang des zu übersetzenden Codes. Es kostet viel Energie, einen funktionierenden, robusten Übersetzer zu erstellen, selbst mit guten Tools. Es scheint zwar sexy und cool zu sein, einen Übersetzer zu bauen, anstatt einfach eine manuelle Konvertierung vorzunehmen, aber für kleine Codebasen (z.B. bis zu etwa 100K SLOC nach unserer Erfahrung) rechtfertigt die Wirtschaftlichkeit dies einfach nicht. Niemandem gefällt diese Antwort, aber wenn Sie wirklich nur 10.000 SLOC Code übersetzen müssen, sind Sie wahrscheinlich besser dran, wenn Sie in den sauren Apfel beißen und es tun. Und ja, das ist schmerzhaft.

Ich halte unsere Werkzeuge für extrem gut (aber ich bin da ziemlich voreingenommen). Und es ist immer noch sehr schwer, einen guten Übersetzer zu entwickeln; wir brauchen dafür etwa 1,5-2 Mannjahre und wissen, wie wir unsere Werkzeuge einsetzen. Der Unterschied besteht darin, dass wir mit diesem großen Maschinenpark Erfolg haben wesentlich häufiger, als wir scheitern.

14voto

Eli Bendersky Punkte 246100

Meine Antwort wird sich mit der spezifischen Aufgabe des Parsens von Python befassen, um es in eine andere Sprache zu übersetzen, und nicht mit den übergeordneten Aspekten, die Ira in seiner Antwort gut behandelt hat.

Kurz gesagt: verwenden Sie nicht das Parser-Modul, es gibt einen einfacheren Weg.

El ast Modul, das seit Python 2.6 verfügbar ist, ist viel besser für Ihre Bedürfnisse geeignet, da es Ihnen ein fertiges AST zur Verfügung stellt, mit dem Sie arbeiten können. Ich habe ein Artikel über diesen letztes Jahr, aber kurz gesagt, nutzen Sie die parse Methode der ast um Python-Quellcode in einen AST zu parsen. Die Website parser Modul erhalten Sie einen Parse-Baum, keinen AST. Achten Sie auf den Unterschied .

Nun, da die ASTs von Python recht detailliert sind, ist die Aufgabe des Front-Ends bei einem AST nicht besonders schwer. Ich nehme an, dass Sie einen einfachen Prototyp für einige Teile der Funktionalität recht schnell fertig haben können. Der Weg zu einer vollständigen Lösung wird jedoch mehr Zeit in Anspruch nehmen, vor allem weil die Semantik der Sprachen unterschiedlich ist. Eine einfache Teilmenge der Sprache (Funktionen, Grundtypen usw.) lässt sich leicht übersetzen, aber sobald man zu den komplexeren Schichten übergeht, benötigt man eine umfangreiche Maschinerie, um den Kern der einen Sprache in einer anderen zu emulieren. Denken Sie zum Beispiel an Pythons Generatoren und List Comprehensions, die es in PHP nicht gibt (nach meinem besten Wissen, das zugegebenermaßen schlecht ist, wenn es um PHP geht).

Ein letzter Tipp: Beachten Sie die 2to3 Werkzeug, das von den Python-Entwicklern entwickelt wurde, um Python 2-Code in Python 3-Code zu übersetzen. Auf der Vorderseite enthält es die meisten Elemente, die Sie für die Übersetzung von Python in etwas . Da die Kerne von Python 2 und 3 jedoch ähnlich sind, ist dort keine Emulationsmaschine erforderlich.

4voto

Wayne Werner Punkte 45176

Einen Übersetzer zu schreiben ist nicht unmöglich, besonders wenn man bedenkt, dass Joel's Intern hat es einen Sommer lang gemacht.

Wenn Sie nur eine Sprache machen wollen, ist das ganz einfach. Wenn man mehr machen will, ist es etwas schwieriger, aber nicht zu schwierig. Das Schwierigste ist, dass zwar jede vollständige Turing-Sprache das tun kann, was eine andere vollständige Turing-Sprache tut, aber eingebaute Datentypen können die Möglichkeiten einer Sprache phänomenal verändern.

Zum Beispiel:

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

nimmt eine Los C++-Code zu duplizieren (ok, man kann es mit einigen Schleifenkonstrukten recht kurz machen, aber trotzdem).

Das nur am Rande, denke ich.

Haben Sie jemals einen Tokenizer/Parser geschrieben, der auf einer Sprachgrammatik basiert? Sie werden wahrscheinlich lernen wollen, wie man das tut, wenn Sie nicht haben, weil das der Hauptteil dieses Projekts ist. Was ich tun würde, ist, eine grundlegende Turing-komplette Syntax zu entwickeln - etwas, das Python ziemlich ähnlich ist Bytecode . Dann erstellen Sie einen Lexer/Parser, der eine Sprachgrammatik (vielleicht mit BNF ), und kompiliert die Sprache auf der Grundlage der Grammatik in Ihre Zwischensprache. Dann wollen Sie den umgekehrten Weg gehen und auf der Grundlage der Grammatik einen Parser von Ihrer Sprache in die Zielsprachen erstellen.

Das offensichtlichste Problem, das ich sehe, ist, dass Sie am Anfang wahrscheinlich furchtbar ineffizienter Code, insbesondere in mächtigeren* Sprachen wie Python.

Aber wenn Sie so vorgehen, werden Sie wahrscheinlich in der Lage sein, im Laufe der Zeit Wege zur Optimierung der Ausgabe zu finden. Um es zusammenzufassen:

  • bereitgestellte Grammatik lesen
  • Kompilieren des Programms in eine intermediäre (aber auch Turing-komplette) Syntax
  • Kompilieren des Zwischenprogramms in die endgültige Sprache (auf der Grundlage der vorgegebenen Grammatik)
  • ...?
  • Gewinn!(?)

*Mit mächtig meine ich, dass dies 4 Zeilen erfordert:

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

Zeigen Sie mir eine andere Sprache, die so etwas in 4 Zeilen kann, und ich zeige Ihnen eine Sprache, die so mächtig ist wie Python.

3voto

Ian Punkte 4305

Es gibt ein paar Antworten, die Ihnen sagen, dass Sie sich nicht bemühen sollen. Nun, wie hilfreich ist das? Sie wollen lernen? Sie können es lernen. Dies ist eine Zusammenstellung. Es ist nur so, dass Ihre Zielsprache nicht Maschinencode ist, sondern eine andere Hochsprache. Das wird ständig gemacht.

Es gibt einen relativ einfachen Weg, damit anzufangen. Holen Sie sich zunächst http://sourceforge.net/projects/lime-php/ (wenn Sie in PHP arbeiten wollen) oder ähnliches und gehen Sie den Beispielcode durch. Als Nächstes können Sie einen lexikalischen Analysator schreiben, der eine Folge von regulären Ausdrücken verwendet, und den von Ihnen erzeugten Parser mit Token füttern. Ihre semantischen Aktionen können entweder direkt Code in einer anderen Sprache ausgeben oder eine Datenstruktur aufbauen (denken Sie an Objekte), die Sie massieren und durchlaufen können, um Ausgabecode zu erzeugen.

Mit PHP und Python haben Sie Glück, denn sie sind in vielerlei Hinsicht die gleiche Sprache, nur mit einer anderen Syntax. Der schwierige Teil ist, die semantischen Unterschiede zwischen den Grammatikformen und Datenstrukturen zu überwinden. Python hat zum Beispiel Listen und Wörterbücher, während PHP nur assoc-Arrays hat.

Der "Lernansatz" besteht darin, etwas zu entwickeln, das für eine begrenzte Teilmenge der Sprache funktioniert (z. B. nur Druckanweisungen, einfache Mathematik und Variablenzuweisung), und dann schrittweise Einschränkungen zu beseitigen. Das ist im Grunde das, was die "Großen" in diesem Bereich alle gemacht haben.

Oh, und da es in Python keine statischen Typen gibt, ist es vielleicht am besten, PHP-Funktionen wie "python_add" zu schreiben und sich darauf zu verlassen, die Zahlen, Zeichenketten oder Objekte entsprechend der Python-Methode addieren.

Das kann natürlich noch viel größer werden, wenn man es zulässt.

2voto

amirouche Punkte 7224

Ich schließe mich der Meinung von @EliBendersky bezüglich der Verwendung von ast.parse anstelle von parser an (was ich vorher nicht wusste). Ich empfehle Ihnen auch wärmstens, seinen Blog zu lesen. Ich habe ast.parse für den Python->JavaScript-Übersetzer verwendet (@ https://bitbucket.org/amirouche/pythonium ). Ich habe mir das Pythonium-Design ausgedacht, indem ich etwas Ich habe mir andere Implementierungen angesehen und sie selbst ausprobiert. Ich forkte Pythonium von https://github.com/PythonJS/PythonJS das ich ebenfalls begonnen habe, ist eigentlich eine komplette Neufassung. Das Gesamtdesign ist inspiriert von PyPy und http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf Papier.

Alles, was ich versucht habe, von Anfang an bis zur besten Lösung, auch wenn es nach Pythonium-Marketing aussieht, ist es das nicht wirklich (zögern Sie nicht, mir zu sagen, wenn etwas nicht der Netiquette entspricht):

  • Implementieren Sie Python semantische in Plain Old JavaScript mit Prototyp Vererbung: AFAIK ist es unmöglich, Python Mehrfachvererbung mit JS-Prototyp-Objekt-System zu implementieren. Ich habe versucht, es mit anderen Tricks später zu tun (vgl. getattribute). Soweit ich weiß, gibt es keine Implementierung von Python-Mehrfachvererbung in JavaScript, das Beste, was es gibt, ist Single inhertance + mixins und ich bin mir nicht sicher, ob sie Diamant-Vererbung behandeln. Ähnlich wie Skulpt, aber ohne Google Clojure.

  • Ich habe versucht, mit Google Clojure, genau wie Skulpt (Compiler) anstelle von tatsächlich lesen Skulpt Code #fail. Auf jeden Fall wegen der JS-Prototyp-basierte Objekt-System noch unmöglich. Erstellen von Bindung war sehr sehr schwierig, müssen Sie JavaScript und eine Menge von Boilerplate-Code zu schreiben (vgl. https://github.com/skulpt/skulpt/issues/50 wo ich der Geist bin). Zu dieser Zeit gab es keine klare Möglichkeit, die Bindung in das Build-System zu integrieren. Ich denke, dass Skulpt eine Bibliothek ist und Sie müssen nur Ihre .py-Dateien in die auszuführende HTML-Datei einbinden, ohne dass der Entwickler eine Kompilierungsphase durchführen muss.

  • Ich habe pyjaco (Compiler) ausprobiert, aber das Erstellen von Bindungen (Aufruf von Javascript-Code aus Python-Code) war sehr schwierig, es gab jedes Mal zu viel Boilerplate-Code zu erstellen. Jetzt denke ich, pyjaco ist die eine, die mehr in der Nähe von Pythonium. pyjaco ist in Python (ast.parse auch) geschrieben, aber eine Menge ist in JavaScript geschrieben und es verwenden Prototyp Vererbung.

Ich habe es nie geschafft, Pyjamas zum Laufen zu bringen #fail und habe nie versucht, den Code zu lesen #fail again. Aber in meinem Kopf machte PyJamas eine API->API Übersetzung (oder Framework zu Framework) und nicht eine Python zu JavaScript Übersetzung. Das JavaScript-Framework verbraucht Daten, die bereits auf der Seite vorhanden sind, oder Daten vom Server. Python-Code ist nur "Klempnerarbeit". Danach entdeckte ich, dass Pyjamas tatsächlich ein echter Python->JS-Übersetzer war.

Dennoch denke ich, dass es möglich ist, API->API (oder Framework->Framework) Übersetzung zu tun, und das ist im Grunde, was ich in Pythonium tun, aber auf niedrigerer Ebene. Wahrscheinlich Pyjamas verwenden den gleichen Algorithmus wie Pythonium...

Dann entdeckte ich Brython vollständig in Javascript geschrieben wie Skulpt, keine Notwendigkeit für die Kompilierung und viel Fluff... aber in JavaScript geschrieben.

Seit der ersten Zeile, die im Rahmen dieses Projekts geschrieben wurde, wusste ich über PyPy Bescheid, sogar über das JavaScript-Backend für PyPy. Ja, man kann, wenn man es findet, direkt einen Python-Interpreter in JavaScript aus PyPy erzeugen. Die Leute sagen, es war eine Katastrophe. Ich habe nirgends gelesen, warum. Aber ich denke, der Grund ist, dass die Zwischensprache, die sie zur Implementierung des Interpreters verwenden, RPython, eine Untermenge von Python ist, die auf die Übersetzung in C (und vielleicht asm) zugeschnitten ist. Ira Baxter sagt, dass man immer Annahmen trifft, wenn man etwas entwickelt, und im Falle von PyPy muss man es wahrscheinlich so abstimmen, dass es das am besten kann, was es tun soll: Python->C-Übersetzung. Diese Annahmen sind vielleicht in einem anderen Kontext nicht relevant, aber sie können zu einem Overhead führen, da die direkte Übersetzung wahrscheinlich immer besser ist.

Den Interpreter in Python zu schreiben, klang nach einer (sehr) guten Idee. Aber ich war mehr daran interessiert, in einem Compiler aus Gründen der Leistung auch ist es eigentlich einfacher zu kompilieren Python zu JavaScript als es zu interpretieren.

Ich habe PythonJS mit der Idee begonnen, eine Teilmenge von Python zusammenzustellen, die ich leicht in JavaScript übersetzen kann. Zuerst habe ich mich nicht einmal darum gekümmert, ein OO-System zu implementieren, weil ich bereits Erfahrung damit hatte. Die Teilmenge von Python, die ich erreicht habe, um sie in JavaScript zu übersetzen, sind:

  • Funktion mit voller Parametersemantik sowohl bei der Definition als auch beim Aufruf. Dies ist der Teil, auf den ich am meisten stolz bin.
  • while/if/elif/else
  • Python-Typen wurden in JavaScript-Typen umgewandelt (es gibt keine Python-Typen mehr)
  • for könnte nur über Javascript-Arrays iterieren (for a in array)
  • Transparenter Zugang zu JavaScript: Wenn Sie Array in den Python-Code schreiben, wird es in Array in JavaScript übersetzt. Dies ist die größte Errungenschaft in Bezug auf die Benutzerfreundlichkeit gegenüber seinen Konkurrenten.
  • Sie können Funktion in Python Quelle definiert, um Javascript-Funktionen übergeben. Standardargumente werden dabei berücksichtigt.
  • Es fügt eine spezielle Funktion namens new hinzu, die in JavaScript new übersetzt wird, z.B.: new(Python)(1, 2, spam, "egg") wird in "new Python(1, 2, spam, "egg") übersetzt.
  • "var" werden automatisch vom Übersetzer behandelt. (sehr schöner Fund von Brett (PythonJS-Mitarbeiter).
  • globales Schlüsselwort
  • Verschlüsse
  • lambdas
  • Listenauffassungen
  • Importe werden über requirejs unterstützt
  • Vererbung einzelner Klassen + Mixin über classyjs

Dies scheint wie eine Menge, aber tatsächlich sehr eng im Vergleich zu vollwertigen semantischen von Python. Es ist wirklich JavaScript mit einer Python-Syntax.

Das generierte JS ist perfekt, d.h. es gibt keinen Overhead, es kann in Bezug auf die Leistung nicht verbessert werden, indem es weiter bearbeitet wird. Wenn Sie den generierten Code verbessern können, können Sie dies auch in der Python-Quelldatei tun. Außerdem hat sich der Compiler nicht auf irgendwelche JS-Tricks verlassen, die Sie in .js finden können, das von http://superherojs.com/ Sie ist also sehr gut lesbar.

Der direkte Nachfahre dieses Teils von PythonJS ist der Pythonium Veloce Modus. Die vollständige Implementierung ist zu finden unter @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + etwa 100 SLOC gemeinsamer Code mit dem anderen Übersetzer.

Eine angepasste Version von pystones.py kann im Veloce-Modus übersetzt werden, siehe. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Nachdem ich die grundlegende Python->JavaScript-Übersetzung eingerichtet hatte, wählte ich einen anderen Weg, um Python vollständig in JavaScript zu übersetzen. Die Art und Weise der Glib tun objektorientierten klassenbasierten Code, außer die Zielsprache ist JS, so dass Sie Zugriff auf Arrays, Map-ähnliche Objekte und viele andere Tricks und all das Teil wurde in Python geschrieben. IIRC gibt es keine Javascript-Code von in Pythonium Übersetzer geschrieben. Erste Single-Vererbung ist nicht schwer, hier sind die schwierigen Teile machen Pythonium voll kompatibel mit Python:

  • spam.egg wird in Python immer übersetzt in getattribute(spam, "egg") Ich habe dieses Profil nicht speziell, aber ich denke, dass, wo es eine Menge Zeit verlieren, und ich bin mir nicht sicher, ich kann auf sie mit asm.js oder etwas anderes zu verbessern.
  • Reihenfolge der Methodenauflösung: Selbst wenn der Algorithmus in Python geschrieben wurde, war es ein großes Unterfangen, ihn in Python Veloce-kompatiblen Code zu übersetzen.
  • getattributre Der eigentliche getattribute-Auflösungsalgorithmus ist ziemlich kompliziert und unterstützt immer noch keine Datendeskriptoren.
  • Metaklasse klassenbasiert: Ich weiß, wo ich den Code einfügen muss, aber trotzdem...
  • last but not least: some_callable(...) wird immer in "call(some_callable)" umgewandelt. AFAIK der Übersetzer nicht verwenden Inferenz überhaupt, so dass jedes Mal, wenn Sie einen Aufruf müssen Sie überprüfen, welche Art von Objekt es ist, um es aufzurufen, wie es gemeint ist, aufgerufen werden.

Dieser Teil ist bereits berücksichtigt https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Es ist in Python geschrieben und mit Python Veloce kompatibel.

Der aktuelle konforme Übersetzer https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master generiert nicht direkt JavaScript-Code und vor allem nicht die Transformation ast->ast. Ich habe versucht, die ast->ast Sache und ast, auch wenn schöner als cst ist nicht schön zu arbeiten, auch mit ast.NodeTransformer und was noch wichtiger ist, ich brauche nicht zu tun, ast->ast.

Die Umwandlung von python ast in python ast wäre zumindest in meinem Fall vielleicht eine Leistungsverbesserung, da ich beispielsweise manchmal den Inhalt eines Blocks prüfe, bevor ich den dazugehörigen Code generiere:

  • var/global: um etwas varieren zu können, muss ich wissen, was ich varieren muss und was nicht. Anstatt einen Block zu generieren, der verfolgt, welche Variablen in einem bestimmten Block erstellt werden, und ihn oben in den generierten Funktionsblock einzufügen, suche ich einfach nach der Zuweisung der Variablen, wenn ich den Block betrete, bevor ich den untergeordneten Knoten besuche, um den zugehörigen Code zu erzeugen.
  • Ertrag, Generatoren haben bisher eine spezielle Syntax in JS, so dass ich wissen muss, welche Python-Funktion ein Generator ist, wenn ich die "var my_generator = function" schreiben will

Ich besuche also nicht wirklich jeden Knoten einmal für jede Phase der Übersetzung.

Der Gesamtprozess kann wie folgt beschrieben werden:

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

Python-Builtins sind in Python-Code (!) geschrieben, IIRC gibt es ein paar Einschränkungen im Zusammenhang mit Bootstraping-Typen, aber Sie haben Zugang zu allem, was Pythonium im konformen Modus übersetzen kann. Werfen Sie einen Blick auf https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

Das Lesen von JS-Code, der aus Pythonium generiert wurde, ist zwar verständlich, aber Source Maps sind eine große Hilfe.

Die wertvollen Ratschläge, die ich Ihnen im Lichte dieser Erfahrung geben kann, sind freundliche alte Fürze:

  • ausgiebig das Thema sowohl in der Literatur als auch in bestehenden Projekten mit geschlossenem oder freiem Quellcode überprüfen. Als ich die verschiedenen bestehenden Projekte überprüfte, hätte ich dem Thema viel mehr Zeit und Motivation widmen sollen.
  • Fragen stellen! Wenn ich vorher gewusst hätte, dass PyPy Backend wegen des Overheads aufgrund der semantischen Unstimmigkeit zwischen C und Javascript nutzlos ist. Ich würde vielleicht hatte Pythonium Idee Weg vor 6 Monaten vielleicht 3 Jahre her.
  • Sie wissen, was Sie tun wollen, haben ein Ziel. Für dieses Projekt hatte ich verschiedene Ziele: ein bisschen Javascript üben, mehr über Python lernen und in der Lage sein, Python-Code zu schreiben, der im Browser läuft (mehr dazu unten).
  • Scheitern ist Erfahrung
  • ein kleiner Schritt ist ein Schritt
  • klein anfangen
  • große Träume
  • Demos machen
  • iterieren

Nur mit dem Python Veloce Modus bin ich sehr zufrieden! Aber auf dem Weg dorthin entdeckte ich, dass das, was ich wirklich wollte, mich und andere von Javascript zu befreien, aber noch wichtiger war, in der Lage zu sein erstellen. auf bequeme Art und Weise. Dies führte mich zu Scheme, DSL, Modellen und schließlich zu domänenspezifischen Modellen (vgl. http://dsmforum.org/ ).

Über das, was Ira Baxter antwortet:

Die Schätzungen sind überhaupt nicht hilfreich. Ich habe mehr oder weniger 6 Monate Freizeit für PythonJS und Pythonium gebraucht. Ich kann also mehr von 6 Monaten Vollzeit erwarten. Ich denke, wir alle wissen, was 100 Mannjahre in einem Unternehmenskontext bedeuten können und was nicht...

Wenn jemand sagt, dass etwas schwierig oder öfters unmöglich ist, antworte ich, dass "es nur Zeit braucht, um eine Lösung für ein Problem zu finden, das unmöglich ist", ansonsten ist nichts unmöglich, es sei denn, es ist erwiesenermaßen unmöglich, in diesem Fall ein mathematischer Beweis...

Wenn die Unmöglichkeit nicht bewiesen ist, bleibt Raum für Phantasie:

  • einen Beweis zu finden, der beweist, dass es unmöglich ist

y

  • Wenn dies nicht möglich ist, gibt es vielleicht ein "minderwertiges" Problem, für das eine Lösung gefunden werden kann.

ou

  • wenn es nicht unmöglich ist, eine Lösung zu finden

Das ist nicht nur optimistisches Denken. Als ich mit Python->Javascript anfing, sagte jeder, es sei unmöglich. PyPy unmöglich. Metaklassen zu schwer. usw... Ich denke, dass die einzige Revolution, die PyPy über Scheme->C-Papier (das 25 Jahre alt ist) bringt, eine automatische JIT-Generierung ist (basierend auf Hinweisen, die im RPython-Interpreter geschrieben wurden, glaube ich).

Die meisten Leute, die sagen, dass etwas "schwer" oder "unmöglich" ist, nennen keine Gründe dafür. C++ ist schwer zu parsen? Das weiß ich, trotzdem gibt es (kostenlose) C++-Parser. Das Böse steckt im Detail? Auch das weiß ich. Allein zu sagen, dass es unmöglich ist, ist nicht hilfreich. Es ist noch schlimmer als "nicht hilfreich", es ist entmutigend, und manche Leute wollen andere entmutigen. Ich hörte von dieser Frage durch https://stackoverflow.com/questions/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

Was wäre Perfektion? für Sie ? So kann man das nächste Ziel definieren und vielleicht das Gesamtziel erreichen.

Ich bin eher daran interessiert zu erfahren, welche Arten von Mustern ich durchsetzen könnte Code erzwingen könnte, um die Übersetzung (z. B. IoC, SOA ?) des Codes zu erleichtern als wie man die Übersetzung durchführt.

Ich sehe keine Muster, die nicht von einer Sprache in eine andere Sprache übersetzt werden können, zumindest nicht perfekt. Da eine Übersetzung von Sprache zu Sprache möglich ist, sollten Sie sich zuerst um diese bemühen. Denn ich denke, nach http://en.wikipedia.org/wiki/Graph_isomorphism_problem Die Übersetzung zwischen zwei Computersprachen ist ein Baum- oder DAG-Isomorphismus. Auch wenn wir bereits wissen, dass sie beide turing-vollständig sind, so...

Framework->Framework, das ich mir besser als API->API-Übersetzung vorstelle, könnte etwas sein, das Sie als Möglichkeit zur Verbesserung des generierten Codes in Betracht ziehen könnten. Z.B.: Prolog hat eine sehr spezifische Syntax, aber man kann trotzdem Prolog-ähnliche Berechnungen durchführen, indem man denselben Graphen in Python beschreibt... Wenn ich einen Prolog-Python-Übersetzer implementieren würde, würde ich die Vereinheitlichung nicht in Python, sondern in einer C-Bibliothek implementieren und eine "Python-Syntax" entwickeln, die für einen Pythonisten sehr lesbar ist. Letztendlich ist die Syntax nur ein "Gemälde", dem wir eine Bedeutung geben (deshalb habe ich mit dem Schema angefangen). Das Böse steckt im Detail der Sprache und ich spreche nicht von der Syntax. Die Konzepte, die in der Sprache verwendet werden getAttribut Haken (man kann auch ohne ihn leben), aber erforderliche VM-Funktionen wie die Tail-Recursion-Optimierung können schwierig zu handhaben sein. Es ist egal, ob das Ausgangsprogramm keine Tail-Rekursion verwendet, und selbst wenn es in der Zielsprache keine Tail-Rekursion gibt, kann man sie mit Greenlets/Event-Loops emulieren.

Für Ziel- und Ausgangssprachen, suchen Sie nach:

  • Große und spezifische Ideen
  • Winzige und gemeinsame gemeinsame Ideen

Daraus wird sich etwas ergeben:

  • Dinge, die leicht zu übersetzen sind
  • Dinge, die schwer zu übersetzen sind

Sie werden wahrscheinlich auch wissen, was in schnellen und langsamen Code übersetzt wird.

Es gibt auch die Frage der stdlib oder jede Bibliothek, aber es gibt keine klare Antwort, es hängt von Ihren Zielen.

Idiomatischer Code oder lesbarer generierter Code sind ebenfalls Lösungen...

Die Ausrichtung auf eine Plattform wie PHP ist viel einfacher als die Ausrichtung auf Browser, da Sie eine C-Implementierung des langsamen und/oder kritischen Pfades anbieten können.

Da Ihr erstes Projekt die Übersetzung von Python nach PHP ist, zumindest für die mir bekannte PHP3-Untermenge, ist die Anpassung von veloce.py die beste Lösung. Wenn Sie veloce.py für PHP implementieren können, werden Sie wahrscheinlich in der Lage sein, den kompatiblen Modus auszuführen... Wenn Sie PHP in die Untermenge von PHP übersetzen können, die Sie mit php_veloce.py erzeugen können, bedeutet das auch, dass Sie PHP in die Untermenge von Python übersetzen können, die veloce.py nutzen kann, was wiederum bedeutet, dass Sie PHP in Javascript übersetzen können. Nur mal so gesagt...

Sie können auch einen Blick auf diese Bibliotheken werfen:

Auch dieser Blogbeitrag (und die Kommentare) könnten Sie interessieren: https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X