Skip to content

Instantly share code, notes, and snippets.

@everpeace
Last active December 14, 2015 02:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save everpeace/5018148 to your computer and use it in GitHub Desktop.
Save everpeace/5018148 to your computer and use it in GitHub Desktop.
ユーザから渡されたブロックにimplicit valを注入するマクロを組んでみたけどうまくいかない。
import reflect.macros.Context
object Macros{
// on(i){ ... }とやるとblockの中にiをimplicitとして注入するマクロ
def on[I, V](i:I)(block:V)= macro impl_on[I,V]
def impl_on[I, V](c:Context)(i:c.Expr[I])(block:c.Expr[V]):c.Expr[V] = {
import c.universe._
// type of block is
// only one sentence => Tree
// _ => Block(stats,expr)
val stats:List[Tree] = block.tree match{
case Block(s,_) => s
case _:Tree => List()
}
val expr:Tree = block.tree match{
case Block(_,e) => e
case _:Tree => block.tree
}
// extract AST of implicit declaration only.
val Block(i_stats,_) = (reify({implicit val _i = i.splice})).tree
c.Expr[V](Block(i_stats:::stats,expr))
}
}
// Test does NOT compile. see blow.
object Test extends App{
import Macros._
def m(a:Int)(implicit b:Int) = a+b
val i = 3
// println(m(5))の前にiがimplicit valとして注入される感じを想定
on(i){
println(m(5))
}
}
// Test2 does compile and macro is successfuly expanded. see blow.
object Test extends App{
import Macros._
def m(a:Int)(implicit b:Int) = a+b
val i = 3
// mを呼ばないようにするとcompileできる
on(i){
println(5)
}
}
$ scalac -version
Scala compiler version 2.10.0 -- Copyright 2002-2012, LAMP/EPFL
$ scalac -language:experimental.macros Macros.scala
$ scalac -Ymacro-debug-lite Test2.scala
// macroによってiがimplicitとして挿入されたコードが生成されているっぽい。
performing macro expansion Macros.on[Int, Unit](Test2.this.i)(scala.this.Predef.println(5)) at source-/Users/omura/Documents/github/everpeace/on-macro/Test2.scala,line-5,offset=100
{
implicit val _i = Test2.this.i;
scala.this.Predef.println(5)
}
Block(List(ValDef(Modifiers(IMPLICIT), newTermName("_i"), TypeTree(), Select(This(newTypeName("Test2")), newTermName("i")))), Apply(Select(Select(This(newTypeName("scala")), scala.Predef), newTermName("println")), List(Literal(Constant(5)))))
$ scalac -version
Scala compiler version 2.10.0 -- Copyright 2002-2012, LAMP/EPFL
$ scalac -language:experimental.macros Macros.scala
// macroの展開より前にこのエラーが出てる?
$ scalac -Ymacro-debug-lite Test.scala
Test.scala:6: error: could not find implicit value for parameter b: Int
println(m(5))
^
one error found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment