summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-10-16 20:42:37 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2017-10-16 20:42:37 -0700
commitcb05d5a1df3d4b7f89ecf0d95d8b9fe0dc40ae3a (patch)
treee1032e6c7067726df9ddb821acaa6168943d93a7
parent191591f8ca8b577807aeabd4d065f293afcca1ec (diff)
downloadmill-cb05d5a1df3d4b7f89ecf0d95d8b9fe0dc40ae3a.tar.gz
mill-cb05d5a1df3d4b7f89ecf0d95d8b9fe0dc40ae3a.tar.bz2
mill-cb05d5a1df3d4b7f89ecf0d95d8b9fe0dc40ae3a.zip
Fleshed out basic implementations
-rw-r--r--build.sbt33
-rw-r--r--src/main/scala/hbt/Implicits.scala71
-rw-r--r--src/main/scala/hbt/Main.scala84
3 files changed, 187 insertions, 1 deletions
diff --git a/build.sbt b/build.sbt
index 6836cb4f..6d412fc5 100644
--- a/build.sbt
+++ b/build.sbt
@@ -3,3 +3,36 @@ scalaVersion := "2.12.3"
name := "hbt"
organization := "com.lihaoyi"
+
+
+libraryDependencies += "com.lihaoyi" %% "sourcecode" % "0.1.4"
+
+sourceGenerators in Compile += Def.task {
+ val dir = (sourceManaged in Compile).value
+ val file = dir/"fasterparser"/"SequencerGen.scala"
+ // Only go up to 21, because adding the last element makes it 22
+ val tuples = (2 to 21).map{ i =>
+ val ts = (1 to i) map ("T" + _)
+ val chunks = (1 to i) map { n =>
+ s"t._$n"
+ }
+ val tsD = (ts :+ "D").mkString(",")
+ s"""
+ implicit def Sequencer$i[$tsD]: Sequencer[(${ts.mkString(", ")}), D, ($tsD)] =
+ Sequencer0((t, d) => (${chunks.mkString(", ")}, d))
+ """
+ }
+ val output = s"""
+ package hbt
+ trait SequencerGen[Sequencer[_, _, _]] extends LowestPriSequencer[Sequencer]{
+ protected[this] def Sequencer0[A, B, C](f: (A, B) => C): Sequencer[A, B, C]
+ ${tuples.mkString("\n")}
+ }
+ trait LowestPriSequencer[Sequencer[_, _, _]]{
+ protected[this] def Sequencer0[A, B, C](f: (A, B) => C): Sequencer[A, B, C]
+ implicit def Sequencer1[T1, T2]: Sequencer[T1, T2, (T1, T2)] = Sequencer0{case (t1, t2) => (t1, t2)}
+ }
+ """.stripMargin
+ IO.write(file, output)
+ Seq(file)
+} \ No newline at end of file
diff --git a/src/main/scala/hbt/Implicits.scala b/src/main/scala/hbt/Implicits.scala
new file mode 100644
index 00000000..b9b12905
--- /dev/null
+++ b/src/main/scala/hbt/Implicits.scala
@@ -0,0 +1,71 @@
+package hbt
+
+
+import scala.collection.mutable
+
+/**
+ * Container for all the type-level logic around appending things
+ * to tuples or flattening `Seq[Unit]`s into `Unit`s.
+ *
+ * Some of these implicits make liberal use of mutable state, so as
+ * to minimize allocations while parsing.
+ */
+object Implicits {
+ trait Sequencer[-T, V, R]{
+ def apply(t: T, v: V): R
+ }
+ object Sequencer extends LowPriSequencer{
+ def apply[T, V, R](f: (T, V) => R) = new Sequencer[T, V, R]{
+ def apply(t: T, v: V): R = f(t, v)
+ }
+ implicit def SingleSequencer[T]: Sequencer[Unit, T, T] = Sequencer( (_, t) => t )
+ }
+ trait LowPriSequencer extends LowerPriSequencer{
+ implicit def UnitSequencer[T]: Sequencer[T, Unit, T] = Sequencer( (t, _) => t )
+ }
+ trait LowerPriSequencer extends SequencerGen[Sequencer]{
+ protected[this] def Sequencer0[A, B, C](f: (A, B) => C) = Sequencer(f)
+ }
+ trait Repeater[-T, R]{
+ type Acc
+ def initial: Acc
+ def accumulate(t: T, acc: Acc): Unit
+ def result(acc: Acc): R
+ }
+ object Repeater extends LowPriRepeater{
+ implicit object UnitRepeater extends Repeater[Unit, Unit]{
+ type Acc = Unit
+ def initial = ()
+ def accumulate(t: Unit, acc: Unit) = acc
+ def result(acc: Unit) = ()
+ }
+ }
+ trait LowPriRepeater{
+ implicit def GenericRepeaterImplicit[T] = GenericRepeater[T]()
+ case class GenericRepeater[T]() extends Repeater[T, Seq[T]]{
+ type Acc = mutable.Buffer[T]
+ def initial = mutable.Buffer.empty[T]
+ def accumulate(t: T, acc: mutable.Buffer[T]) = acc += t
+ def result(acc: mutable.Buffer[T]) = acc
+ }
+ }
+
+ trait Optioner[-T, R]{
+ def none: R
+ def some(value: T): R
+ }
+
+ object Optioner extends LowPriOptioner{
+ implicit object UnitOptioner extends Optioner[Unit, Unit]{
+ def none = ()
+ def some(value: Unit) = ()
+ }
+ }
+ trait LowPriOptioner{
+ implicit def GenericOptionerImplicit[T] = GenericOptioner[T]()
+ case class GenericOptioner[T]() extends Optioner[T, Option[T]]{
+ def none = None
+ def some(value: T) = Some(value)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/scala/hbt/Main.scala b/src/main/scala/hbt/Main.scala
index a8009735..6dc934e4 100644
--- a/src/main/scala/hbt/Main.scala
+++ b/src/main/scala/hbt/Main.scala
@@ -1,6 +1,88 @@
package hbt
+import java.io.FileOutputStream
+
+import collection.JavaConverters._
+import java.nio.file.{Path => JPath}
+import java.util.jar.JarEntry
+import sourcecode.Enclosing
+sealed trait Target[T]{
+ def path: String
+ def map[V](f: T => V)(implicit path: Enclosing) = {
+ Target.Mapped(this, f, path.value)
+ }
+ def zip[V](other: Target[V])(implicit path: Enclosing) = {
+ Target.Zipped(this, other, path.value)
+ }
+ def ~[V, R](other: Target[V])
+ (implicit s: Implicits.Sequencer[T, V, R]): Target[R] = {
+ this.zip(other).map(s.apply _ tupled)
+ }
+
+}
+
+object Target{
+ def traverse[T](source: Seq[Target[T]])(implicit path: Enclosing) = {
+ Traverse(source, path.value)
+ }
+ case class Traverse[T](source: Seq[Target[T]], path: String) extends Target[Seq[T]]
+ case class Mapped[T, V](source: Target[T], f: T => V,
+ path: String) extends Target[V]
+ case class Zipped[T, V](source: Target[T],
+ source2: Target[V],
+ path: String) extends Target[(T, V)]
+ case class Path(path: String) extends Target[JPath]
+ case class Command(inputs: Seq[Target[JPath]],
+ output: Seq[Target[JPath]],
+ path: String) extends Target[Command.Result]
+ object Command{
+ case class Result(stdout: String,
+ stderr: String,
+ writtenFiles: Seq[JPath])
+ }
+}
object Main{
+ def compileAll(sources: Target[Seq[JPath]])
+ (implicit path: Enclosing): Target[JPath] = {
+ for(sources0 <- sources) yield {
+ val output = java.nio.file.Paths.get(path.value)
+ java.nio.file.Files.createDirectories(output)
+ val command =
+ Seq("scalac") ++
+ sources0.map(_.toString) ++
+ Seq("-d", path.value)
+
+
+
+ new java.lang.ProcessBuilder()
+ .command(command: _*)
+ .start()
+ .waitFor()
+
+ output
+ }
+ }
+
+ def list(root: Target[JPath]): Target[Seq[JPath]] = {
+ root.map(java.nio.file.Files.list(_).iterator().asScala.toArray[JPath])
+ }
+ def jarUp(roots: Target[JPath]*)(implicit path: Enclosing): Target[JPath] = {
+ for(rootsValue <- Target.traverse(roots)) yield {
+ val output = new java.util.jar.JarOutputStream(new FileOutputStream(path.value))
+ for{
+ root <- rootsValue
+ path <- java.nio.file.Files.list(root).iterator().asScala
+ }{
+ val relative = root.relativize(path)
+ output.putNextEntry(new JarEntry(relative.toString))
+ output.write(java.nio.file.Files.readAllBytes(path))
+ }
+ java.nio.file.Paths.get(path.value)
+ }
+ }
def main(args: Array[String]): Unit = {
- println("Hello")
+ val sourceRoot: Target[JPath] = ???
+ val resourceRoot: Target[JPath] = ???
+ val classFiles: Target[JPath] = compileAll(list(sourceRoot))
+ val jar: Target[JPath] = jarUp(resourceRoot, classFiles)
}
} \ No newline at end of file