SwiftLanguage.swift 7.6 KB

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