diff options
author | Duncan Mak <duncanmak@gmail.com> | 2017-12-28 01:27:41 -0500 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-12-27 22:27:41 -0800 |
commit | b2cca82786a5fdf0818b4e6be5885855a95f637e (patch) | |
tree | bf164ef396d46bddb1b6f7d5e9fd5cd6205f69ad /build.sc | |
parent | cb3c5f06b17de55a3d64faab79c081642b0c5a59 (diff) | |
download | mill-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-x | build.sc | 104 |
1 files changed, 103 insertions, 1 deletions
@@ -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{ |