diff options
Diffstat (limited to 'core/src/main/scala/forge/define')
-rw-r--r-- | core/src/main/scala/forge/define/Cacher.scala | 29 | ||||
-rw-r--r-- | core/src/main/scala/forge/define/Target.scala | 119 | ||||
-rw-r--r-- | core/src/main/scala/forge/define/Task.scala | 134 |
3 files changed, 147 insertions, 135 deletions
diff --git a/core/src/main/scala/forge/define/Cacher.scala b/core/src/main/scala/forge/define/Cacher.scala index 8d4d836c..56eeb892 100644 --- a/core/src/main/scala/forge/define/Cacher.scala +++ b/core/src/main/scala/forge/define/Cacher.scala @@ -4,32 +4,29 @@ import scala.collection.mutable import scala.reflect.macros.blackbox.Context -trait Cacher[C]{ - private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, C] - protected[this] def cachedTarget[T <: C](t: => T) - (implicit c: sourcecode.Enclosing): T = synchronized{ - cacherLazyMap.getOrElseUpdate(c, t).asInstanceOf[T] +trait Cacher[C[_], V[_]]{ + private[this] val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, V[_]] + def wrapCached[T](in: C[T]): V[T] + protected[this] def cachedTarget[T](t: => C[T]) + (implicit c: sourcecode.Enclosing): V[T] = synchronized{ + cacherLazyMap.getOrElseUpdate(c, wrapCached(t)).asInstanceOf[V[T]] } } object Cacher{ def impl0[M[_], T: c.WeakTypeTag](c: Context)(t: c.Expr[M[T]]): c.Expr[M[T]] = { - wrapCached(c)(t) + c.Expr[M[T]](wrapCached(c)(t.tree)) } - def wrapCached[M[_], T](c: Context)(t: c.Expr[M[T]]) = { + def wrapCached(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.Cacher") - if (ownerIsCacherClass && !owner.isMethod){ - c.abort( - c.enclosingPosition, - "T{} members defined in a Cacher class/trait/object body must be defs" - ) - }else{ - if (!ownerIsCacherClass) t - else c.Expr[M[T]](q"this.cachedTarget($t)") - } + if (ownerIsCacherClass && owner.isMethod) q"this.cachedTarget($t)" + else c.abort( + c.enclosingPosition, + "T{} members must be defs defined in a Cacher class/trait/object body" + ) } }
\ No newline at end of file diff --git a/core/src/main/scala/forge/define/Target.scala b/core/src/main/scala/forge/define/Target.scala deleted file mode 100644 index b98d3902..00000000 --- a/core/src/main/scala/forge/define/Target.scala +++ /dev/null @@ -1,119 +0,0 @@ -package forge.define - -import ammonite.ops.{CommandResult, mkdir} -import forge.define.Applicative.Applyable -import forge.eval.PathRef -import forge.util.{Args, JsonFormatters} -import play.api.libs.json.{Format, Json} - -import scala.annotation.compileTimeOnly -import scala.language.experimental.macros -import scala.reflect.macros.blackbox.Context - -abstract class Target[+T] extends Target.Ops[T] with Applyable[T]{ - /** - * What other Targets does this Target depend on? - */ - val inputs: Seq[Target[_]] - - /** - * Evaluate this target - */ - def evaluate(args: Args): T - - /** - * Even if this target's inputs did not change, does it need to re-evaluate - * anyway? - */ - def sideHash: Int = 0 -} - - -object Target extends Applicative.Applyer[Target, Target, Args]{ - def underlying[A](v: Target[A]) = v - - type Cacher = forge.define.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 forge.define.Cacher.impl0[Target, T] - def command[T](t: T): Target[T] = macro Applicative.impl[Target, T, Args] - def apply[T](t: T): Target[T] = macro impl[Target, T, Args] - def impl[M[_], T: c.WeakTypeTag, Ctx: c.WeakTypeTag] - (c: Context) - (t: c.Expr[T]) - (implicit tt: c.WeakTypeTag[M[_]]): c.Expr[M[T]] = { - forge.define.Cacher.wrapCached[M, T](c)( - Applicative.impl[M, T, Ctx](c)(t) - ) - } - - abstract class Ops[+T]{ this: Target[T] => - def map[V](f: T => V) = new Target.Mapped(this, f) - def mapDest[V](f: (T, Args) => V) = new Target.MappedDest(this, f) - - def filter(f: T => Boolean) = this - def withFilter(f: T => Boolean) = this - def zip[V](other: Target[V]) = new Target.Zipped(this, other) - - } - - def traverse[T](source: Seq[Target[T]]) = { - new Traverse[T](source) - } - class Traverse[+T](val inputs: Seq[Target[T]]) extends Target[Seq[T]]{ - def evaluate(args: Args) = { - for (i <- 0 until args.length) - yield args(i).asInstanceOf[T] - } - - } - class Mapped[+T, +V](source: Target[T], f: T => V) extends Target[V]{ - def evaluate(args: Args) = f(args(0)) - val inputs = List(source) - } - class MappedDest[+T, +V](source: Target[T], f: (T, Args) => V) extends Target[V]{ - def evaluate(args: Args) = f(args(0), args) - val inputs = List(source) - } - class Zipped[+T, +V](source1: Target[T], source2: Target[V]) extends Target[(T, V)]{ - def evaluate(args: Args) = (args(0), args(1)) - val inputs = List(source1, source2) - } - - def path(path: ammonite.ops.Path) = new Path(path) - class Path(path: ammonite.ops.Path) extends Target[PathRef]{ - def handle = PathRef(path) - def evaluate(args: Args) = handle - override def sideHash = handle.hashCode() - val inputs = Nil - } - - - def mapCtx[A, B](t: Target[A])(f: (A, Args) => B) = t.mapDest(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)) - } -} diff --git a/core/src/main/scala/forge/define/Task.scala b/core/src/main/scala/forge/define/Task.scala new file mode 100644 index 00000000..a78fcaa7 --- /dev/null +++ b/core/src/main/scala/forge/define/Task.scala @@ -0,0 +1,134 @@ +package forge.define + +import forge.define.Applicative.Applyable +import forge.eval.PathRef +import forge.util.Args +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +abstract class Task[+T] extends Task.Ops[T] with Applyable[T]{ + /** + * What other Targets does this Target depend on? + */ + val inputs: Seq[Task[_]] + + /** + * Evaluate this target + */ + def evaluate(args: Args): T + + /** + * Even if this target's inputs did not change, does it need to re-evaluate + * anyway? + */ + def sideHash: Int = 0 +} + +class Target[+T](t: Task[T]) extends Task[T] { + val inputs = Seq(t) + def evaluate(args: Args) = args[T](0) +} +class Command[+T](t: Task[T]) extends Task[T] { + val inputs = Seq(t) + def evaluate(args: Args) = args[T](0) +} +object Task extends Applicative.Applyer[Task, Task, Args]{ + + def underlying[A](v: Task[A]) = v + + trait Cacher extends forge.define.Cacher[Task, Target]{ + def wrapCached[T](t: Task[T]): Target[T] = new Target(t) + } + class Target0[T](t: T) extends Task[T]{ + lazy val t0 = t + val inputs = Nil + def evaluate(args: Args) = t0 + } + def apply[T](t: Task[T]): Target[T] = macro Cacher.impl0[Task, T] + + def cmd[T](t: T): Command[T] = macro targetCommandImpl[T] + def targetCommandImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Command[T]] = { + import c.universe._ + c.Expr[Command[T]]( + q"new forge.define.Command(${Applicative.impl[Task, T, Args](c)(t).tree})" + ) + } + def task[T](t: T): Task[T] = macro Applicative.impl[Task, T, Args] + + def apply[T](t: T): Target[T] = macro targetCachedImpl[T] + + def targetCachedImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Target[T]] = { + c.Expr[Target[T]]( + forge.define.Cacher.wrapCached(c)( + Applicative.impl[Task, T, Args](c)(t).tree + ) + ) + } + + abstract class Ops[+T]{ this: Task[T] => + def map[V](f: T => V) = new Task.Mapped(this, f) + def mapDest[V](f: (T, Args) => V) = new Task.MappedDest(this, f) + + def filter(f: T => Boolean) = this + def withFilter(f: T => Boolean) = this + def zip[V](other: Task[V]) = new Task.Zipped(this, other) + + } + + def traverse[T](source: Seq[Task[T]]) = { + new Traverse[T](source) + } + class Traverse[+T](val inputs: Seq[Task[T]]) extends Task[Seq[T]]{ + def evaluate(args: Args) = { + for (i <- 0 until args.length) + yield args(i).asInstanceOf[T] + } + + } + class Mapped[+T, +V](source: Task[T], f: T => V) extends Task[V]{ + def evaluate(args: Args) = f(args(0)) + val inputs = List(source) + } + class MappedDest[+T, +V](source: Task[T], f: (T, Args) => V) extends Task[V]{ + def evaluate(args: Args) = f(args(0), args) + val inputs = List(source) + } + class Zipped[+T, +V](source1: Task[T], source2: Task[V]) extends Task[(T, V)]{ + def evaluate(args: Args) = (args(0), args(1)) + val inputs = List(source1, source2) + } + + def path(path: ammonite.ops.Path) = new Path(path) + class Path(path: ammonite.ops.Path) extends Task[PathRef]{ + def handle = PathRef(path) + def evaluate(args: Args) = handle + override def sideHash = handle.hashCode() + val inputs = Nil + } + + + def mapCtx[A, B](t: Task[A])(f: (A, Args) => B) = t.mapDest(f) + def zip() = new Task.Target0(()) + def zip[A](a: Task[A]) = a.map(Tuple1(_)) + def zip[A, B](a: Task[A], b: Task[B]) = a.zip(b) + def zip[A, B, C](a: Task[A], b: Task[B], c: Task[C]) = new Task[(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: Task[A], b: Task[B], c: Task[C], d: Task[D]) = new Task[(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: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E]) = new Task[(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: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E], f: Task[F]) = new Task[(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: Task[A], b: Task[B], c: Task[C], d: Task[D], e: Task[E], f: Task[F], g: Task[G]) = new Task[(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)) + } +} |