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
84
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
84
SwiftUIとMetalで簡単に作るレアカード風UI
stoticdev
1
180
Swift Testingのモチベを上げたい
stoticdev
2
430
PRレビューのお供にDanger
stoticdev
1
420
Other Decks in Technology
See All in Technology
RAGの精度向上とエージェント活用
kintotechdev
2
120
cccccc
moznion
0
1.3k
技術・能力を向上する原理原則 #きのこセッションa #きのこ2026
bash0c7
0
190
打造你的 AI 工作流:Agent Skill + MCP 實戰工作坊
appleboy
0
360
“全部コピーしない”ファイルデータの活用 : — FSx for ONTAP × S3 Tables × Icebergで作るメタデータカタログ
yoshiki0705
0
270
次世代ランサムウェア対策の考察 / 20260704 Mitsutoshi Matsuo
shift_evolve
PRO
5
1.7k
Terraform 101 (初心者向け) 資料
shuadachi
0
160
どうして今サーバーサイドKotlinを選択したのか
nealle
0
180
「軸足」は 固定しなくていい - 熱量と強みで描く、しなやかなキャリアの形
kakehashi
PRO
1
320
Docker Desktop不要の時代が来る? WSL標準の「wslc」で Linuxコンテナを動かしてみた.
ueponx
0
520
AIDLC_ヤフーショッピングの取り組み
lycorptech_jp
PRO
0
470
AWS Summit の片隅で、体育座りしながらコミュニティがにぎわう理由を考えた
k_adachi_01
2
340
Featured
See All Featured
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
620
It's Worth the Effort
3n
188
29k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
KATA
mclloyd
PRO
35
15k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.4k
Abbi's Birthday
coloredviolet
3
8.4k
Navigating Team Friction
lara
192
16k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Building an army of robots
kneath
306
46k
How to Ace a Technical Interview
jacobian
281
24k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
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