Slide 1

Slide 1 text

Swift ίʔυͷͨΊͷ Swift ϓϩάϥϛϯά 2019/4/24 LINE Developer Meetup #53 in KYOTO LINE גࣜձࣾ
 Yuka Ezura

Slide 2

Slide 2 text

ezura • LINEͷϑΝϛϦʔΞϓϦ։ൃ:
 LINEϚϯΨ, LINE LIVE, LINEϊϕϧ • ొஃ: 
 iOSDC, try!swift, 
 LINE DEVELOPER DAY, ...

Slide 3

Slide 3 text

"Swift ίʔυͷͨΊͷ Swift ϓϩάϥϛϯά" ?

Slide 4

Slide 4 text

࠷ۙྲྀߦΓͷ SwiftSyntax

Slide 5

Slide 5 text

࠷ۙྲྀߦΓͷ SwiftSyntax Λ࢖͏ͱ…

Slide 6

Slide 6 text

textoru https://github.com/ezura/textoru

Slide 7

Slide 7 text

mvvmc-template https://github.com/ezura/MVVMC-template

Slide 8

Slide 8 text

؆୯ʹͰ͖Δ

Slide 9

Slide 9 text

ࠓ঺հͨ͠πʔϧΛؾܰʹ࡞Δ Goal

Slide 10

Slide 10 text

SwiftSyntax Ͱ
 ͲΜͳ໰୊ΛͲ͏΍ͬͯղܾͰ͖Δ͔ Goal ࠓ঺հͨ͠πʔϧΛؾܰʹ࡞Δ

Slide 11

Slide 11 text

• લฤ SwiftSyntax ͱ͸ • ޙฤ ঺հͨ͠πʔϧͷϝΠϯػೳΛ࡞Δ Agenda

Slide 12

Slide 12 text

• SwiftPM ͷ࢖͍ํ • Commandline tool ࣗମͷ࡞Γํ ࠓճ࿩͞ͳ͍͜ͱ

Slide 13

Slide 13 text

SwiftSyntax ͱ͸

Slide 14

Slide 14 text

SwiftSyntax ͱ͸ • ϕʔε͸ Swift compiler ಺Ͱ࢖ΘΕ͍ͯΔ libSyntax • AST (ந৅ߏจ໦) ͷղੳɾ࡞੒ɾॻ͖׵͕͑Ͱ͖Δ • SwiftPM ͷύοέʔδͱͯ͠ఏڙ͞Ε͍ͯΔ

Slide 15

Slide 15 text

ίʔυ ࣈ۟
 ղੳ ߏจ ղੳ ҙຯ
 ղੳ AST AST struct MyStruct { var v = "Meetup" func f() { print(self) } }

Slide 16

Slide 16 text

StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem FunctionDecl MemberDeclListItem VariableDecl struct MyStruct { var v = "Meetup" func f() { print(self) } }

Slide 17

Slide 17 text

SwiftSyntax ͕ಘҙͳ͜ͱ

Slide 18

Slide 18 text

AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

Slide 19

Slide 19 text

AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

Slide 20

Slide 20 text

StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem FunctionDecl MemberDeclListItem VariableDecl struct MyStruct { var v = "Meetup" func f() { print(self) } }

Slide 21

Slide 21 text

AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

Slide 22

Slide 22 text

StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem FunctionDecl MemberDeclListItem VariableDecl struct MyStruct { var v = "Meetup" func f() { print(self) } }

Slide 23

Slide 23 text

StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem FunctionDecl MemberDeclListItem VariableDecl struct MyStruct { private var v = "Meetup" func f() { print(self) } }

Slide 24

Slide 24 text

AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

StructDecl MemberDeclBlock MemberDeclList struct MyStruct { }

Slide 27

Slide 27 text

StructDecl MemberDeclBlock MemberDeclList StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem VariableDecl struct MyStruct { var v = "Meetup" } struct MyStruct { }

Slide 28

Slide 28 text

લฤ ·ͱΊ

Slide 29

Slide 29 text

ߏจ৘ใ͔Β෼͔Δ͜ͱ͸ SwiftSyntax ΋෼͔Δ ͲΜͳ property ͕
 ͋Δʁ Class ͷએݴ͸Ͳ͜ʁ ͜ͷ struct ͸Կʹ
 ४ڌͯ͠Δʁ ͜ͷ struct ͸ͲΜͳ function Λ࣋ͬͯΔʁ integer literal ࢖ͬͯΔ
 ͱ͜Ζશ෦ڭ͑ͯ

Slide 30

Slide 30 text

AST Λૢ࡞Ͱ͖Δ ಛఆͷ property ʹ private ͚͍ͭͨ Class ʹ final ͚͍ͭͨ ४ڌͯ͠Δ protocol ͷ એݴΛฒͼସ͍͑ͨ function Λফ͍ͨ͠ integer literal ͷ
 ϑΥʔϚοτΛ౷Ұ͍ͨ͠

Slide 31

Slide 31 text

• લฤ SwiftSyntax ͱ͸ • ޙฤ ঺հͨ͠πʔϧͷίΞػೳΛ࡞Δ Agenda

Slide 32

Slide 32 text

textoru https://github.com/ezura/textoru text Λݟ͚ͭΔ warning ͰϋΠϥΠτ͢Δ

Slide 33

Slide 33 text

text Λݟ͚ͭΔ => ৘ใΛ୳Δ

Slide 34

Slide 34 text

class SyntaxVisitor

Slide 35

Slide 35 text

open class SyntaxVisitor { public init() open func visit(_ node: InOutExprSyntax) -> SyntaxVisitorContinu open func visit(_ node: PoundColumnExprSyntax) -> SyntaxVisitorC open func visit(_ node: FunctionCallArgumentListSyntax) -> Synta open func visit(_ node: ArrayElementListSyntax) -> SyntaxVisitor open func visit(_ node: DictionaryElementListSyntax) -> SyntaxVi open func visit(_ node: StringInterpolationExprSyntax) -> Syntax open func visit(_ node: TryExprSyntax) -> SyntaxVisitorContinueK "hello!\(name)"

Slide 36

Slide 36 text

open func visit(_ node: ArrayExprSyntax) -> SyntaxVisitorContinu open func visit(_ node: DictionaryExprSyntax) -> SyntaxVisitorCo open func visit(_ node: FunctionCallArgumentSyntax) -> SyntaxVis open func visit(_ node: TupleElementSyntax) -> SyntaxVisitorCont open func visit(_ node: ArrayElementSyntax) -> SyntaxVisitorCont open func visit(_ node: DictionaryElementSyntax) -> SyntaxVisito open func visit(_ node: IntegerLiteralExprSyntax) -> SyntaxVisit open func visit(_ node: StringLiteralExprSyntax) -> SyntaxVisito open func visit(_ node: BooleanLiteralExprSyntax) -> SyntaxVisit open func visit(_ node: TernaryExprSyntax) -> SyntaxVisitorConti

Slide 37

Slide 37 text

class TextVisitor: SyntaxVisitor { override func visit(_ node: StringLiteralExprSyntax) -> SyntaxVisitorContinueKind {
 
 return .skipChildren } override func visit(_ node: StringInterpolationExprSyntax) -> SyntaxVisitorContinueKind {
 
 return .skipChildren } } ܧঝ

Slide 38

Slide 38 text

class TextVisitor: SyntaxVisitor { override func visit(_ node: StringLiteralExprSyntax) -> SyntaxVisitorContinueKind {
 
 return .skipChildren } override func visit(_ node: StringInterpolationExprSyntax) -> SyntaxVisitorContinueKind {
 
 return .skipChildren } } print(node.stringLiteral.withoutTrivia().text)
 print(node.segments) "Hello, world!\n" hello!\(name)

Slide 39

Slide 39 text

let syntaxTree = try SyntaxTreeParser.parse(fileURL)

Slide 40

Slide 40 text

let syntaxTree = try SyntaxTreeParser.parse(fileURL) let textVisitor = TextVisitor() syntaxTree.walk(textVisitor) "couldn't find the products directory" "testExample" "textoru" "Hello, world!\n" prefix_____\(pipe)_____suffix Output

Slide 41

Slide 41 text

Warning ͰϋΠϥΠτ͢Δ

Slide 42

Slide 42 text

print("{file ͷ path}:{line}:{column}: warning: {message}") ৔ॴͷ৘ใ͕ඞཁ

Slide 43

Slide 43 text

override func visit(_ node: StringLiteralExprSyntax) -> SyntaxVisitorContinueKind {
 
 let text = node.stringLiteral.withoutTrivia().text print("\(filePath):\(node.position.line):\(node.position.column):
 warning: `\(text)` is here!") return .skipChildren }

Slide 44

Slide 44 text

Run Script ͱͯ͠ॻ͘

Slide 45

Slide 45 text

warning ͰϋΠϥΠτ͢Δ

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

protocol Ͱͷఆٛॱʹ
 ࣮૷΋ฒͼସ͑Δ

Slide 48

Slide 48 text

protocol SampleViewModeling { var inputs: SampleViewModelInputs { get } var outputs: SampleViewModelOutputs { get } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { get } } protocol SampleViewModelInputs { var viewWillAppear: PublishRelay { get } var okButtonDidTap: PublishRelay { get } } protocol SampleViewModelOutputs { var isOkButtonEnabled: Driver { get } var showError: Signal { get } } protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { return self } // MARK: - SampleViewModelInputs let viewWillAppear: PublishRelay = PublishRelay() let okButtonDidTap: PublishRelay = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver let showError: Signal // MARK: - SampleViewModelCoordinatorOutputs let show: Observable // MARK: -

Slide 49

Slide 49 text

protocol SampleViewModeling { var inputs: SampleViewModelInputs { get } var outputs: SampleViewModelOutputs { get } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { get } } protocol SampleViewModelInputs { var viewWillAppear: PublishRelay { get } var okButtonDidTap: PublishRelay { get } } protocol SampleViewModelOutputs { var isOkButtonEnabled: Driver { get } var showError: Signal { get } } protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self }

Slide 50

Slide 50 text

} protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { return self } // MARK: - SampleViewModelInputs let viewWillAppear: PublishRelay = PublishRelay() let okButtonDidTap: PublishRelay = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver let showError: Signal // MARK: - SampleViewModelCoordinatorOutputs let show: Observable // MARK: - // ... டংΛकΔͨΊͷ࿑ྗͷൃੜ

Slide 51

Slide 51 text

} protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { return self } // MARK: - SampleViewModelInputs let viewWillAppear: PublishRelay = PublishRelay() let okButtonDidTap: PublishRelay = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver let showError: Signal // MARK: - SampleViewModelCoordinatorOutputs let show: Observable // MARK: - // ...

Slide 52

Slide 52 text

} protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { return self } // MARK: - SampleViewModelInputs let viewWillAppear: PublishRelay = PublishRelay() let okButtonDidTap: PublishRelay = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver let showError: Signal // MARK: - SampleViewModelCoordinatorOutputs let show: Observable let showError: Signal // MARK: - ৔ॴͷޡΓ

Slide 53

Slide 53 text

} protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { return self } // MARK: - SampleViewModelInputs let viewWillAppear: PublishRelay = PublishRelay() let okButtonDidTap: PublishRelay = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver let showError: Signal // MARK: - SampleViewModelCoordinatorOutputs let show: Observable // MARK: - // ...

Slide 54

Slide 54 text

} protocol SampleViewModelCoordinatorOutputs { var show: Signal { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self } var outputs: SampleViewModelOutputs { return self } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { return self } // MARK: - SampleViewModelInputs let viewWillAppear: PublishRelay = PublishRelay() let okButtonDidTap: PublishRelay = PublishRelay() // MARK: - SampleViewModelOutputs let showError: Signal let isOkButtonEnabled: Driver // MARK: - SampleViewModelCoordinatorOutputs let show: Observable // MARK: - // ... protocol ͷதͱॱ൪͕ҧ͏
 (௚͢΄Ͳ͡Όͳ͍͚Ͳɺͪΐͬͱؾʹͳͬͯ ἧ͑ͪΌ͏…)

Slide 55

Slide 55 text

protocol Ͱͷఆٛॱʹ
 ࣮૷΋ฒͼସ͑Δ

Slide 56

Slide 56 text

protocol Ͱͷఆٛॱʹ
 ࣮૷΋ฒͼସ͑Δ protocol Λ୳͢

Slide 57

Slide 57 text

class ͱ protocol ͷߏ଄Λ֬ೝ https://swift-ast-explorer.kishikawakatsumi.com/ First step

Slide 58

Slide 58 text

struct `Protocol` { let name: String /// store `VariableDeclSyntax` let memberVariables: [String] } class InputOutputProtocolVisitor: SyntaxVisitor { var foundProtocols: [Protocol] = [] override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
 let members = node.members.members
 ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ.compactMap { ($0.decl as? VariableDeclSyntax)?.variableName } 
 if node.identifier.text.hasSuffix("Inputs") || node.identifier.text.hasSuffix("Outputs") { foundProtocols.append(Interface(name: node.identifier.text, memberVariables: members) } return .skipChildren } }

Slide 59

Slide 59 text

struct `Protocol` { let name: String /// store `VariableDeclSyntax` let memberVariables: [String] } class InputOutputProtocolVisitor: SyntaxVisitor { var foundProtocols: [Protocol] = [] override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
 let members = node.members.members
 ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ.compactMap { ($0.decl as? VariableDeclSyntax)?.variableName } 
 if node.identifier.text.hasSuffix("Inputs") || node.identifier.text.hasSuffix("Outputs") { foundProtocols.append(Interface(name: node.identifier.text, memberVariables: members) } return .skipChildren } }

Slide 60

Slide 60 text

struct `Protocol` { let name: String /// store `VariableDeclSyntax` let memberVariables: [String] } class InputOutputProtocolVisitor: SyntaxVisitor { var foundProtocols: [Protocol] = [] override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
 let members = node.members.members
 ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ.compactMap { ($0.decl as? VariableDeclSyntax)?.variableName } 
 if node.identifier.text.hasSuffix("Inputs") || node.identifier.text.hasSuffix("Outputs") { foundProtocols.append(Interface(name: node.identifier.text, memberVariables: members) } return .skipChildren } }

Slide 61

Slide 61 text

let syntaxTree = try! SyntaxTreeParser.parse(fileURL) let protocolCollector = InputOutputProtocolVisitor() syntaxTree.walk(protocolCollector)

Slide 62

Slide 62 text

protocol Ͱͷఆٛॱʹ
 ࣮૷΋ฒͼସ͑Δ AST Λฤू͢Δ

Slide 63

Slide 63 text

class SyntaxRewriter

Slide 64

Slide 64 text

open class SyntaxRewriter { public init() open func visit(_ node: UnknownDeclSyntax) -> DeclSyntax open func visit(_ node: UnknownExprSyntax) -> ExprSyntax open func visit(_ node: UnknownStmtSyntax) -> StmtSyntax open func visit(_ node: UnknownTypeSyntax) -> TypeSyntax open func visit(_ node: UnknownPatternSyntax) -> PatternSynt open func visit(_ node: CodeBlockItemSyntax) -> Syntax open func visit(_ node: CodeBlockItemListSyntax) -> Syntax

Slide 65

Slide 65 text

open func visit(_ node: DeclModifierSyntax) -> Syntax open func visit(_ node: InheritedTypeSyntax) -> Syntax open func visit(_ node: InheritedTypeListSyntax) -> Syntax open func visit(_ node: TypeInheritanceClauseSyntax) -> Synt open func visit(_ node: ClassDeclSyntax) -> DeclSyntax open func visit(_ node: StructDeclSyntax) -> DeclSyntax open func visit(_ node: ProtocolDeclSyntax) -> DeclSyntax open func visit(_ node: ExtensionDeclSyntax) -> DeclSyntax open func visit(_ node: MemberDeclBlockSyntax) -> Syntax

Slide 66

Slide 66 text

class ImplSectionRewriter: SyntaxRewriter { let protocols: [Protocol] init(protocols: [Protocol]) { self.protocols = protocols } override func visit(_ node: ClassDeclSyntax) -> DeclSyntax { // ४ڌ͍ͯ͠Δ protocol Λ֬ೝ // property Λฒͼସ͑ͨϊʔυΛ࡞੒ // ࡞ͬͨϊʔυΛฦ͢ }

Slide 67

Slide 67 text

class ImplSectionRewriter: SyntaxRewriter { let protocols: [Protocol] init(protocols: [Protocol]) { self.protocols = protocols } override func visit(_ node: ClassDeclSyntax) -> DeclSyntax { guard let inheritance = node.inheritanceClause?.inheritedTypeCollection .compactMap({ $0.typeName.description 
 .trimmingCharacters(in: .whitespacesAndNewlines) }) else { return node } let targetProtocols = protocols.filter { inheritance.contains($0.name) } return targetProtocols.reduce(node) { (result, `protocol`) -> ClassDeclSyntax in grouping(for: `protocol`, in: result) } } private func grouping(for targetProtocol: Protocol, in node: ClassDeclSyntax) -> ClassDeclSyntax { var sourceMembers = node.members.members var protocolImplMembers: [MemberDeclListItemSyntax] = []

Slide 68

Slide 68 text

private func grouping(for targetProtocol: Protocol, in node: ClassDeclSyntax) -> ClassDeclSyntax { var sourceMembers = node.members.members var protocolImplMembers: [MemberDeclListItemSyntax] = [] var sectionHeaderMember: MemberDeclListItemSyntax? = nil var triviaPircesOfSectionComment: [TriviaPiece] = [] for targetVariableName in targetProtocol.memberVariables { guard let index = sourceMembers.firstIndex(where: { guard let originMember = $0.decl as? VariableDeclSyntax else { return false } return originMember.variableName == targetVariableName }) else { continue } let foundDecl = sourceMembers[index] let sectionCommentIndex = foundDecl.leadingTrivia?.firstIndex(where: { (piece) -> Bool in return piece.comment?.contains("MARK: - \(targetProtocol.name)") == true }) if let sectionCommentIndex = sectionCommentIndex, let leadingTrivia = foundDecl.leadingTrivia { sectionHeaderMember = foundDecl let startTriviasOfDeclIndex = leadingTrivia.dropFirst(sectionCommentIndex + 1)

Slide 69

Slide 69 text

} let foundDecl = sourceMembers[index] let sectionCommentIndex = foundDecl.leadingTrivia?.firstIndex(where: { (piece) -> Bool in return piece.comment?.contains("MARK: - \(targetProtocol.name)") == true }) if let sectionCommentIndex = sectionCommentIndex, let leadingTrivia = foundDecl.leadingTrivia { sectionHeaderMember = foundDecl let startTriviasOfDeclIndex = leadingTrivia.dropFirst(sectionCommentIndex + 1) .firstIndex { $0.isNewline } let triviaPircesOfDecl: [TriviaPiece] = (startTriviasOfDeclIndex != nil) ? Array(leadingTrivia.dropFirst(startTriviasOfDeclIndex! + 1)) : [] triviaPircesOfSectionComment = (startTriviasOfDeclIndex != nil) ? Array(leadingTrivia.prefix(upTo: startTriviasOfDeclIndex!)) : leadingTrivia.map { $0 } let trimedDecl = FirstTokenRewriter { token in token.withLeadingTrivia(Trivia.init(pieces: [.newlines(1)] + triviaPircesOfDecl)) } .visit(foundDecl) as! MemberDeclListItemSyntax protocolImplMembers.append(trimedDecl) } else { sourceMembers = sourceMembers.removing(childAt: index) protocolImplMembers.append(foundDecl) }

Slide 70

Slide 70 text

guard let _sectionHeaderMember = sectionHeaderMember, let sectionHeaderMemberIndex = sourceMembers.firstIndex(where: { ($0.decl as? VariableDeclSyntax)?.variableName == (_sectionHeaderMember.decl as? VariableDeclSyntax)?.variableName }) else { return node } // restore section header comment let headDecl = FirstTokenRewriter { (token) -> TokenSyntax in let originLeadingTrivia = token.leadingTrivia.map { $0 } return token.withLeadingTrivia(Trivia.init(pieces: triviaPircesOfSectionComment + originLeadingTrivia)) } .visit(protocolImplMembers.first!) as! MemberDeclListItemSyntax protocolImplMembers[0] = headDecl sourceMembers = sourceMembers.removing(childAt: sectionHeaderMemberIndex) let formedMember = protocolImplMembers.reversed().reduce(sourceMembers) { (result, member) in result.inserting(member, at: sectionHeaderMemberIndex) } let block = node.members.withMembers(formedMember) return node.withMembers(block) } }

Slide 71

Slide 71 text

let syntaxTree = try! SyntaxTreeParser.parse(fileURL)
 let protocolCollector = InputOutputProtocolVisitor()
 syntaxTree.walk(protocolCollector) let rewriter = ImplSectionRewriter(
 protocols: protocolCollector.foundProtocols
 )
 let formedTree = rewriter.visit(syntaxTree)
 try! formedTree.description .write(to: fileURL, atomically: false, encoding: .utf8)

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

Recap

Slide 74

Slide 74 text

ߏจ৘ใ͔Β෼͔Δ͜ͱ͸ SwiftSyntax ΋෼͔Δ ͲΜͳ property ͕
 ͋Δʁ Class ͷએݴ͸Ͳ͜ʁ ͜ͷ struct ͸Կʹ
 ४ڌͯ͠Δʁ ͜ͷ struct ͸ͲΜͳ function Λ࣋ͬͯΔʁ integer literal ࢖ͬͯΔ
 ͱ͜Ζશ෦ڭ͑ͯ

Slide 75

Slide 75 text

AST Λૢ࡞Ͱ͖Δ ಛఆͷ property ʹ private ͚͍ͭͨ Class ʹ final ͚͍ͭͨ ४ڌͯ͠Δ protocol ͷ એݴΛฒͼସ͍͑ͨ function Λফ͍ͨ͠ integer literal ͷ
 ϑΥʔϚοτΛ౷Ұ͍ͨ͠

Slide 76

Slide 76 text

SyntaxVisitor SyntaxRewriter ɿ ɿ AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ SyntaxFactory ɿ

Slide 77

Slide 77 text

͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ