在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中创建一个全新的类.
完整的源代码在这里: 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)
| 归档时间: |
|
| 查看次数: |
982 次 |
| 最近记录: |