Skip to content

Instantly share code, notes, and snippets.

@travisbrown
Created March 11, 2013 19:13
Show Gist options
  • Save travisbrown/5136824 to your computer and use it in GitHub Desktop.
Save travisbrown/5136824 to your computer and use it in GitHub Desktop.
String interpolation with macro-supported access to positions.
sealed trait Piece
case class Place(p: String) extends Piece
case class Name(n: String) extends Piece
case class LocatedPieces(located: Seq[(String, Piece, (Int, Int))])
object S2 extends ReflectionUtils {
import scala.language.experimental.macros
import scala.language.reflectiveCalls
import scala.reflect.macros.Context
implicit class s2pieces(sc: StringContext) {
def s2(pieces: Piece*) = macro s2Impl
}
def s2Impl(c: Context)(pieces: c.Expr[Piece]*): c.Expr[LocatedPieces] = {
import c.universe._
val ac = companionApplier(c.universe)
val parts = c.prefix.tree match {
case Apply(_, List(Apply(_, parts))) => parts zip pieces map {
case (part, piece) =>
val line = c.literal(piece.tree.pos.line).tree
val column = c.literal(piece.tree.pos.column).tree
ac[(_, _, _)](part, piece.tree, ac[(_, _)](line, column))
}
}
c.Expr(ac[LocatedPieces](ac[Seq[_]](parts: _*)))
}
}
trait ReflectionUtils {
import scala.reflect.api.Universe
def companionApplier(u: Universe) = new {
def apply[A: u.TypeTag](xs: u.Tree*): u.Tree = u.Apply(
u.Select(u.Ident(u.typeOf[A].typeSymbol.companionSymbol), "apply"),
xs.toList
)
}
}
@travisbrown
Copy link
Author

And a usage example:

scala> val x = Name("Ben Baxter")
x: Name = Name(Ben Baxter)

scala> val y = Name("Pea Soup Limited")
y: Name = Name(Pea Soup Limited)

scala> val z = Place("Ingleby Barwick, England")
z: Place = Place(Ingleby Barwick, England)

scala> import S2._
import S2._

scala> s2"$x, director of $y, a smoke-machine supplier in $z..."
res0: LocatedPieces = ...

scala> res0.located foreach println
(,Name(Ben Baxter),(13,21))
(, director of ,Name(Pea Soup Limited),(13,37))
(, a smoke-machine supplier in ,Place(Ingleby Barwick, England),(13,69))

@kiritsuku
Copy link

Could you explain why the code snippet with the inlined c.Expr fails to compile? I don't get it.

@travisbrown
Copy link
Author

Actually good point—I'm looking back at it and I don't know why it doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment