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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Martin Odersky
*/
package scala.reflect
package internal
import java.security.MessageDigest
import scala.io.Codec
import Chars.isOperatorPart
/** A trait to encapsulate name mangling. It's intended for the
* values and methods involved in assembling names out of other names,
* and not for simple synthetically named locals.
*/
trait NameManglers {
self: SymbolTable =>
trait NameManglingCommon {
self: CommonNames =>
val MODULE_SUFFIX_STRING = NameTransformer.MODULE_SUFFIX_STRING
val NAME_JOIN_STRING = NameTransformer.NAME_JOIN_STRING
val MODULE_SUFFIX_NAME: TermName = newTermName(MODULE_SUFFIX_STRING)
val NAME_JOIN_NAME: TermName = newTermName(NAME_JOIN_STRING)
def flattenedName(segments: Name*): NameType = compactedString(segments mkString NAME_JOIN_STRING)
/**
* COMPACTIFY
*
* The hashed name has the form (prefix + marker + md5 + marker + suffix), where
* - prefix/suffix.length = MaxNameLength / 4
* - md5.length = 32
*
* We obtain the formula:
*
* FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6
*
* (+6 for ".class"). MaxNameLength can therefore be computed as follows:
*/
private final val marker = "$$$$"
private final val MaxNameLength = math.min(
settings.maxClassfileName.value - 6,
2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32)
)
private lazy val md5 = MessageDigest.getInstance("MD5")
private def toMD5(s: String, edge: Int) = {
val prefix = s take edge
val suffix = s takeRight edge
val cs = s.toArray
val bytes = Codec toUTF8 cs
md5 update bytes
val md5chars = md5.digest() map (b => (b & 0xFF).toHexString) mkString
prefix + marker + md5chars + marker + suffix
}
private def compactedString(s: String) =
if (s.length <= MaxNameLength) s
else toMD5(s, MaxNameLength / 4)
}
trait TypeNameMangling extends NameManglingCommon {
self: tpnme.type =>
}
trait TermNameMangling extends NameManglingCommon {
self: nme.type =>
val IMPL_CLASS_SUFFIX = "$class"
val LOCALDUMMY_PREFIX = "<local " // owner of local blocks
val PROTECTED_PREFIX = "protected$"
val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set"
val SINGLETON_SUFFIX = ".type"
val SUPER_PREFIX_STRING = "super$"
val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$"
val SETTER_SUFFIX: TermName = encode("_=")
@deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
def SPECIALIZED_SUFFIX_STRING = SPECIALIZED_SUFFIX.toString
@deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
def SPECIALIZED_SUFFIX_NAME: TermName = SPECIALIZED_SUFFIX.toTermName
def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR
def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX
def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX
def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX
def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING
def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
def isProtectedAccessorName(name: Name) = name startsWith PROTECTED_PREFIX
def isSuperAccessorName(name: Name) = name startsWith SUPER_PREFIX_STRING
def isReplWrapperName(name: Name) = name containsName INTERPRETER_IMPORT_WRAPPER
def isSetterName(name: Name) = name endsWith SETTER_SUFFIX
def isTraitSetterName(name: Name) = isSetterName(name) && (name containsName TRAIT_SETTER_SEPARATOR_STRING)
def isSingletonName(name: Name) = name endsWith SINGLETON_SUFFIX
def isModuleName(name: Name) = name endsWith MODULE_SUFFIX_NAME
def isOpAssignmentName(name: Name) = name match {
case raw.NE | raw.LE | raw.GE | EMPTY => false
case _ =>
name.endChar == '=' && name.startChar != '=' && isOperatorPart(name.startChar)
}
/** The expanded setter name of `name` relative to this class `base`
*/
def expandedSetterName(name: TermName, base: Symbol): TermName =
expandedName(name, base, separator = TRAIT_SETTER_SEPARATOR_STRING)
/** If `name` is an expandedName name, the original name.
* Otherwise `name` itself.
*/
def originalName(name: Name): Name = {
var i = name.length
while (i >= 2 && !(name(i - 1) == '$' && name(i - 2) == '$')) i -= 1
if (i >= 2) {
while (i >= 3 && name(i - 3) == '$') i -= 1
name.subName(i, name.length)
} else name
}
def unspecializedName(name: Name): Name = (
if (name endsWith SPECIALIZED_SUFFIX)
name.subName(0, name.lastIndexOf('m') - 1)
else name
)
/** Return the original name and the types on which this name
* is specialized. For example,
* {{{
* splitSpecializedName("foo$mIcD$sp") == ('foo', "I", "D")
* }}}
* `foo$mIcD$sp` is the name of a method specialized on two type
* parameters, the first one belonging to the method itself, on Int,
* and another one belonging to the enclosing class, on Double.
*/
def splitSpecializedName(name: Name): (Name, String, String) =
if (name endsWith SPECIALIZED_SUFFIX) {
val name1 = name dropRight SPECIALIZED_SUFFIX.length
val idxC = name1 lastIndexOf 'c'
val idxM = name1 lastIndexOf 'm'
(name1.subName(0, idxM - 1),
name1.subName(idxC + 1, name1.length).toString,
name1.subName(idxM + 1, idxC).toString)
} else
(name, "", "")
def getterName(name: TermName): TermName = if (isLocalName(name)) localToGetter(name) else name
def getterToLocal(name: TermName): TermName = name append LOCAL_SUFFIX_STRING
def getterToSetter(name: TermName): TermName = name append SETTER_SUFFIX
def localToGetter(name: TermName): TermName = name dropRight LOCAL_SUFFIX_STRING.length
def dropLocalSuffix(name: Name): Name = if (name endsWith ' ') name dropRight 1 else name
def setterToGetter(name: TermName): TermName = {
val p = name.pos(TRAIT_SETTER_SEPARATOR_STRING)
if (p < name.length)
setterToGetter(name drop (p + TRAIT_SETTER_SEPARATOR_STRING.length))
else
name.subName(0, name.length - SETTER_SUFFIX.length)
}
def defaultGetterName(name: Name, pos: Int): TermName = {
val prefix = if (isConstructorName(name)) "init" else name
newTermName(prefix + DEFAULT_GETTER_STRING + pos)
}
def defaultGetterToMethod(name: Name): TermName = {
val p = name.pos(DEFAULT_GETTER_STRING)
if (p < name.length) name.toTermName.subName(0, p)
else name.toTermName
}
// def anonNumberSuffix(name: Name): Name = {
// ("" + name) lastIndexOf '$' match {
// case -1 => nme.EMPTY
// case idx =>
// val s = name drop idx
// if (s.toString forall (_.isDigit)) s
// else nme.EMPTY
// }
// }
// If the name ends with $nn where nn are
// all digits, strip the $ and the digits.
// Otherwise return the argument.
def stripAnonNumberSuffix(name: Name): Name = {
var pos = name.length
while (pos > 0 && name(pos - 1).isDigit)
pos -= 1
if (pos <= 0 || pos == name.length || name(pos - 1) != '$') name
else name.subName(0, pos - 1)
}
def stripModuleSuffix(name: Name): Name = (
if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name
)
def dropSingletonName(name: Name): TypeName = name dropRight SINGLETON_SUFFIX.length toTypeName
def singletonName(name: Name): TypeName = name append SINGLETON_SUFFIX toTypeName
def implClassName(name: Name): TypeName = name append IMPL_CLASS_SUFFIX toTypeName
def interfaceName(implname: Name): TypeName = implname dropRight IMPL_CLASS_SUFFIX.length toTypeName
def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">")
def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name)
/** The name of an accessor for protected symbols. */
def protName(name: Name): TermName = newTermName(PROTECTED_PREFIX + name)
/** The name of a setter for protected symbols. Used for inherited Java fields. */
def protSetterName(name: Name): TermName = newTermName(PROTECTED_SET_PREFIX + name)
}
}
|