1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Paul Phillips
*/
package scala.tools.nsc
package interpreter
import java.lang.{ reflect => r }
import r.TypeVariable
import scala.reflect.NameTransformer
/** Logic for turning a type into a String. The goal is to be
* able to take some arbitrary object 'x' and obtain the most precise
* String for which an injection of x.asInstanceOf[String] will
* be valid from both the JVM's and scala's perspectives.
*
* "definition" is when you want strings like
*/
trait TypeStrings {
private val ObjectClass = classOf[java.lang.Object]
private val primitives = Set[String]("byte", "char", "short", "int", "long", "float", "double", "boolean", "void")
private val primitiveMap = primitives.toList map { x =>
val key = x match {
case "void" => "Void"
case "int" => "Integer"
case "char" => "Character"
case s => s.capitalize
}
val value = x match {
case "void" => "Unit"
case s => s.capitalize
}
("java.lang." + key) -> ("scala." + value)
} toMap
def scalaName(s: String): String = {
if (s endsWith "$") s.init + ".type"
else if (s == "void") "scala.Unit"
else if (primitives(s)) "scala." + s.capitalize
else primitiveMap.getOrElse(s, NameTransformer decode s)
}
def scalaName(clazz: JClass): String = {
val name = clazz.getName
scalaName(clazz.getEnclosingClass match {
case null => name
case encl =>
val enclName = encl.getName
if (name startsWith (enclName + "$"))
enclName + "." + (name stripPrefix (enclName + "$"))
else
name
})
}
def scalaName(m: ClassManifest[_]): String = scalaName(m.erasure)
def anyClass(x: Any): JClass = if (x == null) null else x.asInstanceOf[AnyRef].getClass
private def brackets(tps: String*): String =
if (tps.isEmpty) ""
else tps.mkString("[", ", ", "]")
private def tvarString(tvar: TypeVariable[_]): String = tvarString(tvar.getBounds.toList)
private def tvarString(bounds: List[AnyRef]): String = {
val xs = bounds filterNot (_ == ObjectClass) collect { case x: Class[_] => x }
if (xs.isEmpty) "_"
else scalaName(xs.head)
}
private def tparamString(clazz: JClass): String = {
brackets(clazz.getTypeParameters map tvarString: _*)
}
private def tparamString[T: Manifest] : String =
brackets(manifest[T].typeArguments map (m => tvarString(List(m.erasure))): _*)
/** Going for an overabundance of caution right now. Later these types
* can be a lot more precise, but right now the manifests have a habit of
* introducing material which is not syntactically valid as scala source.
* When this happens it breaks the repl. It would be nice if we mandated
* that manifest toString methods (or some other method, since it's bad
* practice to rely on toString for correctness) generated the VALID string
* representation of the type.
*/
def fromTypedValue[T: Manifest](x: T): String = fromManifest[T]
def fromValue(value: Any): String = if (value == null) "Null" else fromClazz(anyClass(value))
def fromClazz(clazz: JClass): String = scalaName(clazz) + tparamString(clazz)
def fromManifest[T: Manifest] : String = scalaName(manifest[T].erasure) + tparamString[T]
/** Reducing fully qualified noise for some common packages.
*/
def quieter(tpe: String, alsoStrip: String*): String = {
val transforms = List(
"scala.collection.immutable." -> "immutable.",
"scala.collection.mutable." -> "mutable.",
"scala.collection.generic." -> "generic.",
"java.lang." -> "jl.",
"scala.runtime." -> "runtime."
) ++ (alsoStrip map (_ -> ""))
transforms.foldLeft(tpe) {
case (res, (k, v)) => res.replaceAll(k, v)
}
}
val typeTransforms = List(
"java.lang." -> "",
"scala.collection.immutable." -> "immutable.",
"scala.collection.mutable." -> "mutable.",
"scala.collection.generic." -> "generic."
)
}
object TypeStrings extends TypeStrings { }
|