我正在尝试获取与所有包级对象相对应的ExprAny列表。我可以找到包符号本身(通过追赶任何顶级对象的符号所有者),然后遍历declaredFields。我可以以这种方式找到顶级对象ValDef节点,但是在ValDef中没有关联的术语。我也不能在包树上使用Term.select来获取声明的成员,因为我无法获得包符号的树。
似乎应该可以从这些顶级单例对象的符号中得到与这些顶级单例对象相关联的术语(而不仅仅是ValDef),但我无法理解。
基本上我想做这样的事情:
inline def packageToucher[T](something : T) : List[Any] = {
${ packageToucherImpl('something) }
}
def packageToucherImpl[T](something : Expr[T])(using Quotes, Type[T]): Expr[List[Any]] = {
import quotes.reflect.*
// assume something is a top level object
val _package = TypeRepr.of[T].typeSymbol.owner
val fields = _package.declaredFields
val packageExpr = _package.tree.asExpr // assertion failed: Cannot get tree of package symbol
val packageTree = packageExpr.asTerm
val fieldExprs : List[Expr[Any]] = fields.map( f => packageTree.select(f).asExpr)
Expr.ofList(fieldExprs)
}使用的一个例子是:
// in actions.scala
package potato
object Actions // dummy object for finding package
object yelling extends Action("yell")
object sleeping extends Action("sleep")
object typing extends Action("type")主要是:
import potato.*
val actions = Macros.packageToucher(Actions) // should be List(Actions, yelling, sleeping, typing)任何帮助都将不胜感激。对于scala 3宏,我是个菜鸟。
谢谢!
发布于 2022-08-25 10:27:36
嗯,经过大量的努力,尝试,和错误:我已经找到了解决办法。也许这对其他人是有用的。
inline def packageToucher[T](something : T) : List[Any] = {
${ packageToucherImpl('something) }
}
@experimental // needed for access to Symbol.termRef
def packageToucherImpl[T](something : Expr[T])(using Quotes, Type[T]): Expr[List[Any]] = {
import quotes.reflect.*
// assume something is a top level object
val _package = TypeRepr.of[T].typeSymbol.owner
val fields = _package.fieldMembers
// for some reason, scala generates erased companion objects for Classes that don't have them.
// Luckily they can be filtered out by checking for the synthetic flag
val valdefs = fields.filter(f => f.isValDef && !f.flags.is(Flags.Synthetic))
// here's where the magic happens, we can't access the package's companion object tree directly
// but we can construct one using AST nodes
val packageTerm = Ident(_package.companionModule.termRef)
val exprs = valdefs.map(Select(packageTerm, _).asExpr)
Expr.ofList(exprs)
}https://stackoverflow.com/questions/69715707
复制相似问题