Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swift macrosの入門ハードルは意外と低いかも
Search
stotic-dev
July 23, 2025
Technology
92
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swift macrosの入門ハードルは意外と低いかも
stotic-dev
July 23, 2025
More Decks by stotic-dev
See All by stotic-dev
低コストで始めるiOSアプリ開発のVRT
stoticdev
0
92
SwiftUIとMetalで簡単に作るレアカード風UI
stoticdev
1
190
Swift Testingのモチベを上げたい
stoticdev
2
430
PRレビューのお供にDanger
stoticdev
1
430
Other Decks in Technology
See All in Technology
[ChatGPT Work LT]事務作業が苦手な人のための バックオフィスの「半」自動化
chimaki_iot
0
330
20260804_Q4AzureUpdateBite_FabricDataAgentの精度を高める設計.pdf
matayuuu
1
150
事業価値と Engineering 2026年度版
recruitengineers
PRO
51
25k
20260807_第6回_関東kaggler会LT_claw系bot xangiと始める、"寂しくない" kaggle
sugupoko
0
360
My broken English still works: speaking at global OSS events
naruoga
0
110
FDEの心得
noriakioji
5
6.3k
LLM Internals: 언어 모델의 계보와 알고리즘 진화 (2023~2026)
inureyes
PRO
0
710
Bill One 開発エンジニア 紹介資料
sansan33
PRO
7
20k
【AG-UI × A2UI × MCP Apps】Generative UIをやさしく解説する
nrinetcom
PRO
1
140
Genie Codeハンズオン基礎編
taka_aki
1
130
Eight Engineering Unit 紹介資料
sansan33
PRO
3
8.2k
ラジオの科学
frievea
0
350
Featured
See All Featured
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
650
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
370
The Language of Interfaces
destraynor
162
27k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
470
Facilitating Awesome Meetings
lara
57
7.1k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
300
Ethics towards AI in product and experience design
skipperchong
2
350
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
490
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
480
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3k
Transcript
Swift macrosೖͷϋʔυϧҙ֎ͱ͍͔ 0
ࣗݾհ ࠤ౻ଡҰ/ͯ͌ʔ ͓ࣄɿiOSΤϯδχΞ 1
Swift macrosͱʁ ίϯύΠϧ࣌ʹίʔυΛࣗಈੜ͢Δػೳ ܁Γฦ͠ॻ͔ΕΔఆܕίʔυΛݮ SwiftSyntaxͷߏจղੳɾੜͷػೳΛͬͯಈ͍͍ͯΔ 2
Swift macrosͱʁ 2
Swift macrosͱʁ 2
Swift macrosͱʁ expansionϝιουͰɺSwiftSyntaxʹΑͬͯղੳ͞ΕͨߏจΛͬͯίʔυΛੜ ͠·͢ɻ 2
Swift macrosɺͦ͠͏ ೖ͢ΔͷʹSwiftSyntaxͷ͕ࣝඞཁͦ͏ 3
Swift macrosɺͦ͠͏ SwiftSyntax͕Θ͔Βͳ͍ɺɺ SwiftSyntaxා͍ɺɺ SwiftSyntaxͬͯͳʹɺɺ 3
Swift macrosɺͦ͠͏ ೖ͢ΔͷʹSwiftSyntaxͷࣝͦΜͳʹඞཁͳ ͔ͬͨʂ 3
ϚΫϩ࡞ͷجຊεςοϓ Swift macrosೖྗͱग़ྗ͕͋Δͱ͍͏ͰؔͱࣅͨΑ͏ͳͷͰ͢ɻ ͳͷͰɺ࣮ͷεςοϓؔͱಉ͡Α͏ʹߟ͑Δ͜ͱ͕Ͱ͖·͢ɻ 4
ϚΫϩ࡞ͷجຊεςοϓ ೖྗΛܾΊΔ @modelConvert(SampleModel.self) struct SampleData { let id: String let
text: String } 4
ϚΫϩ࡞ͷجຊεςοϓ ग़ྗΛܾΊΔ 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
ϚΫϩ࡞ͷجຊεςοϓ ೖྗΛ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
ϚΫϩ࡞ͷجຊεςοϓ ग़ྗΛSwiftSyntaxͰੜ͢Δ ExtensionDeclSyntax(...) 4
"ߏจͷน"ΛΓӽ͑Δ SwiftSyntaxͰίʔυߏจͱͯ͠ද͞Ε͍ͯ·͢ɻ ߏจʹSwiftSyntax⁶Swiftίʔυͷ૬ޓมΛॿ͚ΔͨΊͷඇৗʹ༗༻ͳใ͕٧ ·͍ͬͯ·͢ɻ ߏจΛݟΔϙΠϯτΛ͑ΕɺϚΫϩ࣮ͷϋʔυϧ͕άοͱԼ͕Γ·͢ɻ 5
ߏจ͔ΒҙͷใΛऔಘ͢Δ ߏจͱ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
"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
"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
"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
"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
"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
"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
lldbίϚϯυͰߏจΛදࣔ 6
ίʔυ͔ΒSyntaxͷΦϒδΣΫτม͢Δ ग़ྗ͍ͨ͠ίʔυͷߏจͷ༰͕Θ͔Εɺߏจʹهࡌ͞Ε͍ͯΔSyntaxͷܕͷΠχ γϟϥΠβͰࣗવͱSyntaxͷΦϒδΣΫτมͰ͖·͢ɻ SyntaxͷܕͷΠχγϟϥΠβͷύϥϝʔλ໊ɺߏจͷࢬͷཁૉ໊͕Ұக͍ͯ͠Δ͜ͱ ͕ɺ͜ͷํ๏Λ༰қʹ͍ͯ͠ΔϙΠϯτɻ 7
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
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
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
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
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
7
ҙ ೖϋʔυϧΛԼ͛Δ͜ͱΛॏʹஔ͍͓ͯΓɺ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
·ͱΊ ߏจʹίʔυͱSwiftSyntaxͷ૬ޓม͢ΔͨΊͷใ͕٧·͍ͬͯΔ ߏจͷใΛ׆༻͢ΕɺSwift macrosͷϋʔυϧΛେ͖͘Լ͛ΒΕΔ . ͋͞ɺօ͞ΜϚΫϩΛ࡞ͬͯΈ·͠ΐ͏ʂ 9