summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-11-04 09:09:02 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2017-11-04 09:09:02 -0700
commit3b10725ee3a1f84855a0654c5e386bc7465816d3 (patch)
treedeb6574654db3aab8c855a31c475c94233678a98 /core/src
parentc5f3cb7fdcc610bd167460b75b22863f61d6fb4b (diff)
downloadmill-3b10725ee3a1f84855a0654c5e386bc7465816d3.tar.gz
mill-3b10725ee3a1f84855a0654c5e386bc7465816d3.tar.bz2
mill-3b10725ee3a1f84855a0654c5e386bc7465816d3.zip
First experiment using `Cacher interface` combined with `Caller` implicits to turn `def foo = T{}` into pseudo-`lazy val`s, that we can override in subclasses using stackable traits
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/scala/forge/Discovered.scala6
-rw-r--r--core/src/main/scala/forge/Evaluator.scala1
-rw-r--r--core/src/main/scala/forge/Target.scala15
-rw-r--r--core/src/main/scala/forge/util/Caller.scala12
-rw-r--r--core/src/test/scala/forge/GraphTests.scala66
-rw-r--r--core/src/test/scala/forge/JavaCompileJarTests.scala19
-rw-r--r--core/src/test/scala/forge/TestGraphs.scala29
7 files changed, 133 insertions, 15 deletions
diff --git a/core/src/main/scala/forge/Discovered.scala b/core/src/main/scala/forge/Discovered.scala
index 03577b1f..e3aa31f9 100644
--- a/core/src/main/scala/forge/Discovered.scala
+++ b/core/src/main/scala/forge/Discovered.scala
@@ -29,7 +29,11 @@ object Discovered {
val tpe = c.weakTypeTag[T].tpe
def rec(segments: List[String], t: c.Type): Seq[Seq[String]] = for {
m <- t.members.toSeq
- if m.isTerm && (m.asTerm.isGetter || m.asTerm.isLazy) || m.isModule
+ if
+ (m.isTerm && (m.asTerm.isGetter || m.asTerm.isLazy)) ||
+ m.isModule ||
+ (m.isMethod && m.typeSignature.paramLists.isEmpty && m.typeSignature.resultType <:< c.weakTypeOf[Target[_]])
+
res <- {
val extendedSegments = m.name.toString :: segments
val self =
diff --git a/core/src/main/scala/forge/Evaluator.scala b/core/src/main/scala/forge/Evaluator.scala
index 50dc46d4..3ef605b7 100644
--- a/core/src/main/scala/forge/Evaluator.scala
+++ b/core/src/main/scala/forge/Evaluator.scala
@@ -105,6 +105,7 @@ class Evaluator(workspacePath: Path,
)
val args = new Args(targetInputValues, targetDestPath)
+
val res = target.evaluate(args)
for(targetLabel <- labeling.get(target)){
terminalResults(target) = targetLabel
diff --git a/core/src/main/scala/forge/Target.scala b/core/src/main/scala/forge/Target.scala
index c1790960..df9d9cc3 100644
--- a/core/src/main/scala/forge/Target.scala
+++ b/core/src/main/scala/forge/Target.scala
@@ -32,6 +32,14 @@ abstract class Target[T] extends Target.Ops[T]{
}
object Target{
+ trait Cacher{
+ val cacherLazyMap = mutable.Map.empty[(Any, sourcecode.Line, sourcecode.Enclosing), Target[_]]
+ def T[T](t: T): Target[T] = macro impl[T]
+ def T[T](t: => Target[T])
+ (implicit c: forge.util.Caller, l: sourcecode.Line, e: sourcecode.Enclosing): Target[T] = {
+ cacherLazyMap.getOrElseUpdate((c, l, e), t).asInstanceOf[Target[T]]
+ }
+ }
class Target0[T](t: T) extends Target[T]{
lazy val t0 = t
val inputs = Nil
@@ -68,7 +76,12 @@ object Target{
val bindings = symbols.map(c.internal.valDef(_))
- val embedded = q"new forge.Target.Target1(forge.zipMap(..$exprs){ (..$bindings) => $transformed })"
+ val newTargetTree = q"new forge.Target.Target1(forge.zipMap(..$exprs){ (..$bindings) => $transformed })"
+
+ val embedded =
+ if (!(c.prefix.tree.tpe <:< typeOf[Cacher])) newTargetTree
+ else q"${c.prefix}.T($newTargetTree)"
+
c.Expr[Target[T]](embedded)
}
diff --git a/core/src/main/scala/forge/util/Caller.scala b/core/src/main/scala/forge/util/Caller.scala
new file mode 100644
index 00000000..30dcb22a
--- /dev/null
+++ b/core/src/main/scala/forge/util/Caller.scala
@@ -0,0 +1,12 @@
+package forge.util
+
+import scala.reflect.macros.blackbox
+import language.experimental.macros
+case class Caller(value: Any)
+object Caller {
+ implicit def generate: Caller = macro impl
+ def impl(c: blackbox.Context): c.Tree = {
+ import c.universe._
+ q"new _root_.forge.util.Caller(this)"
+ }
+}
diff --git a/core/src/test/scala/forge/GraphTests.scala b/core/src/test/scala/forge/GraphTests.scala
index 572e459e..ca825683 100644
--- a/core/src/test/scala/forge/GraphTests.scala
+++ b/core/src/test/scala/forge/GraphTests.scala
@@ -70,6 +70,54 @@ object GraphTests extends TestSuite{
diamond.down
)
)
+ 'defCachedDiamond - check(
+ targets = OSet(defCachedDiamond.down),
+ expected = OSet(
+ defCachedDiamond.up,
+ defCachedDiamond.down.inputs(0),
+ defCachedDiamond.down.inputs(1),
+ defCachedDiamond.down
+ )
+ )
+ 'borkedCachedDiamond - {
+ // Make sure these fail because `def`s without `Cacher` will re-evaluate
+ // each time, returning different sets of targets.
+ //
+ // Maybe later we can convert them into compile errors somehow
+ * - intercept[Throwable]{
+ check(
+ targets = OSet(borkedCachedDiamond1.down),
+ expected = OSet(
+ borkedCachedDiamond1.up,
+ borkedCachedDiamond1.down.inputs(0),
+ borkedCachedDiamond1.down.inputs(1),
+ borkedCachedDiamond1.down
+ )
+ )
+ }
+ * - intercept[Throwable]{
+ check(
+ targets = OSet(borkedCachedDiamond2.down),
+ expected = OSet(
+ borkedCachedDiamond2.up,
+ borkedCachedDiamond2.down.inputs(0),
+ borkedCachedDiamond2.down.inputs(1),
+ borkedCachedDiamond2.down
+ )
+ )
+ }
+ * - intercept[Throwable]{
+ check(
+ targets = OSet(borkedCachedDiamond3.down),
+ expected = OSet(
+ borkedCachedDiamond3.up,
+ borkedCachedDiamond3.down.inputs(0),
+ borkedCachedDiamond3.down.inputs(1),
+ borkedCachedDiamond3.down
+ )
+ )
+ }
+ }
'bigSingleTerminal - {
val result = Evaluator.topoSortedTransitiveTargets(OSet(bigSingleTerminal.j)).values
TestUtil.checkTopological(result)
@@ -78,9 +126,9 @@ object GraphTests extends TestSuite{
}
'groupAroundNamedTargets - {
- def check[T: Discovered](base: T,
- target: TestUtil.Test,
- expected: OSet[(OSet[TestUtil.Test], Int)]) = {
+ def check[T: Discovered, R <: Target[Int]](base: T,
+ target: R,
+ expected: OSet[(OSet[R], Int)]) = {
val mapping = Discovered.mapping(base)
val topoSortedTransitive = Evaluator.topoSortedTransitiveTargets(OSet(target))
@@ -122,6 +170,18 @@ object GraphTests extends TestSuite{
OSet(diamond.down) -> 1
)
)
+
+ 'defCachedDiamond - check(
+ defCachedDiamond,
+ defCachedDiamond.down,
+ OSet(
+ OSet(defCachedDiamond.up) -> 1,
+ OSet(defCachedDiamond.left) -> 1,
+ OSet(defCachedDiamond.right) -> 1,
+ OSet(defCachedDiamond.down) -> 1
+ )
+ )
+
'anonDiamond - check(
anonDiamond,
anonDiamond.down,
diff --git a/core/src/test/scala/forge/JavaCompileJarTests.scala b/core/src/test/scala/forge/JavaCompileJarTests.scala
index c1a055ea..8b292a88 100644
--- a/core/src/test/scala/forge/JavaCompileJarTests.scala
+++ b/core/src/test/scala/forge/JavaCompileJarTests.scala
@@ -50,27 +50,26 @@ object JavaCompileJarTests extends TestSuite{
mkdir(pwd / 'target / 'workspace / 'javac)
cp(javacSrcPath, javacDestPath)
- object Build {
- val sourceRootPath = javacDestPath / 'src
- val resourceRootPath = javacDestPath / 'resources
+ object Build extends Target.Cacher{
+ def sourceRootPath = javacDestPath / 'src
+ def resourceRootPath = javacDestPath / 'resources
// sourceRoot -> allSources -> classFiles
// |
// v
// resourceRoot ----> jar
- val sourceRoot = Target.path(sourceRootPath)
- val resourceRoot = Target.path(resourceRootPath)
- val allSources = T{
- ls.rec(sourceRoot().path).map(PathRef(_))
- }
- val classFiles = compileAll(allSources)
- val jar = jarUp(resourceRoot, classFiles)
+ def sourceRoot = T{ Target.path(sourceRootPath) }
+ def resourceRoot = T{ Target.path(resourceRootPath) }
+ def allSources = T{ ls.rec(sourceRoot().path).map(PathRef(_)) }
+ def classFiles = T{ compileAll(allSources) }
+ def jar = T{ jarUp(resourceRoot, classFiles) }
}
import Build._
val mapping = Discovered.mapping(Build)
def check(targets: OSet[Target[_]], expected: OSet[Target[_]]) = {
val evaluator = new Evaluator(workspacePath, mapping)
+
val evaluated = evaluator.evaluate(targets).evaluated.filter(mapping.contains)
assert(evaluated == expected)
}
diff --git a/core/src/test/scala/forge/TestGraphs.scala b/core/src/test/scala/forge/TestGraphs.scala
index 0ee48a18..5960ed4c 100644
--- a/core/src/test/scala/forge/TestGraphs.scala
+++ b/core/src/test/scala/forge/TestGraphs.scala
@@ -1,5 +1,6 @@
package forge
+import forge.Target.Cacher
import forge.TestUtil.test
class TestGraphs(){
@@ -42,6 +43,34 @@ class TestGraphs(){
val down = test(test(up), test(up))
}
+ object defCachedDiamond extends Cacher{
+ def up = T{ test() }
+ def left = T{ test(up) }
+ def right = T{ test(up) }
+ 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()
+ def left = test(up)
+ def right = test(up)
+ def down = test(left, right)
+ }
+
+ object borkedCachedDiamond3 {
+ def up = test()
+ def left = test(up)
+ def right = test(up)
+ def down = test(left, right)
+ }
+
// o g-----o
// \ \ \
// o o h-----I---o