From ca02aef2c98079c695fa616c75ab05a693c9d512 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Sun, 5 Nov 2017 22:00:31 -0800 Subject: Recursive main-method resolution now works, as part of the normal discovery recursion ```scala @ import forge.util.JsonFormatters._ import forge.util.JsonFormatters._ @ forge.discover.Discovered[forge.scalaplugin.MetacircularTests.type] @ forge.discover.Discovered[forge.scalaplugin.MetacircularTests.type].mains res2: Seq[...] = List( NestedEntry(List("ScalaPlugin"), ..., EntryPoint("run", ...)), NestedEntry(List("Core"), ..., EntryPoint("run", ...) ) @ forge.discover.Discovered[forge.scalaplugin.MetacircularTests.Core.type].mains res3: Seq[...] = List( NestedEntry(List(), ..., EntryPoint("run", ...)) ) ``` --- .../src/main/scala/forge/discover/Discovered.scala | 69 +++++++++++++++++----- core/src/main/scala/forge/discover/Labelled.scala | 8 --- core/src/main/scala/forge/discover/Router.scala | 4 -- 3 files changed, 53 insertions(+), 28 deletions(-) delete mode 100644 core/src/main/scala/forge/discover/Labelled.scala (limited to 'core/src') diff --git a/core/src/main/scala/forge/discover/Discovered.scala b/core/src/main/scala/forge/discover/Discovered.scala index 715e9ba9..fcf5ccbd 100644 --- a/core/src/main/scala/forge/discover/Discovered.scala +++ b/core/src/main/scala/forge/discover/Discovered.scala @@ -1,19 +1,31 @@ package forge.discover import forge.define.Target +import forge.discover.Router.EntryPoint import play.api.libs.json.Format import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context -class Discovered[T](val value: Seq[(Seq[String], Format[_], T => Target[_])], - val mains: Seq[Router.EntryPoint[T]]){ - def apply(t: T) = value.map{case (a, f, b) => (a, f, b(t)) } +class Discovered[T](val targets: Seq[(Seq[String], Format[_], T => Target[_])], + val mains: Seq[NestedEntry[T, _]]){ + def apply(t: T) = targets.map{case (a, f, b) => (a, f, b(t)) } +} + +case class Labelled[T](target: Target[T], + format: Format[T], + segments: Seq[String]) + + +case class NestedEntry[T, V](path: Seq[String], resolve: T => V, entryPoint: EntryPoint[V]) +object NestedEntry{ + def make[T, V](path: Seq[String], resolve: T => V) + (entryPoint: EntryPoint[V]) = NestedEntry(path, resolve, entryPoint) } object Discovered { def consistencyCheck[T](base: T, d: Discovered[T]) = { val inconsistent = for{ - (path, formatter, targetGen) <- d.value + (path, formatter, targetGen) <- d.targets if targetGen(base) ne targetGen(base) } yield path inconsistent @@ -34,24 +46,38 @@ object Discovered { 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 + def rec(segments: List[String], t: c.Type): (Seq[(Seq[String], Tree)], Seq[Seq[String]]) = { + val r = new Router(c) + val selfMains = + for(tree <- r.getAllRoutesForClass(t.asInstanceOf[r.c.Type]).asInstanceOf[Seq[c.Tree]]) + yield (segments, tree) + + val items = for { + m <- t.members.toSeq + if (m.isTerm && (m.asTerm.isGetter || m.asTerm.isLazy)) || - m.isModule || - (m.isMethod && m.typeSignature.paramLists.isEmpty && m.typeSignature.resultType <:< c.weakTypeOf[Target[_]]) - if !m.fullName.contains('$') - res <- { + m.isModule || + (m.isMethod && m.typeSignature.paramLists.isEmpty && m.typeSignature.resultType <:< c.weakTypeOf[Target[_]]) + if !m.fullName.contains('$') + } yield { 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 + val (mains, children) = rec(extendedSegments, m.typeSignature) + + + (mains, self ++ children) } - } yield res - val reversedPaths = rec(Nil, tpe) + val (mains, targets) = items.unzip + Tuple2( + selfMains ++ mains.flatten, + targets.flatten + ) + } + + val (entryPoints, reversedPaths) = rec(Nil, tpe) val result = for(reversedPath <- reversedPaths.toList) yield { val base = q"${TermName(c.freshName())}" @@ -63,10 +89,21 @@ object Discovered { q"forge.discover.Discovered.makeTuple($segments, ($base: $tpe) => $ident)" } + val nested = for{ + (reversedSegments, entry) <- entryPoints + } yield { + val segments = reversedSegments.reverse + val arg = TermName(c.freshName()) + val select = segments.foldLeft[Tree](Ident(arg)) { (prefix, name) => + q"$prefix.${TermName(name)}" + } + q"forge.discover.NestedEntry.make(Seq(..$segments), ($arg: $tpe) => $select)($entry)" + } + c.Expr[Discovered[T]](q""" new _root_.forge.discover.Discovered( $result, - forge.discover.Router.generateRoutes[$tpe] + _root_.scala.Seq(..$nested) ) """) } diff --git a/core/src/main/scala/forge/discover/Labelled.scala b/core/src/main/scala/forge/discover/Labelled.scala deleted file mode 100644 index 25c74e9f..00000000 --- a/core/src/main/scala/forge/discover/Labelled.scala +++ /dev/null @@ -1,8 +0,0 @@ -package forge.discover - -import forge.define.Target -import play.api.libs.json.Format - -case class Labelled[T](target: Target[T], - format: Format[T], - segments: Seq[String]) diff --git a/core/src/main/scala/forge/discover/Router.scala b/core/src/main/scala/forge/discover/Router.scala index a07cf678..3d054e29 100644 --- a/core/src/main/scala/forge/discover/Router.scala +++ b/core/src/main/scala/forge/discover/Router.scala @@ -382,14 +382,10 @@ class Router [C <: Context](val c: C) { } def getAllRoutesForClass(curCls: Type): Iterable[c.universe.Tree] = { - pprint.log(curCls) for{ t <- getValsOrMeths(curCls) - _ = pprint.log(t) - _ = pprint.log(t.annotations) if t.annotations.exists(_.tpe =:= typeOf[Router.main]) } yield { - println("Extract!") extractMethod(t, curCls) } } -- cgit v1.2.3