Ich werde den Standpunkt von @EliBendersky bezüglich der Verwendung von ast.parse anstelle von Parser (von dem ich vorher nichts wusste) unterstützen. Ich empfehle Ihnen auch wärmstens, seinen Blog zu überprüfen. Ich habe ast.parse verwendet, um Python-> JavaScript-Übersetzer (@ https://bitbucket.org/amirouche/pythonium ) zu erstellen . Ich habe mir Pythonium-Design ausgedacht, indem ich andere Implementierungen etwas überprüft und selbst ausprobiert habe. Ich habe Pythonium von https://github.com/PythonJS/PythonJS gegabelt, das ich auch gestartet habe. Es ist eigentlich eine vollständige Neufassung. Das Gesamtdesign ist von PyPy- und http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf Papier inspiriert .
Alles, was ich versucht habe, vom Anfang bis zur besten Lösung, auch wenn es wie Pythonium-Marketing aussieht, ist es wirklich nicht (zögern Sie nicht, mir zu sagen, wenn etwas für die Netiquette nicht korrekt erscheint):
Implementieren der Python-Semantik in einfachem altem JavaScript mithilfe der Prototypvererbung: AFAIK Es ist unmöglich, die Python-Mehrfachvererbung mithilfe des JS-Prototypobjektsystems zu implementieren. Ich habe es später mit anderen Tricks versucht (vgl. Getattribute). Soweit ich weiß, gibt es keine Implementierung der Python-Mehrfachvererbung in JavaScript. Das Beste, was es gibt, ist Einzelvererbung + Mixins, und ich bin nicht sicher, ob sie mit Diamantvererbung umgehen. Ähnlich wie Skulpt, aber ohne Google Clojure.
Ich habe es mit Google Clojure versucht, genau wie Skulpt (Compiler), anstatt den Skulpt-Code #fail zu lesen. Auf jeden Fall wegen des JS-Prototyp-basierten Objektsystems immer noch unmöglich. Das Erstellen einer Bindung war sehr, sehr schwierig. Sie müssen JavaScript und viel Code für das Boilerplate schreiben (vgl. Https://github.com/skulpt/skulpt/issues/50, wo ich der Geist bin). Zu diesem Zeitpunkt gab es keine klare Möglichkeit, die Bindung in das Build-System zu integrieren. Ich denke, Skulpt ist eine Bibliothek und Sie müssen nur Ihre .py-Dateien in den HTML-Code aufnehmen, um ausgeführt zu werden. Der Entwickler muss keine Kompilierungsphase durchführen.
Pyjaco (Compiler) ausprobiert, aber das Erstellen von Bindungen (Aufrufen von Javascript-Code aus Python-Code) war sehr schwierig. Es gab zu viel Boilerplate-Code, um jedes Mal erstellt zu werden. Jetzt denke ich, dass Pyjaco derjenige ist, der Pythonium näher kommt. pyjaco ist in Python geschrieben (auch ast.parse), aber viel ist in JavaScript geschrieben und es wird die Vererbung von Prototypen verwendet.
Es ist mir nie gelungen, Pyjamas #fail auszuführen, und ich habe nie wieder versucht, den Code #fail zu lesen. In meinen Augen führte Pyjamas jedoch API-> API-Übersetzungen (oder Framework-zu-Framework) und keine Python-zu-JavaScript-Übersetzung durch. Das JavaScript-Framework verwendet Daten, die sich bereits auf der Seite befinden, oder Daten vom Server. Python-Code ist nur "Sanitär". Danach entdeckte ich, dass Pyjamas tatsächlich ein echter Python-> Js-Übersetzer waren.
Trotzdem denke ich, dass es möglich ist, API-> API- (oder Framework-> Framework-) Übersetzungen durchzuführen, und das ist im Grunde das, was ich in Pythonium mache, aber auf niedrigerer Ebene. Wahrscheinlich verwenden Pyjamas den gleichen Algorithmus wie Pythonium ...
Dann entdeckte ich Brython, das vollständig in Javascript wie Skulpt geschrieben ist, keine Kompilierung und viel Flusen benötigt ... aber in JavaScript geschrieben.
Seit der ersten Zeile im Verlauf dieses Projekts wusste ich über PyPy Bescheid, sogar über das JavaScript-Backend für PyPy. Ja, Sie können, wenn Sie es finden, direkt einen Python-Interpreter in JavaScript aus PyPy generieren. Die Leute sagen, es war eine Katastrophe. Ich lese nein wo warum. Ich denke jedoch, dass der Grund dafür ist, dass die Zwischensprache, mit der der Interpreter RPython implementiert wird, eine Teilmenge von Python ist, die auf die Übersetzung nach C (und möglicherweise asm) zugeschnitten ist. Ira Baxter sagt, dass Sie immer Annahmen treffen, wenn Sie etwas erstellen, und dass Sie es wahrscheinlich so einstellen, dass es das Beste ist, was es im Fall der PyPy: Python-> C-Übersetzung tun soll. Diese Annahmen sind in einem anderen Kontext möglicherweise nicht relevant, da sie den Overhead beeinträchtigen können. Andernfalls ist die direkte Übersetzung höchstwahrscheinlich immer besser.
Den Interpreter in Python schreiben zu lassen, klang nach einer (sehr) guten Idee. Aber ich war aus Leistungsgründen mehr an einem Compiler interessiert, außerdem ist es tatsächlich einfacher, Python in JavaScript zu kompilieren, als es zu interpretieren.
Ich habe PythonJS mit der Idee gestartet, eine Teilmenge von Python zusammenzustellen, die ich leicht in JavaScript übersetzen kann. Anfangs habe ich mich aufgrund früherer Erfahrungen nicht einmal die Mühe gemacht, das OO-System zu implementieren. Die Teilmenge von Python, die ich für die Übersetzung in JavaScript erreicht habe, ist:
- Funktion mit vollständigen semantischen Parametern sowohl in der Definition als auch beim Aufruf. Dies ist der Teil, auf den ich am meisten stolz bin.
- während / if / elif / else
- Python-Typen wurden in JavaScript-Typen konvertiert (es gibt keinerlei Python-Typen)
- for konnte nur über Javascript-Arrays iterieren (für ein In-Array)
- Transparenter Zugriff auf JavaScript: Wenn Sie Array in den Python-Code schreiben, wird es in Javascript in Array übersetzt. Dies ist die größte Errungenschaft in Bezug auf die Benutzerfreundlichkeit gegenüber den Wettbewerbern.
- Sie können die in der Python-Quelle definierte Funktion an Javascript-Funktionen übergeben. Standardargumente werden berücksichtigt.
- Es hat eine spezielle Funktion namens new, die in JavaScript übersetzt wird. New zB: new (Python) (1, 2, Spam, "Ei") wird in "new Python (1, 2, Spam," Ei ") übersetzt.
- "var" werden vom Übersetzer automatisch behandelt. (sehr schöne Entdeckung von Brett (PythonJS-Mitarbeiter).
- globales Schlüsselwort
- Verschlüsse
- Lambdas
- Listenverständnisse
- Importe werden über requirejs unterstützt
- Einzelklassenvererbung + Mixin über classyjs
Dies scheint viel zu sein, ist aber im Vergleich zur vollständigen Python-Semantik sehr eng. Es ist wirklich JavaScript mit einer Python-Syntax.
Das erzeugte JS ist perfekt, dh. Es gibt keinen Overhead, es kann nicht in Bezug auf die Leistung verbessert werden, indem es weiter bearbeitet wird. Wenn Sie den generierten Code verbessern können, können Sie dies auch aus der Python-Quelldatei heraus tun. Außerdem hat sich der Compiler nicht auf JS-Tricks verlassen, die Sie in .js finden, die von http://superherojs.com/ geschrieben wurden , sodass er sehr gut lesbar ist.
Der direkte Nachkomme dieses Teils von PythonJS ist der Pythonium Veloce-Modus. Die vollständige Implementierung finden Sie unter https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + ca. 100 SLOC gemeinsam genutzten Codes mit dem anderen Übersetzer.
Eine angepasste Version von pystones.py kann im Veloce-Modus übersetzt werden, vgl. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master
Nachdem ich die grundlegende Python-> JavaScript-Übersetzung eingerichtet hatte, wählte ich einen anderen Pfad, um vollständiges Python in JavaScript zu übersetzen. Die Art und Weise, wie glib objektorientierten klassenbasierten Code mit Ausnahme der Zielsprache ausführt, ist JS, sodass Sie Zugriff auf Arrays, kartenähnliche Objekte und viele andere Tricks haben und der gesamte Teil in Python geschrieben wurde. IIRC Es gibt keinen Javascript-Code, der von Pythonium Translator geschrieben wurde. Es ist nicht schwierig, eine einzelne Vererbung zu erhalten. Hier sind die schwierigen Teile, die Pythonium vollständig mit Python kompatibel machen:
spam.egg
in Python wird immer übersetzt in getattribute(spam, "egg")
Ich habe dies nicht besonders profiliert, aber ich denke, dass es viel Zeit verliert und ich nicht sicher bin, ob ich es mit asm.js oder irgendetwas anderem verbessern kann.
- Reihenfolge der Methodenauflösung: Selbst mit dem in Python geschriebenen Algorithmus war die Übersetzung in Python Veloce-kompatiblen Code ein großes Unterfangen.
- getattributre : Der eigentliche Algorithmus zur Auflösung von getattribute ist etwas knifflig und unterstützt immer noch keine Datendeskriptoren
- metaklassenklassenbasiert: Ich weiß, wo ich den Code einstecken muss, aber immer noch ...
- last bu not least: some_callable (...) wird immer in "call (some_callable)" umgewandelt. AFAIK, der Übersetzer, verwendet überhaupt keine Inferenz. Jedes Mal, wenn Sie einen Anruf tätigen, müssen Sie überprüfen, um welche Art von Objekt es sich handelt, so wie es aufgerufen werden soll.
Dieser Teil ist in https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master enthalten. Er wurde in Python geschrieben, das mit Python Veloce kompatibel ist.
Der tatsächlich kompatible Übersetzer https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master generiert keinen JavaScript-Code direkt und führt vor allem keine ast-> ast-Transformation durch . Ich habe das Ast-> Ast-Ding ausprobiert und Ast, auch wenn es nicht schön ist, mit Ast.NodeTransformer zu arbeiten, und was noch wichtiger ist, ich muss Ast-> Ast nicht machen.
Zumindest in meinem Fall Python Ast mit Python Ast zu tun, wäre vielleicht eine Leistungsverbesserung, da ich manchmal den Inhalt eines Blocks überprüfe, bevor ich den damit verbundenen Code generiere, zum Beispiel:
- var / global: um etwas var zu können, muss ich wissen, was ich brauche und nicht var. Anstatt einen Block zu generieren, der verfolgt, welche Variablen in einem bestimmten Block erstellt werden, und ihn über den generierten Funktionsblock einzufügen, suche ich beim Eingeben des Blocks nach einer zugewiesenen Variablenzuweisung, bevor ich den untergeordneten Knoten tatsächlich besuche, um den zugehörigen Code zu generieren.
- Ertrag, Generatoren haben bisher eine spezielle Syntax in JS, daher muss ich wissen, welche Python-Funktion ein Generator ist, wenn ich die "var my_generator = function" schreiben möchte.
Ich besuche also nicht wirklich jeden Knoten einmal für jede Phase der Übersetzung.
Der Gesamtprozess kann beschrieben werden als:
Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code
Python-Buildins sind in Python-Code (!) Geschrieben. IIRC Es gibt einige Einschränkungen in Bezug auf Bootstraping-Typen, aber Sie haben Zugriff auf alles, was Pythonium im kompatiblen Modus übersetzen kann. Schauen Sie sich https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master an
Das Lesen von JS-Code, der mit Pythonium-kompatiblem Code generiert wurde, kann verstanden werden, aber Quellkarten helfen sehr.
Die wertvollen Ratschläge, die ich Ihnen angesichts dieser Erfahrung geben kann, sind freundliche alte Fürze:
- Überprüfen Sie das Thema ausführlich sowohl in der Literatur als auch in bestehenden Projekten. Als ich die verschiedenen bestehenden Projekte durchgesehen habe, hätte ich mehr Zeit und Motivation darauf verwenden sollen.
- Fragen stellen! Wenn ich vorher wüsste, dass das PyPy-Backend wegen des Overheads aufgrund der semantischen Nichtübereinstimmung mit C / Javascript nutzlos ist. Ich hätte Pythonium vielleicht schon vor 6 Monaten, vielleicht vor 3 Jahren, auf die Idee gebracht.
- wissen, was Sie tun möchten, haben ein Ziel. Für dieses Projekt hatte ich verschiedene Ziele: ein bisschen Javascript üben, mehr über Python lernen und Python-Code schreiben können, der im Browser ausgeführt wird (mehr und das unten).
- Misserfolg ist Erfahrung
- Ein kleiner Schritt ist ein Schritt
- klein anfangen
- träume groß
- Demos machen
- iterieren
Nur mit dem Python Veloce-Modus bin ich sehr glücklich! Aber auf dem Weg entdeckte ich, dass das, wonach ich wirklich suchte, mich und andere von Javascript befreite, aber vor allem in der Lage war , auf komfortable Weise zu erstellen . Dies führte mich zu Schema, DSL, Modellen und schließlich zu domänenspezifischen Modellen (vgl. Http://dsmforum.org/ ).
Über die Antwort von Ira Baxter:
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 Vollzeit 6 Monate erwarten. Ich denke, wir alle wissen, was 100 Mann pro Jahr in einem Unternehmenskontext bedeuten können und was nicht ...
Wenn jemand sagt, dass etwas schwierig oder öfter unmöglich ist, antworte ich: "Es braucht nur Zeit, um eine Lösung für ein unmögliches Problem zu finden."
Wenn es nicht als unmöglich erwiesen ist, lässt es Raum für Fantasie:
- einen Beweis zu finden, der beweist, dass es unmöglich ist
und
- Wenn es unmöglich ist, kann es ein "minderwertiges" Problem geben, das eine Lösung haben kann.
oder
- Wenn es nicht unmöglich ist, eine Lösung zu finden
Es ist nicht nur optimistisches Denken. Als ich Python-> Javascript startete, sagten alle, es sei unmöglich. PyPy unmöglich. Metaklassen zu hart. etc ... 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, denke ich).
Die meisten Leute, die sagen, dass eine Sache "schwer" oder "unmöglich" ist, geben keine Gründe an. C ++ ist schwer zu analysieren? Ich weiß, dass sie immer noch (kostenlose) C ++ - Parser sind. Das Böse steckt im Detail? Ich weiß das. Zu sagen, dass es allein unmöglich ist, ist nicht hilfreich. Es ist noch schlimmer als "nicht hilfreich", es ist entmutigend, und einige Leute wollen andere entmutigen. Ich habe von dieser Frage über /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus gehört .
Was wäre Perfektion für Sie ? So definieren Sie das nächste Ziel und erreichen möglicherweise das Gesamtziel.
Ich bin mehr daran interessiert zu wissen, welche Arten von Mustern ich für den Code erzwingen könnte, um die Übersetzung des Codes zu vereinfachen (dh IoC, SOA?), Als wie die Übersetzung durchgeführt wird.
Ich sehe keine Muster, die nicht zumindest auf nicht perfekte Weise von einer Sprache in eine andere Sprache übersetzt werden können. Da eine Übersetzung von Sprache zu Sprache möglich ist, sollten Sie dies zuerst anstreben. Da ich denke , dass die Übersetzung zwischen zwei Computersprachen laut http://en.wikipedia.org/wiki/Graph_isomorphism_problem ein Baum- oder DAG-Isomorphismus ist. Auch wenn wir bereits wissen, dass beide vollständig sind, so ...
Framework-> Framework, das ich besser als API-> API-Übersetzung visualisiere, ist möglicherweise immer noch etwas, das Sie berücksichtigen sollten, um den generierten Code zu verbessern. Beispiel: Prolog als sehr spezifische Syntax, aber Sie können trotzdem Prolog-ähnliche Berechnungen durchführen, indem Sie dasselbe Diagramm in Python beschreiben ... Wenn ich einen Prolog-zu-Python-Übersetzer implementieren würde, würde ich die Vereinheitlichung nicht in Python implementieren, sondern in einer C-Bibliothek und kommen mit einer "Python-Syntax", die für einen Pythonisten sehr gut lesbar ist. Am Ende ist Syntax nur "Malen", für das wir eine Bedeutung geben (deshalb habe ich mit dem Schema begonnen). Das Böse steckt im Detail der Sprache und ich spreche nicht über die Syntax. Die Konzepte, die in der Sprache getattribute verwendet werdenHook (Sie können ohne ihn leben), aber erforderliche VM-Funktionen wie die Optimierung der Schwanzrekursion können schwierig zu handhaben sein. Es ist Ihnen egal, ob das ursprüngliche Programm keine Schwanzrekursion verwendet, und selbst wenn es in der Zielsprache keine Schwanzrekursion gibt, können Sie sie mithilfe von Greenlets / Ereignisschleifen emulieren.
Suchen Sie für Ziel- und Quellsprachen nach:
- Große und spezifische Ideen
- Winzige und gemeinsame Ideen
Daraus wird hervorgehen:
- Dinge, die leicht zu übersetzen sind
- Dinge, die schwer zu übersetzen sind
Sie werden wahrscheinlich auch wissen können, was in schnellen und langsamen Code übersetzt wird.
Es gibt auch die Frage der stdlib oder einer Bibliothek, aber es gibt keine klare Antwort, es hängt von Ihren Zielen ab.
Idiomatischer Code oder lesbarer generierter Code haben auch Lösungen ...
Das Targeting einer Plattform wie PHP ist viel einfacher als das Targeting von Browsern, da Sie die C-Implementierung eines langsamen und / oder kritischen Pfads bereitstellen können.
Angesichts der Tatsache, dass Ihr erstes Projekt Python in PHP übersetzt, ist das Anpassen von veloce.py die beste Wahl, zumindest für die mir bekannte PHP3-Teilmenge. Wenn Sie veloce.py für PHP implementieren können, können Sie wahrscheinlich den kompatiblen Modus ausführen ... Auch wenn Sie PHP in die Teilmenge von PHP übersetzen können, die Sie mit php_veloce.py generieren können, bedeutet dies, dass Sie PHP in das übersetzen können Teilmenge von Python, die veloce.py verbrauchen kann, was bedeuten würde, dass Sie PHP in Javascript übersetzen können. Ich sage nur ...
Sie können sich auch diese Bibliotheken ansehen:
Dieser Blog-Beitrag (und seine Kommentare) könnten Sie auch interessieren: https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/