如何在Scala编译器插件中添加新类?

Seb*_*iot 36 scala

在Scala编译器插件中,我正在尝试创建一个实现预先存在的特征的新类.到目前为止我的代码看起来像这样:

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
}
Run Code Online (Sandbox Code Playgroud)

但它似乎没有被添加到包中.我怀疑这是因为实际上包在得到生成的特征之前被"遍历"了,和/或因为TypingTransformer的"覆盖def变换(树:树):树"方法只能为每棵树返回一个树它收到的,所以它实际上不能生成一个新树,但只修改一个.

那么,如何将新类添加到现有包中?也许如果我在"transform(Tree)"得到它的时候改变了包,它会工作,但是我指出我还不知道包的内容,所以我不能在这个早期生成新类(或者我可以吗?) .或者它可能与符号的"位置"参数有关?

到目前为止,我发现了几个树被修改的例子,但没有一个在Compiler Plugin中创建一个全新的类.

Iul*_*gos 3

完整的源代码在这里: https: //gist.github.com/1794246

诀窍是存储新创建的ClassDefs 并在创建新的PackageDef. 请注意,您需要处理符号和树:包符号只是一个句柄。为了生成代码,您需要生成 AST(就像类一样,其中符号保存类名和类型,但代码位于树中ClassDef)。

正如您所指出的,包定义在树上比类更高,因此您需要首先递归(假设您将从现有类生成新类)。然后,一旦遍历完子树,您就可以使用新类准备一个新的PackageDef(每个编译单元都有一个包定义,默认情况下是空包)。

在示例中,假设源代码是

class Foo {
  def foo {
    "spring"
  }
}
Run Code Online (Sandbox Code Playgroud)

编译器将其包装成

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

插件将其转换为

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
  package mypackage {
    class MyClass extends AnyRef
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我理解你的观点,但请不要根据这个问题来评判 Scala 社区。大多数 Scala 问题都能得到高质量、快速的答案,但这个问题绝对不是“无需思考”的问题。它需要从事编译器工作的人才能知道答案(Scala 团队中的大多数人并不经常阅读 SOV),而“scalac”从来没有这样做过,因此不可能找到示例。尽管解决方案很短,但我花了大约一个小时才让一切正常运行。 (3认同)