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

如何在Scala编译器插件中添加新类?,scala,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:

在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
}
但它似乎没有被添加到包中。我怀疑这是因为实际上包在导致生成的特征之前被“遍历”,和/或因为TypingTransformer的“override def transform(tree:tree):tree”方法只能为它接收的每一棵树返回一棵树,因此它实际上不能生成一棵新树,而只能修改一棵树

那么,如何将新类添加到现有包中?如果我在“transform(Tree)”得到包时对包进行了转换,可能会起作用,但我还不知道包的内容,所以我不能这么早生成新类(或者我可以?)。或者可能与符号的“位置”参数有关


到目前为止,我发现了几个修改树的示例,但没有一个在编译器插件中创建全新类的示例。

完整的源代码如下:

诀窍是存储新创建的
ClassDef
s,并在创建新的
PackageDef
时使用它们。注意,您需要同时处理符号和树:包符号只是一个句柄。为了生成代码,您需要生成一个AST(与类类似,其中符号包含类名和类型,但代码位于
ClassDef
树中)

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

在本例中,假设源代码是

class Foo {
  def foo {
    "spring"
  }
}
编译器将其包装到

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
}
包{
福班{
德福{
“春天”
}
}
}
插件将其转换为

package <empty> {
  class Foo {
    def foo {
      "spring"
    }
  }
  package mypackage {
    class MyClass extends AnyRef
  }
}
包{
福班{
德福{
“春天”
}
}
包我的包{
类MyClass扩展了AnyRef
}
}

您解决问题了吗?我有一个类似的,所以我想知道。。。不幸的是,我认为您需要在转换方法中匹配您的特征的父项。也就是说,注意PackageDef和Template,并在它们身上找到所有你的特征。然后您可以返回一个转换后的PackageDef和TemplateYes,我从Scala邮件列表获得了帮助。但是我还没有到那里,因为我只能在同一个包中创建类。当我把事情整理好后,我会试着给自己的问题贴一个答案。请现在回答你的问题!因为我的@iron9light和我说的一样,我有工作代码来创建一个实现trait的类(好吧,had,我尝试了很多东西,当前状态可能会起作用,但它在某个时候起作用了)。不幸的是,我只能在我试图实现的trait包中创建它们。在这里和邮件列表中都毫无结果地寻求帮助后,我决定在基本上没有文档、编译器代码基本上没有注释、大师也没有时间帮助您的情况下尝试创建编译器插件是没有希望的。基本上,你要么读编译器代码,要么放弃。我讨厌“放弃”。我刚刚发现,它从AST读取信息,然后生成源代码。这种“愚蠢”的方式很好用。无论如何,新年快乐!非常感谢。我还没试过,但既然你是“大师”之一,你一定做对了。我只想补充一点,这与你无关,我已经几个月没有使用Scala了,我可以理解一些人抱怨Scala社区对这些基本问题不友好/没有帮助/排斥(在Java编译器插件中,这是一个不需要思考的问题)只有几个月后有人悬赏才能得到答复“。我在Scala语言邮件列表上询问,甚至没有得到有用的帮助。。。请不要把它当成个人的事情;我感谢你的回答!我理解你的观点,但请不要基于这个问题来判断Scala社区。大多数Scala问题都能得到高质量、快速的答案,但这一个肯定不是“无脑的”。它需要从事编译器工作的人知道答案(Scala团队中的大多数人不经常阅读SOV),而这是scalac从来没有读过的,因此不可能找到一个示例。尽管解决方案很短,但我还是花了大约一个小时才让一切正常运行。再次感谢!简而言之,当有人有一个“Java问题”时,他们可以在这里或其他十几个地方提问,并且肯定会找到答案(如果有),但是当Scala问题既没有在这里也没有在Scala邮件列表上得到回答时,就这样了,你只能靠自己了,这真的很令人沮丧。我真希望有人能写一本“铁杆Scala”的书;“Scala深入”还没有完成,如果它大约有200页长,它只会触及所有“硬东西”的表面。但是硬的东西比Java要难得多,而且没有足够的潜在买家。