@@ -74,11 +74,62 @@ fileprivate extension String {
74
74
///
75
75
/// See the proposal SOAR-0001 for details.
76
76
///
77
- /// In addition to replacing illegal characters with an underscores, also
77
+ /// For example, the string `$nake…` would be returned as `_dollar_nake_x2026_`, because
78
+ /// both the dollar and ellipsis sign are not valid characters in a Swift identifier.
79
+ /// So, it replaces such characters with their html entity equivalents or unicode hex representation,
80
+ /// in case it's not present in the `specialCharsMap`. It marks this replacement with `_` as a delimiter.
81
+ ///
82
+ /// In addition to replacing illegal characters, it also
78
83
/// ensures that the identifier starts with a letter and not a number.
79
84
var proposedSafeForSwiftCode : String {
80
- // TODO: New logic proposed in SOAR-0001 goes here.
81
- return " "
85
+ guard !isEmpty else {
86
+ return " _empty "
87
+ }
88
+
89
+ let firstCharSet : CharacterSet = . letters. union ( . init( charactersIn: " _ " ) )
90
+ let numbers : CharacterSet = . decimalDigits
91
+ let otherCharSet : CharacterSet = . alphanumerics. union ( . init( charactersIn: " _ " ) )
92
+
93
+ var sanitizedScalars : [ Unicode . Scalar ] = [ ]
94
+ for (index, scalar) in unicodeScalars. enumerated ( ) {
95
+ let allowedSet = index == 0 ? firstCharSet : otherCharSet
96
+ let outScalar : Unicode . Scalar
97
+ if allowedSet. contains ( scalar) {
98
+ outScalar = scalar
99
+ } else if index == 0 && numbers. contains ( scalar) {
100
+ sanitizedScalars. append ( " _ " )
101
+ outScalar = scalar
102
+ } else {
103
+ sanitizedScalars. append ( " _ " )
104
+ if let entityName = Self . specialCharsMap [ scalar] {
105
+ for char in entityName. unicodeScalars {
106
+ sanitizedScalars. append ( char)
107
+ }
108
+ } else {
109
+ sanitizedScalars. append ( " x " )
110
+ let hexString = String ( scalar. value, radix: 16 , uppercase: true )
111
+ for char in hexString. unicodeScalars {
112
+ sanitizedScalars. append ( char)
113
+ }
114
+ }
115
+ sanitizedScalars. append ( " _ " )
116
+ continue
117
+ }
118
+ sanitizedScalars. append ( outScalar)
119
+ }
120
+
121
+ let validString = String ( UnicodeScalarView ( sanitizedScalars) )
122
+
123
+ //Special case for a single underscore.
124
+ //We can't add it to the map as its a valid swift identifier in other cases.
125
+ if validString == " _ " {
126
+ return " _underscore_ "
127
+ }
128
+
129
+ guard Self . keywords. contains ( validString) else {
130
+ return validString
131
+ }
132
+ return " _ \( validString) "
82
133
}
83
134
84
135
/// A list of Swift keywords.
@@ -138,62 +189,6 @@ fileprivate extension String {
138
189
" true " ,
139
190
" try " ,
140
191
" throws " ,
141
- " __FILE__ " ,
142
- " __LINE__ " ,
143
- " __COLUMN__ " ,
144
- " __FUNCTION__ " ,
145
- " __DSO_HANDLE__ " ,
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
- " #keyPath " ,
175
- " #line " ,
176
- " #selector " ,
177
- " #file " ,
178
- " #fileID " ,
179
- " #filePath " ,
180
- " #column " ,
181
- " #function " ,
182
- " #dsohandle " ,
183
- " #assert " ,
184
- " #sourceLocation " ,
185
- " #warning " ,
186
- " #error " ,
187
- " #if " ,
188
- " #else " ,
189
- " #elseif " ,
190
- " #endif " ,
191
- " #available " ,
192
- " #unavailable " ,
193
- " #fileLiteral " ,
194
- " #imageLiteral " ,
195
- " #colorLiteral " ,
196
- " ) " ,
197
192
" yield " ,
198
193
" String " ,
199
194
" Error " ,
@@ -205,4 +200,40 @@ fileprivate extension String {
205
200
" Protocol " ,
206
201
" await " ,
207
202
]
203
+
204
+ /// A map of ASCII printable characters to their HTML entity names. Used to reduce collisions in generated names.
205
+ private static let specialCharsMap : [ Unicode . Scalar : String ] = [
206
+ " " : " space " ,
207
+ " ! " : " excl " ,
208
+ " \" " : " quot " ,
209
+ " # " : " num " ,
210
+ " $ " : " dollar " ,
211
+ " % " : " percnt " ,
212
+ " & " : " amp " ,
213
+ " ' " : " apos " ,
214
+ " ( " : " lpar " ,
215
+ " ) " : " rpar " ,
216
+ " * " : " ast " ,
217
+ " + " : " plus " ,
218
+ " , " : " comma " ,
219
+ " - " : " hyphen " ,
220
+ " . " : " period " ,
221
+ " / " : " sol " ,
222
+ " : " : " colon " ,
223
+ " ; " : " semi " ,
224
+ " < " : " lt " ,
225
+ " = " : " equals " ,
226
+ " > " : " gt " ,
227
+ " ? " : " quest " ,
228
+ " @ " : " commat " ,
229
+ " [ " : " lbrack " ,
230
+ " \\ " : " bsol " ,
231
+ " ] " : " rbrack " ,
232
+ " ^ " : " hat " ,
233
+ " ` " : " grave " ,
234
+ " { " : " lcub " ,
235
+ " | " : " verbar " ,
236
+ " } " : " rcub " ,
237
+ " ~ " : " tilde " ,
238
+ ]
208
239
}
0 commit comments