From cd7e1a17286cde131e93d1cb1b34dfd3e83d9d59 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 17 Jun 2009 20:51:33 +0000 Subject: 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. --- src/build/genprod.scala | 474 +++++++++++++++++++++++------------------------- 1 file 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 PATH is the desired output directory *

* - * @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) - -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ +object FunctionZero extends Function(0) { + override def descriptiveComment = functionNTemplate.format("currentSeconds", "anonfun0", """ + * + * val currentSeconds = () => System.currentTimeMillis() / 1000L + * + * val anonfun0 = new Function0[Long] { + * def apply(): Long = System.currentTimeMillis() / 1000L + * } + * + * println(currentSeconds()) + * println(anonfun0()) +""") + override def moreMethods = "" +} + +object FunctionOne extends Function(1) { + override def descriptiveComment = functionNTemplate.format("succ", "anonfun1", """ + * + * val succ = (x: Int) => x + 1 + * + * val anonfun1 = new Function1[Int, Int] { + * def 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", """ + * + * val max = (x: Int, y: Int) => if (x < y) y else x + * + * val anonfun2 = new Function2[Int, Int, Int] { + * def apply(x: Int, y: Int): Int = if (x < y) y else 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 = """

+ In the following example the definition of + * %s is a shorthand for the anonymous class + * definition %s: + *

+ *
+  *  object Main extends Application { %s
+  *  }
""" + + def toStr() = "\"" + ("" format i) + "\"" + def apply() = { +{header} /** <p> - * Function with {i} parameters. + * Function with {i} parameter{s}. * </p> - * {descriptiveComment(i)} + * {descriptiveComment} */ -trait {functionClassname(i)}{__typeArgs__} extends AnyRef {{ self => - def apply({__funArgs__}): R - override def toString() = "<function>" - {moreMethods(i)} +trait {className}{contraCoArgs} extends AnyRef {{ self => + def apply({funArgs}): R + override def toString() = {toStr} + {moreMethods} }} } + // (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 => """

- In the following example the definition of - * currentSeconds is a shorthand for the anonymous class - * definition anonfun0: - *

- *
- *  object Main extends Application {
- *
- *    val currentSeconds = () => System.currentTimeMillis() / 1000L
- *
- *    val anonfun0 = new Function0[Long] {
- *      def apply(): Long = System.currentTimeMillis() / 1000L
- *    }
- *
- *    println(currentSeconds())
- *    println(anonfun0())
- *  }
""" - case 1 => """

- In the following example the definition of - * succ is a shorthand for the anonymous class definition - * anonfun1: - *

- *
- *  object Main extends Application {
- *
- *    val succ = (x: Int) => x + 1
- *
- *    val anonfun1 = new Function1[Int, Int] {
- *      def apply(x: Int): Int = x + 1
- *    }
- *
- *    println(succ(0))
- *    println(anonfun1(0))
- *  }
""" - case 2 => """

- In the following example the definition of - * max is a shorthand for the anonymous class definition - * anonfun2: - *

- *
- *  object Main extends Application {
- *
- *    val max = (x: Int, y: Int) => if (x < y) y else x
- *
- *    val anonfun2 = new Function2[Int, Int, Int] {
- *      def apply(x: Int, y: Int): Int = if (x < y) y else x
- *    }
- *
- *    println(max(0, 1))
- *    println(anonfun2(0, 1))
- *  }
""" - 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) - -/* __ *\ -** ________ ___ / / ___ 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() = { +{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} }} } - 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("[",", ","]") - -/* __ *\ -** ________ ___ / / ___ 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() = { +{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} }} } - def moreMethods(i:Int) = i match { - case _ => "" - } - def descriptiveComment(i: Int) = i match { - case _ => "" - } -}; + +} \ No newline at end of file -- cgit v1.2.3