Skip to content

Instantly share code, notes, and snippets.

@landonf
Last active August 29, 2015 13:56
Show Gist options
  • Save landonf/9309063 to your computer and use it in GitHub Desktop.
Save landonf/9309063 to your computer and use it in GitHub Desktop.
NX macro example
/**
* Private implementation of the nx macro; rather than triggering compilation errors,
* it simply returns the result of the validation.
*
* Example usage:
*
* {{{
* val unhandledExceptions: Set[Class[_ <: Throwable]] = NX.check {
* java.inet.InetAddress.getByName("some host")
* }
* }}}
*
* Since java.inet.InetAddress.getByName() declares that it throws an UnknownHostException, the result
* of NX.check will be a Set(classOf[UnknownHostException]).
*
* @param c Compiler context.
* @param expr Expression to be scanned.
* @tparam T Expression type.
* @return An expression that will vend the validation results.
*/
def nx_macro_check[T] (c: Context)(expr: c.Expr[T]): c.Expr[Set[Class[_ <: Throwable]]] = {
import c.universe._
/* Instantiate a macro global-based instance of the plugin core */
val core = new NX {
override val universe: c.universe.type = c.universe
}
/* Kick off our traversal */
val traverse = new core.ExceptionTraversal {
/* Hand any errors off to our macro context */
override def error (pos: core.universe.Position, message: String): Unit = c.error(pos, message)
}
traverse.traverse(expr.tree)
/* Convert the set of unhandled exceptions to an AST representing a classOf[Throwable] argument list. */
val seqArgs = traverse.unhandledExceptions.map(name => Literal(Constant(name))).toList
/* Select the scala.Throwable class */
val throwableClass = Select(Ident(definitions.ScalaPackage), newTypeName("Throwable"))
/* Define our Class[_ <: Throwable] type */
val existentialClassType = ExistentialTypeTree(
/* Define a new applied Class[T] type of _$1 */
AppliedTypeTree(Ident(definitions.ClassClass), List(Ident(newTypeName("_$1")))),
/* Define type _$1 = Class[_ <: Throwable] */
List(TypeDef(Modifiers(Flag.DEFERRED /* | SYNTHETIC */), newTypeName("_$1"), List(), TypeBoundsTree(Ident(definitions.NothingClass), throwableClass)))
)
/* Compose the Seq[_ <: Throwable](traverse.unhandledExceptions:_*) return value */
c.Expr(Select(Apply(TypeApply(Ident(definitions.List_apply), List(existentialClassType)), seqArgs), newTermName("toSet")))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment