Передача параметра типа в мета-макрос / аннотации scala
package scalaworld.macros
import scala.meta._
class Argument(arg: Int) extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
println(this.structure)
val arg = this match {
// The argument needs to be a literal like `1` or a string like `"foobar"`.
// You can't pass in a variable name.
case q"new $_(${Lit(arg: Int)})" => arg
// Example if you have more than one argument.
case q"new $_(${Lit(arg: Int)}, ${Lit(foo: String)})" => arg
case _ => ??? // default value
}
println(s"Arg is $arg")
defn.asInstanceOf[Stat]
}
}
Я хотел бы изменить макрос выше и добавить параметр типа [A]. Я попробовал следующее, но он не компилируется
package scalaworld.macros
import scala.meta._
class Argument2[A](arg: A) extends scala.annotation.StaticAnnotation {
inline def apply(defn: Any): Any = meta {
println(this.structure)
val arg = this match {
case q"new $_(${Lit(arg: A)})" => arg
case q"new $_(${Lit(arg: A)}, ${Lit(foo: String)})" => arg
case _ => ???
}
println(s"Arg is $arg")
defn.asInstanceOf[Stat]
}
}
1 ответ
Аргументы, передаваемые в макроаннотации, передаются в виде мета-деревьев.
Хотя литералы, такие как Int/Double/String, могут быть извлечены через Lit()
экстрактор. это не относится к другим вещам.
Когда анализируется в мета
@someMacro(1)
становится@someMacro(Lit(1))
@someMacro("Foo")
становится@someMacro(Lit("Foo"))
Все остальное проходит как обычно
@someMacro(foo)
становится@someMacro(Term.Name("foo"))
@someMacro(Option(2))
становится@someMacro(Term.Apply(Term.Name("Option"), Seq(Lit(2))))
Это означает, что у вас нет доступа к этой вещи во время выполнения. Вы даже не можете создать экземпляр объекта должным образом без Semantic Api для разрешения символов и т. Д. Это может быть возможно в scalameta 2 и в рае 4, но сейчас это определенно невозможно. Что вы можете сделать, так это сопоставить шаблон времени выполнения, чтобы проверить значение.
Я делаю некоторые подобные вещи здесь (обратите внимание, что это очень WIP): https://github.com/DavidDudson/Elysium/blob/master/gen/src/main/scala/nz/daved/elysium/gen/MacroAnnotation.scala
В частности, см. https://github.com/DavidDudson/Elysium/blob/master/gen/src/main/scala/nz/daved/elysium/gen/MacroAnnotation.scala
Примечание. Это означает, что во время выполнения (которое в данном примере является временем компиляции), если аргумент arg передан неверного типа, исключение времени выполнения