From 17cfdb350fa38454a76ed5370ac6f36c3a532d3e Mon Sep 17 00:00:00 2001 From: Jon Pretty Date: Thu, 25 May 2017 11:26:28 -0600 Subject: Progress with mutual recursion --- core/src/main/scala/generic.scala | 101 +++++++++++++++----------------------- 1 file changed, 39 insertions(+), 62 deletions(-) (limited to 'core/src/main') diff --git a/core/src/main/scala/generic.scala b/core/src/main/scala/generic.scala index 63f3d8f..c045cbc 100644 --- a/core/src/main/scala/generic.scala +++ b/core/src/main/scala/generic.scala @@ -3,74 +3,58 @@ package magnolia import scala.reflect._, macros._ import macrocompat.bundle -object GlobalState { - var globalState: Map[AnyRef, AnyRef] = Map() +import scala.collection.immutable.ListMap + +object GlobalMutableState { + private[magnolia] var state: ListMap[AnyRef, AnyRef] = ListMap() + private[magnolia] def push(key: AnyRef, value: AnyRef): Unit = state += ((key, value)) + private[magnolia] def pop(): Unit = state = state.init + + private[magnolia] def has(c: whitebox.Context)(key: AnyRef): Option[c.universe.TermName] = + state.get(key).asInstanceOf[Option[c.universe.TermName]] } @bundle class Macros(val c: whitebox.Context) { + def dereference(path: c.Tree, elem: String): c.Tree = path + def getImplicit(genericType: c.universe.Type, - typeConstructor: c.universe.Type/*, - scope: Map[c.universe.Type, c.universe.TermName]*/): c.Tree = { + typeConstructor: c.universe.Type, + myName: c.universe.TermName): c.Tree = { import c.universe._ - val scope = GlobalState.globalState.asInstanceOf[Map[Type, TermName]] - - scope.get(genericType) match { - case Some(ref) => - q"$ref" - case None => - - val searchType = appliedType(typeConstructor, genericType) - println(s"${scope.keySet} vs $genericType") - println(s"inferring on $genericType") - try c.inferImplicitValue(searchType, false, false) catch { - case e: Exception => - go(genericType, typeConstructor/*, scope*/) - } - } - - scope.get(genericType).map { nm => - println("substituting "+nm) - q"$nm" - }.orElse { + GlobalMutableState.push(genericType, myName) + + val result = GlobalMutableState.has(c)(genericType).map { nm => q"$nm" }.orElse { val searchType = appliedType(typeConstructor, genericType) - println(s"${scope.keySet} vs $genericType") - if(!scope.keySet.contains(genericType)) { - println(s"inferring on $genericType") - Option({ - val x = try c.inferImplicitValue(searchType, false, false) catch { - case e: Exception => null + if(GlobalMutableState.has(c)(genericType).isEmpty) { + val inferredImplicit = + try Some(c.inferImplicitValue(searchType, false, false)) catch { + case e: Exception => None } - println("Managed to infer "+x) - x - }).orElse { - println("Failed, so recursing") - go(genericType, typeConstructor/*, scope*/) + + inferredImplicit.orElse { + directInferImplicit(genericType, typeConstructor) } } else { - println("recursing") - go(genericType, typeConstructor/*, scope*/) + directInferImplicit(genericType, typeConstructor) } }.getOrElse { c.abort(c.enclosingPosition, "Could not find extractor for type "+genericType) } + + GlobalMutableState.pop() + + result } - def go(genericType: c.universe.Type, - typeConstructor: c.universe.Type/*, - scope: Map[c.universe.Type, c.universe.TermName]*/): Option[c.Tree] = { + def directInferImplicit(genericType: c.universe.Type, + typeConstructor: c.universe.Type): Option[c.Tree] = { import c.universe._ - println(s"go($genericType, ${GlobalState.globalState})") - - val myName = TermName(c.freshName("extractor$")) - println(s"before: ${GlobalState.globalState}") - GlobalState.globalState = GlobalState.globalState + (genericType -> myName) - println(s"after: ${GlobalState.globalState}") val typeSymbol = genericType.typeSymbol val classType = if(typeSymbol.isClass) Some(typeSymbol.asClass) else None val isCaseClass = classType.map(_.isCaseClass).getOrElse(false) @@ -84,20 +68,17 @@ class Macros(val c: whitebox.Context) { case m: MethodSymbol if m.isCaseAccessor => m.asMethod }.map { p => val ret = p.returnType - val imp = getImplicit(ret, typeConstructor/*, newScope*/) + val imp = getImplicit(ret, typeConstructor, myName) q"$imp.extract(src)" } Some(q"new $genericType(..$implicits)") } else if(isSealedTrait) { - //println(s"$resultType a sealed trait") val subtypes = classType.get.knownDirectSubclasses.to[List] - val tries = subtypes.map(_.asType.toType).map(t => getImplicit(t, typeConstructor/*, newScope*/)).foldLeft(q"null": c.Tree) { (a, b) => + Some(subtypes.map(_.asType.toType).map(t => getImplicit(t, typeConstructor, myName)).foldLeft(q"null": c.Tree) { (a, b) => q"(try { $b.extract(src) } catch { case e: _root_.java.lang.Exception => $a })" - } - - Some(q"$tries.asInstanceOf[$genericType]") + }) } else None @@ -110,28 +91,24 @@ class Macros(val c: whitebox.Context) { }""" } - //println(s"Generated result for $genericType: $result") + //GlobalMutableState.pop() + + println(result) result } - def generic[T: c.WeakTypeTag, Tc: c.WeakTypeTag]: c.Tree = try { + + def generic[T: c.WeakTypeTag, Tc: c.WeakTypeTag]: c.Tree = { import c.universe._ val genericType: Type = weakTypeOf[T] val typeConstructor: Type = weakTypeOf[Tc].typeConstructor - val result = go(genericType, typeConstructor) - - println(result) + val result = directInferImplicit(genericType, typeConstructor) result.getOrElse { c.abort(c.enclosingPosition, "Could not infer extractor. Sorry.") } - } catch { - case e: Exception => - println("Macro failed!!! "+e) - //e.printStackTrace() - ??? } } -- cgit v1.2.3