EntryMacro.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //
  2. // EntryMacro.swift
  3. // ark_ui_basic_macros
  4. package import SwiftSyntax
  5. package import SwiftSyntaxMacros
  6. package struct EntryMacro: AccessorMacro, PeerMacro {
  7. package static func expansion(
  8. of node: AttributeSyntax,
  9. providingAccessorsOf declaration: some DeclSyntaxProtocol,
  10. in context: some MacroExpansionContext
  11. ) throws -> [AccessorDeclSyntax] {
  12. guard let varDecl = declaration.as(VariableDeclSyntax.self),
  13. let binding = varDecl.bindings.first,
  14. let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier else {
  15. throw MacroExpansionErrorMessage("@Entry can only be applied to stored properties")
  16. }
  17. // Check that we have either a type annotation OR an initializer (for type inference)
  18. let hasType = binding.typeAnnotation?.type != nil
  19. let hasInitializer = binding.initializer != nil
  20. guard hasType || hasInitializer else {
  21. throw MacroExpansionErrorMessage("@Entry requires either a type annotation or an initial value")
  22. }
  23. let identifierText = identifier.text
  24. let keyName = "__Key_\(identifierText)"
  25. return [
  26. AccessorDeclSyntax(
  27. accessorSpecifier: .keyword(.get),
  28. body: CodeBlockSyntax {
  29. "self[\(raw: keyName).self]"
  30. }
  31. ),
  32. AccessorDeclSyntax(
  33. accessorSpecifier: .keyword(.set),
  34. body: CodeBlockSyntax {
  35. "self[\(raw: keyName).self] = newValue"
  36. }
  37. )
  38. ]
  39. }
  40. package static func expansion(
  41. of node: AttributeSyntax,
  42. providingPeersOf declaration: some DeclSyntaxProtocol,
  43. in context: some MacroExpansionContext
  44. ) throws -> [DeclSyntax] {
  45. guard let varDecl = declaration.as(VariableDeclSyntax.self),
  46. let binding = varDecl.bindings.first,
  47. let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier else {
  48. throw MacroExpansionErrorMessage("@Entry requires a property with valid identifier")
  49. }
  50. let identifierText = identifier.text
  51. let keyName = "__Key_\(identifierText)"
  52. // Determine default value
  53. let defaultValue: ExprSyntax
  54. if let initializer = binding.initializer {
  55. // Has initializer - use the initializer value
  56. defaultValue = initializer.value
  57. } else if let explicitType = binding.typeAnnotation?.type {
  58. // Only type annotation, no initializer
  59. // Check if it's optional type - if so, default to nil
  60. let typeString = explicitType.description
  61. if typeString.contains("?") {
  62. defaultValue = ExprSyntax(NilLiteralExprSyntax())
  63. } else {
  64. throw MacroExpansionErrorMessage("@Entry requires an initial value for non-optional types")
  65. }
  66. } else {
  67. throw MacroExpansionErrorMessage("@Entry requires either a type annotation or an initial value")
  68. }
  69. let keyStruct = StructDeclSyntax(
  70. modifiers: [DeclModifierSyntax(name: .keyword(.private))],
  71. name: .identifier(keyName),
  72. inheritanceClause: InheritanceClauseSyntax {
  73. InheritedTypeSyntax(type: IdentifierTypeSyntax(name: .identifier("ark_ui_basic_core.EnvironmentKey")))
  74. }
  75. ) {
  76. // Create the variable declaration
  77. let patternBinding = PatternBindingSyntax(
  78. pattern: IdentifierPatternSyntax(identifier: .identifier("defaultValue")),
  79. typeAnnotation: binding.typeAnnotation,
  80. initializer: InitializerClauseSyntax(
  81. equal: .equalToken(),
  82. value: defaultValue
  83. )
  84. )
  85. VariableDeclSyntax(
  86. attributes: AttributeListSyntax([
  87. AttributeListSyntax.Element(
  88. AttributeSyntax(
  89. atSign: .atSignToken(),
  90. attributeName: IdentifierTypeSyntax(name: .identifier("__EntryDefaultValue"))
  91. )
  92. )
  93. ]),
  94. modifiers: [DeclModifierSyntax(name: .keyword(.static))],
  95. bindingSpecifier: .keyword(.var),
  96. bindings: PatternBindingListSyntax([patternBinding])
  97. )
  98. }
  99. return [DeclSyntax(keyStruct)]
  100. }
  101. }
  102. package struct MacroExpansionErrorMessage: Error, CustomStringConvertible {
  103. package let description: String
  104. package init(_ description: String) {
  105. self.description = description
  106. }
  107. }