Skip to content

Instantly share code, notes, and snippets.

@pedrofurla
Created January 11, 2014 20:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pedrofurla/8376407 to your computer and use it in GitHub Desktop.
Save pedrofurla/8376407 to your computer and use it in GitHub Desktop.
Example of how to get source locations using scala macros
package slickdemo
import scala.reflect.macros.Context
import scala.language.experimental.macros
object Macros {
// scala.reflect.runtime.currentMirror
// universe.reify
/** Given a Tree, extracts the source code in its range. Assumes -Yrangepos scalac argument. */
def extractRange(t:Context#Tree):Option[String] = {
val pos = t.pos
val source = pos.source.content
if(pos.isRange) Option(new String(source.drop(pos.start).take(pos.end-pos.start))) else None
}
/** Gives the source code of an expression and the result of the expr in a tuple */
def sourceExpr[A](a: A): (String, A) = macro sourceExprImpl[A]
// previously based on log and logImpl
// from https://github.com/retronym/macrocosm/blob/master/src/main/scala/com/github/retronym/macrocosm/Macrocosm.scala
def sourceExprImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[(String, A)] = {
import c.universe._
val portion = extractRange(a.tree) getOrElse ""
val t2 = Select(Select(Ident(newTermName("scala")), newTermName("Tuple2")), newTermName("apply"))
// following advice from https://github.com/kevinwright/macroflection/blob/master/kernel/src/main/scala/net/thecoda/macroflection/Validation.scala
//clone to avoid "Synthetic tree contains nonsynthetic tree" error under -Yrangepos
val adup: Tree = a.tree.duplicate
val tree = treeBuild.mkMethodCall(t2, List(Literal(Constant(portion)), adup))
val expr = c.Expr[(String, A)](tree)
expr
}
def debugExpr[A](a: A): A = macro debugExprImpl[A]
def debugExprImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = {
import c.universe._
val portion = extractRange(a.tree) getOrElse ""
val adup: Tree = a.tree.duplicate
val expr = c.Expr[A](adup)
/*
val t = Block(
ValDef(Modifiers(), newTermName("x"), TypeTree(), adup),
Apply(Select(Ident(newTermName("scala.Predef")), newTermName("println")), List(Ident(newTermName("x")))),
Ident(newTermName("x")))*/
val const=c.Expr[String](Literal(Constant(portion)))
reify {
println(const.splice)
expr.splice
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment