@@ -10,9 +10,9 @@ object WrapFnGen {
10
10
| * This file auto-generated by WrapFnGen.scala. Do not modify directly.
11
11
| */
12
12
| """ .stripMargin
13
-
13
+
14
14
val packaging = " package scala.compat.java8"
15
-
15
+
16
16
import scala .tools .nsc ._
17
17
import scala .reflect .internal ._
18
18
val settings = new Settings (msg => sys.error(msg))
@@ -21,12 +21,12 @@ object WrapFnGen {
21
21
val run = new compiler.Run
22
22
23
23
import compiler ._ , definitions ._
24
-
25
-
24
+
25
+
26
26
implicit class IndentMe (v : Vector [String ]) {
27
27
def indent : Vector [String ] = v.map(" " + _)
28
28
}
29
-
29
+
30
30
implicit class FlattenMe (v : Vector [Vector [String ]]) {
31
31
def mkVec (join : String = " " ): Vector [String ] = {
32
32
val vb = Vector .newBuilder[String ]
@@ -39,7 +39,7 @@ object WrapFnGen {
39
39
vb.result()
40
40
}
41
41
}
42
-
42
+
43
43
implicit class DoubleFlattenMe (v : Vector [Vector [Vector [String ]]]) {
44
44
def mkVecVec (join : String = " " ): Vector [String ] = {
45
45
val vb = Vector .newBuilder[String ]
@@ -57,39 +57,39 @@ object WrapFnGen {
57
57
vb.result()
58
58
}
59
59
}
60
-
60
+
61
61
implicit class SplitMyLinesAndStuff (s : String ) {
62
62
def toVec = s.linesIterator.toVector
63
63
def nonBlank = s.trim.length > 0
64
64
}
65
-
65
+
66
66
implicit class TreeToText (t : Tree ) {
67
67
def text = showCode(t).replace(" $" , " " ).linesIterator.toVector
68
68
}
69
-
69
+
70
70
case class Prioritized (lines : Vector [String ], priority : Int ) {
71
71
def withPriority (i : Int ) = copy(priority = i)
72
72
}
73
-
73
+
74
74
case class SamConversionCode (
75
75
base : String ,
76
76
wrappedAsScala : Vector [String ],
77
+ asScalaAnyVal : Vector [String ],
77
78
implicitToScala : Vector [String ],
78
79
asScalaDef : Vector [String ],
79
80
wrappedAsJava : Vector [String ],
80
81
asJavaAnyVal : Vector [String ],
81
82
implicitToJava : Prioritized ,
82
83
asJavaDef : Vector [String ]
83
84
) {
84
- def impls : Vector [Vector [String ]] = Vector (wrappedAsScala, wrappedAsJava, asJavaAnyVal)
85
+ def impls : Vector [Vector [String ]] = Vector (wrappedAsScala, asScalaAnyVal, wrappedAsJava, asJavaAnyVal)
85
86
def defs : Vector [Vector [String ]] = Vector (asScalaDef, asJavaDef)
86
- def convs : Vector [Vector [String ]] = Vector (implicitToScala, implicitToJava.lines)
87
87
def withPriority (i : Int ): SamConversionCode = copy(implicitToJava = implicitToJava.withPriority(i))
88
88
}
89
89
object SamConversionCode {
90
90
def apply (scc : SamConversionCode * ): (Vector [String ], Vector [Vector [String ]]) = {
91
91
val sccDepthSet = scc.map(_.implicitToJava.priority).toSet
92
- val codes =
92
+ val codes =
93
93
{
94
94
if (sccDepthSet != (0 to sccDepthSet.max).toSet) {
95
95
val sccDepthMap = sccDepthSet.toList.sorted.zipWithIndex.toMap
@@ -98,43 +98,46 @@ object WrapFnGen {
98
98
else scc
99
99
}.toVector.sortBy(_.base)
100
100
def priorityName (n : Int , pure : Boolean = false ): String = {
101
- val pre =
101
+ val pre =
102
102
if (n <= 0 )
103
- if (pure) " functionConverters "
103
+ if (pure) " FunctionConverters "
104
104
else s " package object ${priorityName(n, pure = true )}"
105
105
else
106
106
if (pure) s " Priority ${n}FunctionConverters "
107
107
else s " trait ${priorityName(n, pure = true )}"
108
- if (! pure && n < sccDepthSet.size) s " $pre extends ${priorityName(n+ 1 , pure = true )}" else pre
108
+ if (! pure && n < ( sccDepthSet.size- 1 ) ) s " $pre extends ${priorityName(n+ 1 , pure = true )}" else pre
109
109
}
110
- val impls =
110
+ val impls =
111
111
" package functionConverterImpls {" +: {
112
112
codes.map(_.impls).mkVecVec().indent
113
113
} :+ " }"
114
114
val traits = codes.filter(_.implicitToJava.priority > 0 ).groupBy(_.implicitToJava.priority).toVector.sortBy(- _._1).map{ case (k,vs) =>
115
- s " trait Priority ${k} FunctionConverters {" +:
115
+ s " ${priorityName(k)} { " +:
116
116
s " import functionConverterImpls._ " +:
117
117
s " " +:
118
118
vs.map(_.implicitToJava.lines).mkVec().indent :+
119
119
s " } "
120
120
}
121
121
val explicitDefs = codes.map(_.defs).mkVecVec()
122
122
val packageObj =
123
- s " ${priorityName(0 )} { " +:
123
+ s " ${priorityName(0 )} { " +:
124
124
s " import functionConverterImpls._ " +:
125
125
s " " +:
126
126
{
127
127
explicitDefs.indent ++
128
- codes.filter(_.implicitToJava.priority == 0 ).map(_.convs).mkVecVec().indent
128
+ Vector .fill(3 )(" " ) ++
129
+ codes.filter(_.implicitToJava.priority == 0 ).map(_.implicitToJava.lines).mkVec().indent ++
130
+ Vector .fill(3 )(" " ) ++
131
+ codes.map(_.implicitToScala).mkVec().indent
129
132
} :+ " }"
130
133
(impls, traits :+ packageObj)
131
134
}
132
135
}
133
-
136
+
134
137
private def buildWrappersViaReflection : Seq [SamConversionCode ] = {
135
138
136
139
val pack : Symbol = rootMirror.getPackageIfDefined(TermName (" java.util.function" ))
137
-
140
+
138
141
case class Jfn (iface : Symbol , sam : Symbol ) {
139
142
lazy val genericCount = iface.typeParams.length
140
143
lazy val name = sam.name.toTermName
@@ -145,77 +148,81 @@ object WrapFnGen {
145
148
lazy val rType = sig.resultType
146
149
def arity = params.length
147
150
}
148
-
151
+
149
152
val sams = pack.info.decls.
150
153
map(d => (d, d.typeSignature.members.filter(_.isAbstract).toList)).
151
154
collect{ case (d, m :: Nil ) if d.isAbstract => Jfn (d, m) }
152
-
155
+
153
156
def generate (jfn : Jfn ): SamConversionCode = {
154
157
def mkRef (tp : Type ): Tree = if (tp.typeSymbol.isTypeParameter) Ident (tp.typeSymbol.name.toTypeName) else tq " $tp"
155
-
158
+
156
159
// Types for the Java SAM and the corresponding Scala function, plus all type parameters
157
160
val scalaType = gen.mkAttributedRef(FunctionClass (jfn.arity))
158
161
val javaType = gen.mkAttributedRef(jfn.iface)
159
162
val tnParams : List [TypeName ] = jfn.iface.typeParams.map(_.name.toTypeName)
160
163
val tdParams : List [TypeDef ] = tnParams.map(TypeDef (NoMods , _, Nil , EmptyTree ))
161
164
val javaTargs : List [Tree ] = tdParams.map(_.name).map(Ident (_))
162
165
val scalaTargs : List [Tree ] = jfn.pTypes.map(mkRef) :+ mkRef(jfn.rType)
163
-
166
+
164
167
// Conversion wrappers have three or four components that we need to name
165
168
// (1) The wrapper class that wraps a Java SAM as Scala function, or vice versa (ClassN)
166
169
// (2) A value class that provides .asJava or .asScala to request the conversion (ValCN)
167
170
// (3) A name for an explicit conversion method (DefN)
168
- // (4) If nested-trait lookup is needed to pick types, an implicit conversion method name (ImpN)
169
-
171
+ // (4) An implicit conversion method name (ImpN) that invokes the value class
172
+
170
173
// Names for Java conversions to Scala
171
174
val j2sClassN = TypeName (" FromJava" + jfn.title)
172
175
val j2sValCN = TypeName (" Rich" + jfn.title + " As" + scalaType.name.encoded)
173
176
val j2sDefN = TermName (" asScalaFrom" + jfn.title)
174
-
177
+ val j2sImpN = TermName (" enrichAsScalaFrom" + jfn.title)
178
+
175
179
// Names for Scala conversions to Java
176
180
val s2jClassN = TypeName (" AsJava" + jfn.title)
177
181
val s2jValCN = TypeName (" Rich" + scalaType.name.encoded + " As" + jfn.title)
178
182
val s2jDefN = TermName (" asJava" + jfn.title)
179
183
val s2jImpN = TermName (" enrichAsJava" + jfn.title)
180
-
184
+
181
185
// Argument lists for the function / SAM
182
- val vParams = (jfn.params zip jfn.pTypes).map{ case (p,t) =>
186
+ val vParams = (jfn.params zip jfn.pTypes).map{ case (p,t) =>
183
187
ValDef (NoMods , p.name.toTermName, if (t.typeSymbol.isTypeParameter) Ident (t.typeSymbol.name) else gen.mkAttributedRef(t.typeSymbol), EmptyTree )
184
188
}
185
189
val vParamRefs = vParams.map(_.name).map(Ident (_))
186
-
187
- val j2sClassTree =
190
+
191
+ val j2sClassTree =
188
192
q """ class $j2sClassN[.. $tdParams](jf: $javaType[.. $javaTargs]) extends $scalaType[.. $scalaTargs] {
189
193
def apply(.. $vParams) = jf. ${jfn.name}(.. $vParamRefs)
190
194
} """
191
-
195
+
192
196
val j2sValCTree =
193
- q """ implicit class $j2sValCN[.. $tdParams](private val underlying: $javaType[.. $javaTargs]) extends AnyVal {
197
+ q """ class $j2sValCN[.. $tdParams](private val underlying: $javaType[.. $javaTargs]) extends AnyVal {
194
198
@inline def asScala: $scalaType[.. $scalaTargs] = new $j2sClassN[.. $tnParams](underlying)
195
199
} """
196
-
200
+
197
201
val j2sDefTree =
198
- q """ def $j2sDefN[.. $tdParams](jf: $javaType[.. $javaTargs]): $scalaType[.. $scalaTargs] = new $j2sClassN[.. $tnParams](jf) """
199
-
202
+ q """ @inline def $j2sDefN[.. $tdParams](jf: $javaType[.. $javaTargs]): $scalaType[.. $scalaTargs] = new $j2sClassN[.. $tnParams](jf) """
203
+
204
+ val j2sImpTree =
205
+ q """ @inline implicit def $j2sImpN[.. $tdParams](jf: $javaType[.. $javaTargs]): $j2sValCN[.. $tnParams] = new $j2sValCN[.. $tnParams](jf) """
206
+
200
207
val s2jClassTree =
201
208
q """ class $s2jClassN[.. $tdParams](sf: $scalaType[.. $scalaTargs]) extends $javaType[.. $javaTargs] {
202
209
def ${jfn.name}(.. $vParams) = sf.apply(.. $vParamRefs)
203
210
} """
204
-
211
+
205
212
val s2jValCTree =
206
213
q """ class $s2jValCN[.. $tdParams](private val underlying: $scalaType[.. $scalaTargs]) extends AnyVal {
207
214
@inline def asJava: $javaType[.. $javaTargs] = new $s2jClassN[.. $tnParams](underlying)
208
215
} """
209
-
216
+
210
217
val s2jDefTree =
211
- q """ def $s2jDefN[.. $tdParams](sf: $scalaType[.. $scalaTargs]): $javaType[.. $javaTargs] = new $s2jClassN[.. $tnParams](sf) """
212
-
218
+ q """ @inline def $s2jDefN[.. $tdParams](sf: $scalaType[.. $scalaTargs]): $javaType[.. $javaTargs] = new $s2jClassN[.. $tnParams](sf) """
219
+
213
220
// This is especially tricky because functions are contravariant in their arguments
214
221
// Need to prevent e.g. Any => String from "downcasting" itself to Int => String; we want the more exact conversion
215
222
val s2jImpTree : (Tree , Int ) =
216
223
if (jfn.pTypes.forall(! _.isFinalType) && jfn.sig == jfn.sam.typeSignature)
217
224
(
218
- q """ implicit def $s2jImpN[.. $tdParams](sf: $scalaType[.. $scalaTargs]): $s2jValCN[.. $tnParams] = new $s2jValCN[.. $tnParams](sf) """ ,
225
+ q """ @inline implicit def $s2jImpN[.. $tdParams](sf: $scalaType[.. $scalaTargs]): $s2jValCN[.. $tnParams] = new $s2jValCN[.. $tnParams](sf) """ ,
219
226
tdParams.length
220
227
)
221
228
else {
@@ -242,29 +249,30 @@ object WrapFnGen {
242
249
map(TypeDef (NoMods , _, Nil , EmptyTree )).
243
250
dropRight(if (jfn.rType.isFinalType) 1 else 0 )
244
251
val evs = evidences.map{ case (generic, specific) => ValDef (NoMods , TermName (" ev" + generic.toString), tq " $generic =:= $specific" , EmptyTree ) }
245
- val tree =
246
- q """ implicit def $s2jImpN[.. $scalafnTdefs](sf: $scalaType[.. $scalafnTnames])(implicit .. $evs): $s2jValCN[.. $tnParams] =
252
+ val tree =
253
+ q """ @inline implicit def $s2jImpN[.. $scalafnTdefs](sf: $scalaType[.. $scalafnTnames])(implicit .. $evs): $s2jValCN[.. $tnParams] =
247
254
new $s2jValCN[.. $tnParams](sf.asInstanceOf[ $scalaType[.. $scalaTargs]])
248
255
"""
249
256
val depth = numberedA.size
250
257
(tree, tdParams.length)
251
258
}
252
-
259
+
253
260
SamConversionCode (
254
261
base = jfn.title,
255
262
wrappedAsScala = j2sClassTree.text,
256
- implicitToScala = j2sValCTree.text,
263
+ asScalaAnyVal = j2sValCTree.text,
264
+ implicitToScala = j2sImpTree.text,
257
265
asScalaDef = j2sDefTree.text,
258
266
wrappedAsJava = s2jClassTree.text,
259
267
asJavaAnyVal = s2jValCTree.text,
260
268
implicitToJava = s2jImpTree match { case (t,d) => Prioritized (t.text, d) },
261
269
asJavaDef = s2jDefTree.text
262
270
)
263
271
}
264
-
272
+
265
273
sams.toSeq.map(generate)
266
274
}
267
-
275
+
268
276
lazy val converterContents =
269
277
s """
270
278
| $copyright
@@ -278,21 +286,21 @@ object WrapFnGen {
278
286
(SamConversionCode (buildWrappersViaReflection : _* ) match {
279
287
case (impls, defs) => impls.mkString(" \n " ) + " \n\n\n\n " + defs.map(_.mkString(" \n " )).mkString(" \n\n\n\n " )
280
288
})
281
-
289
+
282
290
def sameText (f : java.io.File , text : String ): Boolean = {
283
291
val x = scala.io.Source .fromFile(f)
284
292
val lines = try { x.getLines.toVector } finally { x.close }
285
293
lines.iterator.filter(_.nonBlank) == text.linesIterator.filter(_.nonBlank)
286
294
}
287
-
295
+
288
296
def write (f : java.io.File , text : String ) {
289
297
if (! f.exists || ! sameText(f, text)) {
290
298
val p = new java.io.PrintWriter (f)
291
299
try { p.println(text) }
292
300
finally { p.close() }
293
301
}
294
302
}
295
-
303
+
296
304
def main (args : Array [String ]) {
297
305
val names = args.iterator.map(x => new java.io.File (x))
298
306
write(names.next, converterContents)
0 commit comments