diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-01 23:22:32 -0700 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-01 23:22:32 -0700 |
commit | bfbbe450d4ac330f83fb28334e57789f3130a51c (patch) | |
tree | fb7e43d942c59481afbf0e3824db1fbfa29ba65e /src | |
parent | 8637fffa264065b4bbc10b686102f5c36334cd6b (diff) | |
download | mill-bfbbe450d4ac330f83fb28334e57789f3130a51c.tar.gz mill-bfbbe450d4ac330f83fb28334e57789f3130a51c.tar.bz2 mill-bfbbe450d4ac330f83fb28334e57789f3130a51c.zip |
First pass at idiom-bracket macro works
Diffstat (limited to 'src')
-rw-r--r-- | src/main/scala/forge/Target.scala | 40 | ||||
-rw-r--r-- | src/main/scala/forge/package.scala | 1 | ||||
-rw-r--r-- | src/main/scala/forge/scalaplugin/Compile.scala | 109 | ||||
-rw-r--r-- | src/test/scala/forge/MetacircularTests.scala | 22 |
4 files changed, 52 insertions, 120 deletions
diff --git a/src/main/scala/forge/Target.scala b/src/main/scala/forge/Target.scala index c0b85f2a..a6a8eda7 100644 --- a/src/main/scala/forge/Target.scala +++ b/src/main/scala/forge/Target.scala @@ -6,6 +6,10 @@ import forge.util.{Args, PathRef} import play.api.libs.json.{Format, JsValue, Json} import scala.annotation.compileTimeOnly +import language.experimental.macros +import reflect.macros.blackbox.Context +import scala.collection.mutable + abstract class Target[T] extends Target.Ops[T]{ /** * What other Targets does this Target depend on? @@ -40,6 +44,42 @@ object Target{ } implicit def toTarget[T](t: T): Target[T] = new Target0(t) implicit def apply[T](t: => Target[T]): Target[T] = new Target1(t) + def raw[T](t: T): Target[T] = macro impl[T] + def impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[Target[T]] = { + import c.universe._ + val bound = collection.mutable.Buffer.empty[(c.Tree, c.TermName)] + + object transformer extends c.universe.Transformer{ + override def transform(tree: c.Tree): c.Tree = tree match{ + case q"$fun.apply()" if fun.tpe <:< weakTypeOf[Target[_]] => + val newTerm = TermName(c.freshName()) + bound.append((fun, newTerm)) + val ident = Ident(newTerm) + ident + case _ => super.transform(tree) + } + } + + val transformed = transformer.transform(t.tree) + val (exprs, names) = bound.unzip + val embedded = bound.length match{ + case 0 => transformed + case 1 => q"zip(..$exprs).map{ case ${names(0)} => $transformed }" + case n => + + // For some reason, pq"(..$names)" doesn't work... + val pq = n match{ + case 2 => pq"(${names(0)}, ${names(1)})" + case 3 => pq"(${names(0)}, ${names(1)}, ${names(2)})" + case 4 => pq"(${names(0)}, ${names(1)}, ${names(2)}, ${names(3)})" + case 5 => pq"(${names(0)}, ${names(1)}, ${names(2)}, ${names(3)}, ${names(4)})" + } + q"zip(..$exprs).map{ case $pq => $transformed }" + } + + + c.Expr[Target[T]](c.untypecheck(embedded)) + } abstract class Ops[T]{ this: Target[T] => def map[V](f: T => V) = new Target.Mapped(this, f) diff --git a/src/main/scala/forge/package.scala b/src/main/scala/forge/package.scala index 00562a85..f7635b9b 100644 --- a/src/main/scala/forge/package.scala +++ b/src/main/scala/forge/package.scala @@ -6,6 +6,7 @@ package object forge { val T = Target type T[T] = Target[T] + def zip[A](a: T[A]) = a def zip[A, B](a: T[A], b: T[B]) = a.zip(b) def zip[A, B, C](a: T[A], b: T[B], c: T[C]) = new Target[(A, B, C)]{ val inputs = Seq(a, b, c) diff --git a/src/main/scala/forge/scalaplugin/Compile.scala b/src/main/scala/forge/scalaplugin/Compile.scala deleted file mode 100644 index 77ff3a5e..00000000 --- a/src/main/scala/forge/scalaplugin/Compile.scala +++ /dev/null @@ -1,109 +0,0 @@ -package forge.scalaplugin -import ammonite.ops._ -import java.io.File - -import coursier._ -import forge.Target -import forge.util.OSet -import sbt.internal.inc.{FreshCompilerCache, ScalaInstance, ZincUtil} -import sbt.internal.util.{ConsoleOut, MainAppender} -import sbt.util.LogExchange -import xsbti.api.{ClassLike, DependencyContext} -import xsbti.compile._ - -import scalaz.concurrent.Task -object Compile { - - def apply(scalaVersion: Target[String], - dependencies: Target[OSet[Dependency]]) = { - for((s, d) <- scalaVersion.zip(dependencies)) - yield underlying(s, d) - - } - def underlying(scalaVersion: String, - dependencies: OSet[Dependency]) = { - - val binaryScalaVersion = scalaVersion.split('.').dropRight(1).mkString(".") - val start = Resolution( - Set( - Dependency(Module("org.scala-lang", "scala-compiler"), scalaVersion), - Dependency(Module("org.scala-lang", "scala-library"), scalaVersion), - Dependency(Module("org.scala-sbt", s"compiler-bridge_$binaryScalaVersion"), "1.0.3"), - Dependency(Module("com.typesafe.play", s"play-json_$binaryScalaVersion"), "2.6.6") - ) - ) - val repositories = Seq( - Cache.ivy2Local, - MavenRepository("https://repo1.maven.org/maven2") - ) - - val fetch = Fetch.from(repositories, Cache.fetch()) - val resolution = start.process.run(fetch).unsafePerformSync - - - val localArtifacts: Seq[File] = Task.gatherUnordered( - resolution.artifacts.map(Cache.file(_).run) - ).unsafePerformSync.flatMap(_.toOption) - - pprint.log(localArtifacts) - def grepJar(s: String) = localArtifacts.find(_.toString.endsWith(s)).get - - val scalac = ZincUtil.scalaCompiler( - new ScalaInstance( - version = scalaVersion, - loader = getClass.getClassLoader, - libraryJar = grepJar(s"scala-library-$scalaVersion.jar"), - compilerJar = grepJar(s"scala-compiler-$scalaVersion.jar"), - allJars = localArtifacts.toArray, - explicitActual = None - ), - grepJar(s"compiler-bridge_$binaryScalaVersion-1.0.3.jar") - ) - - val outputDir = pwd/'target/'zinc - mkdir(outputDir) - - val scalaFiles = Array(pwd/"Test.scala") - - - scalac.apply( - sources = scalaFiles.map(_.toIO), - changes = new DependencyChanges { - def isEmpty = true - def modifiedBinaries() = Array[File]() - def modifiedClasses() = Array[String]() - }, - classpath = localArtifacts.toArray, - singleOutput = outputDir.toIO, - options = Array(), - callback = new xsbti.AnalysisCallback { - def startSource(source: File) = () - def apiPhaseCompleted() = () - def enabled() = true - def binaryDependency(onBinaryEntry: File, onBinaryClassName: String, fromClassName: String, fromSourceFile: File, context: DependencyContext) = () - def generatedNonLocalClass(source: File, classFile: File, binaryClassName: String, srcClassName: String) = () - def problem(what: String, pos: xsbti.Position, msg: String, severity: xsbti.Severity, reported: Boolean) = () - def dependencyPhaseCompleted() = () - def classDependency(onClassName: String, sourceClassName: String, context: DependencyContext) = () - def generatedLocalClass(source: File, classFile: File) = () - def api(sourceFile: File, classApi: ClassLike) = () - - def mainClass(sourceFile: File, className: String) = () - def usedName(className: String, name: String, useScopes: java.util.EnumSet[xsbti.UseScope]) = () - }, - maximumErrors = 10, - cache = new FreshCompilerCache(), - log = { - val console = ConsoleOut.systemOut - val consoleAppender = MainAppender.defaultScreen(console) - val l = LogExchange.logger("Hello") - LogExchange.unbindLoggerAppenders("Hello") - LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Warn) :: Nil) - l - } - ) - - %('java,"-cp", localArtifacts.mkString(":") + ":.", "Test")(pwd/'target/'zinc) - - } -} diff --git a/src/test/scala/forge/MetacircularTests.scala b/src/test/scala/forge/MetacircularTests.scala index 6f7a51d2..f11b4af5 100644 --- a/src/test/scala/forge/MetacircularTests.scala +++ b/src/test/scala/forge/MetacircularTests.scala @@ -8,22 +8,22 @@ import utest._ object MetacircularTests extends TestSuite{ object Self extends scalaplugin.Subproject { val scalaVersion = T{ "2.12.4" } - override val compileDeps = T{ - for(scalaVersion <- scalaVersion) yield Seq( - Dep(Mod("org.scala-lang", "scala-reflect"), scalaVersion, configuration = "provided"), - ) + override val compileDeps = T.raw{ + Seq(Dep(Mod("org.scala-lang", "scala-reflect"), scalaVersion(), configuration = "provided")) } - override val deps = T{ - for((scalaVersion, scalaBinaryVersion) <- zip(scalaVersion, scalaBinaryVersion)) yield Seq( - Dep(Mod("com.lihaoyi", "sourcecode_" + scalaBinaryVersion), "0.1.4"), - Dep(Mod("com.lihaoyi", "pprint_" + scalaBinaryVersion), "0.5.3"), - Dep(Mod("com.lihaoyi", "ammonite_" + scalaVersion), "1.0.3"), - Dep(Mod("com.typesafe.play", "play-json_" + scalaBinaryVersion), "2.6.6"), - Dep(Mod("org.scala-sbt", "zinc_" + scalaBinaryVersion), "1.0.3") + + override val deps = T.raw{ + Seq( + Dep(Mod("com.lihaoyi", "sourcecode_" + scalaBinaryVersion()), "0.1.4"), + Dep(Mod("com.lihaoyi", "pprint_" + scalaBinaryVersion()), "0.5.3"), + Dep(Mod("com.lihaoyi", "ammonite_" + scalaVersion()), "1.0.3"), + Dep(Mod("com.typesafe.play", "play-json_" + scalaBinaryVersion()), "2.6.6"), + Dep(Mod("org.scala-sbt", "zinc_" + scalaBinaryVersion()), "1.0.3") ) } + val basePath = T{ pwd } override val sources = T{ PathRef(pwd/'src/'main/'scala) } override val resources = T{ PathRef(pwd/'src/'main/'resources) } |