pat*_*rit 6 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
}
Run Code Online (Sandbox Code Playgroud)
样品用法:
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) }
}
Run Code Online (Sandbox Code Playgroud)
现在,例如,如果你调用fib(-20),我希望它抛出一个带有Assertion failed: -20 > 0或的消息的异常Assertation failed: i > 0
您是否咨询了以下文档:
http://www.scala-lang.org/api/2.11.0/scala-reflect/#scala.reflect.api.Printers
scala> show(q"-1 < 0")
res6: String = -1.$less(0)
scala> showCode(q"-1 < 0")
res7: String = (-1).<(0)
Run Code Online (Sandbox Code Playgroud)
或者,人们使用源位置来收集片段进行打印.
Dude,是不是断言宏的一个基本用例,你学习如何使用宏?
嗯,这也是我的想法.
通过我的另一个答案中的"glean snippets",我的意思是specs2 在其s2宏中做了什么.
或者,你可以做一个任意的表示,就像在我的变体rip-off of expecty.
我以为我会把你的例子输入REPL,有几行.毕竟,您只是尝试从与表示条件的树对应的源打印片段.
什么可以更容易?
当然,它更容易-Yrangepos,但我们可以假设立场.
在失去兴趣之前,我愿意分享我的成就.
人们(例如,paulp,谁是vox paulpuli)希望树有附件代表"我在键盘上输入的来源",因为,你知道,也许我想要它用于消息或弄清楚用户尝试的是什么完成.
看起来谓词p没有范围位置.所以另一个想法是我们知道宏应用程序的开始,这是第二个参数列表的paren,因此通过源向后工作,匹配第一个参数列表的结束列表是可行的.
请注意,这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]
}
Run Code Online (Sandbox Code Playgroud)
我突然想到以这种方式获得这种笨拙的立场:
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
}
Run Code Online (Sandbox Code Playgroud)
关闭用法x(10 < 5)(println("hi")):requirement failed: (10 < 5)(p.保证金有误.
| 归档时间: |
|
| 查看次数: |
1188 次 |
| 最近记录: |