Swift コードのための Swift プログラミング / Swift programming for Swift code

Swift コードのための Swift プログラミング / Swift programming for Swift code

2019/4/24に行われたLINE Developer meetup #53 in KYOTOでの登壇資料です

53850955f15249a1a9dc49df6113e400?s=128

LINE Developers

April 24, 2019
Tweet

Transcript

  1. Swift ίʔυͷͨΊͷ Swift ϓϩάϥϛϯά 2019/4/24 LINE Developer Meetup #53 in

    KYOTO LINE גࣜձࣾ
 Yuka Ezura
  2. ezura • LINEͷϑΝϛϦʔΞϓϦ։ൃ:
 LINEϚϯΨ, LINE LIVE, LINEϊϕϧ • ొஃ: 


    iOSDC, try!swift, 
 LINE DEVELOPER DAY, ...
  3. "Swift ίʔυͷͨΊͷ Swift ϓϩάϥϛϯά" ?

  4. ࠷ۙྲྀߦΓͷ SwiftSyntax

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

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

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

  8. ؆୯ʹͰ͖Δ

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

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

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

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

  13. SwiftSyntax ͱ͸

  14. SwiftSyntax ͱ͸ • ϕʔε͸ Swift compiler ಺Ͱ࢖ΘΕ͍ͯΔ libSyntax • AST

    (ந৅ߏจ໦) ͷղੳɾ࡞੒ɾॻ͖׵͕͑Ͱ͖Δ • SwiftPM ͷύοέʔδͱͯ͠ఏڙ͞Ε͍ͯΔ
  15. ίʔυ ࣈ۟
 ղੳ ߏจ ղੳ ҙຯ
 ղੳ AST AST struct

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

    var v = "Meetup" func f() { print(self) } }
  17. SwiftSyntax ͕ಘҙͳ͜ͱ

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

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

  20. StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem FunctionDecl MemberDeclListItem VariableDecl struct MyStruct {

    var v = "Meetup" func f() { print(self) } }
  21. AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

  22. StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem FunctionDecl MemberDeclListItem VariableDecl struct MyStruct {

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

    private var v = "Meetup" func f() { print(self) } }
  24. AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

  25. None
  26. StructDecl MemberDeclBlock MemberDeclList struct MyStruct { }

  27. StructDecl MemberDeclBlock MemberDeclList StructDecl MemberDeclBlock MemberDeclList MemberDeclListItem VariableDecl struct MyStruct

    { var v = "Meetup" } struct MyStruct { }
  28. લฤ ·ͱΊ

  29. ߏจ৘ใ͔Β෼͔Δ͜ͱ͸ SwiftSyntax ΋෼͔Δ ͲΜͳ property ͕
 ͋Δʁ Class ͷએݴ͸Ͳ͜ʁ ͜ͷ

    struct ͸Կʹ
 ४ڌͯ͠Δʁ ͜ͷ struct ͸ͲΜͳ function Λ࣋ͬͯΔʁ integer literal ࢖ͬͯΔ
 ͱ͜Ζશ෦ڭ͑ͯ
  30. AST Λૢ࡞Ͱ͖Δ ಛఆͷ property ʹ private ͚͍ͭͨ Class ʹ final

    ͚͍ͭͨ ४ڌͯ͠Δ protocol ͷ એݴΛฒͼସ͍͑ͨ function Λফ͍ͨ͠ integer literal ͷ
 ϑΥʔϚοτΛ౷Ұ͍ͨ͠
  31. • લฤ SwiftSyntax ͱ͸ • ޙฤ ঺հͨ͠πʔϧͷίΞػೳΛ࡞Δ Agenda

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

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

  34. class SyntaxVisitor

  35. 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)"
  36. 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
  37. class TextVisitor: SyntaxVisitor { override func visit(_ node: StringLiteralExprSyntax) ->

    SyntaxVisitorContinueKind {
 
 return .skipChildren } override func visit(_ node: StringInterpolationExprSyntax) -> SyntaxVisitorContinueKind {
 
 return .skipChildren } } ܧঝ
  38. 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)
  39. let syntaxTree = try SyntaxTreeParser.parse(fileURL)

  40. 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
  41. Warning ͰϋΠϥΠτ͢Δ

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

  43. 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 }
  44. Run Script ͱͯ͠ॻ͘

  45. warning ͰϋΠϥΠτ͢Δ

  46. None
  47. protocol Ͱͷఆٛॱʹ
 ࣮૷΋ฒͼସ͑Δ

  48. protocol SampleViewModeling { var inputs: SampleViewModelInputs { get } var

    outputs: SampleViewModelOutputs { get } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { get } } protocol SampleViewModelInputs { var viewWillAppear: PublishRelay<Void> { get } var okButtonDidTap: PublishRelay<Void> { get } } protocol SampleViewModelOutputs { var isOkButtonEnabled: Driver<Bool> { get } var showError: Signal<Sample.Error> { get } } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { 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<Void> = PublishRelay() let okButtonDidTap: PublishRelay<Void> = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver<Bool> let showError: Signal<Sample.Error> // MARK: - SampleViewModelCoordinatorOutputs let show: Observable<RequestScreen> // MARK: -
  49. protocol SampleViewModeling { var inputs: SampleViewModelInputs { get } var

    outputs: SampleViewModelOutputs { get } var coordinatorOutputs: SampleViewModelCoordinatorOutputs { get } } protocol SampleViewModelInputs { var viewWillAppear: PublishRelay<Void> { get } var okButtonDidTap: PublishRelay<Void> { get } } protocol SampleViewModelOutputs { var isOkButtonEnabled: Driver<Bool> { get } var showError: Signal<Sample.Error> { get } } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { get } } final class SampleViewModel: SampleViewModelInputs, SampleViewModelOutputs, SampleViewModelCoordinatorOutputs, SampleViewModeling { var inputs: SampleViewModelInputs { return self }
  50. } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { 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<Void> = PublishRelay() let okButtonDidTap: PublishRelay<Void> = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver<Bool> let showError: Signal<Sample.Error> // MARK: - SampleViewModelCoordinatorOutputs let show: Observable<RequestScreen> // MARK: - // ... டংΛकΔͨΊͷ࿑ྗͷൃੜ
  51. } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { 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<Void> = PublishRelay() let okButtonDidTap: PublishRelay<Void> = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver<Bool> let showError: Signal<Sample.Error> // MARK: - SampleViewModelCoordinatorOutputs let show: Observable<RequestScreen> // MARK: - // ...
  52. } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { 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<Void> = PublishRelay() let okButtonDidTap: PublishRelay<Void> = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver<Bool> let showError: Signal<Sample.Error> // MARK: - SampleViewModelCoordinatorOutputs let show: Observable<RequestScreen> let showError: Signal<Sample.Error> // MARK: - ৔ॴͷޡΓ
  53. } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { 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<Void> = PublishRelay() let okButtonDidTap: PublishRelay<Void> = PublishRelay() // MARK: - SampleViewModelOutputs let isOkButtonEnabled: Driver<Bool> let showError: Signal<Sample.Error> // MARK: - SampleViewModelCoordinatorOutputs let show: Observable<RequestScreen> // MARK: - // ...
  54. } protocol SampleViewModelCoordinatorOutputs { var show: Signal<SampleViewModel.RequestScreen> { 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<Void> = PublishRelay() let okButtonDidTap: PublishRelay<Void> = PublishRelay() // MARK: - SampleViewModelOutputs let showError: Signal<Sample.Error> let isOkButtonEnabled: Driver<Bool> // MARK: - SampleViewModelCoordinatorOutputs let show: Observable<RequestScreen> // MARK: - // ... protocol ͷதͱॱ൪͕ҧ͏
 (௚͢΄Ͳ͡Όͳ͍͚Ͳɺͪΐͬͱؾʹͳͬͯ ἧ͑ͪΌ͏…)
  55. protocol Ͱͷఆٛॱʹ
 ࣮૷΋ฒͼସ͑Δ

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

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

  58. 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 } }
  59. 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 } }
  60. 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 } }
  61. let syntaxTree = try! SyntaxTreeParser.parse(fileURL) let protocolCollector = InputOutputProtocolVisitor() syntaxTree.walk(protocolCollector)

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

  63. class SyntaxRewriter

  64. 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
  65. 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
  66. class ImplSectionRewriter: SyntaxRewriter { let protocols: [Protocol] init(protocols: [Protocol]) {

    self.protocols = protocols } override func visit(_ node: ClassDeclSyntax) -> DeclSyntax { // ४ڌ͍ͯ͠Δ protocol Λ֬ೝ // property Λฒͼସ͑ͨϊʔυΛ࡞੒ // ࡞ͬͨϊʔυΛฦ͢ }
  67. 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] = []
  68. 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)
  69. } 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) }
  70. 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) } }
  71. 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)
  72. None
  73. Recap

  74. ߏจ৘ใ͔Β෼͔Δ͜ͱ͸ SwiftSyntax ΋෼͔Δ ͲΜͳ property ͕
 ͋Δʁ Class ͷએݴ͸Ͳ͜ʁ ͜ͷ

    struct ͸Կʹ
 ४ڌͯ͠Δʁ ͜ͷ struct ͸ͲΜͳ function Λ࣋ͬͯΔʁ integer literal ࢖ͬͯΔ
 ͱ͜Ζશ෦ڭ͑ͯ
  75. AST Λૢ࡞Ͱ͖Δ ಛఆͷ property ʹ private ͚͍ͭͨ Class ʹ final

    ͚͍ͭͨ ४ڌͯ͠Δ protocol ͷ એݴΛฒͼସ͍͑ͨ function Λফ͍ͨ͠ integer literal ͷ
 ϑΥʔϚοτΛ౷Ұ͍ͨ͠
  76. SyntaxVisitor SyntaxRewriter ɿ ɿ AST ͔ΒߏจΛ୳͢ AST Λฤू͢Δ AST Λ࡞Δ

    SyntaxFactory ɿ
  77. ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ