Created
September 4, 2017 14:12
-
-
Save qingwei91/ca02e5450df1348084e835ccc559ad22 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| object CacheMacroImpl { | |
| /** | |
| * | |
| * @param fnTypeParams - Type params of annotation instance, remember our cache macro is generic `class cache[K, V]`, | |
| this will capture Seq(K, V) | |
| * @param cacheExpr - Argument pass to `cache` macro, should be type of `CacheBackEnd[K, V]` | |
| * @param annotatedDef - Methods that is annotated | |
| */ | |
| def expand(fnTypeParams: Seq[Type], cacheExpr: Term.Arg, annotatedDef: Defn.Def): Term = { | |
| val cache = Term.Name(cacheExpr.syntax) // convert Term.Arg to Term.Name | |
| annotatedDef match { | |
| // Another Quasiquote pattern match | |
| // - `..$_` match any modifier | |
| // - `def` match only method | |
| // - `$methodName` bind method name to $methodName | |
| // - `[..$tps]` match some type params of method and bind to $tps | |
| // - `(..$nonCurriedParams)` match non-curried argument list and binf to $nonCurriedParams | |
| // - `$rtType` bind return type to $rtType | |
| // - `$expr` bind method's body to $expr | |
| case q"..$_ def $methodName[..$tps](..$nonCurriedParams): $rtType = $expr" => | |
| // here is the trick to handle different arg size | |
| if (nonCurriedParams.size == 1) { | |
| // if only 1 arg, use the arg as key of cache | |
| val paramAsArg = Term.Name(nonCurriedParams.head.name.value) | |
| q""" | |
| // here we are generating code that call the CacheBackend | |
| val result: ${rtType} = $cache.get($paramAsArg) match { | |
| case Some(v) => v | |
| case None => | |
| val value = ${expr} | |
| $cache.put($paramAsArg, value) | |
| value | |
| } | |
| result | |
| """ | |
| } else { | |
| val paramAsArg = nonCurriedParams.map(p => Term.Name(p.name.value)) | |
| q""" | |
| // if there are multiple arg, convert them in tuple, as use the tuple as key | |
| val result: ${rtType} = $cache.get((..$paramAsArg)) match { | |
| case Some(v) => v | |
| case None => | |
| val value = ${expr} | |
| $cache.put((..$paramAsArg), value) | |
| value | |
| } | |
| result | |
| """ | |
| } | |
| case other => abort(s"Expected non-curried method, got $other") | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment