如何在 Scala 编译器插件中添加新类? [英] How to add a new Class in a Scala Compiler Plugin?

查看:26
本文介绍了如何在 Scala 编译器插件中添加新类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Scala 编译器插件中,我试图创建一个实现预先存在的特征的新类.到目前为止,我的代码如下所示:

In a Scala Compiler Plugin, I'm trying to create a new class that implement a pre-existing trait. So far my code looks like this:

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 的覆盖 def 变换(树:树):树"方法只能返回 one Tree,对于它接收到的每一棵树,所以它实际上不能产生一个新的 Tree,而只能修改一个.

But it doesn't seem to get added to the package. I suspect that is because actually the package got "traversed" before the trait that causes the generation, and/or because the "override def transform(tree: Tree): Tree" method of the TypingTransformer can only return one Tree, for every Tree that it receives, so it cannot actually produce a new Tree, but only modify one.

那么,如何将新类添加到现有包中?如果我在transform(Tree)"得到它时转换包,也许它会起作用,但我当时还不知道包的内容,所以我不能这么早生成新类(或者我可以吗?).或者它可能与 Symbol 的Position"参数有关?

So, how do you add a new Class to an existing package? Maybe it would work if I transformed the package when "transform(Tree)" gets it, but I that point I don't know the content of the package yet, so I cannot generate the new Class this early (or could I?). Or maybe it's related to the "Position" parameter of the Symbol?

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

So far I found several examples where Trees are modified, but none where a completely new Class is created in a Compiler Plugin.

推荐答案

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

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

The trick is to store the newly created ClassDefs and use them when creating a new PackageDef. Note that you need to deal with both Symbols and trees: a package symbol is just a handle. In order to generate code, you need to generate an AST (just like for a class, where the symbol holds the class name and type, but the code is in the ClassDef trees).

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

As you noted, package definitions are higher up the tree than classes, so you'd need to recurse first (assuming you'll generate the new class from an existing class). Then, once the subtrees are traversed, you can prepare a new PackageDef (every compilation unit has a package definition, which by default is the empty package) with the new classes.

在示例中,假设源代码为

In the example, assuming the source code is

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
  }
}

这篇关于如何在 Scala 编译器插件中添加新类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆