@@ -10,7 +10,67 @@ import SwiftSyntax
10
10
///
11
11
/// Format: All numeric literals that should be grouped will have `_`s inserted where appropriate.
12
12
///
13
+ /// TODO: Minimum numeric literal length bounds and numeric groupings selected arbitrarily, could
14
+ /// be reevaluated.
15
+ ///
16
+ /// TODO: Handle floating point literals
17
+ ///
13
18
/// - SeeAlso: https://google.github.io/swift#numeric-literals
14
19
public final class GroupNumericLiterals : SyntaxFormatRule {
20
+ public override func visit( _ node: IntegerLiteralExprSyntax ) -> ExprSyntax {
21
+
22
+ var digits = node. digits. text
23
+ guard !digits. contains ( " _ " ) else { return node }
24
+
25
+ let isNegative = digits. first == " - "
26
+ digits = isNegative ? String ( digits. dropFirst ( ) ) : digits
27
+
28
+ var newDigits = " "
29
+
30
+ switch digits. prefix ( 2 ) {
31
+ case " 0x " :
32
+ // Hexadecimal
33
+ let digitsNoPrefix = String ( digits. dropFirst ( 2 ) )
34
+ guard let intDigits = Int ( digitsNoPrefix, radix: 16 ) else { return node }
35
+ guard intDigits >= 0x1000_0000 else { return node }
36
+ diagnose ( . groupNumericLiteral( byStride: 4 ) , on: node)
37
+ newDigits = " 0x " + groupDigitsByStride( digits: digitsNoPrefix, stride: 4 )
38
+ case " 0b " :
39
+ // Binary
40
+ let digitsNoPrefix = String ( digits. dropFirst ( 2 ) )
41
+ guard let intDigits = Int ( digitsNoPrefix, radix: 2 ) else { return node }
42
+ guard intDigits >= 0b1_000000000 else { return node }
43
+ diagnose ( . groupNumericLiteral( byStride: 8 ) , on: node)
44
+ newDigits = " 0b " + groupDigitsByStride( digits: digitsNoPrefix, stride: 8 )
45
+ case " 0o " :
46
+ // Octal
47
+ return node
48
+ default :
49
+ // Decimal
50
+ guard let intDigits = Int ( digits) else { return node }
51
+ guard intDigits >= 1_000_000 else { return node }
52
+ diagnose ( . groupNumericLiteral( byStride: 3 ) , on: node)
53
+ newDigits = groupDigitsByStride ( digits: digits, stride: 3 )
54
+ }
55
+
56
+ newDigits = isNegative ? " - " + newDigits : newDigits
57
+ return node. withDigits ( SyntaxFactory . makeIdentifier ( newDigits) )
58
+ }
59
+
60
+ func groupDigitsByStride( digits: String , stride: Int ) -> String {
61
+ var newGrouping = Array ( digits)
62
+ var i = 1
63
+ while i * stride < digits. count {
64
+ newGrouping. insert ( " _ " , at: digits. count - i * stride)
65
+ i += 1
66
+ }
67
+ return String ( newGrouping)
68
+ }
69
+ }
15
70
71
+ extension Diagnostic . Message {
72
+ static func groupNumericLiteral( byStride: Int ) -> Diagnostic . Message {
73
+ let ending = byStride == 3 ? " rd " : " th "
74
+ return . init( . warning, " group numeric literal using '_' every \( byStride) \( ending) number " )
75
+ }
16
76
}
0 commit comments