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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
stotic-dev
July 23, 2025
Technology
78
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
83
SwiftUIとMetalで簡単に作るレアカード風UI
stoticdev
1
180
Swift Testingのモチベを上げたい
stoticdev
2
420
PRレビューのお供にDanger
stoticdev
1
420
Other Decks in Technology
See All in Technology
Oracle AI Database@AWS:サービス概要のご紹介
oracle4engineer
PRO
4
2.9k
フロンティアAIのゲート化と地政学リスク
nagatsu
0
120
LLMにもCAP定理があるという話
harukasakihara
0
290
RAG を使わないという選択肢
tatsutaka
1
180
Claude Codeをどのように キャッチアップしているか
oikon48
5
2.5k
SONiC Scale-Up Working Group から探る Scale-UpやUltraEthernet機能の実装方法
ebiken
PRO
1
120
FinOps × AIエージェントで実現する コストインシデントの自動調査
oasis1994liveforever
0
120
2026TECHFRESH畢業分享會 - Lightning Talk - E起 See See : 電商推薦讀心術? 數據說了算
line_developers_tw
PRO
0
780
Djangoユーザが知っ得なPostgreSQL機能 - 設計の選択肢を増やす / Djang-use-PostgreSQL
soudai
PRO
1
230
Amazon Bedrock AgentCore ワークショップ JAWS UG TOHOKU / amazon-bedrock-agentcore-workshop-jawsug-tohoku-2026
gawa
9
670
AIのReact習熟度を測る
uhyo
1
110
自律型AIエージェントは何を破壊するのか
kojira
0
150
Featured
See All Featured
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
190
How to Talk to Developers About Accessibility
jct
2
230
Raft: Consensus for Rubyists
vanstee
141
7.5k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
290
WENDY [Excerpt]
tessaabrams
11
38k
Designing for humans not robots
tammielis
254
26k
The SEO identity crisis: Don't let AI make you average
varn
0
490
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
170
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
200
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
280
The agentic SEO stack - context over prompts
schlessera
0
810
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