おい、アサート マクロは、マクロの使い方を学ぶために実装する基本的なユース ケースの 1 つではありませんか?
そうですね、私もそう思いました。
私の他の回答の「スニペットを収集する」とは、 specs2 がs2 マクロで何をするかを意味していました。
または、 expecty の私の変種のぼったくりのように、任意の表現を行うこともできます。
あなたの例をREPLに数行で入力すると思いました。結局のところ、条件を表すツリーに対応するソースからスニペットを印刷しようとしているだけです。
もっと簡単なことは何ですか?
もちろん、 の方が簡単ですが-Yrangepos
、位置を仮定できます。
興味を失う前にどこまで到達したかを共有したいと思います.
人々 (たとえば、vox paulpuli である paulp) は、"キーボードで入力したソース" を表す添付ファイルをツリーに持つことを望んでいます。達成。
述語p
に範囲位置がないようです。したがって、もう 1 つの考えは、2 番目のパラメーター リストの括弧であるマクロ アプリケーションの開始を知っているため、ソースを逆方向に作業して、最初のパラメーター リストの閉じ括弧と一致させることができるということです。
それが示す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]
}
このように範囲の広い位置を取得することが私に起こりました:
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
}
それは使用法に近いですx(10 < 5)(println("hi"))
: requirement failed: (10 < 5)(p
。エラーのマージン。