在Scala 2.10中使用带有宏的附件

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,但这不应该在这里相关 - 我对一般情况感兴趣.)

有什么方法可以使用附件来获得我想要的东西吗?还有其他方法更合适吗?

gzm*_*zm0 0

更新我应该在摆弄之后再次阅读这个问题...:(我刚刚复制了你所拥有的内容。


我想你当时就在那里。这对我有用:

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)