diff options
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/main/scala/forge/Main.scala | 4 | ||||
-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 | ||||
-rw-r--r-- | core/src/main/scala/forge/discover/Discovered.scala | 18 | ||||
-rw-r--r-- | core/src/main/scala/forge/discover/Router.scala | 6 | ||||
-rw-r--r-- | core/src/main/scala/forge/eval/Evaluator.scala | 48 | ||||
-rw-r--r-- | core/src/main/scala/forge/modules/Jvm.scala | 4 | ||||
-rw-r--r-- | core/src/main/scala/forge/package.scala | 4 | ||||
-rw-r--r-- | core/src/test/examples/javac/build.sc | 14 | ||||
-rw-r--r-- | core/src/test/scala/forge/CacherTests.scala | 6 | ||||
-rw-r--r-- | core/src/test/scala/forge/EvaluationTests.scala | 6 | ||||
-rw-r--r-- | core/src/test/scala/forge/GraphTests.scala | 35 | ||||
-rw-r--r-- | core/src/test/scala/forge/JavaCompileJarTests.scala | 21 | ||||
-rw-r--r-- | core/src/test/scala/forge/MacroErrorTests.scala | 42 | ||||
-rw-r--r-- | core/src/test/scala/forge/TestGraphs.scala | 8 | ||||
-rw-r--r-- | core/src/test/scala/forge/TestUtil.scala | 12 |
17 files changed, 265 insertions, 245 deletions
diff --git a/core/src/main/scala/forge/Main.scala b/core/src/main/scala/forge/Main.scala index e66f5fd8..bb1d5d69 100644 --- a/core/src/main/scala/forge/Main.scala +++ b/core/src/main/scala/forge/Main.scala @@ -2,7 +2,7 @@ package forge import ammonite.ops._ import ammonite.util.{Name, Res} -import forge.define.Target +import forge.define.Task import forge.discover.{Discovered, NestedEntry} import forge.eval.Evaluator import forge.util.OSet @@ -35,7 +35,7 @@ object Main { val targetRoutes = discovered.targets.map(x => x._1 -> Right(x)) val allRoutes = (mainRoutes ++ targetRoutes).toMap[ Seq[String], - Either[NestedEntry[Any, _], (Seq[String], Format[_], Any => Target[_])] + Either[NestedEntry[Any, _], (Seq[String], Format[_], Any => Task[_])] ] allRoutes.get(selector) match{ case Some(Left(nestedEntryPoint)) => 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)) + } +} diff --git a/core/src/main/scala/forge/discover/Discovered.scala b/core/src/main/scala/forge/discover/Discovered.scala index 3b08f7f7..53536e49 100644 --- a/core/src/main/scala/forge/discover/Discovered.scala +++ b/core/src/main/scala/forge/discover/Discovered.scala @@ -1,24 +1,24 @@ package forge.discover -import forge.define.Target +import forge.define.Task import forge.discover.Router.{EntryPoint, Result} import play.api.libs.json.Format import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context -class Discovered[T](val targets: Seq[(Seq[String], Format[_], T => Target[_])], +class Discovered[T](val targets: Seq[(Seq[String], Format[_], T => Task[_])], 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], +case class Labelled[T](target: Task[T], format: Format[T], segments: Seq[String]) case class NestedEntry[T, V](path: Seq[String], resolve: T => V, entryPoint: EntryPoint[V]){ - def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Target[Any]] = { + def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Task[Any]] = { entryPoint.invoke(resolve(target),groupedArgs) } } @@ -34,14 +34,14 @@ object Discovered { } yield path inconsistent } - def makeTuple[T, V](path: Seq[String], func: T => Target[V])(implicit f: Format[V]) = { + def makeTuple[T, V](path: Seq[String], func: T => Task[V])(implicit f: Format[V]) = { (path, f, func) } - def mapping[T: Discovered](t: T): Map[Target[_], Labelled[_]] = { + def mapping[T: Discovered](t: T): Map[Task[_], Labelled[_]] = { implicitly[Discovered[T]].apply(t) - .map(x => x._3 -> Labelled(x._3.asInstanceOf[Target[Any]], x._2.asInstanceOf[Format[Any]], x._1)) + .map(x => x._3 -> Labelled(x._3.asInstanceOf[Task[Any]], x._2.asInstanceOf[Format[Any]], x._1)) .toMap } @@ -62,12 +62,12 @@ object Discovered { if (m.isTerm && (m.asTerm.isGetter || m.asTerm.isLazy)) || m.isModule || - (m.isMethod && m.typeSignature.paramLists.isEmpty && m.typeSignature.resultType <:< c.weakTypeOf[Target[_]]) + (m.isMethod && m.typeSignature.paramLists.isEmpty && m.typeSignature.resultType <:< c.weakTypeOf[Task[_]]) if !m.name.toString.contains('$') } yield { val extendedSegments = m.name.toString :: segments val self = - if (m.typeSignature.resultType <:< c.weakTypeOf[Target[_]]) Seq(extendedSegments) + if (m.typeSignature.resultType <:< c.weakTypeOf[Task[_]]) Seq(extendedSegments) else Nil val (mains, children) = rec(extendedSegments, m.typeSignature) diff --git a/core/src/main/scala/forge/discover/Router.scala b/core/src/main/scala/forge/discover/Router.scala index afb526c7..2c92d847 100644 --- a/core/src/main/scala/forge/discover/Router.scala +++ b/core/src/main/scala/forge/discover/Router.scala @@ -1,7 +1,7 @@ package forge.discover import ammonite.main.Compat -import forge.define.Target +import forge.define.Task import sourcecode.Compat.Context import scala.annotation.StaticAnnotation @@ -57,8 +57,8 @@ object Router{ argSignatures: Seq[ArgSig[T]], doc: Option[String], varargs: Boolean, - invoke0: (T, Map[String, String], Seq[String]) => Result[Target[Any]]){ - def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Target[Any]] = { + invoke0: (T, Map[String, String], Seq[String]) => Result[Task[Any]]){ + def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Task[Any]] = { var remainingArgSignatures = argSignatures.toList diff --git a/core/src/main/scala/forge/eval/Evaluator.scala b/core/src/main/scala/forge/eval/Evaluator.scala index 6f2d43f0..7f50873a 100644 --- a/core/src/main/scala/forge/eval/Evaluator.scala +++ b/core/src/main/scala/forge/eval/Evaluator.scala @@ -1,16 +1,16 @@ package forge.eval import ammonite.ops._ -import forge.define.Target +import forge.define.Task import forge.discover.Labelled import forge.util.{Args, MultiBiMap, OSet} import play.api.libs.json.{Format, JsValue, Json} import scala.collection.mutable class Evaluator(workspacePath: Path, - labeling: Map[Target[_], Labelled[_]]){ + labeling: Map[Task[_], Labelled[_]]){ - def evaluate(targets: OSet[Target[_]]): Evaluator.Results = { + def evaluate(targets: OSet[Task[_]]): Evaluator.Results = { mkdir(workspacePath) val sortedGroups = Evaluator.groupAroundNamedTargets( @@ -18,8 +18,8 @@ class Evaluator(workspacePath: Path, labeling ) - val evaluated = new OSet.Mutable[Target[_]] - val results = mutable.LinkedHashMap.empty[Target[_], Any] + val evaluated = new OSet.Mutable[Task[_]] + val results = mutable.LinkedHashMap.empty[Task[_], Any] for (groupIndex <- sortedGroups.keys()){ val group = sortedGroups.lookupKey(groupIndex) @@ -37,9 +37,9 @@ class Evaluator(workspacePath: Path, Evaluator.Results(targets.items.map(results), evaluated) } - def evaluateGroupCached(group: OSet[Target[_]], - results: collection.Map[Target[_], Any], - sortedGroups: MultiBiMap[Int, Target[_]]): (collection.Map[Target[_], Any], Seq[Target[_]]) = { + def evaluateGroupCached(group: OSet[Task[_]], + results: collection.Map[Task[_], Any], + sortedGroups: MultiBiMap[Int, Task[_]]): (collection.Map[Task[_], Any], Seq[Task[_]]) = { val (externalInputs, terminals) = partitionGroupInputOutput(group, results) @@ -65,7 +65,7 @@ class Evaluator(workspacePath: Path, cached match{ case Some(terminalResults) => - val newResults = mutable.LinkedHashMap.empty[Target[_], Any] + val newResults = mutable.LinkedHashMap.empty[Task[_], Any] for((terminal, res) <- terminals.items.zip(terminalResults)){ newResults(terminal) = labeling(terminal).format.reads(res).get } @@ -87,8 +87,8 @@ class Evaluator(workspacePath: Path, } } - def partitionGroupInputOutput(group: OSet[Target[_]], - results: collection.Map[Target[_], Any]) = { + def partitionGroupInputOutput(group: OSet[Task[_]], + results: collection.Map[Task[_], Any]) = { val allInputs = group.items.flatMap(_.inputs) val (internalInputs, externalInputs) = allInputs.partition(group.contains) val internalInputSet = internalInputs.toSet @@ -96,14 +96,14 @@ class Evaluator(workspacePath: Path, (OSet.from(externalInputs.distinct), terminals) } - def evaluateGroup(group: OSet[Target[_]], - results: collection.Map[Target[_], Any], + def evaluateGroup(group: OSet[Task[_]], + results: collection.Map[Task[_], Any], targetDestPath: Option[Path]) = { targetDestPath.foreach(rm) - val terminalResults = mutable.LinkedHashMap.empty[Target[_], JsValue] - val newEvaluated = mutable.Buffer.empty[Target[_]] - val newResults = mutable.LinkedHashMap.empty[Target[_], Any] + val terminalResults = mutable.LinkedHashMap.empty[Task[_], JsValue] + val newEvaluated = mutable.Buffer.empty[Task[_]] + val newResults = mutable.LinkedHashMap.empty[Task[_], Any] for (target <- group.items) { newEvaluated.append(target) val targetInputValues = target.inputs.toVector.map(x => @@ -129,12 +129,12 @@ class Evaluator(workspacePath: Path, object Evaluator{ - class TopoSorted private[Evaluator] (val values: OSet[Target[_]]) - case class Results(values: Seq[Any], targets: OSet[Target[_]]) + class TopoSorted private[Evaluator] (val values: OSet[Task[_]]) + case class Results(values: Seq[Any], targets: OSet[Task[_]]) def groupAroundNamedTargets(topoSortedTargets: TopoSorted, - labeling: Map[Target[_], Labelled[_]]): MultiBiMap[Int, Target[_]] = { + labeling: Map[Task[_], Labelled[_]]): MultiBiMap[Int, Task[_]] = { - val grouping = new MultiBiMap.Mutable[Int, Target[_]]() + val grouping = new MultiBiMap.Mutable[Int, Task[_]]() var groupCount = 0 @@ -159,7 +159,7 @@ object Evaluator{ } val targetOrdering = topoSortedTargets.values.items.zipWithIndex.toMap - val output = new MultiBiMap.Mutable[Int, Target[_]] + val output = new MultiBiMap.Mutable[Int, Task[_]] // Sort groups amongst themselves, and sort the contents of each group // before aggregating it into the final output @@ -173,9 +173,9 @@ object Evaluator{ * Takes the given targets, finds all the targets they transitively depend * on, and sort them topologically. Fails if there are dependency cycles */ - def topoSortedTransitiveTargets(sourceTargets: OSet[Target[_]]): TopoSorted = { - val transitiveTargets = new OSet.Mutable[Target[_]] - def rec(t: Target[_]): Unit = { + def topoSortedTransitiveTargets(sourceTargets: OSet[Task[_]]): TopoSorted = { + val transitiveTargets = new OSet.Mutable[Task[_]] + def rec(t: Task[_]): Unit = { if (transitiveTargets.contains(t)) () // do nothing else { transitiveTargets.append(t) diff --git a/core/src/main/scala/forge/modules/Jvm.scala b/core/src/main/scala/forge/modules/Jvm.scala index 79a2c989..e707df29 100644 --- a/core/src/main/scala/forge/modules/Jvm.scala +++ b/core/src/main/scala/forge/modules/Jvm.scala @@ -4,7 +4,7 @@ import java.io.FileOutputStream import java.util.jar.{JarEntry, JarOutputStream} import ammonite.ops._ -import forge.define.Target +import forge.define.Task import forge.eval.PathRef import forge.util.Args @@ -59,7 +59,7 @@ object Jvm { Some(outputPath) } } - case class jarUp(roots: Target[PathRef]*) extends Target[PathRef]{ + case class jarUp(roots: Task[PathRef]*) extends Task[PathRef]{ val inputs = roots def evaluate(args: Args): PathRef = { diff --git a/core/src/main/scala/forge/package.scala b/core/src/main/scala/forge/package.scala index 48f5132a..6484c48e 100644 --- a/core/src/main/scala/forge/package.scala +++ b/core/src/main/scala/forge/package.scala @@ -1,6 +1,6 @@ import forge.util.JsonFormatters package object forge extends JsonFormatters{ - val T = define.Target - type T[T] = define.Target[T] + val T = define.Task + type T[T] = define.Task[T] } diff --git a/core/src/test/examples/javac/build.sc b/core/src/test/examples/javac/build.sc index d7ba5662..37d7a5a6 100644 --- a/core/src/test/examples/javac/build.sc +++ b/core/src/test/examples/javac/build.sc @@ -1,4 +1,4 @@ -import forge.define.Target +import forge.define.Task import forge.eval.PathRef object Foo { @@ -21,14 +21,14 @@ object Foo { // | // v // resourceRoot ----> jar - val sourceRoot = Target.path(sourceRootPath) - val resourceRoot = Target.path(resourceRootPath) + val sourceRoot = Task.path(sourceRootPath) + val resourceRoot = Task.path(resourceRootPath) val allSources = list(sourceRoot) val classFiles = compileAll(allSources) val jar = jarUp(resourceRoot, classFiles) - def compileAll(sources: Target[Seq[PathRef]]) = { - new Target.Subprocess( + def compileAll(sources: Task[Seq[PathRef]]) = { + new Task.Subprocess( Seq(sources), args => Seq("javac") ++ @@ -37,11 +37,11 @@ object Foo { ).map(_.dest) } - def list(root: Target[PathRef]): Target[Seq[PathRef]] = { + def list(root: Task[PathRef]): Task[Seq[PathRef]] = { root.map(x => ls.rec(x.path).map(PathRef(_))) } - case class jarUp(roots: Target[PathRef]*) extends Target[PathRef] { + case class jarUp(roots: Task[PathRef]*) extends Task[PathRef] { val inputs = roots diff --git a/core/src/test/scala/forge/CacherTests.scala b/core/src/test/scala/forge/CacherTests.scala index 24a540ff..5f40ee20 100644 --- a/core/src/test/scala/forge/CacherTests.scala +++ b/core/src/test/scala/forge/CacherTests.scala @@ -1,6 +1,6 @@ package forge -import forge.define.Target +import forge.define.Task import forge.discover.Discovered import forge.eval.Evaluator import forge.util.OSet @@ -9,7 +9,7 @@ import utest.framework.TestPath object CacherTests extends TestSuite{ object Base extends Base - trait Base extends Target.Cacher{ + trait Base extends Task.Cacher{ def value = T{ 1 } } object Middle extends Middle @@ -25,7 +25,7 @@ object CacherTests extends TestSuite{ val tests = Tests{ - def eval[T: Discovered, V](base: T, v: Target[V])(implicit tp: TestPath) = { + def eval[T: Discovered, V](base: T, v: Task[V])(implicit tp: TestPath) = { val workspace = ammonite.ops.pwd / 'target / 'workspace / tp.value val evaluator = new Evaluator(workspace, Discovered.mapping(base)) evaluator.evaluate(OSet(v)).values(0) diff --git a/core/src/test/scala/forge/EvaluationTests.scala b/core/src/test/scala/forge/EvaluationTests.scala index 66fe7b8d..72b7deff 100644 --- a/core/src/test/scala/forge/EvaluationTests.scala +++ b/core/src/test/scala/forge/EvaluationTests.scala @@ -1,7 +1,7 @@ package forge -import forge.define.Target +import forge.define.Task import forge.discover.Discovered import forge.eval.Evaluator import forge.util.OSet @@ -24,8 +24,8 @@ object EvaluationTests extends TestSuite{ Discovered.mapping(base) ) - def apply(target: Target[_], expValue: Any, - expEvaled: OSet[Target[_]], + def apply(target: Task[_], expValue: Any, + expEvaled: OSet[Task[_]], extraEvaled: Int = 0) = { val Evaluator.Results(returnedValues, returnedEvaluated) = evaluator.evaluate(OSet(target)) diff --git a/core/src/test/scala/forge/GraphTests.scala b/core/src/test/scala/forge/GraphTests.scala index 1b542882..db522fff 100644 --- a/core/src/test/scala/forge/GraphTests.scala +++ b/core/src/test/scala/forge/GraphTests.scala @@ -2,7 +2,7 @@ package forge import utest._ import TestUtil.test -import forge.define.Target +import forge.define.Task import forge.discover.Discovered import forge.eval.Evaluator import forge.util.OSet @@ -64,14 +64,7 @@ object GraphTests extends TestSuite{ assert(inconsistent == Nil) } - 'borkedCachedDiamond1 - { - val inconsistent = Discovered.consistencyCheck( - borkedCachedDiamond1, - Discovered[borkedCachedDiamond1.type] - ) - assert(inconsistent == expected) - } 'borkedCachedDiamond2 - { val inconsistent = Discovered.consistencyCheck( borkedCachedDiamond2, @@ -90,7 +83,7 @@ object GraphTests extends TestSuite{ 'topoSortedTransitiveTargets - { - def check(targets: OSet[Target[_]], expected: OSet[Target[_]]) = { + def check(targets: OSet[Task[_]], expected: OSet[Task[_]]) = { val result = Evaluator.topoSortedTransitiveTargets(targets).values TestUtil.checkTopological(result) assert(result == expected) @@ -124,9 +117,13 @@ object GraphTests extends TestSuite{ 'defCachedDiamond - check( targets = OSet(defCachedDiamond.down), expected = OSet( + defCachedDiamond.up.inputs(0), defCachedDiamond.up, + defCachedDiamond.down.inputs(0).inputs(0).inputs(0), + defCachedDiamond.down.inputs(0).inputs(0), + defCachedDiamond.down.inputs(0).inputs(1).inputs(0), + defCachedDiamond.down.inputs(0).inputs(1), defCachedDiamond.down.inputs(0), - defCachedDiamond.down.inputs(1), defCachedDiamond.down ) ) @@ -138,9 +135,9 @@ object GraphTests extends TestSuite{ } 'groupAroundNamedTargets - { - def check[T: Discovered, R <: Target[Int]](base: T, - target: R, - expected: OSet[(OSet[R], Int)]) = { + def check[T: Discovered, R <: Task[Int]](base: T, + target: R, + expected: OSet[(OSet[R], Int)]) = { val mapping = Discovered.mapping(base) val topoSortedTransitive = Evaluator.topoSortedTransitiveTargets(OSet(target)) @@ -187,10 +184,10 @@ object GraphTests extends TestSuite{ defCachedDiamond, defCachedDiamond.down, OSet( - OSet(defCachedDiamond.up) -> 1, - OSet(defCachedDiamond.left) -> 1, - OSet(defCachedDiamond.right) -> 1, - OSet(defCachedDiamond.down) -> 1 + OSet(defCachedDiamond.up) -> 2, + OSet(defCachedDiamond.left) -> 2, + OSet(defCachedDiamond.right) -> 2, + OSet(defCachedDiamond.down) -> 2 ) ) @@ -218,10 +215,10 @@ object GraphTests extends TestSuite{ 'labeling - { - def check[T: Discovered](base: T, t: Target[_], relPath: Option[String]) = { + def check[T: Discovered](base: T, t: Task[_], relPath: Option[String]) = { - val names: Seq[(Target[_], Seq[String])] = Discovered.mapping(base).mapValues(_.segments).toSeq + val names: Seq[(Task[_], Seq[String])] = Discovered.mapping(base).mapValues(_.segments).toSeq val nameMap = names.toMap val targetLabel = nameMap.get(t).map(_.mkString(".")) diff --git a/core/src/test/scala/forge/JavaCompileJarTests.scala b/core/src/test/scala/forge/JavaCompileJarTests.scala index 4c3ce06c..fcd81588 100644 --- a/core/src/test/scala/forge/JavaCompileJarTests.scala +++ b/core/src/test/scala/forge/JavaCompileJarTests.scala @@ -3,7 +3,7 @@ package forge import ammonite.ops._ import ImplicitWd._ -import forge.define.Target +import forge.define.Task import forge.discover.Discovered import forge.eval.{Evaluator, PathRef} import forge.modules.Jvm.jarUp @@ -30,7 +30,7 @@ object JavaCompileJarTests extends TestSuite{ mkdir(pwd / 'target / 'workspace / 'javac) cp(javacSrcPath, javacDestPath) - object Build extends Target.Cacher{ + object Build extends Task.Cacher{ def sourceRootPath = javacDestPath / 'src def resourceRootPath = javacDestPath / 'resources @@ -38,26 +38,29 @@ object JavaCompileJarTests extends TestSuite{ // | // v // resourceRoot ----> jar - def sourceRoot = T{ Target.path(sourceRootPath) } - def resourceRoot = T{ Target.path(resourceRootPath) } + def sourceRoot = T{ Task.path(sourceRootPath) } + def resourceRoot = T{ Task.path(resourceRootPath) } def allSources = T{ ls.rec(sourceRoot().path).map(PathRef(_)) } - def classFiles = T{ compileAll(Target.ctx().dest, allSources()) } + def classFiles = T{ compileAll(Task.ctx().dest, allSources()) } def jar = T{ jarUp(resourceRoot, classFiles) } @forge.discover.Router.main - def run(mainClsName: String): Target[CommandResult] = T.command{ + def run(mainClsName: String): Task[CommandResult] = T.cmd{ %%('java, "-cp", classFiles().path, mainClsName) } } import Build._ val mapping = Discovered.mapping(Build) - def eval[T](t: Target[T]): (T, Int) = { + def eval[T](t: Task[T]): (T, Int) = { val evaluator = new Evaluator(workspacePath, mapping) val evaluated = evaluator.evaluate(OSet(t)) - (evaluated.values(0).asInstanceOf[T], evaluated.targets.size) + Tuple2( + evaluated.values(0).asInstanceOf[T], + evaluated.targets.filter(x => mapping.contains(x) || x.isInstanceOf[forge.define.Command[_]]).size + ) } - def check(targets: OSet[Target[_]], expected: OSet[Target[_]]) = { + def check(targets: OSet[Task[_]], expected: OSet[Task[_]]) = { val evaluator = new Evaluator(workspacePath, mapping) val evaluated = evaluator.evaluate(targets).targets.filter(mapping.contains) diff --git a/core/src/test/scala/forge/MacroErrorTests.scala b/core/src/test/scala/forge/MacroErrorTests.scala index 9f41fadc..6e76cd17 100644 --- a/core/src/test/scala/forge/MacroErrorTests.scala +++ b/core/src/test/scala/forge/MacroErrorTests.scala @@ -8,7 +8,7 @@ object MacroErrorTests extends TestSuite{ 'errors{ val expectedMsg = - "T{} members defined in a Cacher class/trait/object body must be defs" + "T{} members must be defs defined in a Cacher class/trait/object body" val err = compileError("object Foo extends forge.define.Target.Cacher{ val x = T{1} }") assert(err.msg == expectedMsg) @@ -19,23 +19,26 @@ object MacroErrorTests extends TestSuite{ // of our `Target#apply()` calls, but we cannot reference any values that // come from inside the T{...} block 'pos - { - val a = T{ 1 } - val arr = Array(a) - val b = { - val c = 0 - T{ - arr(c)() + val e = compileError(""" + val a = T{ 1 } + val arr = Array(a) + val b = { + val c = 0 + T{ + arr(c)() + } } - } + """) + assert(e.msg.contains("must be defs")) } 'neg - { val expectedMsg = "Target#apply() call cannot use `value n` defined within the T{...} block" - val err = compileError("""{ - val a = T{ 1 } + val err = compileError("""new forge.define.Target.Cacher{ + def a = T{ 1 } val arr = Array(a) - val b = { + def b = { T{ val n = 0 arr(n)() @@ -48,10 +51,10 @@ object MacroErrorTests extends TestSuite{ val expectedMsg = "Target#apply() call cannot use `value x` defined within the T{...} block" - val err = compileError("""{ - val a = T{ 1 } + val err = compileError("""new forge.define.Target.Cacher{ + def a = T{ 1 } val arr = Array(a) - val b = { + def b = { T{ arr.map{x => x()} } @@ -59,6 +62,17 @@ object MacroErrorTests extends TestSuite{ }""") assert(err.msg == expectedMsg) } + 'neg3{ + val borkedCachedDiamond1 = utest.compileError(""" + object borkedCachedDiamond1 { + def up = T{ TestUtil.test() } + def left = T{ TestUtil.test(up) } + def right = T{ TestUtil.test(up) } + def down = T{ TestUtil.test(left, right) } + } + """) + assert(borkedCachedDiamond1.msg.contains("must be defs")) + } } } } diff --git a/core/src/test/scala/forge/TestGraphs.scala b/core/src/test/scala/forge/TestGraphs.scala index 5c30f948..9709979d 100644 --- a/core/src/test/scala/forge/TestGraphs.scala +++ b/core/src/test/scala/forge/TestGraphs.scala @@ -1,6 +1,6 @@ package forge -import forge.define.Target.Cacher +import forge.define.Task.Cacher import forge.TestUtil.test class TestGraphs(){ @@ -50,12 +50,6 @@ class TestGraphs(){ def down = T{ test(left, right) } } - object borkedCachedDiamond1 { - def up = T{ test() } - def left = T{ test(up) } - def right = T{ test(up) } - def down = T{ test(left, right) } - } object borkedCachedDiamond2 extends Cacher { def up = test() diff --git a/core/src/test/scala/forge/TestUtil.scala b/core/src/test/scala/forge/TestUtil.scala index 005bcfef..91dc3da9 100644 --- a/core/src/test/scala/forge/TestUtil.scala +++ b/core/src/test/scala/forge/TestUtil.scala @@ -1,13 +1,13 @@ package forge -import forge.define.Target +import forge.define.Task import forge.util.{Args, OSet} import utest.assert import scala.collection.mutable object TestUtil { - def test(inputs: Target[Int]*) = { + def test(inputs: Task[Int]*) = { new Test(inputs, pure = inputs.nonEmpty) } @@ -16,8 +16,8 @@ object TestUtil { * controlled externally, so you can construct arbitrary dataflow graphs and * test how changes propagate. */ - class Test(val inputs: Seq[Target[Int]], - val pure: Boolean) extends Target[Int]{ + class Test(val inputs: Seq[Task[Int]], + val pure: Boolean) extends Task[Int]{ var counter = 0 def evaluate(args: Args) = { counter + args.args.map(_.asInstanceOf[Int]).sum @@ -25,8 +25,8 @@ object TestUtil { override def sideHash = counter } - def checkTopological(targets: OSet[Target[_]]) = { - val seen = mutable.Set.empty[Target[_]] + def checkTopological(targets: OSet[Task[_]]) = { + val seen = mutable.Set.empty[Task[_]] for(t <- targets.items.reverseIterator){ seen.add(t) for(upstream <- t.inputs){ |