Skip to content

Instantly share code, notes, and snippets.

@qingwei91
Created September 4, 2017 14:12
Show Gist options
  • Select an option

  • Save qingwei91/81727024e8a840350c66d2d95843c81b to your computer and use it in GitHub Desktop.

Select an option

Save qingwei91/81727024e8a840350c66d2d95843c81b to your computer and use it in GitHub Desktop.
// @param backend - parameter for `cache` annotation
class cache[K, V](backend: SyncCache[K, V]) extends scala.annotation.StaticAnnotation {
// @param defn - the annotated method (it can also be other scala building block like class, but we are restricting here
// using some checks below
inline def apply(defn: Any): Any = meta {
defn match {
// this annotation should only be annotate on `method`, represented as `Defn.Def` in scalameta's AST
case defn: Defn.Def =>
// this represent the instatiated annotation, ie. `@cache(xxx)`
this match {
// Quasiquote in action, it's a way to pattern match scala AST
// - `new` match instantiation
// - `$_` match the name of the annotation
// - `[..$tpr]` match type params and bind to `tpr`
// - `($backendParam)` match SINGLE argument used in instatiation and bind to `backendParam`
// Note: To match multiple arguments or multiple arguments list (curried), you need different syntax
case q"new $_[..$tpr]($backendParam)" =>
// we use the element we captured to generate code we want, we will look into details next
val body: Term = CacheMacroImpl.expand(tpr, backendParam, defn)
// we only want to replace the method body, so this will do
defn.copy(body = body)
case x =>
abort(s"Unrecognized pattern $x")
}
case _ =>
abort("This annotation only works on `def`") // abort if annotated to anything other than methods
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment