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
93
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
98
SwiftUIとMetalで簡単に作るレアカード風UI
stoticdev
1
190
Swift Testingのモチベを上げたい
stoticdev
2
430
PRレビューのお供にDanger
stoticdev
1
430
Other Decks in Technology
See All in Technology
プロダクトエンジニアに必要な「いい感じ」に作る能力 〜たくさん作れる時代に、どこまで作るかの決め方〜
jnishime_dresscode
2
1.4k
AndroidでHDRメディアを「壊さずに」扱う
chigichan24
0
410
GoにおけるFFIのこれまでとこれから
goccy
1
130
Hub & Spoke 環境のネットワークルーティングを分解してみる
tsuyataku
1
530
多層防御と最⼩権限で実現する、安全なAIエージェント設計パターン
lycorptech_jp
PRO
0
210
「重なり」は迎える側がつくる ― 人もAIエージェントも歓迎するプロダクトエンジニアリング ―
go0517go
PRO
0
260
AIで実装は速くなった。なのにプロダクトは速くならない。職能の壁を越えて価値のフローを設計する
nwiizo
6
7.3k
2026-09-04 SRE Tech Talk #15 怠惰なTerraform / Lazy Terraform
masasuzu
0
210
When Does a Local Qwen Start to Break
morshoto
0
180
AI 駆動 Terraform 開発/SRE_BizReach_MIXI_2
visional_engineering_and_design
2
1.8k
2026/09/10 Spring_Bootから_Jakarta_EE_MicroProfileへの移行
megascus
0
160
Genie Code ワークショップ 応用編 / Genie-Code-Workshop-advanced
databricksjapan
PRO
0
360
Featured
See All Featured
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
870
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
The Curious Case for Waylosing
cassininazir
1
500
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Leo the Paperboy
mayatellez
8
2.2k
How STYLIGHT went responsive
nonsquared
100
6.3k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
270
Color Theory Basics | Prateek | Gurzu
gurzu
0
460
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