在 Scala 2.10 中使用带有宏的附件 [英] Using attachments with macros in Scala 2.10

查看:31
本文介绍了在 Scala 2.10 中使用带有宏的附件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:我怀疑我想要的可能是不可能的,我已经写了一篇博客文章,其中包含我的推理(和一些替代方案)此处.我很高兴被告知我错了.

Update: I suspect that what I want might not be possible, and I've written up a blog post with my reasoning (and some alternatives) here. I'd be very happy to be told that I'm wrong.

假设我想使用带有宏实现的工厂方法创建一个 trait 实例.此方法将把资源的路径作为参数,宏将读取该路径并将其解析(在编译时)到从字符串到字符串的映射中.

Suppose I want to create a instance of a trait using a factory method with a macro implementation. This method will take as an argument a path to a resource that the macro will read and parse (at compile time) into a map from strings to strings.

那部分相当简单.现在假设我想将生成的地图与我正在创建的实例相关联,以便我可以在涉及该实例的后续宏调用中使用它.

That part is all fairly straightforward. Now suppose I want to associate the resulting map with the instance I'm creating so that I can use it in subsequent macro calls involving that instance.

我非常希望地图成为实例的成员,或者在运行时以任何形式存在.我也不想多次解析相同的资源.这是我的目标类型的草图:

I crucially do not want the map to be a member of the instance, or to exist in any form at runtime. I also don't want to parse the same resource more than once. Here's a sketch of the kind of thing I'm aiming for:

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 对于 指针),我有一个基于附件的实现,允许我编写以下内容:

This seems to be the sort of thing that attachments are designed to help with (thanks to Eugene Burmako for the pointer), and I've got an attachment-based implementation that allows me to write the following:

Foo("whatever.txt").lookup("x")

其中 apply_impl 将地图附加到树上,并且 lookup_impl 从同一棵树上读取该附件,它将其视为其前缀.不幸的是,这或多或少是无用的,因为它在 foo.lookup("x") 的情况下不起作用,其中前缀树只是变量 foo.

Where apply_impl attaches the map to the tree and lookup_impl reads that attachment off the same tree, which it sees as its prefix. Unfortunately this is more or less useless, though, since it doesn't work in the foo.lookup("x") case, where the prefix tree is just the variable foo.

(请注意,在我的实际用例中,Foo 扩展了 Dynamic,并且我正在尝试为 selectDynamic 提供一个宏实现,而不是lookup,但这不应该在这里相关 - 我对一般情况感兴趣.)

(Note that in my real use case Foo extends Dynamic, and I'm trying to give a macro implementation for selectDynamic instead of lookup, but that shouldn't be relevant here—I'm interested in the general case.)

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

Is there some way that I can use attachments to get what I want? Is there some other approach that would be more appropriate?

推荐答案

UPDATE 我应该在摆弄之后再次阅读这个问题...... :( 我刚刚复制了你的内容.

UPDATE I should read the question again after fiddling... :( I just reproduced what you have.

我想你就在那里.这对我有用:

You were quite there I think. This works for me:

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)))

  }

}

这篇关于在 Scala 2.10 中使用带有宏的附件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆