scala AST Select 节点找不到从父级继承的成员
scala AST Select node can't find members inherited from parent
我正在编写一个名为 assign
的宏,它的工作是将一个实例的成员的值分配给另一个实例的成员,并在成员的名称中添加一个特定的前缀。例如,我有一个成员名为 my_prefix_data, my_prefix_rden, ...
的实例,我想从另一个实例中的相应成员名为 data, rden, ...
的实例中为这些成员赋值。我制作了一个只处理 my_prefix_data <- data
赋值的宏的原型版本。分配将使用特殊方法 :=
进行,因为此宏最终将应用于 Chisel 代码。
不幸的是,它不起作用。宏实现如下所示
package my_macros
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Macro {
def assign(foo: Any, prefix: String, bundle: Any): Unit = macro Impl.assign
}
class Impl(val c: blackbox.Context) {
def assign(
foo: c.Tree, // Foo
prefix: c.Tree, // string
bundle: c.Tree // bundle
): c.Tree = {
import c.universe._
val Literal(Constant(p: String)) = prefix
Apply(
Select(
Select(
foo,
TermName(s"${p}_data")
),
TermName(":=")
),
List(
Select(
bundle,
TermName("data")
)
)
)
}
}
我有一个像这样设置的失败测试用例
package my_macros
import org.scalatest._
class MacroSpec extends FlatSpec {
behavior of "Macro"
it should "access parent methods" in {
class Data(initial: Int) {
var value: Int = initial
def :=(other: Data): Unit = {
value += other.value
}
}
class UInt(initial: Int) extends Data(initial) {}
class FooBundle {
val my_prefix_data = new UInt(1)
}
class BarBundle {
val data = new UInt(2)
}
val foo = new FooBundle
val bar = new BarBundle
Macro.assign(foo, "my_prefix", bar)
assert(foo.my_prefix_data.value == bar.data.value)
}
}
它因错误而失败
[error] value := is not a member of UInt
[error] Expression does not convert to assignment because receiver is not assignable.
[error] Macro.assign(foo, "my_prefix", bar)
[error] ^
为什么 Select
AST 节点无法从 UInt
的父节点 class Data
中找到继承的 :=
?
继承无关紧要。对于
class UInt(initial: Int) {
var value: Int = initial
def :=(other: UInt): Unit = {
value += other.value
}
}
行为相同。
将TermName(":=")
替换为TermName("$colon$eq")
或TermName(":=").encodedName
或替换手动构建的树
val Literal(Constant(p: String)) = prefix
Apply(
Select(
Select(
foo,
TermName(s"${p}_data")
),
TermName(":=")
),
List(
Select(
bundle,
TermName("data")
)
)
)
带准引用
val q"${p: String}" = prefix
val pdata = TermName(s"${p}_data")
q"$foo.$pdata.:=($bundle.data)"
然后代码编译。
我正在编写一个名为 assign
的宏,它的工作是将一个实例的成员的值分配给另一个实例的成员,并在成员的名称中添加一个特定的前缀。例如,我有一个成员名为 my_prefix_data, my_prefix_rden, ...
的实例,我想从另一个实例中的相应成员名为 data, rden, ...
的实例中为这些成员赋值。我制作了一个只处理 my_prefix_data <- data
赋值的宏的原型版本。分配将使用特殊方法 :=
进行,因为此宏最终将应用于 Chisel 代码。
不幸的是,它不起作用。宏实现如下所示
package my_macros
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Macro {
def assign(foo: Any, prefix: String, bundle: Any): Unit = macro Impl.assign
}
class Impl(val c: blackbox.Context) {
def assign(
foo: c.Tree, // Foo
prefix: c.Tree, // string
bundle: c.Tree // bundle
): c.Tree = {
import c.universe._
val Literal(Constant(p: String)) = prefix
Apply(
Select(
Select(
foo,
TermName(s"${p}_data")
),
TermName(":=")
),
List(
Select(
bundle,
TermName("data")
)
)
)
}
}
我有一个像这样设置的失败测试用例
package my_macros
import org.scalatest._
class MacroSpec extends FlatSpec {
behavior of "Macro"
it should "access parent methods" in {
class Data(initial: Int) {
var value: Int = initial
def :=(other: Data): Unit = {
value += other.value
}
}
class UInt(initial: Int) extends Data(initial) {}
class FooBundle {
val my_prefix_data = new UInt(1)
}
class BarBundle {
val data = new UInt(2)
}
val foo = new FooBundle
val bar = new BarBundle
Macro.assign(foo, "my_prefix", bar)
assert(foo.my_prefix_data.value == bar.data.value)
}
}
它因错误而失败
[error] value := is not a member of UInt
[error] Expression does not convert to assignment because receiver is not assignable.
[error] Macro.assign(foo, "my_prefix", bar)
[error] ^
为什么 Select
AST 节点无法从 UInt
的父节点 class Data
中找到继承的 :=
?
继承无关紧要。对于
class UInt(initial: Int) {
var value: Int = initial
def :=(other: UInt): Unit = {
value += other.value
}
}
行为相同。
将TermName(":=")
替换为TermName("$colon$eq")
或TermName(":=").encodedName
或替换手动构建的树
val Literal(Constant(p: String)) = prefix
Apply(
Select(
Select(
foo,
TermName(s"${p}_data")
),
TermName(":=")
),
List(
Select(
bundle,
TermName("data")
)
)
)
带准引用
val q"${p: String}" = prefix
val pdata = TermName(s"${p}_data")
q"$foo.$pdata.:=($bundle.data)"
然后代码编译。