Que tipos de padrões eu poderia impor ao código para facilitar a tradução para outra linguagem de programação? [fechadas]

95

Estou me preparando para fazer um projeto paralelo que tem o objetivo de traduzir o código de uma linguagem de programação para outra. As linguagens com as quais estou começando são PHP e Python (Python para PHP deve ser mais fácil de começar), mas de preferência eu seria capaz de adicionar outras linguagens com (relativa) facilidade. O plano é:

  • Isso é voltado para o desenvolvimento web. O código original e o código-alvo ficarão sobre os frameworks (que também terei que escrever). Essas estruturas adotarão um padrão de design MVC e seguirão convenções de codificação rígidas. Isso deve tornar a tradução um pouco mais fácil.

  • Também estou analisando o IOC e a injeção de dependência, pois eles podem tornar o processo de tradução mais fácil e menos sujeito a erros.

  • Vou usar o módulo analisador do Python , que me permite mexer na árvore de sintaxe abstrata. Aparentemente, o mais próximo que posso chegar com PHP é token_get_all () , que é um começo.

  • A partir daí posso construir o AST, tabelas de símbolos e fluxo de controle.

Então acredito que posso começar a produzir o código. Não preciso de uma tradução perfeita . Ainda terei que revisar o código gerado e corrigir os problemas. Idealmente, o tradutor deve sinalizar traduções problemáticas.

Antes que você pergunte "Qual é o objetivo disso?" A resposta é ... Será uma experiência de aprendizado interessante. Se você tiver alguma ideia sobre como tornar isso menos assustador, entre em contato.


EDITAR:

Estou mais interessado em saber que tipos de padrões eu poderia aplicar no código para torná-lo mais fácil de traduzir (ou seja: IoC, SOA?) Do código do que como fazer a tradução.

NullUserException
fonte
6
Você já olhou para sistemas como o .NET CLR ou o Parrot do Perl6? Eles compilam um conjunto de linguagens até uma representação intermediária que pode ser executada por um interpretador comum. Se você puder voltar da representação intermediária para um idioma, você tem um tradutor.
Borealid
1
@Borealid AFAIK o .NET CIL é (relativamente) fácil de compilar em , mas boa sorte para conseguir de volta código legível do que isso. Olhando para o Parrot agora.
NullUserException
Existem projetos semelhantes para outras línguas; Não tenho certeza de quão ricos são seus autores. Na verdade, estou me restringindo muito aqui, precisando de uma estrutura e aderindo a convenções de codificação rígidas.
NullUserException
2
Não posso acrescentar nenhum conhecimento específico, mas você já olhou para pijamas ( pyjs.org ), especificamente, Translator.py? Este é um compilador de python para javascript.
stephan
3
Re EDITAR: Se você tem controle sobre o código que será traduzido, a coisa mais óbvia a fazer é evitar construções difíceis de traduzir! Por exemplo, C é muito mais fácil de traduzir para Java se não houver nenhuma aritmética de ponteiro. Para Python, provavelmente ficaria longe de encerramentos. A outra coisa que você pode fazer é escrever o código-fonte de uma maneira que as partes mais difíceis de traduzir sejam sempre codificadas de forma idiomática, tornando-as mais fáceis de reconhecer e lidar com casos especiais.
Ira Baxter

Respostas:

122

Eu tenho construído ferramentas (DMS Software Reengineering Toolkit) para fazer manipulação de programas de propósito geral (com tradução de linguagem sendo um caso especial) desde 1995, apoiado por uma forte equipe de cientistas da computação. O DMS fornece análise genérica, construção de AST, tabelas de símbolos, análise de fluxo de dados e controle, aplicação de regras de tradução, regeneração do texto fonte com comentários, etc., tudo parametrizado por definições explícitas de linguagens de computador.

A quantidade de maquinário de que você precisa para fazer isso bem é vasta (especialmente se você quiser ser capaz de fazer isso para várias linguagens de uma maneira geral), e então você precisa de analisadores confiáveis ​​para linguagens com definições não confiáveis ​​(PHP é um exemplo perfeito disso )

Não há nada de errado em você pensar em construir um tradutor de idioma para idioma ou tentar fazê-lo, mas acho que você achará essa tarefa muito maior para idiomas reais do que espera. Temos cerca de 100 homens-ano investidos apenas em DMS e outros 6-12 meses em cada definição de linguagem "confiável" (incluindo aquela que construímos penosamente para PHP), muito mais para linguagens desagradáveis ​​como C ++. Será um "inferno de uma experiência de aprendizado"; tem sido para nós. (Você pode achar a seção de artigos técnicos no site acima interessante para impulsionar esse aprendizado).

Muitas vezes as pessoas tentam construir algum tipo de maquinário generalizado, começando com alguma peça de tecnologia com a qual estão familiarizados, que faz parte do trabalho. (Python ASTs são um ótimo exemplo). A boa notícia é que parte do trabalho está feito. A má notícia é que o maquinário tem um zilhão de suposições embutidas, a maioria das quais você não descobrirá até que tente lutar para fazer outra coisa. Nesse ponto, você descobre que o maquinário está programado para fazer o que faz originalmente e realmente resistirá à sua tentativa de fazer algo diferente. (Eu suspeito que tentar obter o Python AST para modelar o PHP será muito divertido).

A razão pela qual comecei a construir o DMS originalmente foi construir fundações que tinham muito poucas dessas suposições embutidas. Algumas delas nos dão dores de cabeça. Até agora, nenhum buraco negro. (A parte mais difícil do meu trabalho nos últimos 15 anos é tentar evitar que tais suposições se insinuem).

Muitas pessoas também cometem o erro de presumir que, se puderem analisar (e talvez obter um AST), estarão no caminho certo para fazer algo complicado. Uma das lições difíceis é que você precisa de tabelas de símbolos e análise de fluxo para fazer uma boa análise ou transformação do programa. Os ASTs são necessários, mas não suficientes. Esta é a razão pela qual o livro do compilador de Aho & Ullman não pára no capítulo 2. (O OP tem esse direito, pois está planejando construir maquinário adicional além do AST). Para obter mais informações sobre este tópico, consulte Vida após análise .

O comentário sobre "Não preciso de uma tradução perfeita" é problemático. O que os tradutores fracos fazem é converter os 80% "fáceis" do código, deixando os 20% difíceis para fazer manualmente. Se o aplicativo que você pretende converter for muito pequeno e você só pretende convertê-lo bem uma vez, esses 20% estão OK. Se você deseja converter muitos aplicativos (ou mesmo o mesmo com pequenas alterações ao longo do tempo), isso não é bom. Se você tentar converter 100K SLOC então 20% são 20.000 linhas originais de código que são difíceis de traduzir, entender e modificar no contexto de outras 80.000 linhas de programa traduzido que você ainda não entende. Isso exige um grande esforço. No nível de um milhão de linhas, isso é simplesmente impossível na prática.mais difícil e eles normalmente descobrem dolorosamente com longos atrasos, altos custos e, muitas vezes, falha total.)

O que você precisa almejar para traduzir sistemas em grande escala são altas taxas de conversão percentuais dos anos noventa, ou é provável que você não consiga concluir a parte manual da atividade de tradução.

Outra consideração importante é o tamanho do código a ser traduzido. É preciso muita energia para construir um tradutor robusto e funcional, mesmo com boas ferramentas. Embora pareça atraente e legal construir um tradutor em vez de simplesmente fazer uma conversão manual, para pequenas bases de código (por exemplo, até cerca de 100K SLOC em nossa experiência) a economia simplesmente não o justifica. Ninguém gosta dessa resposta, mas se você realmente tiver que traduzir apenas 10K SLOC de código, provavelmente será melhor apenas morder o marcador e fazê-lo. E sim, isso é doloroso.

Eu considero nossas ferramentas extremamente boas (mas sou bastante tendencioso). E ainda é muito difícil construir um bom tradutor; leva cerca de 1,5-2 anos-homem e sabemos como usar nossas ferramentas. A diferença é que, com tanto maquinário, temos muito mais sucesso do que falha.

Ira Baxter
fonte
8
Você já pensou em contribuir com sua definição de PHP "dolorosamente construída" para a comunidade PHP em geral, ou está muito associado ao seu próprio fluxo de receita para tornar isso viável?
TML
53
Muitas pessoas me pediram para tornar tudo o que fazemos "open source" que não queriam contribuir para um fluxo de receita e não tinham energia para fazer o trabalho e abrir o código por conta própria. Se você contribui apenas com uma pequena parte para um projeto muito grande e / ou tem outra fonte de renda, "código aberto" parece bom. Se você fez todo o trabalho sozinho e é sua única fonte de renda, isso é muito menos atraente. [Não quero entrar em uma discussão sobre os méritos relativos da filosofia do "software livre", então não participarei de nenhum outro comentário nessa linha]
Ira Baxter
9
Concordo com o que você disse aqui, e é por isso que formulei a pergunta dessa maneira. Acho que devemos intuir a partir dessa resposta que você acha que ela está intimamente ligada à sua receita e não há absolutamente nada de errado com isso - achei que valia a pena perguntar.
TML de
3
@IraBaxter Você acabou de dizer expressões comuns sobre práticas relacionadas ao computador que podem ser aplicadas a muitas outras práticas. A única coisa interessante em tudo o que você escreveu são os links para semanticdesigns.com (que por acaso é sua empresa)
amirouche
1
Você costuma fornecer links para páginas relacionadas ao Clang em suas respostas. Isso só prova que outra pessoa pode fazer uma página da web. A maioria de nós presume que uma página da web bem escrita implica que há um trabalho sério e real por trás, e não apenas alguma tentativa fraudulenta de enganar o leitor, como você parece sugerir em sua resposta. Você realmente acredita que a página da web é fraudulenta? A página contém informações de referência para fontes "relevantes"; é anonomizado porque o contrato da obra assim o exigia. Que eu não posso ajudar.
Ira Baxter
13

Minha resposta tratará da tarefa específica de analisar Python para traduzi-lo para outra linguagem, e não dos aspectos de nível superior que Ira abordou bem em sua resposta.

Resumindo: não use o módulo parser, existe uma maneira mais fácil.

O astmódulo, disponível desde o Python 2.6, é muito mais adequado às suas necessidades, pois oferece um AST pronto para trabalhar. Escrevi um artigo sobre isso no ano passado, mas, em resumo, use o parsemétodo de astpara analisar o código-fonte do Python em um AST. O parsermódulo fornecerá uma árvore de análise, não um AST. Desconfie da diferença .

Agora, como os ASTs do Python são bastante detalhados, dado um AST, o trabalho de front-end não é terrivelmente difícil. Suponho que você possa ter um protótipo simples para algumas partes da funcionalidade prontas rapidamente. Porém, chegar a uma solução completa levará mais tempo, principalmente porque a semântica das linguagens é diferente. Um subconjunto simples da linguagem (funções, tipos básicos e assim por diante) pode ser prontamente traduzido, mas assim que você entrar nas camadas mais complexas, precisará de maquinário pesado para emular o núcleo de uma linguagem em outra. Por exemplo, considere os geradores de Python e as compreensões de lista que não existem no PHP (até onde sei, o que é reconhecidamente ruim quando o PHP está envolvido).

Para lhe dar uma dica final, considere a 2to3ferramenta criada pelos desenvolvedores do Python para traduzir o código do Python 2 para o código do Python 3. No front-end, ele contém a maioria dos elementos de que você precisa para traduzir Python em algo . No entanto, como os núcleos do Python 2 e 3 são semelhantes, nenhum mecanismo de emulação é necessário.

Eli Bendersky
fonte
Weeeell. 2to3é apenas AST para AST. Ele não oferece suporte para fazer nada que vá além dos recursos do astmódulo. Observe que todas as traduções vão da sintaxe suportada pelo processo host python para a sintaxe suportada pelo processo host python. Não há tradutor que adicione, digamos, anotações de função, porque o 2.6 não oferece suporte para isso.
habnabit de
... e a questão do OP pode ser formulada, a curto prazo, como ir do Python 2.6 AST para ... algo em PHP. O módulo ast provavelmente não vai querer representar bem a sintaxe do PHP, então não é nem mesmo ast.
Ira Baxter de
2
@Aaron: 2to3pode ser visto como um exemplo de uso do AST gerado a partir ast.
Eli Bendersky
AFAIK, 2to3 sem dúvida é uma tradução mais fácil do que Python para PHP (afinal, é Python para Python, certo)? E mesmo não funciona muito bem. Observe a grande quantidade de Python 2.6 que ainda não passou pelo 2to3 ... porque aparentemente há um monte de correções manuais pós-tradução que ainda precisam ser feitas. Se fosse 100% automatizado, o Python 2.6 estaria morto.
Ira Baxter
5

Escrever um tradutor não é impossível, especialmente considerando que o estagiário de Joel fez isso durante um verão.

Se você quiser fazer um idioma, é fácil. Se você quiser fazer mais, é um pouco mais difícil, mas não muito. A parte mais difícil é que, embora qualquer linguagem completa possa fazer o que outra linguagem completa faz, os tipos de dados integrados podem mudar o que uma linguagem faz de maneira fenomenal.

Por exemplo:

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

requer muito código C ++ para duplicar (ok, bem, você pode fazer isso de forma bem curta com algumas construções de loop, mas ainda assim).

Isso é um pouco à parte, eu acho.

Você já escreveu um tokenizer / analisador baseado em uma gramática de linguagem? Você provavelmente vai querer aprender como fazer isso, se ainda não o fez, porque essa é a parte principal deste projeto. O que eu faria é criar uma sintaxe completa de Turing básica - algo bastante semelhante ao bytecode Python . Em seguida, você cria um lexer / analisador que pega uma gramática de linguagem (talvez usando BNF ) e, com base na gramática, compila a linguagem em sua linguagem intermediária. Então, o que você vai querer fazer é fazer o inverso - criar um analisador de seu idioma para os idiomas de destino com base na gramática.

O problema mais óbvio que vejo é que no início você provavelmente criará um código terrivelmente ineficiente, especialmente em linguagens mais poderosas * como Python.

Mas se você fizer isso dessa maneira, provavelmente será capaz de descobrir maneiras de otimizar a saída à medida que avança. Para resumir:

  • ler gramática fornecida
  • compilar o programa em sintaxe intermediária (mas também completa de Turing)
  • compilar o programa intermediário na linguagem final (com base na gramática fornecida)
  • ...?
  • Lucro!(?)

* por poderoso, quero dizer que leva 4 linhas:

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

Mostre-me outra linguagem que pode fazer algo parecido em 4 linhas, e eu mostrarei a você uma linguagem que é tão poderosa quanto Python.

Wayne Werner
fonte
“Você já escreveu um tokenizer / analisador baseado em uma gramática de linguagem?” Eu fiz isso usando JavaCC.
NullUserException
2
O estagiário de Joel fez um trabalho parcial durante um verão. Seu idioma de origem era um subconjunto de um idioma existente e, presumivelmente, esse subconjunto poderia ser ajustado de alguma forma. Isso torna o trabalho muito mais fácil. Da mesma forma, NullPointerException pode querer começar com as partes mais fáceis do Python, talvez passando pelas coisas mais difíceis para a conversão manual (conforme observado nas perguntas).
David Thornley
@NullUserException: Você terá alguma exposição, mas basicamente estará fazendo uma reimplementação do JavaCC, só que em vez de Java como linguagem de saída, você estará fazendo <insert langauge here>. @David, é isso mesmo. Até o Thistle precisa de alguma ajuda em algumas das construções da linguagem. Se eu fosse o OP, escolheria o funcional primeiro, depois otimizaria, caso contrário, ficaria preso para sempre tentando fazer com que C ++ fizesse o fatiamento de strings (com etapas): p
Wayne Werner
@WayneWerner Para que conste, linguagens como C # não requerem novas linhas de forma alguma. (Pelo menos, não depois de retirar os comentários de uma única linha.) Portanto, você pode escrever qualquer programa C # em uma linha. Mas é claro que entendo aonde você quer chegar.
leviathanbadger de
@ aboveyou00: Não acho isso certo. Se você não permitir condicionais de pré-processador, pode estar certo.
Ira Baxter
3

Existem algumas respostas dizendo para você não se preocupar. Bem, quão útil é isso? Você quer aprender? Você pode aprender. Esta é uma compilação. Acontece que sua linguagem de destino não é um código de máquina, mas outra linguagem de alto nível. Isso é feito o tempo todo.

Existe uma maneira relativamente fácil de começar. Primeiro, vá buscar http://sourceforge.net/projects/lime-php/ (se você quiser trabalhar em PHP) ou algo parecido e vá até o código de exemplo. Em seguida, você pode escrever um analisador léxico usando uma sequência de expressões regulares e tokens de alimentação para o analisador que você gerar. Suas ações semânticas podem produzir código diretamente em outra linguagem ou construir alguma estrutura de dados (pense em objetos, cara) que você pode massagear e atravessar para gerar código de saída.

Você tem sorte com PHP e Python porque em muitos aspectos eles são a mesma linguagem, mas com sintaxe diferente. A parte difícil é superar as diferenças semânticas entre as formas gramaticais e as estruturas de dados. Por exemplo, Python possui listas e dicionários, enquanto PHP possui apenas matrizes associadas.

A abordagem do "aluno" consiste em construir algo que funcione bem para um subconjunto restrito da linguagem (como apenas declarações impressas, matemática simples e atribuição de variáveis) e, em seguida, remover progressivamente as limitações. Isso é basicamente o que todos os "grandes" da área faziam.

Ah, e como você não tem tipos estáticos no Python, pode ser melhor escrever e confiar em funções PHP como "python_add", que adiciona números, strings ou objetos de acordo com a maneira como Python faz isso.

Obviamente, isso pode ficar muito maior se você permitir.

Ian
fonte
3
Na verdade, eu não disse "não se preocupe". O que eu disse foi, "traduzir idiomas de uma maneira geral é muito difícil". Se o OP seguir seu caminho original de usar árvores Python para tentar gerar PHP, ele aprenderá muito e sou totalmente a favor da experiência de aprendizado; Eu comecei lá também. Ele não será capaz de adicionar novos idiomas facilmente.
Ira Baxter
@IraBaxter Não posso apoiar sua afirmação, fazer Python-> PHP e PHP-> Javascript seria meio fácil. cf. última parte de stackoverflow.com/a/22850139/140837 no meio da resposta também trato de sua "argumentação"
amirouche
2

Vou apoiar o ponto de vista de @EliBendersky em relação ao uso de ast.parse em vez de analisador (sobre o qual eu não sabia antes). Eu também recomendo vivamente que você analise seu blog. Usei ast.parse para fazer Python-> tradutor JavaScript (@ https://bitbucket.org/amirouche/pythonium ). Eu vim com o design do Pythonium revisando um pouco outras implementações e testando-as sozinho. Eu criei um fork do Pythonium de https://github.com/PythonJS/PythonJS, que também comecei. Na verdade, é uma reescrita completa. O design geral é inspirado no papel PyPy e http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf .

Tudo o que tentei, do início à melhor solução, mesmo que pareça marketing do Pythonium, na verdade não (não hesite em me dizer se algo não parecer correto para a netiqueta):

  • Implementar a semântica do Python em Plain Old JavaScript usando herança de protótipo: AFAIK é impossível implementar herança múltipla de Python usando sistema de objeto de protótipo JS. Eu tentei fazer isso usando outros truques posteriormente (cf. getattribute). Até onde eu sei, não há implementação de herança múltipla em Python em JavaScript, o melhor que existe é Herança única + mixins e não tenho certeza se eles lidam com herança de diamante. Mais ou menos semelhante ao Skulpt, mas sem google clojure.

  • Eu tentei com o Google clojure, assim como o Skulpt (compilador) em vez de realmente ler o código #fail do Skulpt. De qualquer forma, por causa do sistema de objetos baseado em protótipo JS ainda é impossível. Criar vinculação foi muito difícil, você precisa escrever JavaScript e muito código padrão (cf. https://github.com/skulpt/skulpt/issues/50 onde eu sou o fantasma). Naquela época, não havia uma maneira clara de integrar a vinculação no sistema de compilação. Acho que o Skulpt é uma biblioteca e você só tem que incluir seus arquivos .py no html para serem executados, nenhuma fase de compilação exigida pelo desenvolvedor.

  • Tentei pyjaco (compilador), mas criar vínculos (chamar código Javascript do código Python) era muito difícil, havia muito código clichê para criar todas as vezes. Agora acho que o pyjaco é o que está mais perto do Pythonium. pyjaco é escrito em Python (ast.parse também), mas muito é escrito em JavaScript e usa herança de protótipo.

Na verdade, nunca tive sucesso em executar Pijamas #fail e nunca tentei ler o código #fail novamente. Mas, em minha mente, pijamas estava fazendo tradução de API-> API (ou framework para framework) e não tradução de Python para JavaScript. A estrutura JavaScript consome dados que já estão na página ou dados do servidor. O código Python é apenas "encanamento". Depois disso, descobri que pijama era na verdade um verdadeiro tradutor python-> js.

Ainda assim, acho que é possível fazer tradução API-> API (ou framework-> framework) e isso é basicamente o que faço no Pythonium, mas em um nível inferior. Provavelmente pijamas usam o mesmo algoritmo que Pythonium ...

Então descobri o brython totalmente escrito em Javascript como o Skulpt, sem necessidade de compilação e muito fluff ... mas escrito em JavaScript.

Desde a linha inicial escrita no decorrer deste projeto, eu conhecia o PyPy, até mesmo o back-end JavaScript para PyPy. Sim, você pode, se encontrar, gerar diretamente um interpretador Python em JavaScript a partir do PyPy. As pessoas dizem que foi um desastre. Eu não li por quê. Mas acho que a razão é que a linguagem intermediária que eles usam para implementar o interpretador, RPython, é um subconjunto do Python adaptado para ser traduzido para C (e talvez asm). Ira Baxter diz que você sempre faz suposições ao construir algo e provavelmente faz o ajuste fino para ser o melhor no que se refere ao PyPy: tradução Python-> C. Essas suposições podem não ser relevantes em outro contexto, e pior, elas podem inferir sobrecarga, caso contrário, a tradução direta provavelmente sempre será melhor.

Ter o interpretador escrito em Python parecia uma (muito) boa ideia. Mas eu estava mais interessado em um compilador por motivos de desempenho, também é realmente mais fácil compilar Python para JavaScript do que interpretá-lo.

Comecei o PythonJS com a ideia de reunir um subconjunto do Python que pudesse facilmente traduzir para JavaScript. No início, nem me preocupei em implementar o sistema OO por causa da experiência anterior. O subconjunto de Python que consegui traduzir para JavaScript é:

  • função com parâmetros semânticos completos, tanto na definição quanto na chamada. Esta é a parte de que mais me orgulho.
  • while / if / elif / else
  • Os tipos Python foram convertidos em tipos JavaScript (não há nenhum tipo de Python)
  • pois poderia iterar em matrizes Javascript apenas (para uma matriz in)
  • Acesso transparente ao JavaScript: se você escrever Array no código Python, ele será traduzido para Array em javascript. Esta é a maior conquista em termos de usabilidade sobre seus concorrentes.
  • Você pode passar a função definida no código-fonte Python para funções javascript. Argumentos padrão serão levados em consideração.
  • Ele adiciona tem uma função especial chamada new que é traduzida para JavaScript new, por exemplo: new (Python) (1, 2, spam, "ovo") é traduzido como "novo Python (1, 2, spam," ovo ").
  • "var" são tratados automaticamente pelo tradutor. (muito bom achado de Brett (contribuidor PythonJS).
  • palavra-chave global
  • fechamentos
  • lambdas
  • listar compreensões
  • as importações são suportadas por meio de requirejs
  • herança de classe única + mixin via classyjs

Isso parece muito, mas na verdade é muito restrito em comparação com a semântica desenvolvida do Python. É realmente JavaScript com sintaxe Python.

O JS gerado é perfeito, ou seja. não há sobrecarga, não pode ser melhorado em termos de desempenho editando-o posteriormente. Se você pode melhorar o código gerado, também pode fazê-lo a partir do arquivo-fonte Python. Além disso, o compilador não contou com nenhum truque JS que você possa encontrar em .js escritos por http://superherojs.com/ , então é muito legível.

O descendente direto desta parte do PythonJS é o modo Pythonium Veloce. A implementação completa pode ser encontrada em @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + cerca de 100 SLOC de código compartilhado com o outro tradutor.

Uma versão adaptada de pystones.py pode ser traduzida no modo Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Depois de configurar a tradução básica do Python-> JavaScript, escolhi outro caminho para traduzir o Python completo para o JavaScript. A maneira de glib fazer código baseado em classe orientada a objetos, exceto a linguagem alvo é JS, para que você tenha acesso a arrays, objetos semelhantes a mapas e muitos outros truques e toda essa parte foi escrita em Python. IIRC não há código javascript escrito por no tradutor Pythonium. Obter herança única não é difícil, aqui estão as partes difíceis de tornar o Pythonium totalmente compatível com o Python:

  • spam.eggem Python é sempre traduzido para getattribute(spam, "egg")Não fiz o perfil disso em particular, mas acho que perdi muito tempo e não tenho certeza se posso melhorar com asm.js ou qualquer outra coisa.
  • ordem de resolução do método: mesmo com o algoritmo escrito em Python, traduzi-lo para código compatível com Python Veloce foi um grande esforço.
  • getattributre : o algoritmo de resolução getattribute real é meio complicado e ainda não suporta descritores de dados
  • com base em classe de metaclasse: eu sei onde inserir o código, mas ainda ...
  • por último, mas não menos importante: some_callable (...) é sempre traduzido para "call (some_callable)". O tradutor AFAIK não usa inferência de forma alguma, então cada vez que você faz uma chamada, você precisa verificar que tipo de objeto deve chamá-lo da maneira que deve ser chamado.

Esta parte é fatorada em https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Está escrito em Python compatível com Python Veloce.

O tradutor compatível real https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master não gera código JavaScript diretamente e, o mais importante, não faz a transformação ast-> ast . Eu tentei fazer ast-> ast e ast mesmo se melhor que cst não é bom trabalhar mesmo com ast.NodeTransformer e mais importante, eu não preciso fazer ast-> ast.

Fazer python ast para python ast no meu caso, pelo menos, talvez seja uma melhoria de desempenho, já que às vezes eu inspeciono o conteúdo de um bloco antes de gerar o código associado a ele, por exemplo:

  • var / global: para poder var algo, devo saber o que preciso e não var. Em vez de gerar um bloco de rastreamento de quais variáveis ​​são criadas em um determinado bloco e inseri-lo no topo do bloco de funções gerado, eu apenas procuro por atribuição de variável relevante quando entro no bloco antes de realmente visitar o nó filho para gerar o código associado.
  • rendimento, os geradores têm, até o momento, uma sintaxe especial em JS, então preciso saber qual função Python é um gerador quando quero escrever a "var my_generator = function"

Portanto, não visito cada nó uma vez para cada fase da tradução.

O processo geral pode ser descrito como:

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

Python builtins são escritos em código Python (!), IIRC há algumas restrições relacionadas aos tipos de bootstraping, mas você tem acesso a tudo que pode traduzir Pythonium em modo compatível. Dê uma olhada em https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

A leitura do código JS gerado em compatível com pythonium pode ser entendida, mas os mapas de origem ajudarão muito.

O conselho valioso que posso lhe dar à luz desta experiência são peidos velhos e gentis:

  • revisar extensivamente o assunto tanto na literatura quanto em projetos existentes de código-fonte fechado ou gratuito. Quando revisei os diferentes projetos existentes, deveria ter dedicado muito mais tempo e motivação.
  • pergunte! Se eu soubesse de antemão que o back-end PyPy era inútil por causa da sobrecarga devido à incompatibilidade semântica C / Javascript. Eu talvez tivesse tido a ideia do Pythonium antes de 6 meses atrás, talvez 3 anos atrás.
  • saiba o que quer fazer, tenha um alvo. Para este projeto eu tinha diferentes objetivos: praticar um pouco um javascript, aprender mais sobre Python e ser capaz de escrever código Python que rodaria no navegador (mais e mais abaixo).
  • fracasso é experiência
  • um pequeno passo é um passo
  • Comece pequeno
  • sonhe grande
  • fazer demos
  • iterar

Com o modo Python Veloce apenas, estou muito feliz! Mas ao longo do caminho descobri que o que eu realmente estava procurando era liberar a mim e aos outros do Javascript, mas mais importante, ser capaz de criar de uma maneira confortável. Isso me levou a Scheme, DSL, Models e, eventualmente, modelos específicos de domínio (cf. http://dsmforum.org/ ).

Sobre a resposta de Ira Baxter:

As estimativas não ajudam em nada. Eu tirei mais ou menos 6 meses de tempo livre para PythonJS e Pythonium. Portanto, posso esperar mais de 6 meses em tempo integral. Acho que todos nós sabemos o que 100 homens-ano em um contexto empresarial pode significar e não significar de forma alguma ...

Quando alguém diz que algo é difícil ou mais frequentemente impossível, eu respondo que "só leva tempo para encontrar uma solução para um problema que é impossível", caso contrário, nada é impossível, exceto se for provado impossível neste caso uma prova matemática ...

Se não for impossível, então há espaço para a imaginação:

  • encontrar uma prova provando que é impossível

e

  • Se for impossível, pode haver um problema "inferior" que pode ter uma solução.

ou

  • se não for impossível, encontrar uma solução

Não é apenas um pensamento otimista. Quando comecei o Python-> Javascript, todo mundo dizia que era impossível. PyPy impossível. Metaclasses muito difíceis. etc ... Eu acho que a única revolução que traz o PyPy sobre o papel Scheme-> C (que tem 25 anos) é alguma geração JIT automática (dicas baseadas escritas no interpretador RPython, eu acho).

A maioria das pessoas que dizem que uma coisa é "difícil" ou "impossível" não fornece as razões. C ++ é difícil de analisar? Eu sei disso, eles ainda são analisadores de C ++ (gratuitos). O mal está nos detalhes? Eu sei disso. Dizer que é impossível sozinho não ajuda. É ainda pior do que "não ajuda", é desanimador e algumas pessoas pretendem desencorajar outras. Eu ouvi sobre essa questão via /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

O que seria perfeição para você ? É assim que você define a próxima meta e talvez alcance a meta geral.

Estou mais interessado em saber que tipos de padrões eu poderia aplicar no código para torná-lo mais fácil de traduzir (ou seja: IoC, SOA?) Do código do que como fazer a tradução.

Não vejo padrões que não possam ser traduzidos de um idioma para outro, pelo menos de uma forma menos que perfeita. Como a tradução de idioma para idioma é possível, é melhor você tentar isso primeiro. Já que, eu acho que de acordo com http://en.wikipedia.org/wiki/Graph_isomorphism_problem , a tradução entre duas linguagens de computador é uma árvore ou isomorfismo DAG. Mesmo que já saibamos que os dois estão se tornando completos, então ...

Framework-> Framework que eu visualizo melhor como API-> tradução de API ainda pode ser algo que você deve manter em mente como uma forma de melhorar o código gerado. Ex: Prolog como uma sintaxe muito específica, mas ainda assim você pode fazer Prolog como computação, descrevendo o mesmo gráfico em Python ... Se eu fosse implementar um tradutor de Prolog para Python, não implementaria a unificação em Python, mas em uma biblioteca C e viria com uma "sintaxe Python" muito legível para um pythonista. No final, a sintaxe é apenas "pintura" para a qual damos um significado (é por isso que comecei o esquema). O mal está nos detalhes da linguagem e não estou falando sobre a sintaxe. Os conceitos que são usados ​​na linguagem getattributegancho (você pode viver sem ele), mas os recursos de VM necessários, como otimização de recursão de cauda, ​​podem ser difíceis de lidar. Você não se importa se o programa inicial não usa recursão de cauda e mesmo se não houver recursão de cauda no idioma de destino, você pode emulá-lo usando greenlets / loop de evento.

Para idiomas de destino e de origem, procure por:

  • Ideias grandes e específicas
  • Ideias pequenas e comuns compartilhadas

Disto surgirá:

  • Coisas que são fáceis de traduzir
  • Coisas que são difíceis de traduzir

Você provavelmente também saberá o que será traduzido em código rápido e lento.

Também existe a questão do stdlib ou de qualquer biblioteca, mas não há uma resposta clara, depende de seus objetivos.

Código idiomático ou código gerado legível também tem soluções ...

Almejar uma plataforma como o PHP é muito mais fácil do que almejar navegadores, pois você pode fornecer implementação C de caminho lento e / ou crítico.

Considerando que seu primeiro projeto é traduzir Python para PHP, pelo menos para o subconjunto PHP3 que conheço, personalizar veloce.py é sua melhor aposta. Se você pode implementar veloce.py para PHP, então provavelmente você será capaz de executar o modo compatível ... Além disso, se você pode traduzir PHP para o subconjunto de PHP que você pode gerar com php_veloce.py, significa que você pode traduzir PHP para o subconjunto de Python que veloce.py pode consumir, o que significa que você pode traduzir PHP para Javascript. Apenas dizendo...

Você também pode dar uma olhada nessas bibliotecas:

Você também pode estar interessado nesta postagem do blog (e comentários): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/

Amirouche
fonte
A única coisa que continua emocionante para mim sobre a tradução de linguagem de computador individual para linguagem de computador está descrita em stackoverflow.com/questions/22621164/…
amirouche
Eu apoio a outra resposta sobre os tipos de dados. No Pythonium, eu nem mesmo planejava oferecer suporte a um tipo inteiro e float correto no modo compatível sem asm.js.
amirouche,
OK, então se eu der a você um pacote Python de 100K SLOC e você executá-lo através do seu "tradutor", eu obtenho um programa funcionando? Quanto trabalho manual pós-tradução é necessário para corrigi-lo? O que você disse aqui foi, "dado um bom analisador já existente para Python que constrói ASTs, posso construir um tradutor parcial em 6 meses". Ninguém fica surpreso. 6 meses não é "meio fácil" pelos padrões da maioria das pessoas (citando outro de seus comentários). Resolver os problemas restantes exigirá mais esforço. Minha resposta disse basicamente "fazer isso não é fácil" e "fazer de uma maneira geral é difícil".
Ira Baxter,
... esse último ponto em resposta ao desejo original de OP: "idealmente, eu seria capaz de adicionar outras línguas com (relativa) facilidade.", ao qual minha resposta aborda especificamente.
Ira Baxter,
Eu imploro para discordar, especialmente quando você sabe o que está fazendo, é fácil e o que se segue não é difícil, é apenas uma questão de fazer as coisas. Não tenho certeza de onde você está lidando com algo específico da questão. Você está dizendo em 4 ou 5 parágrafos que sua empresa faz isso, e é difícil. Mas, caso contrário, você está espalhando FUD sobre o assunto, ao mesmo tempo em que está fora do assunto como se estivesse em stackoverflow.com/questions/22621164/… . Em tempo integral 6 meses eu teria escrito um tradutor completo.
amirouche de
0

Você poderia dar uma olhada no compilador Vala , que traduz Vala (uma linguagem semelhante a C #) em C.

ptomato
fonte
Era um objetivo de design do Vala ser traduzido para C e tornar o desenvolvimento com bibliotecas gnome fácil.
amirouche,