@@ -569,3 +569,151 @@ public enum LeftHandOperandFinderMacro: ExpressionMacro {
569569 return node. argumentList. first!. expression
570570 }
571571}
572+
573+ private extension DeclSyntaxProtocol {
574+ var isObservableStoredProperty : Bool {
575+ if let property = self . as ( VariableDeclSyntax . self) ,
576+ let binding = property. bindings. first,
577+ let identifier = binding. pattern. as ( IdentifierPatternSyntax . self) ? . identifier,
578+ identifier. text != " _registrar " , identifier. text != " _storage " ,
579+ binding. accessor == nil {
580+ return true
581+ }
582+
583+ return false
584+ }
585+ }
586+
587+ public struct ObservableMacro : MemberMacro , MemberAttributeMacro {
588+
589+ // MARK: - MemberMacro
590+
591+ public static func expansion(
592+ of node: AttributeSyntax ,
593+ providingMembersOf declaration: some DeclGroupSyntax ,
594+ in context: some MacroExpansionContext
595+ ) throws -> [ DeclSyntax ] {
596+ guard let identified = declaration. asProtocol ( IdentifiedDeclSyntax . self) else {
597+ return [ ]
598+ }
599+
600+ let parentName = identified. identifier
601+
602+ let registrar : DeclSyntax =
603+ """
604+ let _registrar = ObservationRegistrar< \( parentName) >()
605+ """
606+
607+ let addObserver : DeclSyntax =
608+ """
609+ public nonisolated func addObserver(_ observer: some Observer< \( parentName) >) {
610+ _registrar.addObserver(observer)
611+ }
612+ """
613+
614+ let removeObserver : DeclSyntax =
615+ """
616+ public nonisolated func removeObserver(_ observer: some Observer< \( parentName) >) {
617+ _registrar.removeObserver(observer)
618+ }
619+ """
620+
621+ let withTransaction : DeclSyntax =
622+ """
623+ private func withTransaction<T>(_ apply: () throws -> T) rethrows -> T {
624+ _registrar.beginAccess()
625+ defer { _registrar.endAccess() }
626+ return try apply()
627+ }
628+ """
629+
630+ let memberList = MemberDeclListSyntax (
631+ declaration. members. members. filter {
632+ $0. decl. isObservableStoredProperty
633+ }
634+ )
635+
636+ let storageStruct : DeclSyntax =
637+ """
638+ private struct Storage {
639+ \( memberList)
640+ }
641+ """
642+
643+ let storage : DeclSyntax =
644+ """
645+ private var _storage = Storage()
646+ """
647+
648+ return [
649+ registrar,
650+ addObserver,
651+ removeObserver,
652+ withTransaction,
653+ storageStruct,
654+ storage,
655+ ]
656+ }
657+
658+ // MARK: - MemberAttributeMacro
659+
660+ public static func expansion(
661+ of node: AttributeSyntax ,
662+ attachedTo declaration: some DeclGroupSyntax ,
663+ providingAttributesFor member: DeclSyntax ,
664+ in context: some MacroExpansionContext
665+ ) throws -> [ SwiftSyntax . AttributeSyntax ] {
666+ guard member. isObservableStoredProperty else {
667+ return [ ]
668+ }
669+
670+ return [
671+ AttributeSyntax (
672+ attributeName: SimpleTypeIdentifierSyntax (
673+ name: . identifier( " ObservableProperty " )
674+ )
675+ )
676+ ]
677+ }
678+
679+ }
680+
681+ public struct ObservablePropertyMacro : AccessorMacro {
682+ public static func expansion(
683+ of node: AttributeSyntax ,
684+ providingAccessorsOf declaration: some DeclSyntaxProtocol ,
685+ in context: some MacroExpansionContext
686+ ) throws -> [ AccessorDeclSyntax ] {
687+ guard let property = declaration. as ( VariableDeclSyntax . self) ,
688+ let binding = property. bindings. first,
689+ let identifier = binding. pattern. as ( IdentifierPatternSyntax . self) ? . identifier,
690+ binding. accessor == nil
691+ else {
692+ return [ ]
693+ }
694+
695+ let getAccessor : AccessorDeclSyntax =
696+ """
697+ get {
698+ _registrar.beginAccess( \\ . \( identifier) )
699+ defer { _registrar.endAccess() }
700+ return _storage. \( identifier)
701+ }
702+ """
703+
704+ let setAccessor : AccessorDeclSyntax =
705+ """
706+ set {
707+ _registrar.beginAccess( \\ . \( identifier) )
708+ _registrar.register(observable: self, willSet: \\ . \( identifier) , to: newValue)
709+ defer {
710+ _registrar.register(observable: self, didSet: \\ . \( identifier) )
711+ _registrar.endAccess()
712+ }
713+ _storage. \( identifier) = newValue
714+ }
715+ """
716+
717+ return [ getAccessor, setAccessor]
718+ }
719+ }
0 commit comments