Tra*_*own 6 scala scala-macros
更新:我怀疑什么,我想也许是不可能的,我已经写了一篇博客文章与我的推理(和一些替代品)在这里.我很高兴被告知我错了.
假设我想使用带有宏实现的工厂方法创建特征实例.此方法将参数作为资源的路径,宏将读取并在编译时将其解析为从字符串到字符串的映射.
那部分都相当简单.现在假设我想将结果映射与我正在创建的实例相关联,以便我可以在涉及该实例的后续宏调用中使用它.
我至关重要的是不希望地图成为实例的成员,或者在运行时以任何形式存在.我也不想多次解析同一个资源.这是我想要的那种东西的草图:
import scala.language.experimental.macros
import scala.reflect.macros.Context
trait Foo {
def lookup(key: String): String = macro Foo.lookup_impl
}
object Foo {
def parseResource(path: String): Map[String, String] = ???
def apply(path: String): Foo = macro apply_impl
def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
import c.universe._
val m = path.tree match {
case Literal(Constant(s: String)) => parseResource(s)
}
val tree = reify(new Foo {}).tree
// Somehow associate the map with this tree here.
c.Expr(tree)
}
def lookup_impl(c: Context)(key: c.Expr[String]): c.Expr[String] =
/* Somehow read off the map and look up this key. */ ???
}
Run Code Online (Sandbox Code Playgroud)
这似乎是有点那个东西附件旨在帮助(感谢尤金Burmako为指针),和我有一个基于连接的实现,让我写了以下内容:
Foo("whatever.txt").lookup("x")
Run Code Online (Sandbox Code Playgroud)
凡apply_impl重视地图树和lookup_impl读取附件关闭同一棵树,它认为它的前缀.不幸的是,这或多或少是无用的,因为它不适foo.lookup("x")用于前缀树只是变量的情况foo.
(请注意,在我的实际用例Foo扩展中Dynamic,我试图给出一个宏实现selectDynamic而不是lookup,但这不应该在这里相关 - 我对一般情况感兴趣.)
有什么方法可以使用附件来获得我想要的东西吗?还有其他方法更合适吗?
更新我应该在摆弄之后再次阅读这个问题...:(我刚刚复制了你所拥有的内容。
我想你当时就在那里。这对我有用:
object Foo {
// Attachment.get somehow needs a wrapper class.
// Probably because of generics
implicit class LookupMap(m: Map[String, String]) {
def get(s: String) = m.get(s)
}
def parseResource(path: String): LookupMap = Map("test" -> "a")
def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
import c.universe._
val m = path.tree match {
case Literal(Constant(s: String)) => parseResource(s)
}
val tree = reify(new Foo {}).tree.updateAttachment(m)
c.Expr(tree)
}
def lookup_impl(c: Context { type PrefixType = Foo })
(key: c.Expr[String]): c.Expr[String] = {
import c.universe._
val m = c.prefix.tree.attachments.get[LookupMap].get
val s = key.tree match {
case Literal(Constant(s: String)) => m.get(s).get
}
c.Expr(Literal(Constant(s)))
}
}
Run Code Online (Sandbox Code Playgroud)