36 votes

Comment ajouter une nouvelle classe dans un plugin Scala Compiler?

Dans un Compilateur Scala Plugin, je suis en train de créer une nouvelle classe qui mettent en œuvre une pré-existante de trait. Jusqu'à présent, mon code ressemble à ceci:

def trait2Impl(original: ClassDef, newName: String): ClassDef = {
    val impl = original.impl
    // Seems OK to have same self, but does not make sense to me ...
    val self = impl.self
    // TODO: implement methods ...
    val body = impl.body
    // We implement original
    val parents = original :: impl.parents
    val newImpl = treeCopy.Template(impl, parents, self, body)
    val name = newTypeName(newName)
    // We are a syntheic class, not a user-defined trait
    val mods = (original.mods | SYNTHETIC) &~ TRAIT
    val tp = original.tparams
    val result = treeCopy.ClassDef(original, mods, name, tp, newImpl)
    // Same Package?
    val owner = original.symbol.owner
    // New symbol. What's a Position good for?
    val symbol = new TypeSymbol(owner, NoPosition, name)
    result.setSymbol(symbol)
    symbol.setFlag(SYNTHETIC)
    symbol.setFlag(ABSTRACT)
    symbol.resetFlag(INTERFACE)
    symbol.resetFlag(TRAIT)
    owner.info.decls.enter(symbol)
    result
}

Mais il ne semble pas pour obtenir ajouté au package. Je soupçonne que c'est parce qu'en fait, le package a "traversé" avant le trait de caractère qui provoque la génération, et/ou parce que les "override def de transformation(de l'arbre: Arbre): Arbre de la" méthode de la TypingTransformer ne peut que retourner un Arbre pour chaque Arbre qu'il reçoit, il ne peut donc pas vraiment produire un nouvel Arbre, mais seulement de modifier un.

Alors, comment voulez-vous ajouter une nouvelle Classe d'un package existant? Peut-être que ça marcherait si j'ai transformé le paquet lors de la "transformation(Arbre)" il obtient, mais je-je ne sais pas le contenu de la liasse, de sorte que je ne peut pas générer la nouvelle Classe de ce début (ou pourrais-je?). Ou peut-être que c'est lié à la "Position" paramètre du Symbole?

Jusqu'à présent, j'ai trouvé plusieurs exemples où les Arbres sont modifiés, mais aucun où une Classe entièrement nouvelle est créée dans un Compilateur Plugin.

3voto

Iulian Dragos Points 3298

Le code source complet est ici: https://gist.github.com/1794246

Le truc, c'est de stocker le nouveau ClassDefs et de les utiliser lors de la création d'un nouveau PackageDef. Notez que vous avez besoin de traiter à la fois des Symboles et des arbres: un paquet symbole est juste une poignée. Afin de générer le code, vous devez générer un AST (tout comme pour une classe, où le symbole détient le nom de la classe et le type, mais le code est dans l' ClassDef des arbres).

Comme vous l'avez remarqué, les définitions de paquetages sont plus haut de l'arbre que de classes, de sorte que vous ne devez répéter la première (en supposant que vous allez générer la nouvelle classe à partir d'une classe existante). Ensuite, une fois que les sous-arbres sont parcourus, vous pouvez préparer une nouvelle PackageDef (chaque unité de compilation a une définition de package, qui est par défaut le package vide) avec les nouvelles classes.

Dans l'exemple, en supposant que le code source est

class Foo {
  def foo {
    "spring"
  }
}

le compilateur l'enveloppe dans

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
}

et le plugin transforme en

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
  package mypackage {
    class MyClass extends AnyRef
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X