summaryrefslogtreecommitdiff
path: root/core/src/main/scala/forge/define/Target.scala
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-11-05 07:08:02 -0800
committerLi Haoyi <haoyi.sg@gmail.com>2017-11-05 07:08:02 -0800
commit9e1ba56eb49fb62d20fc4ede0627194304a854e8 (patch)
treeb5c9acd55034649f0ac480a29d7bdc2dce8dadb9 /core/src/main/scala/forge/define/Target.scala
parent2fb5b569d30ac09cfda7ce6450c54d0fff6f32ae (diff)
downloadmill-9e1ba56eb49fb62d20fc4ede0627194304a854e8.tar.gz
mill-9e1ba56eb49fb62d20fc4ede0627194304a854e8.tar.bz2
mill-9e1ba56eb49fb62d20fc4ede0627194304a854e8.zip
Split out `ApplicativeMacros` from `Target`
Diffstat (limited to 'core/src/main/scala/forge/define/Target.scala')
-rw-r--r--core/src/main/scala/forge/define/Target.scala108
1 files changed, 30 insertions, 78 deletions
diff --git a/core/src/main/scala/forge/define/Target.scala b/core/src/main/scala/forge/define/Target.scala
index 1d8ecdee..591fd68e 100644
--- a/core/src/main/scala/forge/define/Target.scala
+++ b/core/src/main/scala/forge/define/Target.scala
@@ -31,89 +31,16 @@ abstract class Target[T] extends Target.Ops[T]{
def apply(): T = ???
}
-object Target{
- trait Cacher{
- private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, Target[_]]
- protected[this] def cachedTarget[T](t: => Target[T])
- (implicit c: sourcecode.Enclosing): Target[T] = synchronized{
- cacherLazyMap.getOrElseUpdate(c, t).asInstanceOf[Target[T]]
- }
- }
+object Target extends ApplicativeMacros.Zippable[Target]{
+
+ type Cacher = ApplicativeMacros.Cacher[Target[_]]
class Target0[T](t: T) extends Target[T]{
lazy val t0 = t
val inputs = Nil
def evaluate(args: Args) = t0
}
- def apply[T](t: Target[T]): Target[T] = macro impl0[T]
- def apply[T](t: T): Target[T] = macro impl[T]
- def impl0[T: c.WeakTypeTag](c: Context)(t: c.Expr[Target[T]]): c.Expr[Target[T]] = {
- wrapCached(c)(t.tree)
- }
- def impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Target[T]] = {
- import c.universe._
- def rec(t: Tree): Iterator[c.Tree] = Iterator(t) ++ t.children.flatMap(rec(_))
- val bound = collection.mutable.Buffer.empty[(c.Tree, Symbol)]
- val targetApplySym = c.universe.typeOf[Target[_]].member(TermName("apply"))
- // Derived from @olafurpg's
- // https://gist.github.com/olafurpg/596d62f87bf3360a29488b725fbc7608
-
- val (startPos, endPos) = rec(t.tree)
- .map(t => (t.pos.start, t.pos.end))
- .reduce[(Int, Int)]{ case ((s1, e1), (s2, e2)) => (math.min(s1, s2), math.max(e1, e2))}
-
- val macroSource = t.tree.pos.source
- val transformed = c.internal.typingTransform(t.tree) {
- case (t @ q"$fun.apply()", api) if t.symbol == targetApplySym =>
-
- val used = rec(t)
- val banned = used.filter(x =>
- x.symbol.pos.source == macroSource &&
- x.symbol.pos.start >= startPos &&
- x.symbol.pos.end <= endPos
- )
- if (banned.hasNext){
- val banned0 = banned.next()
- c.abort(
- banned0.pos,
- "Target#apply() call cannot use `" + banned0.symbol + "` defined within the T{...} block"
- )
- }
- val tempName = c.freshName(TermName("tmp"))
- val tempSym = c.internal.newTermSymbol(api.currentOwner, tempName)
- c.internal.setInfo(tempSym, t.tpe)
- val tempIdent = Ident(tempSym)
- c.internal.setType(tempIdent, t.tpe)
- bound.append((fun, tempSym))
- tempIdent
- case (t, api) => api.default(t)
- }
-
- val (exprs, symbols) = bound.unzip
-
- val bindings = symbols.map(c.internal.valDef(_))
-
- wrapCached(c)(q"forge.zipMap(..$exprs){ (..$bindings) => $transformed }")
- }
- def wrapCached[T](c: Context)(t: c.Tree) = {
- import c.universe._
- val owner = c.internal.enclosingOwner
- val ownerIsCacherClass =
- owner.owner.isClass &&
- owner.owner.asClass.baseClasses.exists(_.fullName == "forge.define.Target.Cacher")
-
- if (ownerIsCacherClass && !owner.isMethod){
- c.abort(
- c.enclosingPosition,
- "T{} members defined in a Cacher class/trait/object body must be defs"
- )
- }else{
- val embedded =
- if (!ownerIsCacherClass) t
- else q"this.cachedTarget($t)"
-
- c.Expr[Target[T]](embedded)
- }
- }
+ def apply[T](t: Target[T]): Target[T] = macro ApplicativeMacros.impl0[Target, T]
+ def apply[T](t: T): Target[T] = macro ApplicativeMacros.impl[Target, T]
abstract class Ops[T]{ this: Target[T] =>
def map[V](f: T => V) = new Target.Mapped(this, f)
@@ -172,4 +99,29 @@ object Target{
implicit val tsFormat: Format[Target.Subprocess.Result] = Json.format
}
}
+
+ def map[A, B](t: Target[A], f: A => B) = t.map(f)
+ def zip() = new Target.Target0(())
+ def zip[A](a: Target[A]) = a.map(Tuple1(_))
+ def zip[A, B](a: Target[A], b: Target[B]) = a.zip(b)
+ def zip[A, B, C](a: Target[A], b: Target[B], c: Target[C]) = new Target[(A, B, C)]{
+ val inputs = Seq(a, b, c)
+ def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2))
+ }
+ def zip[A, B, C, D](a: Target[A], b: Target[B], c: Target[C], d: Target[D]) = new Target[(A, B, C, D)]{
+ val inputs = Seq(a, b, c, d)
+ def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3))
+ }
+ def zip[A, B, C, D, E](a: Target[A], b: Target[B], c: Target[C], d: Target[D], e: Target[E]) = new Target[(A, B, C, D, E)]{
+ val inputs = Seq(a, b, c, d, e)
+ def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4))
+ }
+ def zip[A, B, C, D, E, F](a: Target[A], b: Target[B], c: Target[C], d: Target[D], e: Target[E], f: Target[F]) = new Target[(A, B, C, D, E, F)]{
+ val inputs = Seq(a, b, c, d, e, f)
+ def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5))
+ }
+ def zip[A, B, C, D, E, F, G](a: Target[A], b: Target[B], c: Target[C], d: Target[D], e: Target[E], f: Target[F], g: Target[G]) = new Target[(A, B, C, D, E, F, G)]{
+ val inputs = Seq(a, b, c, d, e, f, g)
+ def evaluate(args: Args) = (args[A](0), args[B](1), args[C](2), args[D](3), args[E](4), args[F](5), args[G](6))
+ }
}