Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift macrosの入門ハードルは意外と低いかも

Swift macrosの入門ハードルは意外と低いかも

Avatar for stotic-dev

stotic-dev

July 23, 2025
Tweet

More Decks by stotic-dev

Other Decks in Technology

Transcript

  1. ϚΫϩ࡞੒ͷجຊεςοϓ ग़ྗ஋ΛܾΊΔ extension SampleData: ModelConvertible { typealias ModelType = SampleModel

    init(_ model: SampleModel) throws { id = model.id text = model.text } func toModel() throws -> SampleModel { return .init(id: id, text: text) } } 4
  2. ϚΫϩ࡞੒ͷجຊεςοϓ ೖྗ஋ΛSwiftSyntaxͰղੳ͢Δ public static func expansion( of node: AttributeSyntax, attachedTo

    declaration: some DeclGroupSyntax, providingExtensionsOf type: some TypeSyntaxProtocol, conformingTo protocols: [TypeSyntax], in context: some MacroExpansionContext ) throws -> [ExtensionDeclSyntax] { ... } 4
  3. ߏจ໦͔Β೚ҙͷ৘ใΛऔಘ͢Δ ߏจ໦ͱSyntaxͷΦϒδΣΫτͷϓϩύςΟ͕ಉ͡Ͱ͋Δ͜ͱ͕Θ͔Ε͹ɺղੳ͸؆ ୯Ͱ͢ɻ AttributeSyntax ᵓᴷatSign: atSign ᵓᴷattributeName: IdentifierTypeSyntax │ ‹ᴷname:

    identifier("ModelConvert") ᵓᴷleftParen: leftParen ᵓᴷarguments: LabeledExprListSyntax │ ‹ᴷ<0>: LabeledExprSyntax │ ‹ᴷexpression: MemberAccessExprSyntax │ ᵓᴷbase: DeclReferenceExprSyntax │ │ ‹ᴷbaseName: identifier("SampleModel") │ ᵓᴷperiod: period │ ‹ᴷdeclName: DeclReferenceExprSyntax │ ‹ᴷbaseName: keyword(SwiftSyntax.Keyword.self) ‹ᴷrightParen: rightParen @modelConvert(SampleModel.self) 6
  4. "baseName"ͷऔಘྫ AttributeSyntax ᵓᴷ... ‹ᴷarguments: LabeledExprListSyntax ‹ᴷ<0>: LabeledExprSyntax ‹ᴷexpression: MemberAccessExprSyntax ᵓᴷbase:

    DeclReferenceExprSyntax │ ‹ᴷbaseName: identifier("SampleModel") ᵓᴷperiod: period ‹ᴷdeclName: DeclReferenceExprSyntax… node.arguments!.cast(LabeledExprListSyntax.self).first! .expression.as(MemberAccessExprSyntax.self)? .base?.as(DeclReferenceExprSyntax.self)? .baseName 6
  5. "baseName"ͷऔಘྫ AttributeSyntax ᵓᴷ... ‹ᴷarguments: LabeledExprListSyntax ‹ᴷ<0>: LabeledExprSyntax ‹ᴷexpression: MemberAccessExprSyntax ᵓᴷbase:

    DeclReferenceExprSyntax │ ‹ᴷbaseName: identifier("SampleModel") ᵓᴷperiod: period ‹ᴷdeclName: DeclReferenceExprSyntax… node.arguments!.cast(LabeledExprListSyntax.self).first! .expression.as(MemberAccessExprSyntax.self)? .base?.as(DeclReferenceExprSyntax.self)? .baseName 6
  6. "baseName"ͷऔಘྫ AttributeSyntax ᵓᴷ... ‹ᴷarguments: LabeledExprListSyntax ‹ᴷ<0>: LabeledExprSyntax ‹ᴷexpression: MemberAccessExprSyntax ᵓᴷbase:

    DeclReferenceExprSyntax │ ‹ᴷbaseName: identifier("SampleModel") ᵓᴷperiod: period ‹ᴷdeclName: DeclReferenceExprSyntax… node.arguments!.cast(LabeledExprListSyntax.self).first! .expression.as(MemberAccessExprSyntax.self)? .base?.as(DeclReferenceExprSyntax.self)? .baseName 6
  7. "baseName"ͷऔಘྫ AttributeSyntax ᵓᴷ... ‹ᴷarguments: LabeledExprListSyntax ‹ᴷ<0>: LabeledExprSyntax ‹ᴷexpression: MemberAccessExprSyntax ᵓᴷbase:

    DeclReferenceExprSyntax │ ‹ᴷbaseName: identifier("SampleModel") ᵓᴷperiod: period ‹ᴷdeclName: DeclReferenceExprSyntax… node.arguments!.cast(LabeledExprListSyntax.self).first! .expression.as(MemberAccessExprSyntax.self)? .base?.as(DeclReferenceExprSyntax.self)? .baseName 6
  8. "baseName"ͷऔಘྫ AttributeSyntax ᵓᴷ... ‹ᴷarguments: LabeledExprListSyntax ‹ᴷ<0>: LabeledExprSyntax ‹ᴷexpression: MemberAccessExprSyntax ᵓᴷbase:

    DeclReferenceExprSyntax │ ‹ᴷbaseName: identifier("SampleModel") ᵓᴷperiod: period ‹ᴷdeclName: DeclReferenceExprSyntax… node.arguments!.cast(LabeledExprListSyntax.self).first! .expression.as(MemberAccessExprSyntax.self)? .base?.as(DeclReferenceExprSyntax.self)? .baseName 6
  9. "baseName"ͷऔಘྫ AttributeSyntax ᵓᴷ... ‹ᴷarguments: LabeledExprListSyntax ‹ᴷ<0>: LabeledExprSyntax ‹ᴷexpression: MemberAccessExprSyntax ᵓᴷbase:

    DeclReferenceExprSyntax │ ‹ᴷbaseName: identifier("SampleModel") ᵓᴷperiod: period ‹ᴷdeclName: DeclReferenceExprSyntax… node.arguments!.cast(LabeledExprListSyntax.self).first! .expression.as(MemberAccessExprSyntax.self)? .base?.as(DeclReferenceExprSyntax.self)? .baseName 6
  10. ExtensionDeclSyntaxͷੜ੒ྫ ߏจ໦ ExtensionDeclSyntax ᵓᴷattributes: AttributeListSyntax ᵓᴷmodifiers: DeclModifierListSyntax ᵓᴷextensionKeyword: keyword(SwiftSyntax.Keyword.extension) ᵓᴷextendedType:

    IdentifierTypeSyntax │ ‹ᴷname: identifier("SampleData") ᵓᴷinheritanceClause: InheritanceClauseSyntax │ ᵓᴷcolon: colon │ ‹ᴷinheritedTypes: InheritedTypeListSyntax │ ‹ᴷ<0>: InheritedTypeSyntax │ ‹ᴷtype: IdentifierTypeSyntax │ ‹ᴷname: identifier("ModelConvertible") ‹ᴷmemberBlock: MemberBlockSyntax ᵓᴷleftBrace: leftBrace ᵓᴷ... ... ߏจ໦ʹରԠ͢ΔΠχγϟϥΠβ ExtensionDeclSyntax( extensionKeyword: T##TokenSyntax, extendedType: T##TypeSyntaxProtocol, inheritanceClause: T##InheritanceClauseSyntax? memberBlock: T##MemberBlockSyntax ) 7
  11. ExtensionDeclSyntaxͷੜ੒ྫ ߏจ໦ ExtensionDeclSyntax ᵓᴷattributes: AttributeListSyntax ᵓᴷmodifiers: DeclModifierListSyntax ᵓᴷextensionKeyword: keyword(SwiftSyntax.Keyword.extension) ᵓᴷextendedType:

    IdentifierTypeSyntax │ ‹ᴷname: identifier("SampleData") ᵓᴷinheritanceClause: InheritanceClauseSyntax │ ᵓᴷcolon: colon │ ‹ᴷinheritedTypes: InheritedTypeListSyntax │ ‹ᴷ<0>: InheritedTypeSyntax │ ‹ᴷtype: IdentifierTypeSyntax │ ‹ᴷname: identifier("ModelConvertible") ‹ᴷmemberBlock: MemberBlockSyntax ᵓᴷleftBrace: leftBrace ᵓᴷ... ... ߏจ໦ʹରԠ͢ΔΠχγϟϥΠβ ExtensionDeclSyntax( extensionKeyword: T##TokenSyntax, extendedType: T##TypeSyntaxProtocol, inheritanceClause: T##InheritanceClauseSyntax? memberBlock: T##MemberBlockSyntax ) 7
  12. ExtensionDeclSyntaxͷੜ੒ྫ ߏจ໦ ExtensionDeclSyntax ᵓᴷattributes: AttributeListSyntax ᵓᴷmodifiers: DeclModifierListSyntax ᵓᴷextensionKeyword: keyword(SwiftSyntax.Keyword.extension) ᵓᴷextendedType:

    IdentifierTypeSyntax │ ‹ᴷname: identifier("SampleData") ᵓᴷinheritanceClause: InheritanceClauseSyntax │ ᵓᴷcolon: colon │ ‹ᴷinheritedTypes: InheritedTypeListSyntax │ ‹ᴷ<0>: InheritedTypeSyntax │ ‹ᴷtype: IdentifierTypeSyntax │ ‹ᴷname: identifier("ModelConvertible") ‹ᴷmemberBlock: MemberBlockSyntax ᵓᴷleftBrace: leftBrace ᵓᴷ... ... ߏจ໦ʹରԠ͢ΔΠχγϟϥΠβ ExtensionDeclSyntax( extensionKeyword: T##TokenSyntax, extendedType: T##TypeSyntaxProtocol, inheritanceClause: T##InheritanceClauseSyntax?, memberBlock: T##MemberBlockSyntax ) 7
  13. ExtensionDeclSyntaxͷੜ੒ྫ ߏจ໦ ExtensionDeclSyntax ᵓᴷattributes: AttributeListSyntax ᵓᴷmodifiers: DeclModifierListSyntax ᵓᴷextensionKeyword: keyword(SwiftSyntax.Keyword.extension) ᵓᴷextendedType:

    IdentifierTypeSyntax │ ‹ᴷname: identifier("SampleData") ᵓᴷinheritanceClause: InheritanceClauseSyntax │ ᵓᴷcolon: colon │ ‹ᴷinheritedTypes: InheritedTypeListSyntax │ ‹ᴷ<0>: InheritedTypeSyntax │ ‹ᴷtype: IdentifierTypeSyntax │ ‹ᴷname: identifier("ModelConvertible") ‹ᴷmemberBlock: MemberBlockSyntax ᵓᴷleftBrace: leftBrace ᵓᴷ... ... ߏจ໦ʹରԠ͢ΔΠχγϟϥΠβ ExtensionDeclSyntax( extensionKeyword: T##TokenSyntax, extendedType: T##TypeSyntaxProtocol, inheritanceClause: T##InheritanceClauseSyntax?, memberBlock: T##MemberBlockSyntax ) 7
  14. SwiftParserΛ࢖͑͹ίʔυ͔Βߏจ໦ΛऔಘͰ͖·͢ɻ var parser = Parser(""" extension SampleData: ModelConvertible { typealias

    ModelType = SampleModel init(_ model: SampleModel) throws { id = model.id text = model.text } func toModel() throws -> SampleModel { return .init(id: id, text: text) } } """) let block = CodeBlockSyntax.parse(from: &parser) 7
  15. 7

  16. ஫ҙ఺ ೖ໳ϋʔυϧΛԼ͛Δ͜ͱΛॏ఺ʹஔ͍͓ͯΓɺSwift macrosͷϕετϓϥΫςΟεͳ ࣮૷ํ๏ͱ͸ݶΓ·ͤΜɻ public struct StringifyMacro: ExpressionMacro { public

    static func expansion( of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext ) -> ExprSyntax { ... return "(\(argument), \(literal: argument.description))" } } 8