@@ -2278,4 +2278,68 @@ static String doGeneric(Object self,
2278
2278
return doString (castSelfNode .cast (self , ErrorMessages .REQUIRES_STR_OBJECT_BUT_RECEIVED_P , "casefold" , self ));
2279
2279
}
2280
2280
}
2281
+
2282
+ @ Builtin (name = "swapcase" , minNumOfPositionalArgs = 1 )
2283
+ @ GenerateNodeFactory
2284
+ public abstract static class SwapCaseNode extends PythonUnaryBuiltinNode {
2285
+
2286
+ private static final int CAPITAL_SIGMA = 0x3A3 ;
2287
+
2288
+ @ Specialization
2289
+ @ TruffleBoundary
2290
+ static String doString (String self ) {
2291
+ StringBuilder sb = new StringBuilder (self .length ());
2292
+ for (int i = 0 ; i < self .length ();) {
2293
+ int codePoint = self .codePointAt (i );
2294
+ int charCount = Character .charCount (codePoint );
2295
+ String substr = self .substring (i , i + charCount );
2296
+ if (UCharacter .isUUppercase (codePoint )) {
2297
+ // Special case for capital sigma, needed because ICU4J doesn't have the context
2298
+ // of the whole string
2299
+ if (codePoint == CAPITAL_SIGMA ) {
2300
+ handleCapitalSigma (self , sb , i , codePoint );
2301
+ } else {
2302
+ sb .append (UCharacter .toLowerCase (Locale .ROOT , substr ));
2303
+ }
2304
+ } else if (UCharacter .isULowercase (codePoint )) {
2305
+ sb .append (UCharacter .toUpperCase (Locale .ROOT , substr ));
2306
+ } else {
2307
+ sb .append (substr );
2308
+ }
2309
+ i += charCount ;
2310
+ }
2311
+ return sb .toString ();
2312
+ }
2313
+
2314
+ // Adapted from unicodeobject.c:handle_capital_sigma
2315
+ private static void handleCapitalSigma (String self , StringBuilder sb , int i , int codePoint ) {
2316
+ int j ;
2317
+ for (j = i - 1 ; j >= 0 ; j --) {
2318
+ if (!Character .isHighSurrogate (self .charAt (j ))) {
2319
+ int ch = self .codePointAt (j );
2320
+ if (!UCharacter .hasBinaryProperty (ch , UProperty .CASE_IGNORABLE )) {
2321
+ break ;
2322
+ }
2323
+ }
2324
+ }
2325
+ boolean finalSigma = j >= 0 && UCharacter .hasBinaryProperty (codePoint , UProperty .CASED );
2326
+ if (finalSigma ) {
2327
+ for (j = i + 1 ; j < self .length ();) {
2328
+ int ch = self .codePointAt (j );
2329
+ if (!UCharacter .hasBinaryProperty (ch , UProperty .CASE_IGNORABLE )) {
2330
+ break ;
2331
+ }
2332
+ j += Character .charCount (ch );
2333
+ }
2334
+ finalSigma = j == self .length () || !UCharacter .hasBinaryProperty (codePoint , UProperty .CASED );
2335
+ }
2336
+ sb .appendCodePoint (finalSigma ? 0x3C2 : 0x3C3 );
2337
+ }
2338
+
2339
+ @ Specialization (replaces = "doString" )
2340
+ static String doGeneric (Object self ,
2341
+ @ Cached CastToJavaStringCheckedNode castSelfNode ) {
2342
+ return doString (castSelfNode .cast (self , ErrorMessages .REQUIRES_STR_OBJECT_BUT_RECEIVED_P , "swapcase" , self ));
2343
+ }
2344
+ }
2281
2345
}
0 commit comments