summaryrefslogtreecommitdiff
path: root/core/src/main/scala/forge/Discovered.scala
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-11-03 23:44:39 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2017-11-03 23:44:39 -0700
commit13270145903b457c906a9fa77bd152afb6448ef5 (patch)
treee85b7ed530e0c8e3c3041cbf17641857c448b602 /core/src/main/scala/forge/Discovered.scala
parent66f1c5c2438aeb8f2496575f52c25b09cf5793a6 (diff)
downloadmill-13270145903b457c906a9fa77bd152afb6448ef5.tar.gz
mill-13270145903b457c906a9fa77bd152afb6448ef5.tar.bz2
mill-13270145903b457c906a9fa77bd152afb6448ef5.zip
Split up forge into `scalaplugin` an `core` subprojects, to allow us to use the `T#apply` macro in the implementation of `scalaplugin.Subproject`
Also needed to implement inter-`Subproject` dependencies so the `MetacircularTests` can continue to support the new layout
Diffstat (limited to 'core/src/main/scala/forge/Discovered.scala')
-rw-r--r--core/src/main/scala/forge/Discovered.scala57
1 files changed, 57 insertions, 0 deletions
diff --git a/core/src/main/scala/forge/Discovered.scala b/core/src/main/scala/forge/Discovered.scala
new file mode 100644
index 00000000..03577b1f
--- /dev/null
+++ b/core/src/main/scala/forge/Discovered.scala
@@ -0,0 +1,57 @@
+package forge
+
+import forge.util.Labelled
+import play.api.libs.json.Format
+
+import language.experimental.macros
+import reflect.macros.blackbox.Context
+
+class Discovered[T](val value: Seq[(Seq[String], Format[_], T => Target[_])]){
+ def apply(t: T) = value.map{case (a, f, b) => (a, f, b(t)) }
+
+}
+object Discovered {
+ def makeTuple[T, V](path: Seq[String], func: T => Target[V])(implicit f: Format[V]) = {
+ (path, f, func)
+ }
+
+
+ def mapping[T: Discovered](t: T): Map[Target[_], Labelled[_]] = {
+ implicitly[Discovered[T]].apply(t)
+ .map(x => x._3 -> Labelled(x._3.asInstanceOf[Target[Any]], x._2.asInstanceOf[Format[Any]], x._1))
+ .toMap
+ }
+
+ implicit def apply[T]: Discovered[T] = macro applyImpl[T]
+
+ def applyImpl[T: c.WeakTypeTag](c: Context): c.Expr[Discovered[T]] = {
+ import c.universe._
+ val tpe = c.weakTypeTag[T].tpe
+ def rec(segments: List[String], t: c.Type): Seq[Seq[String]] = for {
+ m <- t.members.toSeq
+ if m.isTerm && (m.asTerm.isGetter || m.asTerm.isLazy) || m.isModule
+ res <- {
+ val extendedSegments = m.name.toString :: segments
+ val self =
+ if (m.typeSignature.resultType <:< c.weakTypeOf[Target[_]]) Seq(extendedSegments)
+ else Nil
+ val children = rec(extendedSegments, m.typeSignature)
+ self ++ children
+ }
+ } yield res
+
+ val reversedPaths = rec(Nil, tpe)
+
+ val result = for(reversedPath <- reversedPaths.toList) yield {
+ val base = q"${TermName(c.freshName())}"
+ val segments = reversedPath.reverse.toList
+ val ident = segments.foldLeft[Tree](base)((prefix, name) =>
+ q"$prefix.${TermName(name)}"
+ )
+
+ q"forge.Discovered.makeTuple($segments, ($base: $tpe) => $ident)"
+ }
+
+ c.Expr[Discovered[T]](q"new _root_.forge.Discovered($result)")
+ }
+}