55#nullable enable
66
77using System ;
8- using System . Collections . Generic ;
8+ using System . Diagnostics ;
99using System . Globalization ;
10- using System . Linq ;
1110using System . Numerics ;
1211using System . Text ;
1312
@@ -205,14 +204,17 @@ public static BigInteger ToBigInteger(this int self) {
205204 #region Public API - String/Bytes
206205
207206 public static string __format__ ( CodeContext /*!*/ context , int self , [ NotNone ] string /*!*/ formatSpec ) {
207+ if ( self == int . MinValue ) return BigIntegerOps . __format__ ( context , self , formatSpec ) ;
208+
208209 StringFormatSpec spec = StringFormatSpec . FromString ( formatSpec ) ;
209210
210211 if ( spec . Precision != null ) {
211212 throw PythonOps . ValueError ( "Precision not allowed in integer format specifier" ) ;
212213 }
213214
215+ int val = Math . Abs ( self ) ;
216+
214217 string digits ;
215- int width = 0 ;
216218
217219 switch ( spec . Type ) {
218220 case 'n' :
@@ -223,94 +225,53 @@ public static string __format__(CodeContext/*!*/ context, int self, [NotNone] st
223225 // include any formatting info.
224226 goto case 'd' ;
225227 }
226- width = spec . Width ?? 0 ;
227228
228229 // If we're padding with leading zeros and we might be inserting
229230 // culture sensitive number group separators. (i.e. commas)
230231 // So use FormattingHelper.ToCultureString for that support.
231- if ( spec . Fill . HasValue && spec . Fill . Value == '0' && width > 1 ) {
232- digits = FormattingHelper . ToCultureString ( self , culture . NumberFormat , spec ) ;
232+ if ( spec . Fill == '0' && spec . Width > 1 ) {
233+ digits = FormattingHelper . ToCultureString ( val , culture . NumberFormat , spec , ( spec . Sign != null && spec . Sign != '-' || self < 0 ) ? spec . Width - 1 : null ) ;
233234 } else {
234- digits = self . ToString ( "N0" , culture ) ;
235+ digits = val . ToString ( "N0" , culture ) ;
235236 }
236237 break ;
237238 case null :
238239 case 'd' :
239- if ( spec . ThousandsComma ) {
240- width = spec . Width ?? 0 ;
240+ if ( spec . ThousandsComma || spec . ThousandsUnderscore ) {
241+ var numberFormat = spec . ThousandsUnderscore ? FormattingHelper . InvariantUnderscoreNumberInfo : CultureInfo . InvariantCulture . NumberFormat ;
241242
242243 // If we're inserting commas, and we're padding with leading zeros.
243244 // AlignNumericText won't know where to place the commas,
244245 // so use FormattingHelper.ToCultureString for that support.
245- if ( spec . Fill . HasValue && spec . Fill . Value == '0' && width > 1 ) {
246- digits = FormattingHelper . ToCultureString ( self , FormattingHelper . InvariantCommaNumberInfo , spec ) ;
246+ if ( spec . Fill == '0' && spec . Width > 1 ) {
247+ digits = FormattingHelper . ToCultureString ( val , numberFormat , spec , ( spec . Sign != null && spec . Sign != '-' || self < 0 ) ? spec . Width - 1 : null ) ;
247248 } else {
248- digits = self . ToString ( "#,0" , CultureInfo . InvariantCulture ) ;
249+ digits = val . ToString ( "#,0" , numberFormat ) ;
249250 }
250251 } else {
251- digits = self . ToString ( "D" , CultureInfo . InvariantCulture ) ;
252+ digits = val . ToString ( "D" , CultureInfo . InvariantCulture ) ;
252253 }
253254 break ;
254255 case '%' :
255- if ( spec . ThousandsComma ) {
256- digits = self . ToString ( "#,0.000000%" , CultureInfo . InvariantCulture ) ;
257- } else {
258- digits = self . ToString ( "0.000000%" , CultureInfo . InvariantCulture ) ;
259- }
260- break ;
261256 case 'e' :
262- if ( spec . ThousandsComma ) {
263- digits = self . ToString ( "#,0.000000e+00" , CultureInfo . InvariantCulture ) ;
264- } else {
265- digits = self . ToString ( "0.000000e+00" , CultureInfo . InvariantCulture ) ;
266- }
267- break ;
268257 case 'E' :
269- if ( spec . ThousandsComma ) {
270- digits = self . ToString ( "#,0.000000E+00" , CultureInfo . InvariantCulture ) ;
271- } else {
272- digits = self . ToString ( "0.000000E+00" , CultureInfo . InvariantCulture ) ;
273- }
274- break ;
275258 case 'f' :
276259 case 'F' :
277- if ( spec . ThousandsComma ) {
278- digits = self . ToString ( "#,########0.000000" , CultureInfo . InvariantCulture ) ;
279- } else {
280- digits = self . ToString ( "#########0.000000" , CultureInfo . InvariantCulture ) ;
281- }
282- break ;
283260 case 'g' :
284- if ( self >= 1000000 || self <= - 1000000 ) {
285- digits = self . ToString ( "0.#####e+00" , CultureInfo . InvariantCulture ) ;
286- } else if ( spec . ThousandsComma ) {
287- // Handle the common case in 'd'.
288- goto case 'd' ;
289- } else {
290- digits = self . ToString ( CultureInfo . InvariantCulture ) ;
291- }
292- break ;
293261 case 'G' :
294- if ( self >= 1000000 || self <= - 1000000 ) {
295- digits = self . ToString ( "0.#####E+00" , CultureInfo . InvariantCulture ) ;
296- } else if ( spec . ThousandsComma ) {
297- // Handle the common case in 'd'.
298- goto case 'd' ;
299- } else {
300- digits = self . ToString ( CultureInfo . InvariantCulture ) ;
301- }
262+ digits = DoubleOps . DoubleToFormatString ( context , val , spec ) ;
302263 break ;
303264 case 'X' :
304- digits = ToHex ( self , false ) ;
265+ digits = ToHex ( val , lowercase : false ) ;
305266 break ;
306267 case 'x' :
307- digits = ToHex ( self , true ) ;
268+ digits = ToHex ( val , lowercase : true ) ;
308269 break ;
309270 case 'o' : // octal
310- digits = ToOctal ( self , true ) ;
271+ digits = ToOctal ( val , lowercase : true ) ;
311272 break ;
312273 case 'b' : // binary
313- digits = ToBinary ( self , false ) ;
274+ digits = ToBinary ( val , includeType : false ) ;
314275 break ;
315276 case 'c' : // single char
316277 if ( spec . Sign != null ) {
@@ -327,9 +288,7 @@ public static string __format__(CodeContext/*!*/ context, int self, [NotNone] st
327288 throw PythonOps . ValueError ( "Unknown format code '{0}' for object of type 'int'" , spec . TypeRepr ) ;
328289 }
329290
330- if ( self < 0 && digits [ 0 ] == '-' ) {
331- digits = digits . Substring ( 1 ) ;
332- }
291+ Debug . Assert ( digits [ 0 ] != '-' ) ;
333292
334293 return spec . AlignNumericText ( digits , self == 0 , self > 0 ) ;
335294 }
0 commit comments