¿Qué tipo de patrones podría aplicar en el código para facilitar la traducción a otro lenguaje de programación? [cerrado]

95

Me propongo hacer un proyecto paralelo que tiene como objetivo traducir código de un lenguaje de programación a otro. Los lenguajes con los que estoy comenzando son PHP y Python (Python a PHP debería ser más fácil para comenzar), pero lo ideal sería que pudiera agregar otros lenguajes con (relativa) facilidad. El plan es:

  • Esto está orientado al desarrollo web. El código original y de destino se colocará encima de los marcos (que también tendré que escribir). Estos marcos adoptarán un patrón de diseño MVC y seguirán estrictas convenciones de codificación. Esto debería facilitar la traducción.

  • También estoy analizando la IOC y la inyección de dependencias, ya que podrían hacer que el proceso de traducción sea más fácil y menos propenso a errores.

  • Haré uso del módulo analizador de Python , que me permite jugar con el árbol de sintaxis abstracta. Aparentemente, lo más cercano que puedo estar con PHP es token_get_all () , que es un comienzo.

  • A partir de entonces puedo construir el AST, las tablas de símbolos y el flujo de control.

Entonces creo que puedo empezar a generar código. No necesito una traducción perfecta . Aún tendré que revisar el código generado y solucionar problemas. Idealmente, el traductor debería señalar las traducciones problemáticas.

Antes de preguntar "¿Cuál es el punto de esto?" La respuesta es ... Será una experiencia de aprendizaje interesante. Si tiene alguna idea sobre cómo hacer que esto sea menos desalentador, hágamelo saber.


EDITAR:

Estoy más interesado en saber qué tipo de patrones podría aplicar en el código para facilitar la traducción (es decir, ¿IoC, SOA?) Del código que en cómo hacer la traducción.

NullUserException
fuente
6
¿Ha mirado sistemas como .NET CLR o Perl6's Parrot? Compilan un conjunto de lenguajes hasta una representación intermedia que puede ser ejecutada por un intérprete común. Si puede volver de la representación intermedia a un idioma, tiene un traductor.
Borealid
1
@Borealid yo sepa el .NET CIL es (relativamente) fácil compilar en , pero la buena suerte de volver código legible de eso. Mirando a Parrot ahora.
NullUserException
Hay proyectos similares para otros idiomas; No estoy seguro de cuán ricos sean sus autores. Y en realidad me estoy refrenando mucho aquí, al necesitar un marco y adherirme a estrictas convenciones de codificación.
NullUserException
2
No puedo agregar ningún conocimiento específico, pero ¿ha mirado pijamas ( pyjs.org ), específicamente traductor.py? Este es un compilador de python a javascript.
stephan
3
Vuelva a EDITAR: si tiene control sobre el código que se traducirá, lo más obvio es evitar las construcciones que son difíciles de traducir. Por ejemplo, C es mucho más fácil de traducir a Java si no hay aritmética de punteros. Para Python, probablemente me mantendría alejado de los cierres. La otra cosa que puede hacer es escribir el código fuente de una manera que las partes más difíciles de traducir siempre estén codificadas idiomáticamente, haciéndolas más fáciles de reconocer y manejar casos especiales.
Ira Baxter

Respuestas:

122

He estado construyendo herramientas (DMS Software Reengineering Toolkit) para realizar manipulación de programas de propósito general (siendo la traducción de idiomas un caso especial) desde 1995, con el apoyo de un sólido equipo de científicos informáticos. DMS proporciona análisis genérico, construcción AST, tablas de símbolos, control y análisis de flujo de datos, aplicación de reglas de traducción, regeneración del texto fuente con comentarios, etc., todo parametrizado por definiciones explícitas de lenguajes de computadora.

La cantidad de maquinaria que necesita para hacer esto bien es enorme (especialmente si desea poder hacer esto para varios idiomas de manera general), y luego necesita analizadores confiables para idiomas con definiciones poco confiables (PHP es un ejemplo perfecto de esto ).

No tiene nada de malo pensar en construir un traductor de idioma a idioma o intentarlo, pero creo que encontrará que esta es una tarea mucho más grande para los idiomas reales de lo que espera. Tenemos unos 100 años-hombre invertidos en DMS y otros 6-12 meses en cada definición de lenguaje "confiable" (incluida la que construimos dolorosamente para PHP), mucho más para lenguajes desagradables como C ++. Será una "gran experiencia de aprendizaje"; ha sido para nosotros. (Es posible que la sección de artículos técnicos del sitio web anterior le resulte interesante para iniciar ese aprendizaje).

Las personas a menudo intentan construir algún tipo de maquinaria generalizada comenzando con alguna pieza de tecnología con la que están familiarizados, que hace parte del trabajo. (Los AST de Python son un gran ejemplo). La buena noticia es que parte del trabajo está hecho. La mala noticia es que la maquinaria tiene un trillón de suposiciones incorporadas, la mayoría de las cuales no descubrirá hasta que intente luchar para hacer otra cosa. En ese momento, descubres que la maquinaria está programada para hacer lo que originalmente hace, y realmente resistirá tu intento de hacer que haga otra cosa. (Sospecho que intentar hacer que Python AST modele PHP va a ser muy divertido).

La razón por la que comencé a construir DMS originalmente fue para construir cimientos que tuvieran muy pocas suposiciones incorporadas. Tiene algunas que nos dan dolores de cabeza. Hasta ahora, no hay agujeros negros. (La parte más difícil de mi trabajo durante los últimos 15 años es tratar de evitar que tales suposiciones se filtren).

Mucha gente también comete el error de asumir que si pueden analizar (y quizás obtener un AST), están en camino de hacer algo complicado. Una de las lecciones difíciles es que necesita tablas de símbolos y análisis de flujo para realizar un buen análisis o transformación de programas. Los AST son necesarios pero no suficientes. Esta es la razón por la que el libro del compilador de Aho & Ullman no se detiene en el capítulo 2. (El OP tiene este derecho en el sentido de que planea construir maquinaria adicional más allá del AST). Para obtener más información sobre este tema, consulte Vida después del análisis .

El comentario sobre "No necesito una traducción perfecta" es problemático. Lo que hacen los traductores débiles es convertir el 80% "fácil" del código, dejando el 20% difícil para hacerlo a mano. Si la aplicación que desea convertir es bastante pequeña y solo tiene la intención de convertirla bien una vez, ese 20% está bien. Si desea convertir muchas aplicaciones (o incluso la misma con cambios menores a lo largo del tiempo), esto no es bueno. Si intenta convertir 100K SLOC, entonces el 20% son 20,000 líneas originales de código que son difíciles de traducir, comprender y modificar en el contexto de otras 80,000 líneas de programa traducido que ya no comprende. Eso requiere un gran esfuerzo. En el nivel de un millón de líneas, esto es simplemente imposible en la práctica.más difícil y normalmente se dan cuenta de manera dolorosa con retrasos prolongados, altos costos y, a menudo, fallas totales).

Lo que tiene que buscar para traducir sistemas a gran escala es un alto porcentaje de conversión de los noventa, o es probable que no pueda completar la parte manual de la actividad de traducción.

Otra consideración clave es el tamaño del código a traducir. Se necesita mucha energía para construir un traductor sólido y que funcione, incluso con buenas herramientas. Si bien parece atractivo y genial construir un traductor en lugar de simplemente hacer una conversión manual, para bases de código pequeñas (por ejemplo, hasta aproximadamente 100K SLOC en nuestra experiencia) la economía simplemente no lo justifica. A nadie le gusta esta respuesta, pero si realmente tiene que traducir solo 10K SLOC de código, probablemente sea mejor que muerda la bala y lo haga. Y sí, eso es doloroso.

Considero que nuestras herramientas son extremadamente buenas (pero estoy bastante sesgado). Y todavía es muy difícil construir un buen traductor; nos lleva entre 1,5 y 2 años-hombre y sabemos cómo utilizar nuestras herramientas. La diferencia es que con tanta maquinaria, tenemos mucho más éxito de lo que fracasamos.

Ira Baxter
fuente
8
¿Alguna vez ha considerado contribuir con su definición de PHP "dolorosamente construida" a la comunidad de PHP en general, o está demasiado asociado con su propio flujo de ingresos para hacerlo factible?
TML
53
Muchas personas que no querían contribuir a un flujo de ingresos y no tenían la energía para hacer el trabajo y abrir el código abierto me pidieron que hiciera todo lo que hacemos "código abierto". Si solo contribuye con una pequeña parte a un proyecto muy grande y / o tiene otra fuente de ingresos, el "código abierto" parece estar bien. Si ha hecho todo el trabajo usted mismo y es su única fuente de ingresos, esto es mucho menos atractivo. [No quiero entrar en una discusión sobre los méritos relativos de la filosofía del "software libre", así que no participaré en ningún otro comentario en esta línea]
Ira Baxter
9
Estoy de acuerdo con lo que dijo aquí, razón por la cual formulé la pregunta como lo hice. Supongo que debemos intuir a partir de esa respuesta que sientes que está demasiado relacionado con tus ingresos, y no hay absolutamente nada de malo en eso, solo pensé que valía la pena preguntar.
TML
3
@IraBaxter Solo dices modismos comunes sobre prácticas relacionadas con la computadora que se pueden aplicar a muchas otras prácticas. Lo único interesante en todo lo que ha escrito son los enlaces a semanticdesigns.com (que resulta ser su empresa)
amirouche
1
A menudo, proporciona enlaces a páginas relacionadas con Clang en sus respuestas. Eso solo prueba que alguien más puede crear una página web. La mayoría de nosotros asumimos que una página web bien escrita implica que hay un trabajo serio y real detrás y no solo un intento fraudulento de engañar al lector como usted parece insinuar en su respuesta. ¿De verdad cree que la página web es fraudulenta? La página contiene información de referencia a la fuente "relevante"; está anonomizado porque el contrato de la obra lo requería. Eso no puedo ayudar.
Ira Baxter
13

Mi respuesta abordará la tarea específica de analizar Python para traducirlo a otro idioma, y ​​no los aspectos de nivel superior que Ira abordó bien en su respuesta.

En resumen: no use el módulo analizador, hay una manera más fácil.

El astmódulo, disponible desde Python 2.6, es mucho más adecuado para sus necesidades, ya que le brinda un AST listo para usar para trabajar. Escribí un artículo sobre esto el año pasado, pero en resumen, use el parsemétodo de astpara analizar el código fuente de Python en un AST. El parsermódulo le dará un árbol de análisis, no un AST. Tenga cuidado con la diferencia .

Ahora, dado que los AST de Python son bastante detallados, dado un AST, el trabajo de front-end no es terriblemente difícil. Supongo que puede tener un prototipo simple para algunas partes de la funcionalidad listo con bastante rapidez. Sin embargo, llegar a una solución completa llevará más tiempo, principalmente porque la semántica de los lenguajes es diferente. Un subconjunto simple del lenguaje (funciones, tipos básicos, etc.) se puede traducir fácilmente, pero una vez que ingrese a las capas más complejas, necesitará maquinaria pesada para emular el núcleo de un idioma en otro. Por ejemplo, considere los generadores de Python y las comprensiones de listas que no existen en PHP (que yo sepa, que es ciertamente pobre cuando PHP está involucrado).

Para darle un consejo final, considere la 2to3herramienta creada por los desarrolladores de Python para traducir el código Python 2 al código Python 3. En cuanto al front-end, tiene la mayoría de los elementos que necesita para traducir Python a algo . Sin embargo, dado que los núcleos de Python 2 y 3 son similares, no se requiere maquinaria de emulación allí.

Eli Bendersky
fuente
Weeeell. 2to3es solo de AST a AST. No admite hacer nada que vaya más allá de las capacidades del astmódulo. Tenga en cuenta que todas las traducciones van desde la sintaxis admitida por el proceso de Python del host a la sintaxis admitida por el proceso de Python del host. No hay ningún traductor que agregue, digamos, anotaciones de funciones, porque 2.6 no lo admite.
Habnabit
... y la pregunta del OP podría estar enmarcada, a corto plazo, cómo pasar de Python 2.6 AST a ... algo en PHP. Es probable que el módulo ast no quiera representar bien la sintaxis de PHP, por lo que ni siquiera es ast.
Ira Baxter
2
@Aaron: 2to3puede verse como un ejemplo del uso del AST generado a partir de ast.
Eli Bendersky
AFAIK, 2to3 podría decirse que es una traducción más fácil que Python a PHP (después de todo, es Python a Python, ¿verdad)? E incluso no funciona particularmente bien. Observe la gran cantidad de Python 2.6 que aún no ha pasado de 2 a 3 ... porque aparentemente hay un montón de parches manuales posteriores a la traducción que aún deben hacerse. Si estuviera 100% automatizado, Python 2.6 estaría muerto.
Ira Baxter
5

Escribir un traductor no es imposible, especialmente considerando que Joel's Intern lo hizo durante un verano.

Si quieres aprender un idioma, es fácil. Si quieres hacer más, es un poco más difícil, pero no demasiado. La parte más difícil es que, mientras que cualquier lenguaje turing completo puede hacer lo que hace otro lenguaje turing completo, los tipos de datos incorporados pueden cambiar fenomenalmente lo que hace un lenguaje.

Por ejemplo:

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

se necesita mucho código C ++ para duplicarlo (bueno, puedes hacerlo bastante corto con algunas construcciones en bucle, pero aún así).

Eso es un poco aparte, supongo.

¿Alguna vez ha escrito un tokenizador / analizador basado en la gramática del idioma? Probablemente querrá aprender a hacer eso si no lo ha hecho, porque esa es la parte principal de este proyecto. Lo que haría es crear una sintaxis completa básica de Turing, algo bastante similar al bytecode de Python . Luego, crea un lexer / parser que toma una gramática del idioma (quizás usando BNF ) y, basándose en la gramática, compila el idioma en su idioma intermedio. Entonces, lo que querrá hacer es hacer lo contrario: crear un analizador de su idioma en los idiomas de destino según la gramática.

El problema más obvio que veo es que al principio probablemente creará un código terriblemente ineficiente, especialmente en lenguajes más potentes * como Python.

Pero si lo hace de esta manera, probablemente podrá encontrar formas de optimizar la salida a medida que avanza. Para resumir:

  • leer la gramática proporcionada
  • compilar el programa en sintaxis intermedia (pero también completa de Turing)
  • compilar el programa intermedio en el lenguaje final (basado en la gramática proporcionada)
  • ...?
  • ¡Lucro!(?)

* por poderoso me refiero a que esto toma 4 líneas:

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

Muéstreme otro lenguaje que pueda hacer algo así en 4 líneas y le mostraré un lenguaje que es tan poderoso como Python.

Wayne Werner
fuente
"¿Alguna vez ha escrito un analizador / tokenizador basado en una gramática de lenguaje?" Lo he hecho usando JavaCC.
NullUserException
2
El pasante de Joel hizo un trabajo parcial durante un verano. Su idioma de origen era un subconjunto de un idioma existente, y presumiblemente este subconjunto podría ajustarse un poco. Eso facilita mucho el trabajo. De manera similar, NullPointerException podría querer comenzar con las partes más fáciles de Python, quizás pasando por las cosas más difíciles para la conversión manual (como se indica en las preguntas).
David Thornley
@NullUserException: tendrá algo de exposición, pero básicamente estará haciendo una reimplementación de JavaCC, solo que en lugar de Java como lenguaje de salida, estará haciendo <insertar idioma aquí>. @David, bastante. Incluso Thistle necesita ayuda con algunas de las construcciones del lenguaje. Si yo fuera el OP, primero optaría por lo funcional, luego lo optimizaría; de lo contrario, estaría atrapado para siempre tratando de hacer que C ++ haga un corte de cadenas (con pasos): p
Wayne Werner
@WayneWerner Para que conste, lenguajes como C # no requieren nuevas líneas en absoluto. (Al menos, no después de haber eliminado los comentarios de una sola línea). Por lo tanto, podría escribir cualquier programa C # en una línea. Pero, por supuesto, entiendo a qué te refieres.
leviathanbadger
@ aboveyou00: No creo que sea correcto. Si rechaza los condicionales del preprocesador, es posible que tenga razón.
Ira Baxter
3

Hay un par de respuestas que le dicen que no se moleste. Bueno, ¿qué tan útil es eso? ¿Tu quieres aprender? Puedes aprender. Esta es la compilación. Da la casualidad de que su idioma de destino no es el código máquina, sino otro idioma de alto nivel. Esto se hace todo el tiempo.

Hay una forma relativamente sencilla de empezar. Primero, obtenga http://sourceforge.net/projects/lime-php/ (si desea trabajar en PHP) o algo así y revise el código de ejemplo. A continuación, puede escribir un analizador léxico utilizando una secuencia de expresiones regulares y alimentar tokens al analizador que genera. Sus acciones semánticas pueden generar código directamente en otro idioma o construir alguna estructura de datos (piense en objetos, hombre) que puede masajear y recorrer para generar código de salida.

Tienes suerte con PHP y Python porque en muchos aspectos son el mismo lenguaje que el otro, pero con diferente sintaxis. La parte difícil es superar las diferencias semánticas entre las formas gramaticales y las estructuras de datos. Por ejemplo, Python tiene listas y diccionarios, mientras que PHP solo tiene matrices asociadas.

El enfoque de "aprendiz" es construir algo que funcione bien para un subconjunto restringido del lenguaje (como solo declaraciones impresas, matemáticas simples y asignación de variables) y luego eliminar progresivamente las limitaciones. Eso es básicamente lo que hicieron todos los "grandes" en el campo.

Ah, y dado que no tiene tipos estáticos en Python, podría ser mejor escribir y confiar en funciones PHP como "python_add" que agrega números, cadenas u objetos de acuerdo con la forma en que Python lo hace.

Obviamente, esto puede ser mucho más grande si lo dejas.

Ian
fuente
3
En realidad, no dije "no te molestes". Lo que dije fue, "traducir idiomas de manera general es muy difícil". Si el OP continúa con su camino original de usar árboles de Python para intentar generar PHP, aprenderá mucho y estoy a favor de la experiencia de aprendizaje; Yo también empecé allí. No podrá agregar nuevos idiomas fácilmente.
Ira Baxter
@IraBaxter No puedo respaldar tu declaración, hacer Python-> PHP y PHP-> Javascript sería algo fácil. cf. última parte de stackoverflow.com/a/22850139/140837 en el medio de la respuesta también me ocupo de su "argumentación"
amirouche
2

Segundo el punto de vista de @EliBendersky con respecto al uso de ast.parse en lugar de parser (que no conocía antes). También te recomiendo encarecidamente que revises su blog. Usé ast.parse para hacer Python-> traductor de JavaScript (@ https://bitbucket.org/amirouche/pythonium ). Se me ocurrió el diseño de Pythonium revisando un poco otras implementaciones y probándolas por mi cuenta. Bifurqué Pythonium de https://github.com/PythonJS/PythonJS, que también comencé, en realidad es una reescritura completa. El diseño general está inspirado en PyPy y http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf paper.

Todo lo que probé, desde el principio hasta la mejor solución, incluso si parece que el marketing de Pythonium realmente no lo es (no dude en decirme si algo no parece correcto para la etiqueta de la red):

  • Implementar la semántica de Python en Plain Old JavaScript usando la herencia de prototipos: AFAIK, es imposible implementar la herencia múltiple de Python usando el sistema de objetos prototipo JS. Intenté hacerlo usando otros trucos más tarde (cf. getattribute). Hasta donde yo sé, no existe una implementación de la herencia múltiple de Python en JavaScript, lo mejor que existe es Herencia única + mixins y no estoy seguro de que manejen la herencia de diamantes. Algo similar a Skulpt pero sin google clojure.

  • Intenté con Google clojure, al igual que Skulpt (compilador) en lugar de leer el código Skulpt #fail. De todos modos, debido a que el sistema de objetos basado en prototipos JS sigue siendo imposible. Crear enlaces fue muy, muy difícil, necesitas escribir JavaScript y mucho código repetitivo (cf. https://github.com/skulpt/skulpt/issues/50 donde soy el fantasma). En ese momento no había una forma clara de integrar el enlace en el sistema de compilación. Creo que Skulpt es una biblioteca y solo tiene que incluir sus archivos .py en el html para que se ejecuten, no es necesario que el desarrollador realice una fase de compilación.

  • Probé pyjaco (compilador) pero crear enlaces (llamar al código Javascript desde el código Python) fue muy difícil, había demasiado código repetitivo para crear cada vez. Ahora creo que pyjaco es el que más se acerca a Pythonium. pyjaco está escrito en Python (ast.parse también) pero mucho está escrito en JavaScript y usa la herencia de prototipos.

En realidad, nunca logré ejecutar Pyjamas #fail y nunca intenté leer el código #fail nuevamente. Pero en mi mente, pijamas estaba haciendo API-> traducción de API (o de marco a marco) y no de Python a traducción de JavaScript. El marco de JavaScript consume datos que ya están en la página o datos del servidor. El código Python es solo "plomería". Después de eso descubrí que pijamas era en realidad un verdadero traductor de python-> js.

Aún así, creo que es posible hacer la traducción de API-> API (o framework-> framework) y eso es básicamente lo que hago en Pythonium pero en un nivel inferior. Probablemente Pyjamas use el mismo algoritmo que Pythonium ...

Luego descubrí brython completamente escrito en Javascript como Skulpt, sin necesidad de compilación y mucha pelusa ... pero escrito en JavaScript.

Desde la línea inicial escrita en el curso de este proyecto, sabía sobre PyPy, incluso el backend de JavaScript para PyPy. Sí, puede, si lo encuentra, generar directamente un intérprete de Python en JavaScript desde PyPy. La gente dice que fue un desastre. No leí por qué. Pero creo que la razón es que el lenguaje intermedio que usan para implementar el intérprete, RPython, es un subconjunto de Python diseñado para ser traducido a C (y tal vez asm). Ira Baxter dice que siempre haces suposiciones cuando construyes algo y probablemente lo ajustas para que sea el mejor en lo que debe hacer en el caso de PyPy: traducción Python-> C. Esos supuestos pueden no ser relevantes en otro contexto, peor pueden inferir gastos generales, de lo contrario, la traducción directa probablemente siempre será mejor.

Tener el intérprete escrito en Python sonaba como una (muy) buena idea. Pero estaba más interesado en un compilador por razones de rendimiento, y en realidad es más fácil compilar Python en JavaScript que interpretarlo.

Comencé PythonJS con la idea de armar un subconjunto de Python que pudiera traducir fácilmente a JavaScript. Al principio ni siquiera me molesté en implementar el sistema OO debido a la experiencia pasada. El subconjunto de Python que logré traducir a JavaScript es:

  • función con parámetros semánticos completos tanto en la definición como en la llamada. Esta es la parte de la que estoy más orgulloso.
  • while / if / elif / else
  • Los tipos de Python se convirtieron a tipos de JavaScript (no hay tipos de Python de ningún tipo)
  • para podría iterar solo sobre matrices de Javascript (para una matriz)
  • Acceso transparente a JavaScript: si escribe Array en el código Python, se traducirá a Array en javascript. Este es el mayor logro en términos de usabilidad sobre sus competidores.
  • Puede pasar una función definida en la fuente de Python a funciones de JavaScript. Se tendrán en cuenta los argumentos predeterminados.
  • Tiene una función especial llamada nueva que se traduce a JavaScript nuevo, por ejemplo: nuevo (Python) (1, 2, spam, "huevo") se traduce a "nuevo Python (1, 2, spam," huevo ").
  • "var" son manejados automáticamente por el traductor. (muy buen hallazgo de Brett (colaborador de PythonJS).
  • palabra clave global
  • cierres
  • lambdas
  • lista de comprensiones
  • las importaciones son compatibles a través de requirejs
  • herencia de clase única + mixin a través de classyjs

Esto parece mucho, pero en realidad es muy estrecho en comparación con la semántica completa de Python. Es realmente JavaScript con sintaxis de Python.

El JS generado es perfecto, es decir. no hay gastos generales, no se puede mejorar en términos de rendimiento editándolo más. Si puede mejorar el código generado, también puede hacerlo desde el archivo fuente de Python. Además, el compilador no se basó en ningún truco de JS que pueda encontrar en .js escrito por http://superherojs.com/ , por lo que es muy legible.

El descendiente directo de esta parte de PythonJS es el modo Pythonium Veloce. La implementación completa se puede encontrar en https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + alrededor de 100 SLOC de código compartido con el otro traductor.

Una versión adaptada de pystones.py se puede traducir en modo Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Después de haber configurado la traducción básica de Python-> JavaScript, elegí otra ruta para traducir Python completo a JavaScript. La forma de hacer glib haciendo código basado en clases orientado a objetos, excepto el lenguaje de destino, es JS, por lo que tiene acceso a matrices, objetos tipo mapa y muchos otros trucos, y toda esa parte se escribió en Python. IIRC no hay código javascript escrito por en el traductor de Pythonium. Obtener una herencia única no es difícil, aquí están las partes difíciles que hacen que Pythonium sea totalmente compatible con Python:

  • spam.egg en Python siempre se traduce a getattribute(spam, "egg") No perfilé esto en particular, pero creo que se pierde mucho tiempo y no estoy seguro de poder mejorarlo con asm.js o cualquier otra cosa.
  • orden de resolución del método: incluso con el algoritmo escrito en Python, traducirlo al código compatible con Python Veloce fue un gran esfuerzo.
  • getattributre : el algoritmo de resolución de getattribute real es un poco complicado y todavía no admite descriptores de datos
  • basado en la clase de metaclase: sé dónde conectar el código, pero aún así ...
  • último pero no menos importante: some_callable (...) siempre se traduce como "llamar (some_callable)". AFAIK, el traductor no usa inferencia en absoluto, por lo que cada vez que realiza una llamada, debe verificar qué tipo de objeto es para llamarlo de la manera en que debe llamarse.

Esta parte se incluye en https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Está escrito en Python compatible con Python Veloce.

El traductor compatible real https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master no genera código JavaScript directamente y, lo más importante, no realiza una transformación ast-> ast . Probé la cosa ast-> ast y ast incluso si es más agradable que cst no es agradable trabajar incluso con ast.NodeTransformer y lo más importante no necesito hacer ast-> ast.

Hacer python ast a python ast en mi caso al menos tal vez sería una mejora del rendimiento, ya que en algún momento inspecciono el contenido de un bloque antes de generar el código asociado con él, por ejemplo:

  • var / global: para poder variar algo debo saber lo que necesito y no var. En lugar de generar un bloque que rastrea qué variables se crean en un bloque dado e insertarlas en la parte superior del bloque de funciones generado, solo busco una asignación de variable relevante cuando entro al bloque antes de visitar el nodo hijo para generar el código asociado.
  • rendimiento, los generadores tienen, hasta el momento, una sintaxis especial en JS, por lo que necesito saber qué función de Python es un generador cuando quiero escribir la "var my_generator = function"

Por lo tanto, no visito cada nodo una vez para cada fase de la traducción.

El proceso general se puede describir como:

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

Las incorporaciones de Python están escritas en código Python (!), IIRC hay algunas restricciones relacionadas con los tipos de arranque, pero tiene acceso a todo lo que puede traducir Pythonium en modo compatible. Eche un vistazo a https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

Se puede entender la lectura del código JS generado a partir de pythonium, pero los mapas de origen serán de gran ayuda.

El valioso consejo que puedo darte a la luz de esta experiencia son los viejos y amables pedos:

  • Revisar extensamente el tema tanto en la literatura como en proyectos existentes de código cerrado o gratuito. Cuando revisé los diferentes proyectos existentes debería haberle dado más tiempo y motivación.
  • ¡hacer preguntas! Si supiera de antemano que el backend de PyPy es inútil debido a la sobrecarga debido a la falta de coincidencia semántica de C / Javascript. Quizás hubiera tenido una idea de Pythonium antes de hace 6 meses, quizás hace 3 años.
  • sepa lo que quiere hacer, tenga un objetivo. Para este proyecto tenía diferentes objetivos: practicar un poco de javascript, aprender más de Python y poder escribir código Python que se ejecutaría en el navegador (más y eso más abajo).
  • el fracaso es experiencia
  • un pequeño paso es un paso
  • empieza pequeño
  • Sueño grande
  • hacer demostraciones
  • iterar

Solo con el modo Python Veloce, ¡estoy muy feliz! Pero en el camino descubrí que lo que realmente estaba buscando era liberarme a mí y a otros de Javascript pero, lo que es más importante, poder crear de una manera cómoda. Esto me llevó a Scheme, DSL, Modelos y eventualmente modelos específicos de dominio (cf. http://dsmforum.org/ ).

Sobre la respuesta de Ira Baxter:

Las estimaciones no ayudan en absoluto. Me tomé más o menos 6 meses de tiempo libre tanto para PythonJS como para Pythonium. Así que puedo esperar más de 6 meses a tiempo completo. Creo que todos sabemos lo que 100 años-hombre en un contexto empresarial pueden significar y no significar en absoluto ...

Cuando alguien dice que algo es difícil o más a menudo imposible, yo respondo que "solo se necesita tiempo para encontrar una solución a un problema que es imposible", de lo contrario, dije que nada es imposible excepto si se demuestra que es imposible en este caso una prueba matemática ...

Si no se demuestra que es imposible, deja espacio para la imaginación:

  • encontrar una prueba que demuestre que es imposible

y

  • Si es imposible, puede haber un problema "inferior" que puede tener solución.

o

  • si no es imposible encontrar una solución

No es solo un pensamiento optimista. Cuando comencé Python-> Javascript, todos decían que era imposible. PyPy imposible. Metaclases demasiado duras. etc ... Creo que la única revolución que trae PyPy sobre el papel Scheme-> C (que tiene 25 años) es alguna generación automática de JIT (sugerencias basadas en el intérprete de RPython, creo).

La mayoría de las personas que dicen que algo es "difícil" o "imposible" no dan las razones. ¿C ++ es difícil de analizar? Lo sé, todavía son analizadores de C ++ (gratuitos). ¿El mal está en los detalles? Yo sé eso. Decir que es imposible solo no es útil. Es incluso peor que "no es útil", es desalentador y algunas personas tienen la intención de desanimar a otras. Escuché sobre esta pregunta a través de /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

¿Cuál sería la perfección para ti ? Así es como se define el próximo objetivo y tal vez se alcance el objetivo general.

Estoy más interesado en saber qué tipo de patrones podría aplicar en el código para facilitar la traducción (es decir, ¿IoC, SOA?) Del código que en cómo hacer la traducción.

No veo patrones que no puedan traducirse de un idioma a otro, al menos de una manera menos que perfecta. Dado que la traducción de un idioma a otro es posible, es mejor que apuntes a esto primero. Dado que, creo que según http://en.wikipedia.org/wiki/Graph_isomorphism_problem , la traducción entre dos lenguajes informáticos es un árbol o isomorfismo DAG. Incluso si ya sabemos que ambos se están completando, entonces ...

Framework-> Framework que mejor visualizo como API-> La traducción de API aún puede ser algo que debe tener en cuenta como una forma de mejorar el código generado. Por ejemplo: Prolog como una sintaxis muy específica, pero aún puede hacer Prolog como un cálculo describiendo el mismo gráfico en Python ... Si tuviera que implementar un traductor de Prolog a Python, no implementaría la unificación en Python sino en una biblioteca C y vendría con una "sintaxis de Python" que es muy legible para un Pythonist. Al final, la sintaxis es solo "pintura" a la que le damos un significado (por eso comencé a planificar). El mal está en el detalle del lenguaje y no me refiero a la sintaxis. Los conceptos que se utilizan en el idioma getattributehook (puede vivir sin él) pero las características de VM requeridas como la optimización de recursividad de cola pueden ser difíciles de manejar. No le importa si el programa inicial no usa la recursividad de cola e incluso si no hay recursión de cola en el idioma de destino, puede emularlo usando greenlets / event loop.

Para los idiomas de origen y de destino, busque:

  • Ideas grandes y específicas
  • Pequeñas y comunes ideas compartidas

De esto surgirá:

  • Cosas que son fáciles de traducir
  • Cosas que son difíciles de traducir

Probablemente también podrá saber qué se traducirá a código rápido y lento.

También está la cuestión del stdlib o cualquier biblioteca, pero no hay una respuesta clara, depende de sus objetivos.

El código idiomático o el código generado legible también tienen soluciones ...

Apuntar a una plataforma como PHP es mucho más fácil que apuntar a navegadores, ya que puede proporcionar una implementación C de una ruta lenta y / o crítica.

Dado que su primer proyecto es traducir Python a PHP, al menos para el subconjunto PHP3 que conozco, personalizar veloce.py es su mejor opción. Si puede implementar veloce.py para PHP, entonces probablemente podrá ejecutar el modo compatible ... Además, si puede traducir PHP al subconjunto de PHP que puede generar con php_veloce.py, significa que puede traducir PHP al subconjunto de Python que veloce.py puede consumir, lo que significa que puede traducir PHP a Javascript. Solo digo...

También puede echar un vistazo a esas bibliotecas:

También puede estar interesado en esta publicación de blog (y comentarios): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/

amirouche
fuente
Lo único que sigue siendo emocionante para mí acerca de la traducción de un idioma de computadora a otro se describe en stackoverflow.com/questions/22621164/…
amirouche
Secundo la otra respuesta sobre los tipos de datos. En Pythonium ni siquiera planeaba admitir un tipo entero y flotante correcto en el modo compatible sin asm.js.
amirouche
Bien, si le doy un paquete Python de 100K SLOC y lo ejecuta a través de su "traductor", ¿obtengo un programa que funcione? ¿Cuánto trabajo manual posterior a la traducción se necesita para solucionarlo? Lo que dijiste aquí fue, "dado un buen analizador ya existente para Python que construye AST, puedo construir un traductor parcial en 6 meses". Nadie se sorprende. 6 meses no es, según los estándares de la mayoría de la gente, "algo fácil" (citando otro de sus comentarios). Resolver los problemas restantes requerirá más esfuerzo. Mi respuesta decía, básicamente "hacer esto no es fácil" y "hacerlo de manera general es difícil".
Ira Baxter
... ese último punto en respuesta al deseo original de OP: "idealmente, podría agregar otros idiomas con (relativa) facilidad", que mi respuesta aborda específicamente.
Ira Baxter
Ruego no estar de acuerdo, especialmente cuando sabes lo que estás haciendo, es fácil y lo que sigue no es difícil, es solo una cuestión de hacer las cosas. No estoy seguro de dónde está lidiando con algo específico de la pregunta. Está diciendo en 4 o 5 párrafos que su empresa lo hace, y es difícil. Pero, de lo contrario, está difundiendo FUD sobre el tema, mientras se aleja del tema como en stackoverflow.com/questions/22621164/… . En 6 meses a tiempo completo habría escrito un traductor completo.
amirouche
0

Podría echar un vistazo al compilador de Vala , que traduce Vala (un lenguaje similar a C #) a C.

tomate
fuente
Un objetivo de diseño de Vala era traducirlo a C y facilitar el desarrollo con bibliotecas gnome.
amirouche