summaryrefslogtreecommitdiff
path: root/build.sc
diff options
context:
space:
mode:
authorDuncan Mak <duncanmak@gmail.com>2017-12-28 01:27:41 -0500
committerLi Haoyi <haoyi.sg@gmail.com>2017-12-27 22:27:41 -0800
commitb2cca82786a5fdf0818b4e6be5885855a95f637e (patch)
treebf164ef396d46bddb1b6f7d5e9fd5cd6205f69ad /build.sc
parentcb3c5f06b17de55a3d64faab79c081642b0c5a59 (diff)
downloadmill-b2cca82786a5fdf0818b4e6be5885855a95f637e.tar.gz
mill-b2cca82786a5fdf0818b4e6be5885855a95f637e.tar.bz2
mill-b2cca82786a5fdf0818b4e6be5885855a95f637e.zip
Generate zipmap definitions for higher arities (#81)
* Remove method defns for zipMap/zip that will be generated. The trait Applyer will now extend from ApplyerGenerated which will contain the code-generated definitions. * Script to generate code for Applicative * Generate the zip methods in Target * Generate zip methods in ApplicativeTests * Make sure the full 22-arities are generated * Move code generator into build.sc. Remove generate.sc from directories where code will be generated. * Generate code as part of the SBT also * Properly wire up the test sources * Generate all the code in one place
Diffstat (limited to 'build.sc')
-rwxr-xr-xbuild.sc104
1 files changed, 103 insertions, 1 deletions
diff --git a/build.sc b/build.sc
index 705e50d3..07909ebf 100755
--- a/build.sc
+++ b/build.sc
@@ -48,7 +48,6 @@ trait MillModule extends SbtScalaModule{ outer =>
def ivyDeps = Seq(Dep("com.lihaoyi", "utest", "0.6.0"))
def testFramework = "mill.UTestFramework"
def scalacPluginClasspath = super.scalacPluginClasspath() ++ Seq(CompilerPlugin.jar())
-
}
}
@@ -70,6 +69,109 @@ object Core extends MillModule {
def basePath = pwd / 'core
+ object CodeGenerator {
+ private def generateLetters(n: Int) = {
+ val base = 'A'.toInt
+ (0 until n).map(i => (i + base).toChar)
+ }
+
+ private def write(dir: String, filename: String, s: String) = {
+ import java.io.{BufferedWriter, FileWriter}
+
+ val path = java.nio.file.Paths.get(dir, filename)
+ val w = new BufferedWriter(new FileWriter(path.toFile))
+ w.write(s)
+ w.close()
+ }
+
+ def generateApplyer(dir: String) = {
+ def generate(n: Int) = {
+ val uppercases = generateLetters(n)
+ val lowercases = uppercases.map(Character.toLowerCase)
+ val typeArgs = uppercases.mkString(", ")
+ val zipArgs = lowercases.mkString(", ")
+ val parameters = lowercases.zip(uppercases).map { case (lower, upper) => s"$lower: TT[$upper]" }.mkString(", ")
+
+ val body = s"mapCtx(zip($zipArgs)) { case (($zipArgs), z) => cb($zipArgs, z) }"
+ val zipmap = s"def zipMap[$typeArgs, Res]($parameters)(cb: ($typeArgs, Ctx) => Z[Res]) = $body"
+ val zip = s"def zip[$typeArgs]($parameters): TT[($typeArgs)]"
+
+ if (n < 22) List(zipmap, zip).mkString(System.lineSeparator) else zip
+ }
+ val output = List(
+ "package mill.define",
+ "import scala.language.higherKinds",
+ "trait ApplyerGenerated[TT[_], Z[_], Ctx] {",
+ "def mapCtx[A, B](a: TT[A])(f: (A, Ctx) => Z[B]): TT[B]",
+ (2 to 22).map(generate).mkString(System.lineSeparator),
+ "}").mkString(System.lineSeparator)
+
+ write(dir, "ApplicativeGenerated.scala", output)
+ }
+
+ def generateTarget(dir: String) = {
+ def generate(n: Int) = {
+ val uppercases = generateLetters(n)
+ val lowercases = uppercases.map(Character.toLowerCase)
+ val typeArgs = uppercases.mkString(", ")
+ val args = lowercases.mkString(", ")
+ val parameters = lowercases.zip(uppercases).map { case (lower, upper) => s"$lower: TT[$upper]" }.mkString(", ")
+ val body = uppercases.zipWithIndex.map { case (t, i) => s"args[$t]($i)" }.mkString(", ")
+
+ s"def zip[$typeArgs]($parameters) = makeT[($typeArgs)](Seq($args), (args: Ctx) => ($body))"
+ }
+
+ val output = List(
+ "package mill.define",
+ "import scala.language.higherKinds",
+ "import mill.eval.Result",
+ "import mill.util.Ctx",
+ "trait TargetGenerated {",
+ "type TT[+X]",
+ "def makeT[X](inputs: Seq[TT[_]], evaluate: Ctx => Result[X]): TT[X]",
+ (3 to 22).map(generate).mkString(System.lineSeparator),
+ "}").mkString(System.lineSeparator)
+ write(dir, "TaskGenerated.scala", output)
+ }
+
+ def generateApplicativeTest(dir: String) = {
+ def generate(n: Int): String = {
+ val uppercases = generateLetters(n)
+ val lowercases = uppercases.map(Character.toLowerCase)
+ val typeArgs = uppercases.mkString(", ")
+ val parameters = lowercases.zip(uppercases).map { case (lower, upper) => s"$lower: Option[$upper]" }.mkString(", ")
+ val result = lowercases.mkString(", ")
+ val forArgs = lowercases.map(i => s"$i <- $i").mkString("; ")
+ s"def zip[$typeArgs]($parameters) = { for ($forArgs) yield ($result) }"
+ }
+
+ val output = List(
+ "package mill.define",
+ "trait OptGenerated {",
+ (2 to 22).map(generate).mkString(System.lineSeparator),
+ "}"
+ ).mkString(System.lineSeparator)
+
+ write(dir, "ApplicativeTestsGenerated.scala", output)
+ }
+
+ def generateSources(p: Path) = {
+ val dir = p.toString()
+ generateApplyer(dir)
+ generateTarget(dir)
+ }
+
+ def generateTests(p: Path) = {
+ generateApplicativeTest(p.toString())
+ }
+ }
+
+ def sources = {
+ CodeGenerator.generateSources(this.basePath / 'src / 'main / 'scala / 'mill / 'define)
+ CodeGenerator.generateTests(pwd / 'core / 'src / 'test / 'scala / 'mill / 'define)
+ super.sources
+ }
+
val cross =
for(jarLabel <- mill.define.Cross("jarA", "jarB", "jarC"))
yield new mill.Module{