对于 Scala 3 宏,有谁知道如何查找具有给定注释的所有函数吗?
例如:
@fruit
def apple(): Int = ???
@fruit
def banana(): Int = ???
@fruit
def coconut(): Int = ???
@fruit
def durian(): Int = ???
def elephant(): Int = ???
@fruit
def fig(): Int = ???
我想找到
apple, banana, coconut, durian, fig
的列表。它们可以在任何地方定义,但在我的例子中,它们都将在一个包中。
此解决方案将从给定包中提取带有某些注释的所有定义。我还将利用编译时反射。
此解决方案将从给定包中提取带有一些注释的所有定义。我还将利用编译时反射。 因此,为了解决您的问题,我们需要将其分为:
inline def findAllFunction[P, A <: ConstantAnnotation, R]: List[() => R] =
${Implementation.myMacroImpl[P, A, R]()}
第一点很简单。我们可以提取所有定义为的方法:
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
第二点也很简单。
Symbol
类具有可以在这种情况下使用的方法 hasAnnotation
:
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
最后一点有点挑战性。这里我们应该构造方法调用。所以我们需要创建与方法调用相对应的 AST。受这个示例的启发,我们可以使用
Apply
来调用定义。 Select
和 This
用于选择要调用的正确方法:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
这里我使用了lambda调用,如果你想直接返回值你应该改变最后两条指令:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => apply.asExprOf[R])
Expr.ofList(appliedDef)
总而言之,所有方法可以定义为:
def myMacroImpl[P: Type, A: Type, R: Type]()(using
Quotes
): Expr[List[() => R]] = {
import quotes.reflect.*
val annotation = TypeRepr.of[A].typeSymbol
val moduleTarget = TypeRepr.of[P].typeSymbol
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
def transformToFunctionApplication(
methods: List[Symbol]
): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
val methods = methodsFromPackage(moduleTarget)
val annotatedMethod = methodsAnnotatatedWith(methods, annotation)
transformToFunctionApplication(annotatedMethod)
}
最后,您可以将宏用作:
package org.tests
import org.tests.Macros.fruit
package foo {
@fruit
def check(): Int = 10
@fruit
def other(): Int = 11
}
@main def hello: Unit =
println("Hello world!")
println(Macros.findAllFunction[org.tests.foo, fruit, Int].map(_.apply())) /// List(10, 11)
我认为你必须使用 Scala 3 中的 Tasty Inspector。 因此,为了分析代码,您使用 Tasty Inspector,为了调用等,您使用宏。 此代码仅适用于基元和基元集合