SwiftLanguage.swift 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Sources/SwiftProtobufPluginLibrary/SwiftLanguage.swift - Swift language utilities
  2. //
  3. // Copyright (c) 2014 - 2016 Apple Inc. and the project authors
  4. // Licensed under Apache License v2.0 with Runtime Library Exception
  5. //
  6. // See LICENSE.txt for license information:
  7. // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
  8. //
  9. // -----------------------------------------------------------------------------
  10. ///
  11. /// Utility functions for dealing with Swift language issues
  12. ///
  13. // -----------------------------------------------------------------------------
  14. import Swift
  15. import Foundation
  16. /// Used to check if a character is a valid identifier head character.
  17. ///
  18. /// This is mainly a building block for isValidSwiftIdentifier(), but is exposed
  19. /// within the plugin library so other parts of the library can use it.
  20. func isSwiftIdentifierHeadCharacter(_ c: UnicodeScalar) -> Bool {
  21. switch c.value {
  22. // identifier-head → Upper- or lowercase letter A through Z
  23. case 0x61...0x7a, 0x41...0x5a: return true
  24. // identifier-head → _
  25. case 0x5f: return true
  26. // identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA
  27. case 0xa8, 0xaa, 0xad, 0xaf, 0xb2...0xb5, 0xb7...0xba: return true
  28. // identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF
  29. case 0xbc...0xbe, 0xc0...0xd6, 0xd8...0xf6, 0xf8...0xff: return true
  30. // identifier-head → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF
  31. case 0x100...0x2ff, 0x370...0x167f, 0x1681...0x180d, 0x180f...0x1dbf: return true
  32. // identifier-head → U+1E00–U+1FFF
  33. case 0x1e00...0x1fff: return true
  34. // identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F
  35. case 0x200b...0x200d, 0x202a...0x202e, 0x203F, 0x2040, 0x2054, 0x2060...0x206f: return true
  36. // identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793
  37. case 0x2070...0x20cf, 0x2100...0x218f, 0x2460...0x24ff, 0x2776...0x2793: return true
  38. // identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF
  39. case 0x2c00...0x2dff, 0x2e80...0x2fff: return true
  40. // identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF
  41. case 0x3004...0x3007, 0x3021...0x302f, 0x3031...0x303f, 0x3040...0xd7ff: return true
  42. // identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44
  43. case 0xf900...0xfd3d, 0xfd40...0xfdcf, 0xfdf0...0xfe1f, 0xfe30...0xfe44: return true
  44. // identifier-head → U+FE47–U+FFFD
  45. case 0xfe47...0xfffd: return true
  46. // identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD
  47. case 0x10000...0x1fffd, 0x20000...0x2fffd, 0x30000...0x3fffd, 0x40000...0x4fffd: return true
  48. // identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD
  49. case 0x50000...0x5fffd, 0x60000...0x6fffd, 0x70000...0x7fffd, 0x80000...0x8fffd: return true
  50. // identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD
  51. case 0x90000...0x9fffd, 0xa0000...0xafffd, 0xb0000...0xbfffd, 0xc0000...0xcfffd: return true
  52. // identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD
  53. case 0xd0000...0xdfffd, 0xe0000...0xefffd: return true
  54. default: return false
  55. }
  56. }
  57. /// Used to check if a character is a valid identifier character.
  58. ///
  59. /// This is mainly a building block for isValidSwiftIdentifier(), but is exposed
  60. /// within the plugin library so other parts of the library can use it.
  61. func isSwiftIdentifierCharacter(_ c: UnicodeScalar) -> Bool {
  62. switch c.value {
  63. // identifier-character → Digit 0 through 9
  64. case 0x30...0x39: return true
  65. // identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F
  66. case 0x300...0x36F, 0x1dc0...0x1dff, 0x20d0...0x20ff, 0xfe20...0xfe2f: return true
  67. // identifier-character → identifier-head
  68. default: return isSwiftIdentifierHeadCharacter(c)
  69. }
  70. }
  71. /// Use this to check whether a generated identifier is actually
  72. /// valid for use in generated Swift code.
  73. ///
  74. /// This implements the full grammar for validating an arbitrary Swift
  75. /// identifier as documented in "The Swift Programming Language."
  76. /// In particular, it does correctly handle identifiers with
  77. /// arbitrary Unicode in them.
  78. ///
  79. /// For details, see:
  80. ///
  81. /// https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/zzSummaryOfTheGrammar.html
  82. ///
  83. /// Note: This is purely a syntactic check; it does not test whether
  84. /// the identifier is a Swift reserved word. We do exclude implicit
  85. /// parameter identifiers ("$1", "$2", etc) and "_", though.
  86. ///
  87. /// - Parameter s: The string to check.
  88. /// - Parameter allowQuoted: If the parameter to should allowed to be a quoted
  89. /// identifier.
  90. ///
  91. public func isValidSwiftIdentifier(_ s: String, allowQuoted: Bool = false) -> Bool {
  92. var s = s
  93. if allowQuoted && s.hasPrefix("`") && s.hasSuffix("`") {
  94. s.removeFirst()
  95. s.removeLast()
  96. }
  97. // "_" is technically a valid identifier but is magic so we don't want to
  98. // count it as valid.
  99. if s == "_" {
  100. return false
  101. }
  102. var i = s.unicodeScalars.makeIterator()
  103. guard let first = i.next(), isSwiftIdentifierHeadCharacter(first) else {
  104. return false
  105. }
  106. while let c = i.next() {
  107. if !isSwiftIdentifierCharacter(c) {
  108. return false
  109. }
  110. }
  111. return true
  112. }
  113. /// These lists of keywords are taken directly from the Swift language
  114. /// spec. See:
  115. ///
  116. /// https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/zzSummaryOfTheGrammar.html
  117. public let swiftKeywordsUsedInDeclarations: Set<String> = [
  118. "associatedtype", "class", "deinit", "enum", "extension",
  119. "fileprivate", "func", "import", "init", "inout", "internal",
  120. "let", "open", "operator", "private", "protocol", "public",
  121. "static", "struct", "subscript", "typealias", "var"
  122. ]
  123. public let swiftKeywordsUsedInStatements: Set<String> = [ "break", "case",
  124. "continue", "default", "defer", "do", "else", "fallthrough",
  125. "for", "guard", "if", "in", "repeat", "return", "switch", "where",
  126. "while"
  127. ]
  128. public let swiftKeywordsUsedInExpressionsAndTypes: Set<String> = [ "as",
  129. "Any", "catch", "false", "is", "nil", "rethrows", "super", "self",
  130. "Self", "throw", "throws", "true", "try"
  131. ]
  132. public let swiftKeywordsWithNumberSign: Set<String> = [ "#available",
  133. "#colorLiteral", "#column", "#else", "#elseif", "#endif", "#file",
  134. "#fileLiteral", "#function", "#if", "#imageLiteral", "#line",
  135. "#selector", "#sourceLocation"
  136. ]
  137. public let swiftKeywordsReservedInParticularContexts: Set<String> = [
  138. "associativity", "convenience", "dynamic", "didSet", "final",
  139. "get", "infix", "indirect", "lazy", "left", "mutating", "none",
  140. "nonmutating", "optional", "override", "postfix", "precedence",
  141. "prefix", "Protocol", "required", "right", "set", "Type",
  142. "unowned", "weak", "willSet"
  143. ]
  144. /// These are standard Swift types that are heavily used, although
  145. /// they are not technically reserved. Defining fields or structs
  146. /// with these names would break our generated code quite badly:
  147. public let swiftCommonTypes: Set<String> = [ "Bool", "Data", "Double", "Float", "Int",
  148. "Int32", "Int64", "String", "UInt", "UInt32", "UInt64",
  149. ]
  150. /// Special magic variables defined by the compiler that we don't
  151. /// really want to interfere with:
  152. public let swiftSpecialVariables: Set<String> = [ "__COLUMN__",
  153. "__FILE__", "__FUNCTION__", "__LINE__",
  154. ]