2011-01-05 4 views
2

J'ai vu ce nice blog post about a Scala continuations qui 'émule' une instruction GOTO dans le langage Scala. (En savoir plus sur Continuations here)Comment l'instruction GOTO dans Groovy?

Je voudrais avoir la même chose dans le langage de programmation Groovy. Je pense que c'est possible dans un Groovy compiler phase transformation.

Je travaille sur un langage spécifique au domaine (DSL), et je préfère incorporé dans Groovy. Je voudrais avoir l'instruction GOTO, car le langage DSL est un langage non structuré (et est généré à partir des diagrammes de workflow). J'ai besoin d'une instruction goto 'étiquetée', pas de numéros de ligne. Le langage DSL est un langage pour les définitions de workflow, et comme il n'y a pas de restrictions pour les flèches entre les nœuds, un goto est nécessaire. (ou code illisible avec while etc)

En tant que débutant de Groovy et Scala je ne sais pas Si je peux traduire la solution Scala à Groovy, mais je ne pense pas qu'il y ait des suites dans Groovy.

Je cherche un algorithme/code pour émuler des goto étiquetés dans Groovy. Un algorithme que j'avais à l'esprit utilise eval à plusieurs reprises; faire le eval lorsque vous êtes à un goto. Le DSL est déjà évalué avec un eval.

Je ne suis pas à la recherche d'un « tout » en boucle ou quelque chose, mais la traduction de ce code afin qu'il fonctionne (une autre syntaxe est pas un problème)

label1: 
a(); 
b(); 
goto label1; 

PS: je ne préférais pas la discussion si je devrais vraiment utiliser/vouloir l'instruction GOTO. Le DSL est un langage de spécification et ne fait probablement pas face aux variables, à l'efficacité, etc.

PS2: Un autre mot-clé puis GOTO peut être utilisé.

+0

Juste un sidenote, goto marqué peut être simulé plus facilement que par des suites ... –

+0

@Gabriel: Alors pouvez-vous me donner des colles? – Julian

+0

Non, je n'ai pas de colle:) ... je ne sais pas quelles contraintes votre DSL a vraiment et je ne connais pas beaucoup Groovy, mais une façon de gérer goto pourrait être d'avoir un tableau/une liste/une carte de fermeture constantes et une méthode exécutant index/clé en cours, qui peut être modifiée avec goto. –

Répondre

1

Vous n'obtiendrez nulle part en essayant cela, car goto est un reserved word in Groovy (comme c'est en Java), donc l'utiliser dans votre DSL sera problématique.

Ce n'est pas reserved word in Scala, donc ce n'est pas un problème

+0

Alors, nous utilisons le mot clé 'gooto'? Il s'agit du comportement, pas du mot clé réel. – Julian

1

Vous pouvez émuler if et goto avec while boucles. Ce ne sera pas joli, cela introduira beaucoup de blocs de code inutiles, mais cela devrait fonctionner pour n'importe quelle fonction. Il y a des preuves qu'il est toujours possible de réécrire du code comme ça, mais bien sûr, cela ne veut pas dire que c'est bien ou facile.

Fondamentalement, vous déplacez toutes les variables locales au début de la fonction et ajoutez une variable locale bool takeJump. Ajoutez ensuite une paire while(takeJump){ + } pour toute paire d'étiquettes goto + et définissez le drapeau avant et après la fin de la valeur souhaitée.

Mais pour être honnête, je ne recommande pas cette approche. Je préfère utiliser une bibliothèque qui me permet de construire un AST avec des étiquettes et des gotos, puis de le traduire directement en byte-code.

Ou utiliser un autre langage construit sur le Java vm qui prend en charge goto. Je suis sûr qu'il y a une telle langue.

+0

Je sais et par conséquent dans le post de départ j'ai dit: "Je ne cherche pas un 'while' boucle ou quelque chose";) – Julian

+0

Ça devient un peu plus facile avec si et tandis que, mais ce n'est pas joli et cela pourrait nécessiter 3/2 augmentation de la longueur du code dans le pire des cas. –

5

Vous voudrez peut-être en dire un peu plus sur la langue que vous essayez de construire, peut-être est-ce assez simple que de traiter des transformations serait une sur-ingénierie.
Jouer avec l'AST est quelque chose que les gens groovy ont fait pendant des années et c'est vraiment puissant.
Les gars du framework spock réécrivent les tests que vous créez en annotant le code avec des étiquettes. Hamlet D'Arcy a donné plusieurs présentations à ce sujet. Plusieurs posts peuvent également être trouvés sur son blog. http://hamletdarcy.blogspot.com/
Cédric Champeau décrit une transformation intéressante qu'il a construit et son évolution http://www.jroller.com/melix/

beaucoup d'autres manque probablement gars, mais ceux que je me souviens.
Un point de départ possible que vous connaissez probablement déjà mais qui est vraiment utile. http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations
http://groovy.codehaus.org/Building+AST+Guide

Longue histoire courte, je dirais que son tout à fait possible

+0

Je pense que les transformations AST sont une bonne direction. Je mets à jour le post de départ avec plus d'informations sur le DSL. – Julian

+0

Pouvez-vous donner des colliers pour écrire la transformation AST? – Julian

+0

@Julian désolé, j'ai perdu la trace de cela. Je peux vous donner un indice sur les transformations, mais maintenant que je relis votre message, je crois que le langage que vous voulez construire nécessitera beaucoup de réflexion. En gros, si vous voulez une langue complètement libre de structure, vous aurez besoin de plus d'une astuce pour l'écrire dans un langage structuré. boucles injectées seront assez restrictives en ce qui concerne l'imbrication, vous devrez peut-être redessiner l'ensemble du séquençage, comme quelqu'un l'a suggéré. en tout cas, si vous voulez jouer avec ast, ceci est un exemple extrêmement simpliste http://groovyconsole.appspot.com/script/418002 – jpertino

1

Il suffit de jeter ce là-bas, vous pourriez peut-être un cas de commutation scope

Donc, si dit DSL ceci:

def foo() { 
    def x = x() 
    def y 
    def z 
    label a: 
    y = y(x) 
    if(y < someConst) goto a 
    label b: 
    z = y(z) 
    if(z > someConst) goto c 
    x = y(y(z+x)) 
    z = y(x) 
    label c: 
    return z; 
} 

Votre "compilateur" peut transformer en ceci:

def foo() { 
    String currentLABEL = "NO_LABEL" 
    while(SCOPED_INTO_BLOCK_0143) { 
     def x 
     def y 
     def z 
     def retval 
     switch(currentLABEL) { 
     case "NO_LABEL": 
      x = x() 
     case "LABEL_A" 
      y = y(x) 

      if(y < someConst) { 
      currentLABEL = "LABEL_A" 
      break 
      } 
     case "LABEL_B" 
      z = y(z) 

      if(z > someConst) { 
      currentLabel = "LABEL_C" 
      break 
      } 
      x = y(y(z+x)) 
      z = y(x) 
     case "LABEL_C" 
      SCOPED_INTO_BLOCK_0143 = false 
      retval = z 
     } 
    } 
    return retval 
}