4

我的问题可能是人为的,我想将其视为可行性证明,而不是推荐的东西。为了给你一些背景信息,我会尝试在嵌入式 DSL 中使用与

val myVal = "someContent"

我希望能够做这样的事情:

assign("SomeContent","someVariable") => converted to
someVariable = "SomeContent"

然后在代码的后面,该变量可用。通常我们可以在 REPL 中有类似的东西:

assign("John","name")
println("Hello " + name)

我一直在考虑使用宏(或 ScalaCompiler 插件,但我认为这里更复杂)来解决问题。首先,我不知道这对于宏来说是否可行。

考虑到我只会操纵字符串,我从一些简单的东西开始,我从类似的东西开始

def assign(content: String, targetVal: String):Unit = macro assignMacro

def assignMacro(c:Context)(content: c.Expr[String], 
                           targetVal: c.Expr[String]):c.expr[Unit] = {
  import c.universe._

  c.Expr[Unit](ValDef(Modifiers(), TermName(targetVal.value),
                      TypeTree(), Literal(Constant(content.value)))
}

不幸的是,由于几个错误,它似乎失败了

  • 首先,当我尝试创建一个新的术语名称时它会抱怨,如果我确定那么我应该调用我的表达式的 eval。不幸的是,我不确定;)如果我尝试,它会失败;)
  • 如果我用 myVal 和 myContent 等常量替换此 targetVal 和内容,我会收到第二条错误消息,例如 compiler found and required Unit

我有点卡住了。首先这可能吗?我猜是的;)我怎么能做到这一点?

谢谢您的帮助

此致

4

1 回答 1

3

在 2.10 和 2.11 中,def 宏都扩展为块,这意味着它们引入的定义成为该块的本地定义。这可能会在宏观天堂发生变化,但我不确定何时以及如何。

目前 Scala 中的宏不提供将新变量透明地引入现有范围的方法。这是 Scala 宏演变的历史产物,原因是我们的反射小组优先考虑了黑盒宏(行为类似于常规方法的宏,完全由它们的类型签名描述,因此人类和程序可以将它们的实现视为黑盒而不会丢失什么都出来了)。

最近对白盒宏(不适合黑盒方案的宏)的兴趣产生了一些结果,但这些结果尚未包含在主线 Scala 中。我将在明天的 Strange Loop 演讲中详细说明这个问题:https ://thestrangeloop.com/sessions/evolution-of-scala-macros 。


同时,您可以查看可能提供您正在寻找的自由度的宏注释。例如,通过适当地定义mydsl注释,您可以拥有

@mydsl 
def foo = {
  assign("SomeContent", "someVariable")
  ...
}

转化成

def foo = {
  someVariable = "SomeContent"
  ...
}
于 2013-09-18T04:52:21.957 回答