Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala宏打印代码?_Scala_Scala 2.10_Scala Macros_Scala 2.11_Scala Macro Paradise - Fatal编程技术网

Scala宏打印代码?

Scala宏打印代码?,scala,scala-2.10,scala-macros,scala-2.11,scala-macro-paradise,Scala,Scala 2.10,Scala Macros,Scala 2.11,Scala Macro Paradise,我想这样做: def assuming[A](condition: => Boolean)(f: => A): A = { require(condition, /* print source-code of condition */) f } 示例用法: def fib(n: Int) = n match { // yes, yes, I know this is not efficient case 0 => 0 case 1 => 1 cas

我想这样做:

def assuming[A](condition: => Boolean)(f: => A): A = {
  require(condition, /* print source-code of condition */)
  f
}
示例用法:

def fib(n: Int) = n match { // yes, yes, I know this is not efficient
  case 0 => 0 
  case 1 => 1
  case i => assuming(i > 0) { fib(i-1) + fib(i-2) }
}

现在,例如,如果您调用
fib(-20)
,我希望它抛出一个异常,并显示一条消息,如
断言失败:-20>0
断言失败:I>0

您是否查阅了以下文档:

scala>show(q“-1<0”)
res6:String=-1.$less(0)
scala>showCode(q“-1<0”)

res7:String=-1.Dude,assert宏不是学习如何使用宏的基本用例之一吗

我也是这么想的

在我的另一个回答中,我所说的“收集片段”是指specs2的功能

或者,您可以执行任意表示,如所示

我想我应该把你的例子输入REPL,用几行。毕竟,您只是试图打印源代码中的代码段,该代码段对应于表示条件的树

还有什么更容易的

当然,在
-Yrangepos
下更容易,但我们可以假设位置

我愿意分享在我失去兴趣之前我已经走了多远

人们(例如,paulp,他是vox paulpuli)希望树有代表“我在键盘上键入的源”的附件,因为,你知道,也许我希望它用于一条消息,或者用于了解用户试图完成的任务

谓词
p
似乎没有范围位置。因此,另一个想法是我们知道宏应用程序的开始,即第二个参数列表的参数,因此通过源反向工作,匹配第一个参数列表的结束参数,是可行的

请注意,
showCode
没有帮助,因为对于像
10<5
这样的条件语句,它会显示
false
,并整齐地折叠起来

object X {
  import reflect.macros.blackbox.Context
  def impl[A: c.WeakTypeTag](c: Context)(p: c.Expr[Boolean])(body: c.Expr[A]) = {
    import c.universe._
    def treeLine(t: Tree): String = lineAt(t.pos)
    def lineAt(pos: Position): String = if (pos.isRange) pos.lineContent.drop(pos.column - 1).take(pos.end - pos.start + 1) else "???"
    val msg =
      if (p.tree.pos.isRange) {  // oh, joy
        treeLine(p.tree)
      } else {
        /*
        Console println s"content ${p.tree.pos.lineContent}"
        Console println s"column ${p.tree.pos.column}"  // alas, that's the column of the point of the top of the tree, e.g., < in "a < b".
        val len = body.tree.pos.start - p.tree.pos.start
        p.tree.pos.lineContent drop (p.tree.pos.column - 1) take len
        */
        // OK, I get it: positions are a big mystery. Make woo-woo ghost noises.
        // What we do know is the start of the apply, which must have a close paren or brace in front of it to match:
        // apply(condition)(body)
        showCode(p.tree)
      }
    q"require($p, $msg) ; $body"
  }
  def x[A](p: Boolean)(body: =>A): A = macro X.impl[A]
}

这接近用法
x(10<5)(println(“hi”))
要求失败:(10<5)(p
。错误余量。

如果您使用的是Scala 2.11.x,最好的方法是该方法。此方法将正确打印任意Scala树。例如:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

showCode(q"3.14 < 42")
res1: String = 3.14.<(42)

方法
showCode
的设计考虑到了正确性,因此它不一定能打印出漂亮的代码。如果美丽对你来说很重要,你可以为Scala做贡献,也可以自己编写打印机。Scala树的另一个有趣的打印机是Scala重构的
PrettyPrinter

Scala macros codes是如此不可读/不可调试…等不及了:
object X {
  import reflect.macros.blackbox.Context
  def impl(c: Context)(p: c.Expr[Boolean]) = {
    import c.universe._
    def lineAt(pos: Position): String = if (pos.isRange) pos.lineContent.drop(pos.column - 1).take(pos.end - pos.start + 1) else "???" 
    val msg = lineAt(c.macroApplication.pos)  // oh, joy
    q"require($p, $msg) ; new { def apply[A](body: =>A): A = body }"
  }
  def x(p: Boolean): { def apply[A](body: =>A): A } = macro X.impl
}
scala> import reflect.runtime.universe._
import reflect.runtime.universe._

showCode(q"3.14 < 42")
res1: String = 3.14.<(42)
scala> show(q"3.14 < 42")
res2: String = 3.14.$less(42)