Last active
August 29, 2015 13:56
-
-
Save landonf/9309063 to your computer and use it in GitHub Desktop.
NX macro example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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