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/
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.
2 Stimmen
Ich kann kein spezifisches Wissen beisteuern, aber haben Sie sich Pyjamas angesehen ( pyjs.org ), insbesondere translator.py? Dies ist ein Python zu Javascript Compiler.
0 Stimmen
@stephan Ich liebe den Namen (Pyjama). Danke für den Link. Ich glaube, Python hat es dank des Parser-Moduls wirklich einfach gemacht, diese Übersetzungen zu machen. Deshalb gibt es auch einen Python-zu-Perl-Übersetzer, aber nicht andersherum.
0 Stimmen
Werfen Sie einen Blick auf phpqatools.org für einige Tools, die eine AST- und Opcode-basierte Analyse von PHP-Code ermöglichen.
0 Stimmen
@NullUserException Als Antwort auf "AFAIK ist die .NET CIL (relativ) einfach zu kompilieren, aber viel Glück dabei, lesbaren Code daraus zu erhalten." Nun, das ist genau das, was Reflector tut!
0 Stimmen
@NullUserException Reflector leistet in der Tat perfekte Arbeit. Denken Sie immer an pdbs :)
3 Stimmen
Re EDIT: Wenn Sie die Kontrolle über den zu übersetzenden Code haben, ist es am naheliegendsten, schwer zu übersetzende Konstrukte zu vermeiden! C lässt sich zum Beispiel viel leichter nach Java übersetzen, wenn es keine Zeigerarithmetik gibt. Bei Python würde ich mich wahrscheinlich von Closures fernhalten. Eine andere Möglichkeit ist, den Quellcode so zu schreiben, dass schwierig zu übersetzende Teile immer idiomatisch kodiert sind, so dass sie leichter zu erkennen sind und Sonderfälle besser behandelt werden können.
0 Stimmen
Ich kann hier keine Frage finden.
0 Stimmen
Ein Llvm-Frontend schreiben