summaryrefslogtreecommitdiff
path: root/src/build/genprod.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-06-17 20:51:33 +0000
committerPaul Phillips <paulp@improving.org>2009-06-17 20:51:33 +0000
commitcd7e1a17286cde131e93d1cb1b34dfd3e83d9d59 (patch)
treee1d99427617a570df5fc0e296f0f246e52e08e21 /src/build/genprod.scala
parent4788fee88e2cee8b072193bd11e4fe29c0ec8988 (diff)
downloadscala-cd7e1a17286cde131e93d1cb1b34dfd3e83d9d59.tar.gz
scala-cd7e1a17286cde131e93d1cb1b34dfd3e83d9d59.tar.bz2
scala-cd7e1a17286cde131e93d1cb1b34dfd3e83d9d59.zip
Close to complete rewrite of genprod so it's ea...
Close to complete rewrite of genprod so it's easier to modify and leverage for other exciting Foo1-Foo22 classes.
Diffstat (limited to 'src/build/genprod.scala')
-rw-r--r--src/build/genprod.scala474
1 files changed, 229 insertions, 245 deletions
diff --git a/src/build/genprod.scala b/src/build/genprod.scala
index 9e05ab6299..f5dd393d3d 100644
--- a/src/build/genprod.scala
+++ b/src/build/genprod.scala
@@ -17,85 +17,76 @@
* where <code>PATH</code> is the desired output directory
* </p>
*
- * @author Burak Emir, Stephane Micheloud, Geoffrey Washburn
+ * @author Burak Emir, Stephane Micheloud, Geoffrey Washburn, Paul Phillips
* @version 1.1
*/
object genprod {
+ val MAX_ARITY = 22
+ def arities = (1 to MAX_ARITY).toList
- /** The biggest ?? has Sup?? - 1 components/arguments */
- val SUP_PRODUCT_ARITY = 23
- val SUP_TUPLE_ARITY = 23
- val SUP_FUNCTION_ARITY = 23
-
- def productClassname(i: Int) = "Product"+i
- def productFilename(i: Int) = productClassname(i)+".scala"
-
- def tupleClassname(i: Int) = "Tuple"+i
- def tupleFilename(i: Int) = tupleClassname(i)+".scala"
-
- def functionClassname(i: Int) = "Function"+i
- def functionFilename(i: Int) = functionClassname(i)+".scala"
-
- def join(sep: String, xs: Seq[String]): String =
- if (xs.length == 0) ""
- else xs.drop(1).foldLeft(xs.first) { (acc, x) => acc + sep + x }
-
-
- def targs(i: Int) =
- for (j <- List.range(1, i+1)) yield "T" + j
-
- def covariantArgs(i: Int) =
- for (t <- targs(i)) yield "+" + t
-
- def contraCoArgs(i: Int) =
- (for (t <- targs(i)) yield "-" + t) ::: List("+R")
-
- def vdefs(i: Int) =
- for (j <- List.range(1, i+1)) yield "v" + j
-
- def mdefs(i: Int) =
- for (j <- List.range(1, i+1)) yield "_" + j
-
- def zippedAndCommaSeparated(left: List[String], right: List[String]): String = {
- val sb = new StringBuilder
- val it = (left zip right).iterator
- def append1 = {
- val p = it.next
- sb.append(p._1).append(':').append(p._2)
- }
- if (it.hasNext) {
- append1
- while(it.hasNext) { sb.append(", "); append1 }
- }
- sb.toString
+ class Group(val name: String) {
+ def className(i: Int) = name + i
+ def fileName(i: Int) = className(i) + ".scala"
}
- def fields(i: Int) = zippedAndCommaSeparated(mdefs(i), targs(i))
-
- def funArgs(i: Int) = zippedAndCommaSeparated(vdefs(i), targs(i))
-
- def productFiles =
- for (i <- List.range(1, SUP_PRODUCT_ARITY)) yield ProductFile.make(i)
+ def productFiles = arities map Product.make
+ def tupleFiles = arities map Tuple.make
+ def functionFiles = (0 :: arities) map Function.make
+ def allfiles = productFiles ::: tupleFiles ::: functionFiles
+
+ trait Arity extends Group {
+ def i: Int // arity
+
+ def typeArgsString(xs: Seq[String]) = xs.mkString("[", ", ", "]")
+
+ def to = (1 to i).toList
+ def s = if (i == 1) "" else "s"
+ def className = name + i
+ def fileName = className + ".scala"
+ def targs = to map ("T" + _)
+ def vdefs = to map ("v" + _)
+ def xdefs = to map ("x" + _)
+ def mdefs = to map ("_" + _)
+ def invariantArgs = typeArgsString(targs)
+ def covariantArgs = typeArgsString(targs map ("+" + _))
+ def contraCoArgs = typeArgsString((targs map ("-" + _)) ::: List("+R"))
+ def fields = List.map2(mdefs, targs)(_ + ":" + _) mkString ","
+ def funArgs = List.map2(vdefs, targs)(_ + ":" + _) mkString ","
+
+ def genprodString = "// generated by genprod on %s %s %s".format(now, withFancy, withMoreMethods)
+ def now = new java.util.Date().toString()
+ def moreMethods = ""
+ def descriptiveComment = ""
+ def withFancy = if (descriptiveComment.isEmpty) "" else "(with fancy comment)"
+ def withMoreMethods = if (moreMethods.isEmpty) "" else "(with extra methods)"
+
+ def header = """
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
- def tupleFiles =
- for (i <- List.range(1, SUP_TUPLE_ARITY)) yield TupleFile.make(i)
+// $Id$
- def functionFiles =
- for (i <- List.range(0, SUP_FUNCTION_ARITY)) yield FunctionFile.make(i)
+%s
- def allfiles =
- productFiles ::: tupleFiles ::: functionFiles
+package scala
+""".trim.format(genprodString) + "\n\n"
+ }
def main(args: Array[String]) {
if (args.length != 1) {
println("please give path of output directory")
exit(-1)
}
- import java.io.{File, FileOutputStream}
- import java.nio.channels.Channels
val out = args(0)
- for (node <- allfiles) {
- val f = new File(out + File.separator + node.attributes("name"))
+ def writeFile(node: scala.xml.Node) {
+ import java.io.{File, FileOutputStream}
+ import java.nio.channels.Channels
+ val f = new File(out, node.attributes("name").toString)
try {
f.createNewFile
val fos = new FileOutputStream(f)
@@ -109,222 +100,225 @@ object genprod {
exit(-1)
}
}
+
+ allfiles foreach writeFile
}
}
+import genprod._
+
/* zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
F U N C T I O N
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz */
-object FunctionFile {
- import genprod._
- def make(i: Int) = {
- val __typeArgs__ = contraCoArgs(i).mkString("[",", ","]")
- val __funArgs__ = funArgs(i)
-<file name={functionFilename(i)}>
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
+object FunctionZero extends Function(0) {
+ override def descriptiveComment = functionNTemplate.format("currentSeconds", "anonfun0", """
+ *
+ * <b>val</b> currentSeconds = () => System.currentTimeMillis() / 1000L
+ *
+ * <b>val</b> anonfun0 = <b>new</b> Function0[Long] {
+ * <b>def</b> apply(): Long = System.currentTimeMillis() / 1000L
+ * }
+ *
+ * println(currentSeconds())
+ * println(anonfun0())
+""")
+ override def moreMethods = ""
+}
+
+object FunctionOne extends Function(1) {
+ override def descriptiveComment = functionNTemplate.format("succ", "anonfun1", """
+ *
+ * <b>val</b> succ = (x: Int) => x + 1
+ *
+ * <b>val</b> anonfun1 = <b>new</b> Function1[Int, Int] {
+ * <b>def</b> apply(x: Int): Int = x + 1
+ * }
+ *
+ * println(succ(0))
+ * println(anonfun1(0))
+""")
+
+ override def moreMethods = """
+ /** (f compose g)(x) == f(g(x))
+ */
+ def compose[A](g: A => T1): A => R = { x => apply(g(x)) }
-// {"$Id$"}
+ /** (f andThen g)(x) == g(f(x))
+ */
+ def andThen[A](g: R => A): T1 => A = { x => g(apply(x)) }
+"""
+}
-// generated by genprod on {new java.util.Date().toString()} {if(descriptiveComment(i).length > 0) "(with fancy comment)" else ""} {if(moreMethods(i).length > 0) "(with extra methods)" else ""}
+object FunctionTwo extends Function(2) {
+ override def descriptiveComment = functionNTemplate.format("max", "anonfun2", """
+ *
+ * <b>val</b> max = (x: Int, y: Int) => <b>if</b> (x < y) y <b>else</b> x
+ *
+ * <b>val</b> anonfun2 = <b>new</b> Function2[Int, Int, Int] {
+ * <b>def</b> apply(x: Int, y: Int): Int = <b>if</b> (x < y) y <b>else</b> x
+ * }
+ *
+ * println(max(0, 1))
+ * println(anonfun2(0, 1))
+""")
+}
-package scala
+object Function
+{
+ def make(i: Int) = apply(i)()
+ def apply(i: Int) = i match {
+ case 0 => FunctionZero
+ case 1 => FunctionOne
+ case 2 => FunctionTwo
+ case _ => new Function(i)
+ }
+}
+class Function(val i: Int) extends Group("Function") with Arity
+{
+ val functionNTemplate = """<p>
+ In the following example the definition of
+ * <code>%s</code> is a shorthand for the anonymous class
+ * definition <code>%s</code>:
+ * </p>
+ * <pre>
+ * <b>object</b> Main <b>extends</b> Application { %s
+ * }</pre>"""
+
+ def toStr() = "\"" + ("<function%d>" format i) + "\""
+ def apply() = {
+<file name={fileName}>{header}
/** &lt;p&gt;
- * Function with {i} parameters.
+ * Function with {i} parameter{s}.
* &lt;/p&gt;
- * {descriptiveComment(i)}
+ * {descriptiveComment}
*/
-trait {functionClassname(i)}{__typeArgs__} extends AnyRef {{ self =>
- def apply({__funArgs__}): R
- override def toString() = "&lt;function>"
- {moreMethods(i)}
+trait {className}{contraCoArgs} extends AnyRef {{ self =>
+ def apply({funArgs}): R
+ override def toString() = {toStr}
+ {moreMethods}
}}
</file>
}
+ // (x1: T1) => (x2: T2) => (x3: T3) => (x4: T4) => apply(x1,x2,x3,x4)
+ def shortCurry = {
+ val body = xdefs.mkString("apply(", ",", ")")
+ List.map2(xdefs, targs)("(%s: %s) => ".format(_, _)).mkString("", "", body)
+ }
- def moreMethods(i:Int) = i match {
- case 1 => """
- /** (f compose g)(x) == f(g(x))
- */
- def compose[A](g: A => T1): A => R = { x => apply(g(x)) }
+ // (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7) => self.apply(x1,x2,x3,x4,x5,x6,x7)).curry
+ def longCurry = (List.map2(xdefs, targs)(_ + ": " + _) drop 1).mkString(
+ "(x1: T1) => ((",
+ ", ",
+ ") => self.apply(%s)).curry".format(xdefs mkString ",")
+ )
- /** (f andThen g)(x) == g(f(x))
+ // f(x1,x2,x3,x4,x5,x6) == (f.curry)(x1)(x2)(x3)(x4)(x5)(x6)
+ def curryComment = { """
+ /** f(%s) == (f.curry)%s
*/
- def andThen[A](g: R => A): T1 => A = { x => g(apply(x)) }
-"""
- case _ if (i > 1) => """
- /** f(""" + join(",", (1 to i).map(i => "x" + i)) + """) == (f.curry)""" + join("", (1 to i).map(i => "(x" + i + ")")) + """
- */
- def curry: """ + join(" => ", (1 to i).map(i => "T" + i)) + """ => R = {
-""" +
- (if (i < 5) {
- " " + join(" => ", (1 to i).map(i => "(x" + i + ": T" + i + ")")) + """ => apply(""" + join(",", (1 to i).map(i => "x" + i)) + ")\n }"
- } else {
- """ (x1: T1) => ((""" + join(", ", (2 to i).map(i => "x" + i + ": T" + i)) + """) => self.apply(""" + join(",", (1 to i).map(i => "x" + i)) + ")).curry\n }"
- })
- case _ => """
-"""
-
+""".format(xdefs mkString ",", xdefs map ("(" + _ + ")") mkString)
}
- def descriptiveComment(i: Int) = i match {
- case 0 => """<p>
- In the following example the definition of
- * <code>currentSeconds</code> is a shorthand for the anonymous class
- * definition <code>anonfun0</code>:
- * </p>
- * <pre>
- * <b>object</b> Main <b>extends</b> Application {
- *
- * <b>val</b> currentSeconds = () => System.currentTimeMillis() / 1000L
- *
- * <b>val</b> anonfun0 = <b>new</b> Function0[Long] {
- * <b>def</b> apply(): Long = System.currentTimeMillis() / 1000L
- * }
- *
- * println(currentSeconds())
- * println(anonfun0())
- * }</pre>"""
- case 1 => """<p>
- In the following example the definition of
- * <code>succ</code> is a shorthand for the anonymous class definition
- * <code>anonfun1</code>:
- * </p>
- * <pre>
- * <b>object</b> Main <b>extends</b> Application {
- *
- * <b>val</b> succ = (x: Int) => x + 1
- *
- * <b>val</b> anonfun1 = <b>new</b> Function1[Int, Int] {
- * <b>def</b> apply(x: Int): Int = x + 1
- * }
- *
- * println(succ(0))
- * println(anonfun1(0))
- * }</pre>"""
- case 2 => """<p>
- In the following example the definition of
- * <code>max</code> is a shorthand for the anonymous class definition
- * <code>anonfun2</code>:
- * </p>
- * <pre>
- * <b>object</b> Main <b>extends</b> Application {
- *
- * <b>val</b> max = (x: Int, y: Int) => <b>if</b> (x < y) y <b>else</b> x
- *
- * <b>val</b> anonfun2 = <b>new</b> Function2[Int, Int, Int] {
- * <b>def</b> apply(x: Int, y: Int): Int = <b>if</b> (x < y) y <b>else</b> x
- * }
- *
- * println(max(0, 1))
- * println(anonfun2(0, 1))
- * }</pre>"""
- case _ => ""
+
+ def curryMethod = {
+ val body = if (i < 5) shortCurry else longCurry
+ " def curry: %s => R = {\n %s\n }\n".format(
+ targs mkString " => ", body
+ )
}
-} // object FunctionFile
+ override def moreMethods = curryComment + curryMethod
+} // object Function
+
+
/* zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
T U P L E
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz */
-object TupleFile {
- import genprod._
- def make(i: Int) = {
- val __typeArgs__ = covariantArgs(i).mkString("[",", ","]")
- val __typeArgRefs__ = targs(i).mkString("[",", ","]")
- val __fields__ = fields(i)
-<file name={tupleFilename(i)}>
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
+object Tuple
+{
+ def make(i: Int) = apply(i)()
+ def apply(i: Int) = i match {
+ case 2 => TupleTwo
+ case _ => new Tuple(i)
+ }
+}
-// {"$Id$"}
+object TupleTwo extends Tuple(2)
+{
+ override def moreMethods = """
+ /** Swap the elements of the tuple */
+ def swap: Tuple2[T2,T1] = Tuple2(_2, _1)
+"""
+}
-// generated by genprod on {new java.util.Date().toString()} {if(descriptiveComment(i).length > 0) "(with fancy comment)" else ""} {if(moreMethods(i).length > 0) "(with extra methods)" else ""}
+class Tuple(val i: Int) extends Group("Tuple") with Arity
+{
+ // prettifies it a little if it's overlong
+ def mkToString() = {
+ def str(xs: List[String]) = xs.mkString(""" + ", " + """)
+ if (i <= MAX_ARITY / 2) str(mdefs)
+ else {
+ val s1 = str(mdefs take (i / 2))
+ val s2 = str(mdefs drop (i / 2))
+ s1 + " +\n \", \" + " + s2
+ }
+ }
-package scala
+ def apply() = {
+<file name={fileName}>{header}
-/** {tupleClassname(i)} is the canonical representation of a @see {productClassname(i)}
- * {descriptiveComment(i)}
+/** {className} is the canonical representation of a @see {Product.className(i)}
+ * {descriptiveComment}
*/
-case class {tupleClassname(i)}{__typeArgs__}({ __fields__ })
- extends {productClassname(i)}{__typeArgRefs__} {{
-
- override def toString() = {{
- val sb = new StringBuilder
- { if ({i} == 1)
- "sb.append('(').append(_" + {i} + ").append(\",)\")"
- else {
- val xs = (1 to i).map(i => ".append(_" + i + ")")
- xs.mkString("sb.append('(')", ".append(',')",".append(')')")
- }
- }
- sb.toString
- }}
- {moreMethods(i)}
+case class {className}{covariantArgs}({fields})
+ extends {Product.className(i)}{invariantArgs}
+{{
+ override def toString() = "(" + {mkToString} + ")"
+ {moreMethods}
}}
</file>}
- def moreMethods(i:Int) = i match {
- case 2 => """
- /** Swap the elements of the tuple */
- def swap: Tuple2[T2,T1] = Tuple2(_2, _1)
-"""
- case _ => ""
- }
- def descriptiveComment(i: Int) = i match {
- case _ => ""
- }
-} // object TupleFile
-
+} // object Tuple
/* zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
P R O D U C T
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz */
-object ProductFile {
- import genprod._
- def make(i:Int) = {
- val __typeArgs__ = if (i==0) Nil else covariantArgs(i).mkString("[",", ","]")
- val __refArgs__ = if (i==0) Nil else targs(i).mkString("[",", ","]")
-<file name={productFilename(i)}>
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-// {"$Id$"}
-
-// generated by genprod on {new java.util.Date().toString()} {if(descriptiveComment(i).length > 0) "(with fancy comment)" else ""} {if(moreMethods(i).length > 0) "(with extra methods)" else ""}
+object Product extends Group("Product")
+{
+ def make(i: Int) = apply(i)()
+ def apply(i: Int) = new Product(i)
+}
-package scala
+class Product(val i: Int) extends Group("Product") with Arity
+{
+ def cases = {
+ val xs = for ((x, i) <- mdefs.zipWithIndex) yield "case %d => %s".format(i, x)
+ val default = "case _ => throw new IndexOutOfBoundsException(n.toString())"
+ "\n" + ((xs ::: List(default)) map (" " + _ + "\n") mkString)
+ }
+ def proj = {
+ List.map2(mdefs, targs)(
+ " /** projection of this product */\n def %s: %s\n\n".format(_, _)
+ ) mkString
+ }
+ def apply() = {
+<file name={fileName}>{header}
import Predef._
-object {productClassname(i)} {{
- def unapply{__refArgs__}(x: {productClassname(i)}{__refArgs__}): Option[{productClassname(i)}{__refArgs__}] =
+object {className} {{
+ def unapply{invariantArgs}(x: {className}{invariantArgs}): Option[{className}{invariantArgs}] =
Some(x)
}}
-/** {productClassname(i)} is a cartesian product of {i} components
- * {descriptiveComment(i)}
+/** {className} is a cartesian product of {i} component{s}.
+ * {descriptiveComment}
*/
-trait {productClassname(i)}{__typeArgs__} extends Product {{
-
+trait {className}{covariantArgs} extends Product {{
/**
* The arity of this product.
* @return {i}
@@ -340,21 +334,11 @@ trait {productClassname(i)}{__typeArgs__} extends Product {{
* @throws IndexOutOfBoundsException
*/
@throws(classOf[IndexOutOfBoundsException])
- override def productElement(n: Int) = n match {{
- {for ((m, j) <- mdefs(i).zip(List.range(0, i)))
- yield "case "+j+" => "+m+"\n "}case _ => throw new IndexOutOfBoundsException(n.toString())
- }}
-
- {for ((m, t) <- mdefs(i) zip targs(i)) yield
- "/** projection of this product */\n def " + m + ": " + t + "\n\n" }
+ override def productElement(n: Int) = n match {{ {cases} }}
- {moreMethods(i)}
+{proj}
+{moreMethods}
}}
</file>}
- def moreMethods(i:Int) = i match {
- case _ => ""
- }
- def descriptiveComment(i: Int) = i match {
- case _ => ""
- }
-};
+
+} \ No newline at end of file