Quali tipi di pattern potrei applicare al codice per rendere più facile la traduzione in un altro linguaggio di programmazione? [chiuso]


95

Mi sto proponendo di fare un progetto parallelo che ha l'obiettivo di tradurre il codice da un linguaggio di programmazione a un altro. I linguaggi con cui sto iniziando sono PHP e Python (da Python a PHP dovrebbe essere più facile iniziare), ma idealmente sarei in grado di aggiungere altri linguaggi con (relativa) facilità. Il piano è:

  • Questo è orientato allo sviluppo web. Il codice originale e quello di destinazione saranno posizionati sopra i framework (che dovrò anche scrivere). Questi framework abbracceranno un modello di progettazione MVC e seguiranno rigide convenzioni di codifica. Questo dovrebbe rendere la traduzione un po 'più semplice.

  • Sto anche esaminando il CIO e l'inserimento delle dipendenze, in quanto potrebbero rendere il processo di traduzione più semplice e meno soggetto a errori.

  • Userò il modulo parser di Python , che mi consente di giocherellare con l'Albero della sintassi astratta. Apparentemente il più vicino che posso ottenere con PHP è token_get_all () , che è un inizio.

  • Da quel momento in poi posso costruire l'AST, le tabelle dei simboli e il flusso di controllo.

Quindi credo di poter iniziare a trasmettere il codice. Non ho bisogno di una traduzione perfetta . Dovrò comunque rivedere il codice generato e risolvere i problemi. Idealmente il traduttore dovrebbe segnalare le traduzioni problematiche.

Prima di chiedere "Che diavolo è il punto di questo?" La risposta è ... Sarà un'esperienza di apprendimento interessante. Se hai qualche idea su come renderlo meno scoraggiante, fammelo sapere.


MODIFICARE:

Sono più interessato a sapere quali tipi di pattern potrei applicare al codice per rendere più facile tradurre (ad esempio: IoC, SOA?) Il codice piuttosto che come fare la traduzione.


6
Hai esaminato sistemi come .NET CLR o Parrot di Perl6? Compilano un insieme di linguaggi fino a una rappresentazione intermedia che può essere eseguita da un interprete comune. Se puoi risalire dalla rappresentazione intermedia a una lingua, hai un traduttore.
Borealid

1
@Borealid AFAIK .NET CIL è (relativamente) facile da compilare in , ma buona fortuna di tornare codice leggibile da questo. Guardando Parrot adesso.
NullUserException

Esistono progetti simili per altre lingue; Non sono sicuro di quanto siano ricchi i loro autori. E in realtà mi sto trattenendo molto qui, avendo bisogno di una struttura e aderendo a rigide convenzioni di codifica.
NullUserException

2
Non posso aggiungere alcuna conoscenza specifica, ma hai guardato pigiama ( pyjs.org ), in particolare traduttore.py? Questo è un compilatore da python a javascript.
stephan

3
Re EDIT: Se hai il controllo sul codice che verrà tradotto, la cosa più ovvia da fare è evitare costrutti difficili da tradurre! Ad esempio, C è molto più facile da tradurre in Java se non c'è alcuna aritmetica dei puntatori. Per Python, probabilmente starei lontano dalle chiusure. L'altra cosa che puoi fare è scrivere il codice sorgente in modo che le parti più difficili da tradurre siano sempre codificate in modo idiomatico, rendendole più facili da riconoscere e gestire casi speciali.
Ira Baxter

Risposte:


122

Ho costruito strumenti (DMS Software Reengineering Toolkit) per la manipolazione di programmi generici (con la traduzione della lingua come un caso speciale) dal 1995, supportato da un forte team di scienziati informatici. DMS fornisce analisi generiche, creazione di AST, tabelle di simboli, controllo e analisi del flusso di dati, applicazione di regole di traduzione, rigenerazione del testo di origine con commenti, ecc., Il tutto parametrizzato da definizioni esplicite di linguaggi informatici.

La quantità di macchinari di cui hai bisogno per farlo bene è vasta (specialmente se vuoi essere in grado di farlo per più lingue in modo generale), e quindi hai bisogno di analizzatori affidabili per linguaggi con definizioni inaffidabili (PHP è un perfetto esempio di questo ).

Non c'è niente di sbagliato nel pensare di costruire un traduttore da lingua a lingua o di provarlo, ma penso che troverai questo un compito molto più grande per le lingue reali di quanto ti aspetti. Abbiamo circa 100 anni-uomo investiti solo in DMS e altri 6-12 mesi in ciascuna definizione di linguaggio "affidabile" (inclusa quella che abbiamo faticosamente costruito per PHP), molto di più per linguaggi cattivi come C ++. Sarà un "inferno di un'esperienza di apprendimento"; è stato per noi. (Potresti trovare interessante la sezione Documenti tecnici nel sito Web sopra per iniziare subito l'apprendimento).

Le persone spesso tentano di costruire un qualche tipo di macchinario generalizzato partendo da qualche pezzo di tecnologia con cui hanno familiarità, che fa una parte del lavoro. (Gli AST Python sono un ottimo esempio). La buona notizia è che una parte del lavoro è finita. La cattiva notizia è che la macchina ha un'infinità di presupposti incorporati, la maggior parte dei quali non scoprirai finché non proverai a lottare per fare qualcos'altro. A quel punto scopri che la macchina è programmata per fare ciò che fa originariamente e resisterà davvero, davvero al tuo tentativo di fargli fare qualcos'altro. (Sospetto che provare a convincere Python AST a modellare PHP sarà molto divertente).

Il motivo per cui ho iniziato a costruire DMS originariamente era per costruire fondamenta che contenevano pochissime ipotesi di questo tipo. Ne ha alcune che ci danno mal di testa. Finora niente buchi neri. (La parte più difficile del mio lavoro negli ultimi 15 anni è cercare di evitare che tali presupposti si insinuino).

Molte persone commettono anche l'errore di presumere che se possono analizzare (e forse ottenere un AST), sono sulla buona strada per fare qualcosa di complicato. Una delle lezioni più difficili è che sono necessarie tabelle dei simboli e analisi del flusso per eseguire una buona analisi o trasformazione del programma. Gli AST sono necessari ma non sufficienti. Questa è la ragione per cui il libro del compilatore di Aho & Ullman non si ferma al capitolo 2. (L'OP ha questo diritto in quanto sta progettando di costruire macchinari aggiuntivi oltre l'AST). Per ulteriori informazioni su questo argomento, vedere Life After Parsing .

L'osservazione "Non ho bisogno di una traduzione perfetta" è problematica. Quello che fanno i traduttori deboli è convertire l'80% "facile" del codice, lasciando il 20% difficile da fare a mano. Se le applicazioni che intendi convertire sono piuttosto piccole e intendi convertirla bene solo una volta, allora quel 20% va bene. Se vuoi convertire molte applicazioni (o anche la stessa con piccole modifiche nel tempo), questo non è carino. Se si tenta di convertire 100K SLOC, il 20% corrisponde a 20.000 righe di codice originali che sono difficili da tradurre, comprendere e modificare nel contesto di altre 80.000 righe di programma tradotto che già non si comprendono. Ciò richiede un enorme sforzo. A livello di un milione di linee, questo è semplicemente impossibile in pratica.più difficile e normalmente lo scoprono dolorosamente con lunghi ritardi, costi elevati e spesso fallimento totale.)

Quello che devi fare per tradurre sistemi su larga scala sono tassi di conversione percentuali elevati degli anni novanta, o è probabile che tu non possa completare la parte manuale dell'attività di traduzione.

Un'altra considerazione chiave è la dimensione del codice da tradurre. Ci vuole molta energia per costruire un traduttore funzionante e robusto, anche con buoni strumenti. Mentre sembra sexy e interessante costruire un traduttore invece di fare semplicemente una conversione manuale, per piccole basi di codice (ad esempio, fino a circa 100K SLOC nella nostra esperienza) l'economia semplicemente non lo giustifica. A nessuno piace questa risposta, ma se devi davvero tradurre solo 10K SLOC di codice, probabilmente faresti meglio a mordere il proiettile e farlo. E sì, è doloroso.

Considero i nostri strumenti estremamente buoni (ma del resto sono piuttosto di parte). Ed è ancora molto difficile costruire un buon traduttore; ci impieghiamo circa 1,5-2 anni-uomo e sappiamo come utilizzare i nostri strumenti. La differenza è che con così tanti macchinari riusciamo molto più spesso di quanto falliamo.


8
Hai mai considerato di contribuire con la tua definizione PHP "costruita in modo doloroso" alla comunità PHP in generale, o è troppo strettamente associata al tuo flusso di entrate per renderlo fattibile?
TML

53
Mi è stato chiesto di rendere "open source" tutto ciò che facciamo da molte persone che non volevano contribuire a un flusso di entrate e non avevano l'energia per fare il lavoro e aprirlo da sole. Se contribuisci solo una piccola parte a un progetto molto grande e / o hai un'altra fonte di reddito, "open source" sembra a posto. Se hai fatto tutto il lavoro da solo ed è la tua unica fonte di reddito, questo è molto meno attraente. [Non voglio entrare in una discussione sui meriti relativi della filosofia del "software libero", quindi non parteciperò ad altri commenti su questa linea]
Ira Baxter

9
Sono d'accordo con quanto hai detto qui, motivo per cui ho formulato la domanda come ho fatto. Immagino che dovremmo intuire da quella risposta che ritieni che sia troppo strettamente legato alle tue entrate, e non c'è assolutamente niente di sbagliato in questo - ho solo pensato che valesse la pena chiedere.
TML

3
@IraBaxter Dite solo espressioni idiomatiche comuni su pratiche relative al computer che possono essere applicate a molte altre pratiche. L'unica cosa interessante in tutto ciò che hai scritto sono i link a semanticdesigns.com (che sembra essere la tua azienda)
amirouche

1
Spesso fornisci collegamenti a pagine relative a Clang nelle tue risposte. Ciò dimostra solo che qualcun altro può creare una pagina web. La maggior parte di noi presume che una pagina web ben scritta implichi che dietro ci sia un lavoro serio e reale e non solo un tentativo fraudolento di ingannare il lettore come sembri implicare nella tua risposta. Credi davvero che la pagina web sia fraudolenta? La pagina contiene informazioni di riferimento alla fonte "pertinente"; è anonomizzato perché il contratto di lavoro lo richiedeva. Che non posso aiutare
Ira Baxter

13

La mia risposta affronterà il compito specifico di analizzare Python per tradurlo in un'altra lingua, e non gli aspetti di livello superiore che Ira ha affrontato bene nella sua risposta.

In breve: non utilizzare il modulo parser, c'è un modo più semplice.

Il astmodulo, disponibile a partire da Python 2.6 è molto più adatto alle tue esigenze, poiché ti fornisce un AST già pronto con cui lavorare. Ho scritto un articolo su quest'ultimo anno, ma in breve, usa il parsemetodo astper analizzare il codice sorgente Python in un AST. Il parsermodulo ti darà un albero di analisi, non un AST. Diffidare della differenza .

Ora, poiché gli AST di Python sono piuttosto dettagliati, dato un AST il lavoro di front-end non è particolarmente difficile. Suppongo che tu possa avere un semplice prototipo per alcune parti della funzionalità pronte abbastanza rapidamente. Tuttavia, arrivare a una soluzione completa richiederà più tempo, principalmente perché la semantica delle lingue è diversa. Un semplice sottoinsieme del linguaggio (funzioni, tipi di base e così via) può essere facilmente tradotto, ma una volta entrati negli strati più complessi, avrai bisogno di macchinari pesanti per emulare il nucleo di una lingua in un'altra. Ad esempio, considera i generatori di Python e le liste di comprensione che non esistono in PHP (per quanto ne so, che è certamente scadente quando è coinvolto PHP).

Per darti un suggerimento finale, considera lo 2to3strumento creato dagli sviluppatori di Python per tradurre il codice Python 2 in codice Python 3. Dal punto di vista del front-end, ha la maggior parte degli elementi necessari per tradurre Python in qualcosa . Tuttavia, poiché i core di Python 2 e 3 sono simili, non è richiesto alcun meccanismo di emulazione.


Weeeell. 2to3è solo AST per AST. Non supporta le operazioni che vanno oltre le capacità del astmodulo. Si noti che tutte le traduzioni vanno dalla sintassi supportata dal processo Python host alla sintassi supportata dal processo Python host. Non esiste un traduttore che aggiunge, ad esempio, annotazioni di funzioni, perché 2.6 non lo supporta.
habnabit

... e la domanda dell'OP potrebbe essere inquadrata, a breve termine, come passare da Python 2.6 AST a ... qualcosa in PHP. Il modulo ast probabilmente non vorrà rappresentare bene la sintassi PHP, quindi non è nemmeno da ast ad ast.
Ira Baxter

2
@Aaron: 2to3può essere visto come un esempio di utilizzo dell'AST generato da ast.
Eli Bendersky

AFAIK, 2to3 è probabilmente una traduzione più semplice di Python in PHP (dopotutto, è Python in Python, giusto)? E anche non funziona particolarmente bene. Si noti la grande quantità di Python 2.6 che non è stato ancora trasferito attraverso 2to3 ... perché apparentemente c'è un sacco di patch manuali post-traduzione che devono ancora essere fatte. Se fosse automatizzato al 100%, Python 2.6 sarebbe morto.
Ira Baxter

5

Scrivere un traduttore non è impossibile, soprattutto considerando che lo stagista di Joel fatto durante un'estate.

Se vuoi fare una lingua, è facile. Se vuoi fare di più, è un po 'più difficile, ma non troppo. La parte più difficile è che, mentre qualsiasi lingua turing complete può fare ciò che fa un'altra lingua turing complete, i tipi di dati incorporati possono cambiare ciò che fa una lingua in modo fenomenale.

Per esempio:

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

richiede molto codice C ++ per essere duplicato (ok, puoi farlo abbastanza brevemente con alcuni costrutti di loop, ma comunque).

È un po 'a parte, immagino.

Hai mai scritto un tokenizer / parser basato su una grammatica linguistica? Probabilmente vorrai imparare come farlo se non l'hai fatto, perché questa è la parte principale di questo progetto. Quello che vorrei fare è trovare una sintassi completa di Turing di base, qualcosa di abbastanza simile al bytecode di Python . Quindi crei un lexer / parser che accetta una grammatica linguistica (magari usando BNF ) e, in base alla grammatica, compila la lingua nella tua lingua intermedia. Quindi quello che vorrai fare è fare il contrario: creare un parser dalla tua lingua nelle lingue di destinazione in base alla grammatica.

Il problema più ovvio che vedo è che all'inizio probabilmente creerai codice orribilmente inefficiente, specialmente in linguaggi più potenti * come Python.

Ma se lo fai in questo modo, probabilmente sarai in grado di trovare modi per ottimizzare l'output mentre procedi. Riassumere:

  • leggere la grammatica fornita
  • compilare il programma nella sintassi intermedia (ma anche Turing completa)
  • compilare il programma intermedio nella lingua finale (in base alla grammatica fornita)
  • ...?
  • Profitto!(?)

* per potente intendo che questo richiede 4 righe:

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

Mostrami un altro linguaggio che può fare qualcosa del genere in 4 righe e ti mostrerò un linguaggio potente come Python.


"Hai mai scritto un tokenizer / parser basato su una grammatica del linguaggio?" L'ho fatto usando JavaCC.
NullUserException

2
Lo stagista di Joel ha svolto un lavoro parziale durante un'estate. La sua lingua di origine era un sottoinsieme di una lingua esistente e presumibilmente questo sottoinsieme potrebbe essere modificato in qualche modo. Questo rende il lavoro molto più semplice. Allo stesso modo, NullPointerException potrebbe voler iniziare con le parti più semplici di Python, magari passando attraverso le cose più difficili per la conversione manuale (come indicato nelle domande).
David Thornley

@NullUserException: avrai un po 'di visibilità, ma fondamentalmente farai una reimplementazione di JavaCC, solo che invece di Java come linguaggio di output, farai <inserisci langauge qui>. @ David, proprio così. Anche Thistle ha bisogno di aiuto su alcuni costrutti del linguaggio. Se fossi l'OP, sceglierei prima funzionale, quindi ottimizzerei, altrimenti sarei bloccato per sempre cercando di ottenere C ++ per eseguire il taglio delle stringhe (con passaggi): p
Wayne Werner

@WayneWerner Per la cronaca, linguaggi come C # non richiedono affatto le nuove righe. (Almeno, non dopo aver eliminato i commenti su una sola riga.) Quindi potresti scrivere qualsiasi programma C # in una riga. Ma ovviamente capisco a cosa stai arrivando.
leviathanbadger

@ aboveyou00: non penso sia giusto. Se disattivi i condizionali del preprocessore, potresti avere ragione.
Ira Baxter

3

Ci sono un paio di risposte che ti dicono di non preoccuparti. Bene, quanto è utile? Vuoi imparare? Si può imparare. Questa è la compilazione. Accade solo che la tua lingua di destinazione non sia un codice macchina, ma un altro linguaggio di alto livello. Questo viene fatto tutto il tempo.

C'è un modo relativamente semplice per iniziare. Per prima cosa, vai a prendere http://sourceforge.net/projects/lime-php/ (se vuoi lavorare in PHP) o qualcosa del genere e segui il codice di esempio. Successivamente, puoi scrivere un analizzatore lessicale utilizzando una sequenza di espressioni regolari e feed token al parser che generi. Le tue azioni semantiche possono produrre codice direttamente in un altro linguaggio o costruire una struttura dati (pensa a oggetti, man) che puoi massaggiare e attraversare per generare codice di output.

Sei fortunato con PHP e Python perché per molti aspetti sono la stessa lingua l'uno dell'altro, ma con una sintassi diversa. La parte difficile è superare le differenze semantiche tra le forme grammaticali e le strutture dei dati. Ad esempio, Python ha elenchi e dizionari, mentre PHP ha solo array assoc.

L'approccio "discente" consiste nel creare qualcosa che funzioni bene per un sottoinsieme ristretto del linguaggio (come solo istruzioni di stampa, matematica semplice e assegnazione di variabili) e quindi rimuovere progressivamente le limitazioni. Questo è fondamentalmente quello che hanno fatto tutti i "grandi" in campo.

Oh, e poiché non hai tipi statici in Python, potrebbe essere meglio scrivere e fare affidamento su funzioni PHP come "python_add" che aggiunge numeri, stringhe o oggetti a seconda del modo in cui Python lo fa.

Ovviamente, questo può diventare molto più grande se lo lasci.


3
In realtà, non ho detto "non preoccuparti". Quello che ho detto è stato "tradurre le lingue in modo generale è molto difficile". Se l'OP procede lungo il suo percorso originale di utilizzo degli alberi Python per provare a generare PHP, imparerà molto e sono tutti a favore dell'esperienza di apprendimento; Anch'io ho iniziato lì. Non sarà in grado di aggiungere facilmente nuove lingue.
Ira Baxter

@IraBaxter Non posso supportare la tua dichiarazione, fare Python-> PHP e PHP-> Javascript sarebbe piuttosto facile. cfr. ultima parte di stackoverflow.com/a/22850139/140837 nel mezzo della risposta mi occupo anche della tua "argomentazione"
amirouche

2

Secondo @EliBendersky il punto di vista sull'uso di ast.parse invece del parser (di cui non ero a conoscenza prima). Ti consiglio anche vivamente di rivedere il suo blog. Ho usato ast.parse per eseguire il traduttore Python-> JavaScript (@ https://bitbucket.org/amirouche/pythonium ). Ho ideato il design Pythonium rivedendo in qualche modo altre implementazioni e provandole da solo. Ho biforcato Pythonium da https://github.com/PythonJS/PythonJS che ho anche iniziato, in realtà è una riscrittura completa. Il design complessivo è ispirato da PyPy e http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf paper.

Tutto ciò che ho provato, dall'inizio alla soluzione migliore, anche se sembra che il marketing di Pythonium in realtà non lo sia (non esitate a dirmi se qualcosa non sembra corretto nella netiquette):

  • Implementa la semantica di Python in Plain Old JavaScript utilizzando l'ereditarietà del prototipo: AFAIK è impossibile implementare l'ereditarietà multipla di Python utilizzando il sistema di oggetti prototipo JS. Ho provato a farlo usando altri trucchi in seguito (cfr. Getattribute). Per quanto ne so non esiste alcuna implementazione dell'ereditarietà multipla di Python in JavaScript, la migliore che esiste è l'ereditarietà singola + mixin e non sono sicuro che gestiscano l'ereditarietà del diamante. Un po 'simile a Skulpt ma senza google clojure.

  • Ho provato con Google clojure, proprio come Skulpt (compilatore) invece di leggere effettivamente il codice Skulpt #fail. Comunque a causa del sistema di oggetti basato su prototipi JS ancora impossibile. Creare il binding è stato molto molto difficile, è necessario scrivere JavaScript e molto codice boilerplate (cfr. Https://github.com/skulpt/skulpt/issues/50 dove sono io il fantasma). A quel tempo non c'era un modo chiaro per integrare l'associazione nel sistema di compilazione. Penso che Skulpt sia una libreria e devi solo includere i tuoi file .py nell'html per essere eseguito, nessuna fase di compilazione deve essere eseguita dallo sviluppatore.

  • Ho provato pyjaco (compilatore) ma la creazione di associazioni (chiamando il codice Javascript dal codice Python) è stata molto difficile, c'era troppo codice boilerplate da creare ogni volta. Ora penso che il pyjaco sia quello più vicino a Pythonium. pyjaco è scritto in Python (anche ast.parse) ma molto è scritto in JavaScript e utilizza l'ereditarietà dei prototipi.

Non riesco mai a eseguire Pyjamas #fail e non ho mai provato a leggere di nuovo il codice #fail. Ma nella mia mente il pigiama stava facendo la traduzione API-> API (o da framework a framework) e non da Python a JavaScript. Il framework JavaScript utilizza i dati già presenti nella pagina o i dati dal server. Il codice Python è solo "idraulico". Dopo di che ho scoperto che il pigiama era in realtà un vero traduttore python-> js.

Tuttavia penso che sia possibile fare la traduzione API-> API (o framework-> framework) e questo è fondamentalmente quello che faccio in Pythonium ma a un livello inferiore. Probabilmente i pigiami usano lo stesso algoritmo di Pythonium ...

Poi ho scoperto brython completamente scritto in Javascript come Skulpt, senza bisogno di compilazione e un sacco di confusione ... ma scritto in JavaScript.

Sin dalla riga iniziale scritta nel corso di questo progetto, conoscevo PyPy, anche il backend JavaScript per PyPy. Sì, puoi, se lo trovi, generare direttamente un interprete Python in JavaScript da PyPy. La gente dice che è stato un disastro. Ho letto da nessuna parte perché. Ma penso che il motivo sia che il linguaggio intermedio che usano per implementare l'interprete, RPython, è un sottoinsieme di Python su misura per essere tradotto in C (e forse asm). Ira Baxter dice che fai sempre supposizioni quando costruisci qualcosa e probabilmente lo metti a punto per essere il migliore in quello che dovrebbe fare nel caso della traduzione PyPy: Python-> C. Quelle ipotesi potrebbero non essere rilevanti in un altro contesto, peggio che possono derivare da sovraccarico, altrimenti la traduzione diretta sarà molto probabilmente sempre migliore.

Avere l'interprete scritto in Python suonava come una (molto) buona idea. Ma ero più interessato a un compilatore per motivi di prestazioni, inoltre è in realtà più facile compilare Python in JavaScript che interpretarlo.

Ho iniziato PythonJS con l'idea di mettere insieme un sottoinsieme di Python che avrei potuto facilmente tradurre in JavaScript. All'inizio non mi sono nemmeno preoccupato di implementare il sistema OO a causa dell'esperienza passata. Il sottoinsieme di Python che ho ottenuto per tradurre in JavaScript sono:

  • funzione con parametri semantici completi sia in definizione che in chiamata. Questa è la parte di cui sono più orgoglioso.
  • mentre / if / elif / else
  • I tipi Python sono stati convertiti in tipi JavaScript (non esistono tipi Python di alcun tipo)
  • perché potrebbe iterare solo su array Javascript (per un array in)
  • Accesso trasparente a JavaScript: se scrivi Array nel codice Python verrà tradotto in Array in javascript. Questo è il più grande risultato in termini di usabilità rispetto ai suoi concorrenti.
  • Puoi passare la funzione definita nel sorgente Python alle funzioni javascript. Verranno presi in considerazione gli argomenti predefiniti.
  • Aggiunge ha una funzione speciale chiamata new che viene tradotta in JavaScript new es: new (Python) (1, 2, spam, "egg") viene tradotto in "new Python (1, 2, spam," egg ").
  • "var" vengono gestiti automaticamente dal traduttore. (scoperta molto bella da Brett (collaboratore di PythonJS).
  • parola chiave globale
  • chiusure
  • lambdas
  • elenchi di comprensioni
  • le importazioni sono supportate tramite requirejs
  • ereditarietà di una singola classe + mixin tramite classyjs

Questo sembra molto ma in realtà molto stretto rispetto alla semantica in piena regola di Python. È davvero JavaScript con una sintassi Python.

Il JS generato è perfetto cioè. non c'è overhead, non può essere migliorato in termini di prestazioni modificandolo ulteriormente. Se puoi migliorare il codice generato, puoi farlo anche dal file sorgente di Python. Inoltre, il compilatore non si basava su alcun trucco JS che puoi trovare in .js scritto da http://superherojs.com/ , quindi è molto leggibile.

Il discendente diretto di questa parte di PythonJS è la modalità Pythonium Veloce. L'implementazione completa può essere trovata @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + circa 100 SLOC di codice condiviso con l'altro traduttore.

Una versione adattata di pystones.py può essere tradotta in modalità Veloce cfr. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Dopo aver impostato la traduzione di base Python-> JavaScript, ho scelto un altro percorso per tradurre Python completo in JavaScript. Il modo in cui glib esegue codice basato su classi orientate agli oggetti, tranne il linguaggio di destinazione, è JS, quindi si ha accesso a array, oggetti simili a mappe e molti altri trucchi e tutta quella parte è stata scritta in Python. IIRC non esiste un codice javascript scritto da nel traduttore Pythonium. Ottenere l'ereditarietà singola non è difficile: ecco le parti difficili che rendono Pythonium completamente compatibile con Python:

  • spam.egg in Python è sempre tradotto in getattribute(spam, "egg") Non l'ho profilato in particolare ma penso che perda molto tempo e non sono sicuro di poterlo migliorare con asm.js o qualsiasi altra cosa.
  • ordine di risoluzione del metodo: anche con l'algoritmo scritto in Python, tradurlo in codice compatibile con Python Veloce è stato un grande sforzo.
  • getattributre : l'attuale algoritmo di risoluzione getattribute è un po 'complicato e ancora non supporta i descrittori di dati
  • basato sulla classe metaclass: so dove inserire il codice, ma comunque ...
  • ultimo ma non meno importante: some_callable (...) viene sempre tradotto in "call (some_callable)". Per quanto ne so, il traduttore non usa affatto l'inferenza, quindi ogni volta che fai una chiamata devi controllare quale tipo di oggetto è per chiamarlo nel modo in cui deve essere chiamato.

Questa parte è fattorizzata in https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master È scritto in Python compatibile con Python Veloce.

Il traduttore conforme effettivo https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master non genera direttamente codice JavaScript e, soprattutto, non esegue la trasformazione ast-> ast . Ho provato la cosa ast-> ast e ast anche se più bella di cst non è piacevole lavorare con ast.NodeTransformer e, cosa più importante, non ho bisogno di fare ast-> ast.

Fare da python ast a python ast nel mio caso almeno sarebbe forse un miglioramento delle prestazioni poiché a volte ispeziono il contenuto di un blocco prima di generare il codice ad esso associato, ad esempio:

  • var / global: per poter var qualcosa devo sapere di cosa ho bisogno e non var. Invece di generare un blocco che tiene traccia di quali variabili vengono create in un dato blocco e inserirle sopra il blocco funzione generato, cerco solo un'assegnazione di variabile rilevante quando entro nel blocco prima di visitare effettivamente il nodo figlio per generare il codice associato.
  • yield, i generatori hanno ancora una sintassi speciale in JS, quindi ho bisogno di sapere quale funzione Python è un generatore quando voglio scrivere "var my_generator = function"

Quindi non visito davvero ogni nodo una volta per ogni fase della traduzione.

Il processo complessivo può essere descritto come:

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

I builtin di Python sono scritti in codice Python (!), IIRC ci sono alcune restrizioni relative ai tipi di bootstrap, ma hai accesso a tutto ciò che può tradurre Pythonium in modalità conforme. Dai un'occhiata a https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

La lettura del codice JS generato da pythonium compatibile può essere compresa, ma le mappe sorgente saranno di grande aiuto.

I preziosi consigli che posso darti alla luce di questa esperienza sono delle vecchie scoregge gentili:

  • rivedere ampiamente l'argomento sia in letteratura che in progetti esistenti closed source o gratuiti. Quando ho esaminato i diversi progetti esistenti avrei dovuto dargli più tempo e motivazione.
  • fare domande! Se avessi saputo in anticipo che il backend PyPy era inutile a causa del sovraccarico dovuto alla mancata corrispondenza semantica di C / Javascript. Forse avrei avuto un'idea di Pythonium molto prima di 6 mesi fa, forse 3 anni fa.
  • sapere cosa vuoi fare, avere un obiettivo. Per questo progetto avevo diversi obiettivi: praticare un po 'javascript, imparare di più su Python ed essere in grado di scrivere codice Python che sarebbe stato eseguito nel browser (altro e quello sotto).
  • il fallimento è esperienza
  • un piccolo passo è un passo
  • inizia in piccolo
  • sogna in grande
  • fare demo
  • iterare

Solo con la modalità Python Veloce, sono molto felice! Ma lungo la strada ho scoperto che quello che stavo veramente cercando era liberare me e gli altri da Javascript, ma soprattutto essere in grado di creare in modo confortevole. Questo mi ha portato a Scheme, DSL, Models e, infine, a modelli specifici di dominio (cfr. Http://dsmforum.org/ ).

A proposito della risposta di Ira Baxter:

Le stime non sono affatto utili. Mi ci sono voluti più o meno 6 mesi di tempo libero sia per PythonJS che per Pythonium. Quindi posso aspettarmi di più da 6 mesi a tempo pieno. Penso che tutti sappiamo cosa possono significare e non significano affatto 100 anni / uomo in un contesto aziendale ...

Quando qualcuno dice che qualcosa è difficile o più spesso impossibile, rispondo che "ci vuole solo tempo per trovare una soluzione per un problema che è impossibile" altrimenti detto niente è impossibile tranne se si è dimostrato impossibile in questo caso una prova matematica ...

Se non è dimostrato impossibile, lascia spazio all'immaginazione:

  • trovare una prova che dimostri che è impossibile

e

  • Se è impossibile, potrebbe esserci un problema "inferiore" che può avere una soluzione.

o

  • se non è impossibile, trovare una soluzione

Non è solo un pensiero ottimistico. Quando ho avviato Python-> Javascript tutti dicevano che era impossibile. PyPy impossibile. Metaclassi troppo duri. ecc ... Penso che l'unica rivoluzione che porta PyPy su Scheme-> C paper (che ha 25 anni) sia una generazione JIT automatica (suggerimenti basati sull'interprete RPython credo).

La maggior parte delle persone che dicono che una cosa è "difficile" o "impossibile" non fornisce le ragioni. C ++ è difficile da analizzare? Lo so, ancora sono parser C ++ (gratuiti). Il male è nei dettagli? Lo so. Dire che è impossibile da soli non è utile, è anche peggio che "non utile" è scoraggiante, e alcune persone intendono scoraggiare gli altri. Ho sentito parlare di questa domanda tramite /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

Quale sarebbe la perfezione per te ? È così che definisci il prossimo obiettivo e forse raggiungi l'obiettivo generale.

Sono più interessato a sapere quali tipi di pattern potrei applicare al codice per rendere più facile tradurre (ad esempio: IoC, SOA?) Il codice piuttosto che come fare la traduzione.

Non vedo schemi che non possano essere tradotti da una lingua a un'altra lingua almeno in modo meno che perfetto. Poiché la traduzione da lingua a lingua è possibile, è meglio mirare prima a questo. Dal momento che, secondo http://en.wikipedia.org/wiki/Graph_isomorphism_problem , la traduzione tra due linguaggi di computer è un albero o isomorfismo DAG. Anche se sappiamo già che sono entrambi completati, quindi ...

Framework-> Framework che visualizzo meglio come API-> traduzione API potrebbe ancora essere qualcosa che potresti tenere a mente come un modo per migliorare il codice generato. Ad esempio: Prolog come sintassi molto specifica, ma puoi comunque eseguire calcoli simili a Prolog descrivendo lo stesso grafico in Python ... Se dovessi implementare un traduttore da Prolog a Python non implementerei l'unificazione in Python ma in una libreria C e verrei con una "sintassi Python" che è molto leggibile per un Pythonist. Alla fine, la sintassi è solo "pittura" a cui diamo un significato (ecco perché ho iniziato lo schema). Il male è nei dettagli del linguaggio e non sto parlando della sintassi. I concetti utilizzati nella lingua getattributehook (puoi vivere senza di esso) ma le funzionalità VM richieste come l'ottimizzazione della ricorsione della coda possono essere difficili da gestire. Non ti interessa se il programma iniziale non usa la ricorsione in coda e anche se non c'è ricorsione in coda nella lingua di destinazione puoi emularla usando greenlets / event loop.

Per le lingue di destinazione e di origine, cerca:

  • Idee grandi e specifiche
  • Idee condivise minuscole e comuni

Da questo emergeranno:

  • Cose facili da tradurre
  • Cose difficili da tradurre

Probabilmente sarai anche in grado di sapere cosa verrà tradotto in codice veloce e lento.

C'è anche la questione dello stdlib o di qualsiasi libreria ma non c'è una risposta chiara, dipende dai tuoi obiettivi.

Anche il codice idiomatico o il codice generato leggibile hanno soluzioni ...

Scegliere come target una piattaforma come PHP è molto più facile che indirizzare i browser poiché è possibile fornire l'implementazione C del percorso lento e / o critico.

Dato che il tuo primo progetto è tradurre Python in PHP, almeno per il sottoinsieme PHP3 che conosco, la personalizzazione di veloce.py è la soluzione migliore. Se puoi implementare veloce.py per PHP allora probabilmente sarai in grado di eseguire la modalità conforme ... Inoltre se puoi tradurre PHP nel sottoinsieme di PHP puoi generare con php_veloce.py significa che puoi tradurre PHP nel sottoinsieme di Python che veloce.py può consumare, il che significherebbe che puoi tradurre PHP in Javascript. Sto solo dicendo ...

Puoi anche dare un'occhiata a quelle librerie:

Inoltre potresti essere interessato da questo post del blog (e commenti): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/


L'unica cosa che rimane emozionante per me di linguaggio di programmazione one-to-one di traduzione in lingua del computer sono descritte in stackoverflow.com/questions/22621164/...
Amirouche

Secondo l'altra risposta sui tipi di dati. In Pythonium non avevo nemmeno intenzione di supportare un intero corretto e tipo float in modalità conforme senza asm.js.
amirouche

OK, quindi se ti do un pacchetto Python di 100K SLOC, e lo esegui attraverso il tuo "traduttore", ottengo un programma funzionante? Quanto lavoro manuale post-traduzione ci vuole per risolverlo? Quello che hai detto qui era, "dato un buon parser già esistente per Python che costruisce AST, posso costruire un traduttore parziale in 6 mesi". Nessuno è sorpreso. 6 mesi non sono per la maggior parte delle persone "abbastanza facili" (citando un altro dei tuoi commenti). Risolvere i problemi rimanenti richiederà uno sforzo maggiore. La mia risposta diceva, fondamentalmente "farlo non è facile" e "farlo in modo generale è difficile".
Ira Baxter

... quell'ultimo punto in risposta al desiderio originale di OP: "idealmente sarei in grado di aggiungere altre lingue con (relativa) facilità.", che la mia risposta si rivolge specificamente.
Ira Baxter

Chiedo di non essere d'accordo, soprattutto quando sai cosa stai facendo, è facile e ciò che segue non è difficile, è solo questione di fare le cose. Non sono sicuro di dove hai a che fare con qualcosa di specifico per la domanda. Stai dicendo in 4 o 5 paragrafi che la tua azienda lo fa, ed è difficile. Ma per il resto stai diffondendo FUD sull'argomento, pur essendo gentile fuori tema come se fossi in stackoverflow.com/questions/22621164/… . In 6 mesi a tempo pieno avrei scritto un traduttore completo.
amirouche

0

Potresti dare un'occhiata al compilatore Vala , che traduce Vala (un linguaggio simile a C #) in C.


Era uno degli obiettivi di progettazione di Vala essere tradotto in C e rendere facile lo sviluppo con le librerie gnome.
amirouche
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.