diff options
author | Jon Pretty <jon.pretty@propensive.com> | 2017-06-11 16:56:44 +0200 |
---|---|---|
committer | Jon Pretty <jon.pretty@propensive.com> | 2017-06-11 16:56:44 +0200 |
commit | 9ff2305bcdd742529bd184ba90ecdef32ca2fe4d (patch) | |
tree | 26e6df52df42eb3ac4206c198ee97c2ea0c11053 | |
parent | f22b602f0180500e45db76ec20f6bfd3f2450842 (diff) | |
download | magnolia-9ff2305bcdd742529bd184ba90ecdef32ca2fe4d.tar.gz magnolia-9ff2305bcdd742529bd184ba90ecdef32ca2fe4d.tar.bz2 magnolia-9ff2305bcdd742529bd184ba90ecdef32ca2fe4d.zip |
Generalized for typeclass-based extension
-rw-r--r-- | core/src/main/scala/magnolia.scala | 40 | ||||
-rw-r--r-- | examples/src/main/scala/example.scala | 6 |
2 files changed, 15 insertions, 31 deletions
diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala index 7b05bbf..9aafb44 100644 --- a/core/src/main/scala/magnolia.scala +++ b/core/src/main/scala/magnolia.scala @@ -6,17 +6,11 @@ import scala.util.Try import language.existentials import language.higherKinds -abstract class Transformation[C <: whitebox.Context](val c: C) { - def typeclassBody(genericType: c.Type, implementation: c.Tree): c.Tree - def coproductReduction(left: c.Tree, right: c.Tree): c.Tree -} - -abstract class MagnoliaMacro(val c: whitebox.Context) { +@bundle +class Macros(val c: whitebox.Context) { import c.universe._ import CompileTimeState._ - protected def transformation(c: whitebox.Context): Transformation[c.type] - private def findType(key: c.universe.Type): Option[c.TermName] = recursionStack(c.enclosingPosition).frames.find(_.genericType == key).map(_.termName(c)) @@ -108,11 +102,9 @@ abstract class MagnoliaMacro(val c: whitebox.Context) { c.abort(c.enclosingPosition, s"failed to get implicit for type $genericType") } - val dereferencedValue = q"$dereferencerImplicit.dereference(src, ${param.name.toString})" + val dereferencedValue = q"$dereferencerImplicit.dereference(sourceParameter, ${param.name.toString})" - val result = q"$dereferencerImplicit.delegate($derivedImplicit, $dereferencedValue)" - println(result+"\n\n") - result + q"$dereferencerImplicit.delegate($derivedImplicit, $dereferencedValue)" } Some(q"new $genericType(..$implicits)") @@ -127,17 +119,15 @@ abstract class MagnoliaMacro(val c: whitebox.Context) { }.getOrElse { c.abort(c.enclosingPosition, s"failed to get implicit for type $searchType") } - }.reduce(transformation(c).coproductReduction) + }.reduce { (left, right) => q"$dereferencerImplicit.combine($left, $right)" } - q"$dereferencerImplicit.delegate($reduction, src)" + q"$dereferencerImplicit.delegate($reduction, sourceParameter)" } } else None construct.map { const => - val bodyImplementation = transformation(c).typeclassBody(genericType, const) - q"""{ - def $assignedName: $resultType = new $resultType { $bodyImplementation } + def $assignedName: $resultType = $dereferencerImplicit.construct { sourceParameter => $const } $assignedName }""" } @@ -220,22 +210,10 @@ private[magnolia] object CompileTimeState { Map() } - -@bundle -class Macros(val context: whitebox.Context) extends MagnoliaMacro(context) { - protected def transformation(c: whitebox.Context): Transformation[c.type] = - new Transformation[c.type](c) { - import c.universe._ - - def typeclassBody(genericType: c.Type, implementation: c.Tree): c.Tree = - q"""def extract(src: _root_.magnolia.Thing): $genericType = $implementation""" - - def coproductReduction(left: c.Tree, right: c.Tree): c.Tree = q"$left.orElse($right)" - } -} - trait Dereferencer[Typeclass[_]] { type Value def dereference(value: Value, param: String): Value def delegate[T](typeclass: Typeclass[T], value: Value): T + def combine[Supertype, Right <: Supertype](left: Typeclass[_ <: Supertype], right: Typeclass[Right]): Typeclass[Supertype] + def construct[T](body: Value => T): Typeclass[T] } diff --git a/examples/src/main/scala/example.scala b/examples/src/main/scala/example.scala index 6a6a1cc..e61f8bd 100644 --- a/examples/src/main/scala/example.scala +++ b/examples/src/main/scala/example.scala @@ -34,6 +34,12 @@ object Extractor extends Extractor_1 { type Value = Thing def dereference(value: Thing, param: String): Thing = value.access(param) def delegate[T](extractor: Extractor[T], value: Thing): T = extractor.extract(value) + def combine[Supertype, Right <: Supertype](left: Extractor[_ <: Supertype], + right: Extractor[Right]): Extractor[Supertype] = left.orElse(right) + + def construct[T](body: Thing => T): Extractor[T] = new Extractor[T] { + def extract(source: Thing): T = body(source) + } } } |