Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cec8baf

Browse files
committedMar 14, 2014
Merge pull request #4 from retronym/topic/2.10-support
Topic/2.10 support
2 parents 9f5fe46 + 909f39d commit cec8baf

File tree

2 files changed

+102
-49
lines changed

2 files changed

+102
-49
lines changed
 

‎build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
scalaVersion := "2.11.0-RC1"
1+
scalaVersion := "2.10.3"
22

33
sourceGenerators in Compile <+= sourceManaged in Compile map { dir =>
44
def write(name: String, content: String) = {

‎project/CodeGen.scala

Lines changed: 101 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -147,71 +147,124 @@ object CodeGen {
147147
| * Copyright (C) 2012-2014 Typesafe Inc. <http://www.typesafe.com>
148148
| */""".stripMargin.trim
149149

150-
private def apply0MethodSpec(r: Type): String = {
151-
val name = "apply$mc" + s"${r.code}" + "$sp"
152-
val applyCall = s"apply();"
153-
def body = if (r == Type.Void) applyCall else s"return (${r.ref}) $applyCall"
154-
s"""
155-
|default ${r.prim} $name() {
156-
| $body
157-
|}
158-
|""".stripMargin.trim
150+
private def function0SpecMethods = {
151+
val apply = specialized("apply", function0Spec) {
152+
case (name, List(r)) =>
153+
val applyCall = s"apply();"
154+
def body = if (r == Type.Void) applyCall else s"return (${r.ref}) $applyCall"
155+
s"""
156+
|default ${r.prim} $name() {
157+
| $body
158+
|}
159+
|""".stripMargin.trim
160+
}
161+
indent(apply)
159162
}
160163

161-
private def apply0SpecMethods = {
164+
private val function0Spec = {
162165
val rs = List(Type.Void, Type.Byte, Type.Short, Type.Int, Type.Long, Type.Char, Type.Float, Type.Double, Type.Boolean)
163-
val methods = for (r <- rs) yield apply0MethodSpec(r)
164-
methods.map(indent).mkString("\n\n")
165-
}
166-
167-
private def apply1MethodSpec(t1: Type, r: Type): String = {
168-
val name = "apply$mc" + s"${r.code}${t1.code}" + "$sp"
169-
val applyCall = s"apply((T1) ((${t1.ref}) v1));"
170-
def body = if (r == Type.Void) applyCall else s"return (${r.ref}) $applyCall"
171-
172-
s"""
173-
|default ${r.prim} $name(${t1.prim} v1) {
174-
| $body
175-
|}
176-
|""".stripMargin.trim
166+
List("R" -> rs)
177167
}
178-
179-
private def apply1SpecMethods = {
168+
private val function1Spec = {
180169
val ts = List(Type.Int, Type.Long, Type.Float, Type.Double)
181170
val rs = List(Type.Void, Type.Boolean, Type.Int, Type.Float, Type.Long, Type.Double)
182-
val methods = for (t1 <- ts; r <- rs) yield apply1MethodSpec(t1, r)
183-
methods.map(indent).mkString("\n\n")
171+
List("T1" -> ts, "R" -> rs)
172+
}
173+
private val function2Spec = {
174+
val ts = List(Type.Int, Type.Long, Type.Double)
175+
val rs = List(Type.Void, Type.Boolean, Type.Int, Type.Float, Type.Long, Type.Double)
176+
List("T1" -> ts, "T2" -> ts, "R" -> rs)
184177
}
185178

186-
private def apply2MethodSpec(t1: Type, t2: Type, r: Type): String = {
187-
val name = "apply$mc" + s"${r.code}${t1.code}${t2.code}" + "$sp"
188-
val applyCall = s"apply((T1) ((${t1.ref}) v1), (T2) ((${t2.ref}) v2));"
189-
def body = if (r == Type.Void) applyCall else s"return (${r.ref}) $applyCall"
179+
private def function1SpecMethods = {
180+
val apply = specialized("apply", function1Spec) {
181+
case (name, List(t1, r)) =>
182+
val applyCall = s"apply((T1) ((${t1.ref}) v1));"
183+
def body = if (r == Type.Void) applyCall else s"return (${r.ref}) $applyCall"
184+
s"""
185+
|default ${r.prim} $name(${t1.prim} v1) {
186+
| $body
187+
|}
188+
|""".stripMargin.trim
189+
}
190+
// andThen / compose variants are no longer needed under 2.11 (@unspecialized has been fixed),
191+
// but harmless. With them, we can use the same artifact for 2.10 and 2.11
192+
val compose = specialized("compose", function1Spec) {
193+
case (name, List(t1, r1)) =>
194+
s"""
195+
|default scala.Function1 $name(scala.Function1 g) {
196+
| return compose(g);
197+
|}""".stripMargin.trim
198+
}
199+
val andThen = specialized("andThen", function1Spec) {
200+
case (name, List(t1, r1)) =>
201+
s"""
202+
|default scala.Function1 $name(scala.Function1 g) {
203+
| return andThen(g);
204+
|}""".stripMargin.trim
205+
}
206+
indent(List(apply, compose, andThen).mkString("\n\n"))
207+
}
190208

191-
s"""
192-
|default ${r.prim} $name(${t1.prim} v1, ${t2.prim} v2) {
193-
| $body
194-
|}
195-
|""".stripMargin.trim
209+
// No longer needed under 2.11 (@unspecialized has been fixed), but harmless to keep around to avoid cross-publishing this artifact.
210+
private def function2SpecMethods = {
211+
val apply = specialized("apply", function2Spec) {
212+
case (name, List(t1, t2, r)) =>
213+
val applyCall = s"apply((T1) ((${t1.ref}) v1), (T2) ((${t2.ref}) v2));"
214+
def body = if (r == Type.Void) applyCall else s"return (${r.ref}) $applyCall"
215+
216+
s"""
217+
|default ${r.prim} $name(${t1.prim} v1, ${t2.prim} v2) {
218+
| $body
219+
|}
220+
|""".stripMargin.trim
221+
}
222+
val curried = specialized("curried", function2Spec) {
223+
case (name, List(t1, t2, r)) =>
224+
s"""
225+
|default scala.Function1 $name() {
226+
| return curried();
227+
|}""".stripMargin.trim
228+
}
229+
val tupled = specialized("tupled", function2Spec) {
230+
case (name, List(t1, t2, r)) =>
231+
s"""
232+
|default scala.Function1 $name() {
233+
| return tupled();
234+
|}""".stripMargin.trim
235+
}
236+
indent(List(apply, curried, tupled).mkString("\n\n"))
196237
}
197238

198-
private def apply2SpecMethods = {
199-
val ts = List(Type.Int, Type.Long, Type.Double)
200-
val rs = List(Type.Void, Type.Boolean, Type.Int, Type.Float, Type.Long, Type.Double)
201-
val methods = for (t1 <- ts; t2 <- ts; r <- rs) yield apply2MethodSpec(t1, t2, r)
202-
methods.map(indent).mkString("\n\n")
239+
private def specialized(name: String, tps: List[(String, List[Type])])(f: (String, List[Type]) => String): String = {
240+
val tparamNames = tps.map(_._1)
241+
def code(tps: List[Type]) = {
242+
val sorted = (tps zip tparamNames).sortBy(_._2).map(_._1) // as per scalac, sort by tparam name before assembling the code
243+
sorted.map(_.code).mkString
244+
}
245+
val ms = for {
246+
variantTypes <- crossProduct(tps.map(_._2))
247+
specName = name + "$mc" + code(variantTypes) + "$sp"
248+
} yield f(specName, variantTypes)
249+
ms.mkString("\n")
250+
}
251+
252+
def crossProduct[A](input: List[List[A]]): List[List[A]] = input match {
253+
case Nil => Nil
254+
case head :: Nil => head.map(_ :: Nil)
255+
case head :: tail => for (elem <- head; sub <- crossProduct(tail)) yield elem :: sub
203256
}
204257

205258
def fN(n: Int) = {
206259
val header = arity(n).fHeader
207-
val applyMethods = n match {
208-
case 0 => apply0SpecMethods
209-
case 1 => apply1SpecMethods
210-
case 2 => apply2SpecMethods
260+
val specializedVariants = n match {
261+
case 0 => function0SpecMethods
262+
case 1 => function1SpecMethods
263+
case 2 => function2SpecMethods
211264
case x => ""
212265
}
213-
val trailer = "}\n"
214-
List(header, applyMethods, trailer).mkString
266+
val trailer = "\n}\n"
267+
List(header, specializedVariants, trailer).mkString
215268
}
216269

217270
def pN(n: Int) = arity(n).pN

0 commit comments

Comments
 (0)
Please sign in to comment.