Использование вложений с макросами в Scala 2.10
Обновление: я подозреваю, что то, что я хочу, могло бы быть невозможным, и я написал сообщение в блоге со своими рассуждениями (и некоторыми альтернативами) здесь. Я был бы очень рад, если бы мне сказали, что я неправ.
Предположим, я хочу создать экземпляр свойства с использованием фабричного метода с реализацией макроса. Этот метод будет принимать в качестве аргумента путь к ресурсу, который макрос будет читать и анализировать (во время компиляции) в карту из строк в строки.
Эта часть довольно проста. Теперь предположим, что я хочу связать полученную карту с экземпляром, который я создаю, чтобы я мог использовать его в последующих вызовах макросов, включающих этот экземпляр.
Я принципиально не хочу, чтобы карта была членом экземпляра или существовала в любой форме во время выполнения. Я также не хочу анализировать один и тот же ресурс более одного раза. Вот эскиз того, к чему я стремлюсь:
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. */ ???
}
Это похоже на то, с чем вложения предназначены для помощи (спасибо Eugene Burmako за указатель), и у меня есть реализация на основе вложений, которая позволяет мне написать следующее:
Foo("whatever.txt").lookup("x")
куда apply_impl
прикрепляет карту к дереву и lookup_impl
читает это вложение из того же дерева, которое оно видит в качестве префикса. К сожалению, это более или менее бесполезно, поскольку в foo.lookup("x")
случай, когда префиксное дерево является просто переменной foo
,
(Обратите внимание, что в моем реальном случае использования Foo
продолжается Dynamic
и я пытаюсь дать реализацию макроса для selectDynamic
вместо lookup
, но это не должно быть актуально здесь - меня интересует общий случай.)
Есть ли способ, которым я могу использовать вложения, чтобы получить то, что я хочу? Есть ли другой подход, который был бы более уместным?
1 ответ
ОБНОВЛЕНИЕ Я должен прочитать вопрос снова после возни...:(Я просто воспроизвел то, что у вас есть.
Вы были довольно там, я думаю. Это работает для меня:
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)))
}
}