Slide 1

Slide 1 text

.BTUFSJOH4XJGU4ZOUBY LJTIJLBXBLBUTVNJ !LJTIJLBXBLBUTVNJ!IBDIZEFSNJP LJTIJLBXBLBUTVNJ

Slide 2

Slide 2 text

r 4XJGUιʔείʔυͷߏจղੳɺݕࠪɺॻ͖׵͑ɺιʔείʔυͷੜ੒Λ͓͜ͳ ͏4XJGUϥΠϒϥϦ r 4XJGUϓϩδΣΫτͷҰ෦ͱͯ͠"QQMF͔Βఏڙ͞Ε͍ͯΔެࣜπʔϧ IUUQTHJUIVCDPNBQQMFTXJGUTZOUBY r Φʔϓϯιʔειϑτ΢ΣΞ 8IBUJT4XJGU4ZOUBY 4XJGU4ZOUBYͱ͸Կ͔

Slide 3

Slide 3 text

r SFBMN4XJGU-JOU IUUQTHJUIVCDPNSFBMN4XJGU-JOU r BQQMFTXJGUGPSNBU IUUQTHJUIVCDPNBQQMFTXJGUGPSNBU r LS[ZT[UPG[BCMPDLJ4PVSDFSZ IUUQTHJUIVCDPNLS[ZT[UPG[BCMPDLJ4PVSDFSZ r VCFSNPDLPMP IUUQTHJUIVCDPNVCFSNPDLPMP 8IPVTF4XJGU4ZOUBY 4XJGU4ZOUBYͷར༻ྫ

Slide 4

Slide 4 text

r 4XJGU͔Βಋೖ༧ఆ r ίϯύΠϧ࣌ʹίʔυͷੜ੒Λͨ͠Γ ಠࣗͷݕࠪΛ௥ՃͰ͖Δ r ϚΫϩͷ࣮૷ʹ͸4XJGU4ZOUBYΛ࢖༻ ͢Δ r ϚΫϩͷྫ#Previewɺ @Observableɺ@ModelͳͲ 4XJGU.BDSPT 4XJGUϚΫϩ

Slide 5

Slide 5 text

r *OUSPEVDUJPO r 4XJGU4ZOUBY0WFSWJFX r "OBUPNZPG4ZOUBY5SFF r 4XJGU4ZOUBY"1* r &YFSDJTFT ‣ 4XJGU.BDSPT ‣ 4XJGU-JOU ‣ 4PVSDF&EJUPS&YUFOTJPOT 0VUMJOF ໨࣍

Slide 6

Slide 6 text

4XJGU4ZOUBY0WFSWJFX

Slide 7

Slide 7 text

let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let 4ZOUBY5SFF

Slide 8

Slide 8 text

let sourceFile = Parser.parse(source: "let number = 100") print(sourceFile.debugDescription) import SwiftParser 4XJGU1BSTFS 4PVSDF$PEFUP4ZOUBY5SFF

Slide 9

Slide 9 text

SourceFileSyntax ├─statements: CodeBlockItemListSyntax │ ╰─[0]: CodeBlockItemSyntax │ ╰─item: VariableDeclSyntax │ ├─attributes: AttributeListSyntax │ ├─modifiers: DeclModifierListSyntax │ ├─bindingSpecifier: keyword(SwiftSyntax.Keyword.let) │ ╰─bindings: PatternBindingListSyntax │ ╰─[0]: PatternBindingSyntax │ ├─pattern: IdentifierPatternSyntax │ │ ╰─identifier: identifier("number") │ ╰─initializer: InitializerClauseSyntax │ ├─equal: equal │ ╰─value: IntegerLiteralExprSyntax │ ╰─literal: integerLiteral("100") ╰─endOfFileToken: endOfFile let sourceFile = Parser.parse(source: "let number = 100") print(sourceFile.debugDescription) // 509.0.0 or later

Slide 10

Slide 10 text

let number = 100 let amount = 100 3FXSJUF4PVSDF$PEF 3FQMBDF4ZOUBY5SFF/PEFXJUI/FX/PEF

Slide 11

Slide 11 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 12

Slide 12 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 13

Slide 13 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile amount = 100 let SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 14

Slide 14 text

4ZOUBY5SFFΛஔ͖׵͍͑ͨϊʔυ·ͰͨͲΔ ॻ͖׵͑ͨ݁ՌΛද͢৽͍͠ϊʔυΛ༻ҙ͢Δ ৽͍͠ϊʔυͰஔ͖׵͍͑ͨϊʔυΛஔ׵͢Δ 4UFQTUP3FXSJUF4PVSDF$PEF ιʔείʔυͷॻ͖׵͑ʹඞཁͳखॱ

Slide 15

Slide 15 text

let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 16

Slide 16 text

let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 17

Slide 17 text

let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 18

Slide 18 text

πϦʔߏ଄ΛԼํ޲ʹͨͲΔ SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken let sourceFile = Parser.parse(source: "let number = 100")

Slide 19

Slide 19 text

SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken let statements = sourceFile.statements SourceFileSyntax

Slide 20

Slide 20 text

let statements = Array(sourceFile.statements) SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken

Slide 21

Slide 21 text

let statements = Array(sourceFile.statements) let codeBlock = statements[0] CodeBlockItemSyntax SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken

Slide 22

Slide 22 text

let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken

Slide 23

Slide 23 text

SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item print(item.syntaxNodeType) print(item.syntaxNodeType)

Slide 24

Slide 24 text

let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item print(item.syntaxNodeType) SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken VariableDeclSyntax

Slide 25

Slide 25 text

SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item if let decl = item.as(VariableDeclSyntax.self) { } item.as(VariableDeclSyntax.self)

Slide 26

Slide 26 text

SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item if let decl = item.as(VariableDeclSyntax.self) { let bindings = Array(decl.bindings) }

Slide 27

Slide 27 text

let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item if let decl = item.as(VariableDeclSyntax.self) { let bindings = Array(decl.bindings) let binding = bindings[0] } SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken

Slide 28

Slide 28 text

let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item if let decl = item.as(VariableDeclSyntax.self) { let bindings = Array(decl.bindings) let binding = bindings[0] if let pattern = binding.pattern.as( IdentifierPatternSyntax.self ) { } } SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken

Slide 29

Slide 29 text

let statements = Array(sourceFile.statements) let codeBlock = statements[0] let item = codeBlock.item if let decl = item.as(VariableDeclSyntax.self) { let bindings = Array(decl.bindings) let binding = bindings[0] if let pattern = binding.pattern.as( IdentifierPatternSyntax.self ) { let identifier = pattern.identifier } } SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken if let pattern = binding.pattern.as( IdentifierPatternSyntax.self ) { let identifier = pattern.identifier }

Slide 30

Slide 30 text

let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 31

Slide 31 text

let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let

Slide 32

Slide 32 text

if let number = number { } ؔ਺ͷҾ਺ ϩʔΧϧม਺ 0QUJPOBM#JOEJOH func () { let number = 0 } CodeBlockItem PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax number VariableDeclSyntax OptionalBindingConditionSyntax let IdentifierPatternSyntax number ConditionElementSyntax func round(number: Int) { ... } FunctionParameterSyntax number FunctionParameterListSyntax πϦʔͷܗΛߏ଄తʹϚονϯά͢Δ

Slide 33

Slide 33 text

4XJGU"45&YQMPSFS IUUQTTXJGUBTUFYQMPSFSDPN

Slide 34

Slide 34 text

4XJGU"45&YQMPSFS IUUQTTXJGUBTUFYQMPSFSDPN

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

πϦʔߏ଄Λ্ํ޲ʹͨͲΔ if let pattern = identifier.parent?.as( IdentifierPatternSyntax.self ) { if let binding = pattern.parent?.as( PatternBindingSyntax.self ) { } } SourceFileSyntax ├─statements │ ╰─[0] │ ╰─item │ ├─attributes │ ├─modifiers │ ├─bindingSpecifier │ ╰─bindings │ ╰─[0] │ ├─pattern │ │ ╰─identifier: "number" │ ╰─initializer │ ├─equal: equal │ ╰─value │ ╰─literal: "100" ╰─endOfFileToken

Slide 37

Slide 37 text

ιʔείʔυͷॻ͖׵͑ identifier.with(\.tokenKind, .identifier("amount"))

Slide 38

Slide 38 text

ιʔείʔυͷॻ͖׵͑ identifier.with(\.tokenKind, .identifier("amount")) amount number

Slide 39

Slide 39 text

identifier.with(\.tokenKind, .identifier("amount")) IdentifierPatternSyntax number IdentifierPatternSyntax amount ผͷ৽͍͠5SFFΛฦ͢

Slide 40

Slide 40 text

let result = decl.with( \.bindings, [ binding.with( \.pattern, PatternSyntax( pattern.with( \.identifier, identifier.with( \.tokenKind, .identifier("amount") ) ) ) ) ] ) let number = 100 let amount = 100

Slide 41

Slide 41 text

let result = decl.with( \.bindings, [ binding.with( \.pattern, PatternSyntax( pattern.with( \.identifier, identifier.with( \.tokenKind, .identifier("amount") ) ) ) ) ] ) let number = 100 let amount = 100 ݩͷཁૉ ݩͷཁૉ ݩͷཁૉ ͜ͷཁૉ͚ͩม͑Δ

Slide 42

Slide 42 text

print(result.description) let amount = 100 4ZOUBY5SFF͔ΒιʔείʔυΛੜ੒

Slide 43

Slide 43 text

let number = 100 WT3FHVMBS&YQSFTTJPO

Slide 44

Slide 44 text

let number = 100 WT3FHVMBS&YQSFTTJPO /\s*let\s+(number)\s*/

Slide 45

Slide 45 text

let /* let number defines a constant. */ number = 100 WT3FHVMBS&YQSFTTJPO /\s*let\s+(number)\s*/

Slide 46

Slide 46 text

let /* let number defines a constant. */ number = 100 WT3FHVMBS&YQSFTTJPO /\s*let\s+(number)\s*/

Slide 47

Slide 47 text

VariableDeclSyntax ├─attributes: AttributeListSyntax ├─modifiers: DeclModifierListSyntax ├─bindingSpecifier: keyword(SwiftSyntax.Keyword.let) ╰─bindings: PatternBindingListSyntax ╰─[0]: PatternBindingSyntax ├─pattern: IdentifierPatternSyntax │ ╰─identifier: identifier("number") ╰─initializer: InitializerClauseSyntax ├─equal: equal ╰─value: IntegerLiteralExprSyntax ╰─literal: integerLiteral("100") let /* let number defines a constant. */ number = 100 print(sourceFile.debugDescription)

Slide 48

Slide 48 text

VariableDeclSyntax ├─attributes: AttributeListSyntax ├─modifiers: DeclModifierListSyntax ├─bindingSpecifier: keyword(SwiftSyntax.Keyword.let) trailingTrivia=[spaces(1), blockComment("..."), spaces(1)] ╰─bindings: PatternBindingListSyntax ╰─[0]: PatternBindingSyntax ├─pattern: IdentifierPatternSyntax │ ╰─identifier: identifier("number") trailingTrivia=spaces(1) ╰─initializer: InitializerClauseSyntax ├─equal: equal trailingTrivia=spaces(1) ╰─value: IntegerLiteralExprSyntax ╰─literal: integerLiteral("100") print(sourceFile.debugDescription(includeTrivia: true)) let /* let number defines a constant. */ number = 100

Slide 49

Slide 49 text

VariableDeclSyntax ├─attributes: AttributeListSyntax ├─modifiers: DeclModifierListSyntax ├─bindingSpecifier: keyword(SwiftSyntax.Keyword.let) trailingTrivia=[spaces(1), blockComment("..."), spaces(1)] ╰─bindings: PatternBindingListSyntax ╰─[0]: PatternBindingSyntax ├─pattern: IdentifierPatternSyntax │ ╰─identifier: identifier("number") trailingTrivia=spaces(1) ╰─initializer: InitializerClauseSyntax ├─equal: equal trailingTrivia=spaces(1) ╰─value: IntegerLiteralExprSyntax ╰─literal: integerLiteral("100") print(sourceFile.debugDescription(includeTrivia: true)) let /* let number defines a constant. */ number = 100

Slide 50

Slide 50 text

VariableDeclSyntax ├─attributes: AttributeListSyntax ├─modifiers: DeclModifierListSyntax ├─bindingSpecifier: keyword(SwiftSyntax.Keyword.let) trailingTrivia=[spaces(1), blockComment("..."), spaces(1)] ╰─bindings: PatternBindingListSyntax ╰─[0]: PatternBindingSyntax ├─pattern: IdentifierPatternSyntax │ ╰─identifier: identifier("number") trailingTrivia=spaces(1) ╰─initializer: InitializerClauseSyntax ├─equal: equal trailingTrivia=spaces(1) ╰─value: IntegerLiteralExprSyntax ╰─literal: integerLiteral("100") print(sourceFile.debugDescription(includeTrivia: true)) let /* let number defines a constant. */ number = 100

Slide 51

Slide 51 text

CodeBlockItem PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax number VariableDeclSyntax let number = 100 3PVOE5SJQ4ZOUBY5SFF

Slide 52

Slide 52 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100

Slide 53

Slide 53 text

@nonobjc public let number: Int = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let AttributeListSyntax @ IdentifierTypeSyntax nonobjc DeclModifierListSyntax DeclModifierSyntax public

Slide 54

Slide 54 text

@nonobjc public let number: Int = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let AttributeListSyntax @ IdentifierTypeSyntax nonobjc DeclModifierListSyntax DeclModifierSyntax public

Slide 55

Slide 55 text

8BZTUP1SPEVDF4ZOUBY5SFF r 4XJGU1BSTFS r ϊʔυͷΠχγϟϥΠβ r 4ZOUBY#VJMEFS ˞ཁ4XJGU4ZOUBY#VJMEFS ‣ 3FTVMU#VJMEFS ‣ 4USJOH*OUFSQPMBUJPO Parser.parse(source: "let number = 100") let tree = VariableDeclSyntax( .let, name: PatternSyntax(stringLiteral: "number"), initializer: InitializerClauseSyntax( value: IntegerLiteralExprSyntax( integerLiteral: 100 ) ) ) tree.formatted() let tree: DeclSyntax = "let number = 100"

Slide 56

Slide 56 text

4XJGU4ZOUBY0WFSWJFX r 1BSTFS͸ιʔείʔυ͔Β4ZOUBY5SFFΛੜ੒͢Δ r 4ZOUBY5SFF͸ιʔείʔυΛҰఆͷߏ଄ͱͯ͠ѻ͑Δ r ۭന΍վߦɺίϝϯτ͸5SJWJBͱͯ͠4ZOUBY5SFFΛߏ੒͢Δ r ಛఆͷมΘΒͳ͍ܗΛݟ͚ͭͯߏ଄తʹϚονϯά͢Δ r 4XJGU4ZOUBYΛ࢖ͬͯ4ZOUBY5SFFΛ෦෼తʹॻ͖׵͑ΒΕΔ

Slide 57

Slide 57 text

"OBUPNZPG4ZOUBY5SFF

Slide 58

Slide 58 text

SyntaxProtocol SourceFileSyntax Pr S DeclSyntax S CodeBlockItem S VariableDeclSyntax S

Slide 59

Slide 59 text

SyntaxProtocol SourceFileSyntax Pr S DeclSyntax S CodeBlockItem S VariableDeclSyntax S

Slide 60

Slide 60 text

SyntaxProtocol TokenSyntax Pr S DeclSynta S VariableDeclS S SourceFileSyntax S 5PLFO τʔΫϯ 4ZOUBY ߏจ

Slide 61

Slide 61 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100 5PLFO

Slide 62

Slide 62 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100 5PLFO

Slide 63

Slide 63 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100 5PLFO

Slide 64

Slide 64 text

let number = 100 5PLFO 4ZOUBY5SFFͷ࠷খ୯Ґ

Slide 65

Slide 65 text

4ZOUBY/PEF ߏจͷछྨΛද͢ let number = 100 4PVSDF'JMF4ZOUBY 7BSJBCMF%FDM4ZOUBY *EFOUJ fi FS1BUUFSO4ZOUBY

Slide 66

Slide 66 text

if let decl = item.as(VariableDeclSyntax.self) { ... } if let decl = item as? VariableDeclSyntax { } ϊʔυͷܕΛม׵͢Δ ܕม׵ͷؔ਺Λ࢖͏

Slide 67

Slide 67 text

ϊʔυͷܕΛม׵͢Δ if let decl = item.as(VariableDeclSyntax.self) { // == `as?` operator } if item.is(VariableDeclSyntax.self) { == `is` operator } let decl = item.cast(VariableDeclSyntax.self) // Force cast (== as!) let decl = VariableDeclSyntax(item) // == `as?` operator ܕม׵ͷؔ਺Λ࢖͏

Slide 68

Slide 68 text

ϊʔυͷܕΛม׵͢Δ if let decl = item.as(VariableDeclSyntax.self) { // == `as?` operator } if item.is(VariableDeclSyntax.self) { == `is` operator } let decl = item.cast(VariableDeclSyntax.self) // Force cast (== as!) let decl = VariableDeclSyntax(item) // == `as?` operator ܕม׵ͷؔ਺Λ࢖͏

Slide 69

Slide 69 text

ϊʔυͷܕΛม׵͢Δ if let decl = item.as(VariableDeclSyntax.self) { // == `as?` operator } if item.is(VariableDeclSyntax.self) { == `is` operator } let decl = item.cast(VariableDeclSyntax.self) // Force cast (== as!) let decl = VariableDeclSyntax(item) // == `as?` operator ܕม׵ͷؔ਺Λ࢖͏

Slide 70

Slide 70 text

ϊʔυͷܕΛม׵͢Δ if let decl = item.as(VariableDeclSyntax.self) { // == `as?` operator } if item.is(VariableDeclSyntax.self) { == `is` operator } let decl = item.cast(VariableDeclSyntax.self) // Force cast (== as!) let decl = VariableDeclSyntax(item) // == `as?` operator ܕม׵ͷؔ਺Λ࢖͏

Slide 71

Slide 71 text

r 4ZOUBY5SFFͷ֤ϊʔυ͸ͳΜΒ͔ͷ4ZOUBY 4ZOUBY1SPUPDPM r ۩ମతͳܕΛௐ΂Δ͜ͱͰߏจͷछྨ͕Θ͔Δ FH7BSJBCMF%FDM4ZOUBYɺ'VODUJPO$BMM&YQS4ZOUBYɺ'PS4UNU4ZOUBY r 4ZOUBYͷ࠷খ୯Ґ͸τʔΫϯ 5PLFO4ZOUBY r πϦʔߏ଄ΛԼํ޲ʹͨͲΔͱ͖͸ܕͷϓϩύςΟ͕࢖͑Δ FHsourceFile.statementsɺpattern.identifier ˞ෳ਺ͷܕͷީิ͕͋Δ৔߹͸μ΢ϯΩϟετ͕ඞཁ r ্ํ޲ʹཁૉΛͨͲΔͱ͖͸దٓμ΢ϯΩϟετ͢Δ "OBUPNZPG4ZOUBY5SFF

Slide 72

Slide 72 text

r એݴ ‣ ม਺ɺؔ਺ɺΫϥεͷએݴͳͲ ‣ $MBTT%FDM4ZOUBYɺ'VODUJPO%FDM4ZOUBYɺ7BSJBCMF%FDM4ZOUBYɺ r ࣜ ஋Λฦ͢ ‣ ஋Λฦ͢ߏจɻؔ਺ݺͼग़͠ɺϓϩύςΟΞΫηεɺΫϩʔδϟͳͲ ‣ $MPTVSF&YQS4ZOUBYɺ'VODUJPO$BMM&YQS4ZOUBYɺ 4USJOH-JUFSBM&YQS4ZOUBYɺ r ͦͷଞ ‣ ܕΞϊςʔγϣϯͳͲ ‣ *EFOUJ fi FS5ZQF4ZOUBYɺ.FNCFS5ZQF4ZOUBYɺ0QUJPOBM5ZQF4ZOUBYɺ ͍Ζ͍Ζͳߏจϊʔυͷܕ

Slide 73

Slide 73 text

␣␣␣␣let␣ number␣ =␣ 100↲ 5PLFO4ZOUBY 5PLFO4ZOUBY 5PLFO4ZOUBY 5PLFO4ZOUBY 4ZOUBY5SFFͷ຤୺ɾ༿ϊʔυ

Slide 74

Slide 74 text

␣␣␣␣let␣ number␣ =␣ 100↲ 5PLFO4ZOUBY var leadingTrivia: Trivia trailingTrivia trailingTrivia trailingTrivia trailingTrivia -FBEJOH5SJWJB5SBJMJOH5SJWJB

Slide 75

Slide 75 text

␣␣␣␣let␣ number␣ =␣ 100↲ 5PLFO4ZOUBY keyword(Keyword.let) endOfFile integerLiteral("100") identifier("number") let firstToken = sourceFile.firstToken(viewMode: .sourceAccurate) let lastToken = sourceFile.lastToken(viewMode: .sourceAccurate) let previousToken = lastToken?.previousToken(viewMode: .sourceAccurate) let nextToken = firstToken?.nextToken(viewMode: .sourceAccurate) /BWJHBUF5PLFO4ZOUBY

Slide 76

Slide 76 text

4XJGU4ZOUBY"1*

Slide 77

Slide 77 text

r 4ZOUBY7JTJUPS ‣ 4ZOUBY5SFFΛਂ͞༏ઌ୳ࡧ %'4 ͰͨͲΔ αϒΫϥεͰॲཧΛ͢Δର৅ͷϊʔυͷWJTJUؔ਺ΛΦʔόʔϥΠυ͢Δ r 4ZOUBY3FXSJUFS ‣ 4ZOUBY7JTJUPSͷػೳʹՃ͑ͯɺWJTJUؔ਺ͰͨͲͬͨϊʔυΛผͷϊʔυʹॻ ͖׵͑Δ͜ͱ͕Ͱ͖Δ ‣ ϚΫϩ΍ϦϑΝΫλϦϯάɺϑΥʔϚολʔͳͲ4ZOUBY5SFFΛ༻͍ͯιʔε ίʔυΛม׵͢Δ༻్ʹ෯޿͘࢖ΘΕΔ 4XJGU4ZOUBY"1* 4ZOUBY7JTJUPS4ZOUBY3FXSJUFS

Slide 78

Slide 78 text

4ZOUBY7JTJUPS4ZOUBY3FXSJUFS visit() visit() visit() visit() visit() visit() visit() visit() visit() visit() visit() visit() visit()

Slide 79

Slide 79 text

4ZOUBY7JTJUPS open class SyntaxVisitor { public init(viewMode: SyntaxTreeViewMode) public func walk(_ node: some SyntaxProtocol) open func visit(_ node: AccessorBlockSyntax) -> SyntaxVisitorContinueKind open func visitPost(_ node: AccessorBlockSyntax) open func visit(_ node: AccessorDeclSyntax) -> SyntaxVisitorContinueKind open func visitPost(_ node: AccessorDeclSyntax) ... }

Slide 80

Slide 80 text

4ZOUBY7JTJUPS open class SyntaxVisitor { public init(viewMode: SyntaxTreeViewMode) public func walk(_ node: some SyntaxProtocol) open func visit(_ node: AccessorBlockSyntax) -> SyntaxVisitorContinueKind open func visitPost(_ node: AccessorBlockSyntax) open func visit(_ node: AccessorDeclSyntax) -> SyntaxVisitorContinueKind open func visitPost(_ node: AccessorDeclSyntax) ... } ୳ࡧ͢Δର৅ͷܕͷϊʔυͷ WJTJUؔ਺ΛΦʔόʔϥΠυ͢Δ

Slide 81

Slide 81 text

&YBNQMF'JOE"MMGBUBM&SSPS'VODUJPO$BMMT 4ZOUBY7JTJUPS class FatalErrorChecker: SyntaxVisitor { override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { ... } } return .visitChildren } }

Slide 82

Slide 82 text

&YBNQMF'JOE"MMGBUBM&SSPS'VODUJPO$BMMT 4ZOUBY7JTJUPS class FatalErrorChecker: SyntaxVisitor { override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { ... } } return .visitChildren } }

Slide 83

Slide 83 text

&YBNQMF'JOE"MMGBUBM&SSPS'VODUJPO$BMMT 4ZOUBY7JTJUPS class FatalErrorChecker: SyntaxVisitor { override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { ... } } return .visitChildren } }

Slide 84

Slide 84 text

ιʔείʔυͷςΩετΛൺֱ if calledExpression.baseName.tokenKind == .identifier("fatalError") { ... } *EFOUJGZUIF/PEFPG*OUFSFTU

Slide 85

Slide 85 text

ιʔείʔυͷςΩετΛൺֱ if calledExpression.baseName.tokenKind == .identifier("fatalError") { ... } if calledExpression.baseName.trimmed.description == "fatalError" { ... } if calledExpression.baseName.text == "fatalError" { ... } if calledExpression.baseName.description == "fatalError" { ... }

Slide 86

Slide 86 text

ιʔείʔυͷςΩετΛൺֱ if calledExpression.baseName.tokenKind == .identifier("fatalError") { ... } if calledExpression.baseName.trimmed.description == "fatalError" { ... } if calledExpression.baseName.text == "fatalError" { ... } if calledExpression.baseName.description == "fatalError" { ... } public extension SyntaxProtocol { ... var trimmed: Self { return self .with(\.leadingTrivia, []) .with(\.trailingTrivia, []) } ... }

Slide 87

Slide 87 text

ιʔείʔυͷςΩετΛൺֱ 4XJGU4ZOUBY#VJMEFS if calledExpression.baseName == "fatalError" { ... } import SwiftSyntaxBuilder ... 4USJOHϦςϥϧ͔Β4ZOUBY͕࡞ΒΕΔͷͰ ίϯύΠϧΤϥʔʹͳΒͳ͍

Slide 88

Slide 88 text

4ZOUBY"OZ7JTJUPS &YBNQMF$POWFSU4ZOUBY5SFFUP)5.- class HTMLConverter: SyntaxAnyVisitor { var html = "" override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { html += #""# return .visitChildren } override func visitAnyPost(_ node: Syntax) { html += "" } }

Slide 89

Slide 89 text

4ZOUBY"OZ7JTJUPS &YBNQMF$POWFSU4ZOUBY5SFFUP)5.- class HTMLConverter: SyntaxAnyVisitor { var html = "" override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { html += #""# return .visitChildren } override func visitAnyPost(_ node: Syntax) { html += "" } }

Slide 90

Slide 90 text

class HTMLConverter: SyntaxAnyVisitor { var html = "" override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { html += #""# return .visitChildren } override func visitAnyPost(_ node: Syntax) { html += "" } override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind { html += node.description return .visitChildren } override func visitPost(_ node: TokenSyntax) {} }

Slide 91

Slide 91 text

class HTMLConverter: SyntaxAnyVisitor { var html = "" override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { html += #""# return .visitChildren } override func visitAnyPost(_ node: Syntax) { html += "" } override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind { html += node.description return .visitChildren } override func visitPost(_ node: TokenSyntax) {} } visitAnyPost()͕ݺ͹Εͳ͍Α͏ʹ

Slide 92

Slide 92 text

class HTMLConverter: SyntaxAnyVisitor { var html = "" override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { html += #""# return .visitChildren } override func visitAnyPost(_ node: Syntax) { html += "" } override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind { html += node.description return .visitChildren } override func visitPost(_ node: TokenSyntax) {} } var kind = "\(node.tokenKind)" if let index = kind.firstIndex(of: "(") { kind = String(kind.prefix(upTo: index)) } if kind.hasSuffix("Keyword") { kind = "keyword" } html += node.leadingTrivia.pieces.map { $0.htmlEscaped() }.joined() html += """ \(node.text.htmlEscaped()) """ html += node.trailingTrivia.pieces.map { $0.htmlEscaped() }.joined() return .visitChildren

Slide 93

Slide 93 text

... let  number  =  100 ...

Slide 94

Slide 94 text

No content

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

4ZOUBY3FXSJUFS open class SyntaxRewriter { public func rewrite(_ node: some SyntaxProtocol) -> Syntax open func visitPre(_ node: Syntax) open func visitAny(_ node: Syntax) -> Syntax? open func visitPost(_ node: Syntax) open func visit(_ node: AccessorBlockSyntax) -> AccessorBlockSyntax open func visit(_ node: AccessorDeclListSyntax) -> AccessorDeclListSyntax ...

Slide 97

Slide 97 text

4ZOUBY3FXSJUFS open class SyntaxRewriter { public func rewrite(_ node: some SyntaxProtocol) -> Syntax open func visitPre(_ node: Syntax) open func visitAny(_ node: Syntax) -> Syntax? open func visitPost(_ node: Syntax) open func visit(_ node: AccessorBlockSyntax) -> AccessorBlockSyntax open func visit(_ node: AccessorDeclListSyntax) -> AccessorDeclListSyntax ... ฦͨ͠ϊʔυͷ಺༰Ͱ 4ZOUBY5SFF͕ॻ͖׵ΘΔ

Slide 98

Slide 98 text

4ZOUBY3FXSJUFS open class SyntaxRewriter { public func rewrite(_ node: some SyntaxProtocol) -> Syntax open func visitPre(_ node: Syntax) open func visitAny(_ node: Syntax) -> Syntax? open func visitPost(_ node: Syntax) open func visit(_ node: AccessorBlockSyntax) -> AccessorBlockSyntax open func visit(_ node: AccessorDeclListSyntax) -> AccessorDeclListSyntax ... WJTJU"OZ @

Slide 99

Slide 99 text

4ZOUBY3FXSJUFS open class SyntaxRewriter { public func rewrite(_ node: some SyntaxProtocol) -> Syntax open func visitPre(_ node: Syntax) open func visitAny(_ node: Syntax) -> Syntax? open func visitPost(_ node: Syntax) open func visit(_ node: AccessorBlockSyntax) -> AccessorBlockSyntax open func visit(_ node: AccessorDeclListSyntax) -> AccessorDeclListSyntax ... WJTJU1SF @

Slide 100

Slide 100 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } }

Slide 101

Slide 101 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } }

Slide 102

Slide 102 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } }

Slide 103

Slide 103 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } } ݩͷιʔείʔυͷ5SJWJBΛ ͦͷ··෮ݩ͢Δ

Slide 104

Slide 104 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } } ʮࣜʯͷߏจͷϕʔεϊʔυ Ͱ͋Δ&YQS4ZOUBYܕΛฦ͢

Slide 105

Slide 105 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } }

Slide 106

Slide 106 text

class FatalToPreconditionRewriter: SyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { if let calledExpression = node.calledExpression.as(DeclReferenceExprSyntax.self) { if calledExpression.baseName.tokenKind == .identifier("fatalError") { return super.visit( ExprSyntax( node.with( \.calledExpression, ExprSyntax( calledExpression .with(\.baseName, .identifier("preconditionFailure")) .with(\.leadingTrivia, calledExpression.leadingTrivia) ) ) ) ) } } return super.visit(node) } } TVQFSΛݺͿͱࢠཁૉͷ୳ࡧΛଓ͚Δ

Slide 107

Slide 107 text

4ZOUBY3FXSJUFS #BTF/PEFT r %FDM4ZOUBYએݴ ‣ ม਺ɺؔ਺ɺΫϥεͷએݴͳͲ r &YQS4ZOUBYࣜ ஋Λฦ͢ ‣ ஋Λฦ͢ߏจɻؔ਺ݺͼग़͠ɺϓϩύςΟΞΫηεɺΫϩʔδϟͳͲ r 1BUUFSO4ZOUBY ‣ 4XJUDIจͷ$BTFઅ΍ม਺એݴ಺ͷม਺ͷఆٛͳͲ r 5ZQF4ZOUBY ‣ ܕΞϊςʔγϣϯͳͲ

Slide 108

Slide 108 text

4ZOUBY3FXSJUFS #BTF/PEFT // Non-failable initializer let expr = ExprSyntax(MemberAccessExprSyntax(name: .identifier("red"))) .red

Slide 109

Slide 109 text

4ZOUBY3FXSJUFS #BTF/PEFT // Non-failable initializer let expr = ExprSyntax(MemberAccessExprSyntax(name: .identifier("red"))) // Failable initializer let decl = DeclSyntax(MemberAccessExprSyntax(name: .identifier("red"))) .red nil

Slide 110

Slide 110 text

4PVSDF-PDBUJPO 4PVSDF-PDBUJPO$POWFSUFS let sourceFile = Parser.parse(source: "let number = 100") let locationConverter = SourceLocationConverter(fileName: "", tree: sourceFile) ... let identifier = pattern.identifier let start = identifier.startLocation(converter: locationConverter) let end = identifier.endLocation(converter: locationConverter) print("\(start.line):\(start.column)...\(end.line):\(end.column)") 1:5...1:11

Slide 111

Slide 111 text

4PVSDF-PDBUJPO 4PVSDF-PDBUJPO$POWFSUFS let sourceFile = Parser.parse(source: "let number = 100") let locationConverter = SourceLocationConverter(fileName: "", tree: sourceFile) ... let identifier = pattern.identifier let start = identifier.startLocation(converter: locationConverter) let end = identifier.endLocation(converter: locationConverter) print("\(start.line):\(start.column)...\(end.line):\(end.column)") 1:5...1:11 let start = identifier.startLocation(converter: locationConverter) let end = identifier.endLocation(converter: locationConverter) print("\(start.line):\(start.column)...\(end.line):\(end.column)") let number = 100 1:5 1:11

Slide 112

Slide 112 text

4PVSDF-PDBUJPO 4PVSDF-PDBUJPO$POWFSUFS func startLocation( converter: SourceLocationConverter, afterLeadingTrivia: Bool = true ) -> SourceLocation func endLocation( converter: SourceLocationConverter, afterTrailingTrivia: Bool = false ) -> SourceLocation number

Slide 113

Slide 113 text

4XJGU4ZOUBYJT0OMZ"CPVU4ZOUBY *U%PFTO`U,OPX"OZUIJOH"CPVU5ZQFTBOE*OIFSJUBODF r 4XJGU4ZOUBY͸ߏจ ςΩετ ͷΈΛѻ͏ r ܕ৘ใ΍ίϯύΠϧՄೳ͔Ͳ͏͔ͳͲ͸4XJGU4ZOUBY͸Θ͔Βͳ͍ ‣ ಉ໊͡લͷผͷؔ਺ͷ۠ผ͕͔ͭͳ͍ ‣ ܕΞϊςʔγϣϯ͕লུ͞Εͨม਺΍Ҿ਺ͷܕ͕Θ͔Βͳ͍

Slide 114

Slide 114 text

4XJGU4ZOUBYJT0OMZ"CPVU4ZOUBY *U%PFTO`U,OPX"OZUIJOH"CPVU5ZQFTBOE*OIFSJUBODF let result = run() IdentifierPatternSyntax

Slide 115

Slide 115 text

let result = run() : Int TypeAnnotationSyntax 4XJGU4ZOUBYJT0OMZ"CPVU4ZOUBY *U%PFTO`U,OPX"OZUIJOH"CPVU5ZQFTBOE*OIFSJUBODF IdentifierPatternSyntax

Slide 116

Slide 116 text

1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT r จ๏Τϥʔ͕͋ͬͯ΋ࣗಈతʹͭͭ͡·ͷ߹͏τʔΫϯΛ௥Ճͯ͠ଓߦ͢Δ r ਖ਼͘͠ͳ͍จ๏ɺίϯύΠϧͰ͖ͳ͍ιʔείʔυͰ΋1BSTFͰ͖Δ

Slide 117

Slide 117 text

1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT

Slide 118

Slide 118 text

1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT 1BSTFS͕ิ׬ͨ͠τʔΫϯ

Slide 119

Slide 119 text

1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT SyntaxVisitor(viewMode: .sourceAccurate) enum SyntaxTreeViewMode { case sourceAccurate case fixedUp case all } ιʔείʔυʹදࣔ͞ΕΔτʔΫϯͷΈ 1BSTFS͕ิ׬ͨ͠τʔΫϯ΋८ճ͢Δ 1BSTFS͕ิ׬ͨ͠τʔΫϯ͓Αͼ༧ظ͠ͳ͍ϊʔυ΋८ճ͢Δ

Slide 120

Slide 120 text

1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT r จ๏Τϥʔ͕͋ͬͯ΋ࣗಈతʹͭͭ͡·ͷ߹͏τʔΫϯΛ௥Ճͯ͠ଓߦ͢Δ r ਖ਼͘͠ͳ͍จ๏ɺίϯύΠϧͰ͖ͳ͍ιʔείʔυͰ΋1BSTFͰ͖Δ r ϚΫϩʹ͸ίϯύΠϥͷνΣοΫޙͷΤϥʔͷͳ͍4ZOUBY5SFF͕౉͞ΕΔ r ෆ׬શͳίʔυɺΤϥʔΛؚΉ4ZOUBY5SFF IBT&SSPSϓϩύςΟΛνΣοΫ ͷѻ͍ʹ஫ҙ

Slide 121

Slide 121 text

&YFSDJTFT4XJGU.BDSPT *OJU.BDSP

Slide 122

Slide 122 text

4XJGU.BDSPT *OJU.BDSP @Init class Person { let name: String let age: Int let birthday: Date? } class Person { let name: String let age: Int let birthday: Date? }

Slide 123

Slide 123 text

4XJGU.BDSPT *OJU.BDSP @Init class Person { let name: String let age: Int let birthday: Date? } class Person { let name: String let age: Int let birthday: Date? } } init( name: String, age: Int, birthday: Date? ) { self.name = name self.age = age self.birthday = birthday }

Slide 124

Slide 124 text

4XJGU.BDSPT *OJU.BDSP struct InitMacro: MemberMacro { static func expansion( of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { ... } }

Slide 125

Slide 125 text

4XJGU.BDSPT *OJU.BDSP struct InitMacro: MemberMacro { static func expansion( of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { ... } } @Init

Slide 126

Slide 126 text

4XJGU.BDSPT *OJU.BDSP struct InitMacro: MemberMacro { static func expansion( of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { ... } } @Init class Person { let name: String let age: Int let birthday: Date? }

Slide 127

Slide 127 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\($0.)\($0.)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\($0.) = \($0.)" }.joined(separator: "\n")) } """ ]

Slide 128

Slide 128 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\($0.)\($0.)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\($0.) = \($0.)" }.joined(separator: "\n")) } """ ] class Person { let name: String let age: Int let birthday: Date? }

Slide 129

Slide 129 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\($0.)\($0.)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\($0.) = \($0.)" }.joined(separator: "\n")) } """ ] (name, String) (age, Int) (birthday, Date?)

Slide 130

Slide 130 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\($0.)\($0.)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\($0.) = \($0.)" }.joined(separator: "\n")) } """ ] (pattern, typeAnnotation)

Slide 131

Slide 131 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ]

Slide 132

Slide 132 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } init( pattern: typeAnnotation, ) { self.pattern = pattern }

Slide 133

Slide 133 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ] return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ] import SwiftSyntaxBuilder ...

Slide 134

Slide 134 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ] return [ DeclSyntax( InitializerDeclSyntax( signature: FunctionSignatureSyntax( input: ParameterClauseSyntax( parameterList: FunctionParameterListSyntax( variableDecls.map { (pattern, typeAnnotation) in FunctionParameterSyntax(firstName: pattern.identifier, type: typeAnnotation.type) } ) ) ), body: CodeBlockSyntax( statements: CodeBlockItemListSyntax( variableDecls.map { (pattern, typeAnnotation) in CodeBlockItemSyntax( item: CodeBlockItemSyntax.Item( InfixOperatorExprSyntax( leftOperand: MemberAccessExprSyntax( base: IdentifierExprSyntax(identifier: .keyword(.self)), name: pattern.identifier ), operatorOperand: AssignmentExprSyntax(), rightOperand: IdentifierExprSyntax(identifier: pattern.identifier) ) ) ) } ) ) ) ) ]

Slide 135

Slide 135 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ] init(name:Stringage:Intbirthday:Date?){self.name=nameself.age=ageself.birthday=birthday}

Slide 136

Slide 136 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ] init(name: String age: Int birthday: Date?) { self.name = name self.age = age self.birthday = birthday } .formatted(using: BasicFormat())

Slide 137

Slide 137 text

let variableDecls: [(pattern: IdentifierPatternSyntax, typeAnnotation: TypeAnnotationSyntax)] variableDecls = declaration.memberBlock.members.compactMap { guard let decl = $0.decl.as(VariableDeclSyntax.self) else { return nil } guard let binding = decl.bindings.first else { return nil } guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } guard let typeAnnotation = binding.typeAnnotation else { return nil } return (pattern, typeAnnotation) } return [ """ init( \(raw: variableDecls.map { "\(pattern)\(typeAnnotation)" }.joined(separator: ",\n")) ) { \(raw: variableDecls.map { "self.\(pattern) = \(pattern)" }.joined(separator: "\n")) } """ ] init(name: String age: Int birthday: Date?) { self.name = name self.age = age self.birthday = birthday } .formatted(using: BasicFormat()) struct InitMacro: MemberMacro { static var formatMode: FormatMode = .disabled ...

Slide 138

Slide 138 text

'PMEJOH4FRVFODF&YQSFTTJPOT 4XJGU0QFSBUPST SequenceExprSyntax ExprListSyntax DeclReferenceExprSyntax BinaryOperatorExpr a + DeclReferenceExprSyntax BinaryOperatorExpr * b DeclReferenceExprSyntax c InfixOperatorExprSyntax DeclReferenceExprSyntax BinaryOperatorExpr a + DeclReferenceExprSyntax BinaryOperatorExpr * b DeclReferenceExprSyntax c InfixOperatorExprSyntax if a + b * c == d { ... } 1BSTF 'PME

Slide 139

Slide 139 text

'PMEJOH4FRVFODF&YQSFTTJPOT 4XJGU0QFSBUPST r ԋࢉࢠͷ༏ઌॱҐʹैͬͯ4ZOUBY5SFFΛʮંΓͨͨΉʯ r ԋࢉࢠͷ༏ઌॱҐͷ௨Γʹ८ճͰ͖ΔπϦʔߏ଄͕ੜ੒͞ΕΔ r ԋࢉࢠͷ༏ઌॱҐ͸ԋࢉࢠςʔϒϧʹ͋Β͔͡Ίొ࿥͢Δ r ະ஌ͷԋࢉࢠ ಠࣗఆٛͷԋࢉࢠ ͕ԋࢉࢠ͕͋Δͱࣦഊ͢Δ r ϚΫϩͷ৔߹ɺࣗಈͰંΓͨͨΜͩ4ZOUBY5SFF͕౉͞ΕΔ ‣ ࣗ෼Ͱ1BSTFͨ͠4ZOUBY5SFFͱҟͳ͍ͬͯͯ΋͋Θͯͳ͍ r ϚΫϩͷ৔߹ɺಠࣗఆٛͷԋࢉࢠ͕͋ͬͯ΋ڧҾʹંΓͨͨΉ ‣ ༏ઌॱҐ͕ؒҧͬͯંΓͨͨ·ΕΔ ৔߹͕͋Δ r ໰୊͕͋Δ৔߹͸4ZOUBY5SFF͔ΒιʔείʔυΛੜ੒ͯࣗ͠෼Ͱ࠶1BSTF͢Δ

Slide 140

Slide 140 text

"OBUPNZPG4XJGU4ZOUBY 4XJGU4ZOUBY 4XJGU4ZOUBY.BDSPT 4XJGU0QFSBUPST 4XJGU4ZOUBY#VJMEFS 4XJGU1BSTFS 4XJGU$PNQJMFS1MVHJO 4XJGU#BTJD'PSNBU 4ZOUBY5SFFͷσʔλߏ଄ ܕ ͱ7JTJUPSɾ 3FXSJUFSͳͲجຊతͳ"1*Λఏڙ ߏจղੳͱ4ZOUBY5SFFͷੜ੒ จࣈྻϦςϥϧ &YQSFTTJCMF#Z4USJOH-JUFSBM ΍3FTVMU#VJMEFS͔Β4ZOUBY5SFFΛੜ੒͢Δ "1*Λఏڙ ϚΫϩͷ࣮૷ʹඞཁͳ"1*Λఏڙ ඞཁͳۭന΍վߦΛࣗಈతʹૠೖ͢Δ ԋࢉࢠͷ༏ઌॱҐʹैͬͯࣜΛʮંΓͨͨΉʯ

Slide 141

Slide 141 text

*OJU.BDSP "EWBODFE&YFSDJTFT r $MBTTɺ4USVDUɺ"DUPSҎ֎ͷܕʹద༻͠ͳ͍ r ܕʹͭ͘ΞΫηεम০ࢠ QVCMJDɺQSJWBUFͳͲ ͱΠχγϟϥΠβͷΞΫηεϨ ϕϧΛҰகͤ͞Δ r $PNQVUFE1SPQFSUZΛআ֎͢Δ r ؔ਺ܕͷϓϩύςΟʹରԠ͢Δ r αϯϓϧίʔυ IUUQTHJUIVCDPNLJTIJLBXBLBUTVNJJPTEDTBNQMFT

Slide 142

Slide 142 text

&YFSDJTFT4XJGU-JOU 0QFOJOH#SBDF4QBDJOH3VMF

Slide 143

Slide 143 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF PQFOJOH@CSBDF r 0QFOJOHCSBDFTTIPVMECFQSFDFEFECZBTJOHMFTQBDFBOEPOUIFTBNF MJOFBTUIFEFDMBSBUJPO func run() { } if a == b { } func run(){ } func run() { } if a == b { } guard let a = b else { }

Slide 144

Slide 144 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF 'BMDF1PTUJWF let pattern = /(\{(?\w+)\})/ Opening Brace Spacing Violation

Slide 145

Slide 145 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF %FUFDUWJPMBUJPO🔎 override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind { if node.tokenKind == .leftBrace { if let previousToken = node.previousToken(viewMode: .sourceAccurate), previousToken.trailingTrivia == .space { let position = node.positionAfterSkippingLeadingTrivia violations.append(position) } } return .visitChildren }

Slide 146

Slide 146 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF %FUFDUWJPMBUJPO🔎 override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind { if node.tokenKind == .leftBrace { if let previousToken = node.previousToken(viewMode: .sourceAccurate), previousToken.trailingTrivia == .space { let position = node.positionAfterSkippingLeadingTrivia violations.append(position) } } return .visitChildren }

Slide 147

Slide 147 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF %FUFDUWJPMBUJPO🔎 override func visit(_ node: TokenSyntax) -> SyntaxVisitorContinueKind { if node.tokenKind == .leftBrace { if let previousToken = node.previousToken(viewMode: .sourceAccurate), previousToken.trailingTrivia == .space { let position = node.positionAfterSkippingLeadingTrivia violations.append(position) } } return .visitChildren }

Slide 148

Slide 148 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF "VUPDPSSFDUJPO🪄 func run() { } func run(){ } func run() { } if a == b { } func run() { } if a == b { }

Slide 149

Slide 149 text

5IF5SJWJB"UUSJCVUJPO3VMF "UPLFOPXOTBMMPGJUTUSBJMJOHUSJWJBVQUP CVUOPUJODMVEJOH UIFOFYU OFXMJOFDIBSBDUFS -PPLJOHCBDLXBSEJOUIFUFYU BUPLFOPXOTBMMPGUIFMFBEJOHUSJWJBVQ UPBOEJODMVEJOHUIF fi STUDPOUJHVPVTTFRVFODFPGOFXMJOFTDIBSBDUFST IUUQTHJUIVCDPNBQQMFTXJGUTZOUBYJTTVFT

Slide 150

Slide 150 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF 5IF5SJWJB"UUSJCVUJPO3VMF func run()␣␣{↲ ␣␣*** }

Slide 151

Slide 151 text

func run()␣␣↲ {↲ ␣␣*** } func run()↲ {↲ ␣␣*** } func run()␣␣{↲ ␣␣*** } 4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF 5IF5SJWJB"UUSJCVUJPO3VMF

Slide 152

Slide 152 text

SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax FunctionDeclSyntax FunctionSignatureSyntax FunctionParameterSyntax FunctionParameterClauseSyntax CodeBlockSyntax CodeBlockItemListSyntax endOfFile ( { } func run FunctionParameterListSyntax )

Slide 153

Slide 153 text

override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) }

Slide 154

Slide 154 text

override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) }

Slide 155

Slide 155 text

override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) }

Slide 156

Slide 156 text

override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) } private extension TokenSyntax { func hasSingleSpaceLeading() -> Bool { if let previousToken = previousToken(viewMode: .sourceAccurate), previousToken.trailingTrivia == .space { return true } else { return false } } }

Slide 157

Slide 157 text

override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) }

Slide 158

Slide 158 text

override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) } func run(name: T) { } ??????????????

Slide 159

Slide 159 text

No content

Slide 160

Slide 160 text

No content

Slide 161

Slide 161 text

No content

Slide 162

Slide 162 text

func run(name: T) where T: StringProtocol { }

Slide 163

Slide 163 text

override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) if let genericWhereClause = node.genericWhereClause { return super.visit( node .with(\.genericWhereClause, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) }

Slide 164

Slide 164 text

override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { guard let body = node.body else { return super.visit(node) } let openingBrace = body.leftBrace if !openingBrace.hasSingleSpaceLeading() { let position = openingBrace.positionAfterSkippingLeadingTrivia correctionPositions.append(position) if let genericWhereClause = node.genericWhereClause { return super.visit( node .with(\.genericWhereClause, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit( node .with(\.signature, node.signature.with(\.trailingTrivia, .space)) .with(\.leftBrace, node.leftBrace.with(\.leadingTrivia, [])) ) } return super.visit(node) }

Slide 165

Slide 165 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF "VUPDPSSFDUJPO🪄 func run(name: T) where T: StringProtocol { } func run() { } func run(){ } func run(name: T) where T: StringProtocol { } if a == b { } if a == b { } *Gจ΋ର৅ɻଞʹ͸ʁ

Slide 166

Slide 166 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS IUUQTEPDTTXJGUPSHTXJGUCPPLEPDVNFOUBUJPOUIFTXJGUQSPHSBNNJOHMBOHVBHFTVNNBSZPGUIFHSBNNBS

Slide 167

Slide 167 text

-BOHVBHF3FGFSFODF "CPVUUIF-BOHVBHF3FGFSFODF IUUQTEPDTTXJGUPSHTXJGUCPPLEPDVNFOUBUJPOUIFTXJGUQSPHSBNNJOHMBOHVBHFBCPVUUIFMBOHVBHFSFGFSFODF

Slide 168

Slide 168 text

-BOHVBHF3FGFSFODF "CPVUUIF-BOHVBHF3FGFSFODF r "OBSSPX ˠ JTVTFEUPNBSLHSBNNBSQSPEVDUJPOTBOEDBOCFSFBEBTlDBODPOTJTUPGz r 4ZOUBDUJDDBUFHPSJFTBSFJOEJDBUFECZJUBMJDUFYUBOEBQQFBSPOCPUITJEFTPGBHSBNNBS QSPEVDUJPOSVMF r -JUFSBMXPSETBOEQVODUVBUJPOBSFJOEJDBUFECZCPMEGBDFDPOTUBOUXJEUIUFYUBOEBQQFBSPOMZPO UIFSJHIUIBOETJEFPGBHSBNNBSQSPEVDUJPOSVMF r "MUFSOBUJWFHSBNNBSQSPEVDUJPOTBSFTFQBSBUFECZWFSUJDBMCBST c 8IFOBMUFSOBUJWF QSPEVDUJPOTBSFUPPMPOHUPSFBEFBTJMZ UIFZ`SFCSPLFOJOUPNVMUJQMFHSBNNBSQSPEVDUJPOSVMFT POOFXMJOFT r *OBGFXDBTFT SFHVMBSGPOUUFYUJTVTFEUPEFTDSJCFUIFSJHIUIBOETJEFPGBHSBNNBSQSPEVDUJPO SVMF r 0QUJPOBMTZOUBDUJDDBUFHPSJFTBOEMJUFSBMTBSFNBSLFECZBUSBJMJOHRVFTUJPONBSL

Slide 169

Slide 169 text

-BOHVBHF3FGFSFODF "CPVUUIF-BOHVBHF3FGFSFODF r ໼ҹ ˠ ͸ߏจΛࣔ͠ɺʮࠨล͸ӈลͷʓʓͰߏ੒͞ΕΔʯͱಡΈ·͢ r ߏจΧςΰϦ͸ΠλϦοΫͷςΩετͰࣔ͞Εɺߏจϧʔϧͷ྆ଆʹݱΕ·͢ r ୯ޠϦςϥϧͱه߸͸ɺଠࣈͰ౳෯ͷॻମͰࣔ͞ΕɺߏจϧʔϧͷӈଆʹͷΈݱΕ ·͢ r ෳ਺ͷॻ͖ํ͕͋Δߏจ͸ύΠϓ c Ͱ۠੾ΒΕ·͢ɻԣʹ௕͘ಡΈʹ͘͘ͳΔ৔߹ ͸৽͍͠ߦͰෳ਺ͷߏจϧʔϧʹ෼ׂ͞Ε·͢ r ௨ৗͷॻମΛ࢖༻ͯ͠จ๏نଇͷӈଆΛهड़͢Δ͜ͱ͕͋Γ·͢ r ඞਢͰ͸ͳ͍ߏจΧςΰϦͱϦςϥϧ͸ɺ຤ඌʹΫΤενϣϯϚʔΫA A͕෇͖·͢

Slide 170

Slide 170 text

-BOHVBHF3FGFSFODF "CPVUUIF-BOHVBHF3FGFSFODF Grammar of a getter-setter block getter-setter-block → { getter-clause setter-clause? } | { setter-clause getter-clause } var name: String { get { ... } set { ... } } var name: String { get { ... } }

Slide 171

Slide 171 text

Grammar of a function declaration function-declaration → function-head function-name generic-parameter-clause? function-signature generic-where-clause? function-body? function-head → attributes? declaration-modi fi ers? func function-name → identi fi er | operator function-signature → parameter-clause async? throws? function-result? function-signature → parameter-clause async? rethrows function-result? function-result → -> attributes? type function-body → code-block parameter-clause → ( ) | ( parameter-list ) parameter-list → parameter | parameter , parameter-list parameter → external-parameter-name? local-parameter-name type-annotation default-argument-clause? parameter → external-parameter-name? local-parameter-name type-annotation parameter → external-parameter-name? local-parameter-name type-annotation ... external-parameter-name → identi fi er local-parameter-name → identi fi er default-argument-clause → = expression

Slide 172

Slide 172 text

Grammar of a function declaration function-declaration → function-head function-name generic-parameter-clause? function-signature generic-where-clause? function-body? function-head → attributes? declaration-modi fi ers? func function-name → identi fi er | operator function-signature → parameter-clause async? throws? function-result? function-signature → parameter-clause async? rethrows function-result? function-result → -> attributes? type function-body → code-block parameter-clause → ( ) | ( parameter-list ) parameter-list → parameter | parameter , parameter-list parameter → external-parameter-name? local-parameter-name type-annotation default-argument-clause? parameter → external-parameter-name? local-parameter-name type-annotation parameter → external-parameter-name? local-parameter-name type-annotation ... external-parameter-name → identi fi er local-parameter-name → identi fi er default-argument-clause → = expression

Slide 173

Slide 173 text

Grammar of a function declaration function-declaration → function-head function-name generic-parameter-clause? function-signature generic-where-clause? function-body? function-head → attributes? declaration-modi fi ers? func function-name → identi fi er | operator function-signature → parameter-clause async? throws? function-result? function-signature → parameter-clause async? rethrows function-result? function-result → -> attributes? type function-body → code-block parameter-clause → ( ) | ( parameter-list ) parameter-list → parameter | parameter , parameter-list parameter → external-parameter-name? local-parameter-name type-annotation default-argument-clause? parameter → external-parameter-name? local-parameter-name type-annotation parameter → external-parameter-name? local-parameter-name type-annotation ... external-parameter-name → identi fi er local-parameter-name → identi fi er default-argument-clause → = expression

Slide 174

Slide 174 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS Grammar of a code block code-block → { statements? }

Slide 175

Slide 175 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r ม਺એݴ r $PNQVUFE1SPQFSUZ r HFUUFSTFUUFS r XJMM4FUEJE4FU r GPSJOXIJMFSFQFBUXIJMFJGHVBSETXJUDI r EFGFS r EPEPDBUDI

Slide 176

Slide 176 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS Grammar of a structure declaration struct-declaration → attributes? access-level-modi fi er? struct struct-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? struct-body struct-name → identi fi er struct-body → { struct-members? } struct-members → struct-member struct-members? struct-member → declaration | compiler-control-statement

Slide 177

Slide 177 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r FOVNTUSVDUDMBTTBDUPSQSPUPDPMFYUFOTJPOએݴ r QSFDFEFODFHSPVQએݴ r $MPTVSF r 6OJDPEF&TDBQF r "UUSJCVUFT

Slide 178

Slide 178 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r FOVNTUSVDUDMBTTBDUPSQSPUPDPMFYUFOTJPOએݴ r QSFDFEFODFHSPVQએݴ r $MPTVSF r 6OJDPEF&TDBQF r "UUSJCVUFT

Slide 179

Slide 179 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r ม਺એݴ r $PNQVUFE1SPQFSUZ r HFUUFSTFUUFS r XJMM4FUEJE4FU r GPSJOXIJMFSFQFBUXIJMFJGHVBSETXJUDI r EFGFS r EPEPDBUDI r FOVNTUSVDUDMBTTBDUPSQSPUPDPMFYUFOTJPOએݴ r QSFDFEFODFHSPVQએݴ r $MPTVSF

Slide 180

Slide 180 text

-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r ม਺એݴ r $PNQVUFE1SPQFSUZ r HFUUFSTFUUFS r XJMM4FUEJE4FU r GPSJOXIJMFSFQFBUXIJMFJGHVBSEEFGFSEPEPDBUDI r FOVNTUSVDUDMBTTBDUPSQSPUPDPMFYUFOTJPOએݴ r QSFDFEFODFHSPVQએݴ r TXJUDI$MPTVSF %FDM(SPVQ4ZOUBY 8JUI$PEF#MPDL4ZOUBY 8JUI4UBUFNFOUT4ZOUBY

Slide 181

Slide 181 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF "VUPDPSSFDUJPO🪄 extension DeclGroupSyntax { func violationPosition() -> AbsolutePosition? { let openingBrace = memberBlock.leftBrace if !openingBrace.hasSingleSpaceLeading() { return openingBrace.positionAfterSkippingLeadingTrivia } return nil } }

Slide 182

Slide 182 text

override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { if let position = node.violationPosition() { violations.append(position) } return .visitChildren } override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { if let position = node.violationPosition() { violations.append(position) } return .visitChildren } ...

Slide 183

Slide 183 text

private extension DeclGroupSyntax { ... func correct(keyPath: WritableKeyPath) -> Self { return self .with(keyPath, self[keyPath: keyPath].with(\.trailingTrivia, .space)) .with(\.memberBlock, memberBlock.with(\.leadingTrivia, [])) } func correct(keyPath: WritableKeyPath) -> Self? { guard let value = self[keyPath: keyPath] else { return nil } return self .with(keyPath, value.with(\.trailingTrivia, .space)) .with(\.memberBlock, memberBlock.with(\.leadingTrivia, [])) } }

Slide 184

Slide 184 text

4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF -FTTPOT-FBSOFE r 4ZOUBY7JTJUPSΛ࢖ͬͯҧ൓ΛνΣοΫ r 4ZOUBY3FXSJUFSΛ࢖ͬͯҧ൓ΛνΣοΫˍࣗಈमਖ਼ r 1SPUPDPM&YUFOTJPOΛ࢖ͬͯॲཧΛ·ͱΊΔ r 4XJGU-BOHVBHF3FGFSFODF r 1VMM3FRVFTU IUUQTHJUIVCDPNSFBMN4XJGU-JOUQVMM

Slide 185

Slide 185 text

&YFSDJTFT4XJGU-JOU $PMMFDUJPO&MFNFOU"MJHONFOU

Slide 186

Slide 186 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU DPMMFDUJPO@BMJHONFOU r "MMFMFNFOUTJOBDPMMFDUJPOMJUFSBMTIPVMECFWFSUJDBMMZBMJHOFE let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ] let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ] let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ] let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ]

Slide 187

Slide 187 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU DPMMFDUJPO@BMJHONFOU r "MMFMFNFOUTJOBDPMMFDUJPOMJUFSBMTIPVMECFWFSUJDBMMZBMJHOFE r "MMFMFNFOUTJOBDPMMFDUJPOMJUFSBMTIPVMECFWFSUJDBMMZBMJHOFE let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ] let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ] let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ] let abc = [ "alpha": "a", "beta": "b", "gamma": "g", "delta": "d" ]

Slide 188

Slide 188 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU 'BMTF1PTJUJWF NSAttributedString( string: "…", attributes: [.font: UIFont.systemFont(ofSize: 12, weight: .regular), .foregroundColor: UIColor(white: 0, alpha: 0.2)] ) IUUQTHJUIVCDPNSFBMN4XJGU-JOUJTTVFT

Slide 189

Slide 189 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU 'BMTF1PTJUJWF NSAttributedString( string: "…", attributes: [.font: UIFont.systemFont(ofSize: 12, weight: .regular), .foregroundColor: UIColor(white: 0, alpha: 0.2)] ) IUUQTHJUIVCDPNSFBMN4XJGU-JOUJTTVFT 31 29

Slide 190

Slide 190 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU DPMMFDUJPO@BMJHONFOU "…".utf8.count 3

Slide 191

Slide 191 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU DPMMFDUJPO@BMJHONFOU override func visitPost(_ node: DictionaryElementListSyntax) { let locations = node.map { element in let position = alignColons ? element.colon.positionAfterSkippingLeadingTrivia : element.keyExpression.positionAfterSkippingLeadingTrivia return locationConverter.location(for: position) } violations.append(contentsOf: validate(keyLocations: locations)) } "4$** 65'ͰCZUF ͳΒ੒Γཱͭ

Slide 192

Slide 192 text

override func visitPost(_ node: DictionaryElementListSyntax) { let locations = node.map { element in let position = alignColons ? element.colon.positionAfterSkippingLeadingTrivia : element.keyExpression.positionAfterSkippingLeadingTrivia let location = locationConverter.location(for: position) let graphemeColumn: Int let graphemeClusters = String( locationConverter.sourceLines[location.line - 1].utf8.prefix(location.column - 1) ) if let graphemeClusters { graphemeColumn = graphemeClusters.count + 1 } else { graphemeColumn = location.column } return SourceLocation( line: location.line, column: graphemeColumn, offset: location.offset, file: location.file ) } violations.append(contentsOf: validate(keyLocations: locations)) }

Slide 193

Slide 193 text

override func visitPost(_ node: DictionaryElementListSyntax) { let locations = node.map { element in let position = alignColons ? element.colon.positionAfterSkippingLeadingTrivia : element.keyExpression.positionAfterSkippingLeadingTrivia let location = locationConverter.location(for: position) let graphemeColumn: Int let graphemeClusters = String( locationConverter.sourceLines[location.line - 1].utf8.prefix(location.column - 1) ) if let graphemeClusters { graphemeColumn = graphemeClusters.count + 1 } else { graphemeColumn = location.column } return SourceLocation( line: location.line, column: graphemeColumn, offset: location.offset, file: location.file ) } violations.append(contentsOf: validate(keyLocations: locations)) } locationConverter.sourceLines[location.line - 1].utf8.prefix(location.column - 1) ݩͷιʔείʔυ͕ߦ͝ͱʹ֨ೲ͞Εͨ഑ྻ

Slide 194

Slide 194 text

override func visitPost(_ node: DictionaryElementListSyntax) { let locations = node.map { element in let position = alignColons ? element.colon.positionAfterSkippingLeadingTrivia : element.keyExpression.positionAfterSkippingLeadingTrivia let location = locationConverter.location(for: position) let graphemeColumn: Int let graphemeClusters = String( locationConverter.sourceLines[location.line - 1].utf8.prefix(location.column - 1) ) if let graphemeClusters { graphemeColumn = graphemeClusters.count + 1 } else { graphemeColumn = location.column } return SourceLocation( line: location.line, column: graphemeColumn, offset: location.offset, file: location.file ) } violations.append(contentsOf: validate(keyLocations: locations)) } 29 31

Slide 195

Slide 195 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU 'BMTF1PTJUJWF NSAttributedString( string: "…", attributes: [.font: UIFont.systemFont(ofSize: 12, weight: .regular), .foregroundColor: UIColor(white: 0, alpha: 0.2)] ) IUUQTHJUIVCDPNSFBMN4XJGU-JOUJTTVFT

Slide 196

Slide 196 text

No content

Slide 197

Slide 197 text

let graphemeStartColumn: Int if let prefix = String(locationConverter.sourceLines[start.line - 1].utf8.prefix(start.column - 1)) { graphemeStartColumn = prefix.utf16.count + 1 } else { graphemeStartColumn = start.column } let graphemeEndColumn: Int if let prefix = String(locationConverter.sourceLines[end.line - 1].utf8.prefix(end.column - 1)) { graphemeEndColumn = prefix.utf16.count + 1 } else { graphemeEndColumn = end.column } 4XJGU"45&YQMPSFS +BWB4DSJQU4USJOH-FOHUI*TJO65'$PEF6OJUT

Slide 198

Slide 198 text

4XJGU-JOU$PMMFDUJPO&MFNFOU"MJHONFOU -FTTPOT-FBSOFE r 4XJGU4ZOUBYͷߏจϊʔυͷҐஔ৘ใ͸65'ͷόΠτ਺ r ࣮ࡍͷιʔείʔυͷҐஔͱ͸ඞͣ͠΋Ұக͠ͳ͍ "4$**Ҏ֎ͷจࣈͳͲ r ࠷ऴతͳग़ྗઌʹ߹Θͤͯ޻෉͕ඞཁ ‣ ݟͨ໨ͷจࣈ਺ˠॻهૉΫϥελ ‣ +BWB4DSJQUˠ65' r 1VMM3FRVFTU IUUQTHJUIVCDPNSFBMN4XJGU-JOUJTTVFT

Slide 199

Slide 199 text

&YFSDJTFT4PVSDF&EJUPS&YUFOTJPOT

Slide 200

Slide 200 text

&YFSDJTFT4PVSDF&EJUPS&YUFOTJPOT $POWFSU9$5"TTFSU'VODUJPOTUP1PXFS"TTFSU.BDSPT XCTAssert(actual == expected) XCTAssertEqual(actual, expected) XCTAssertNotEqual(actual, expected) XCTAssertGreaterThan(a, b) XCTAssertGreaterThanOrEqual(a, b) XCTAssertIdentical(actual, expected) XCTAssertNotIdentical(actual, expected) #assert(actual == expected) #assert(actual == expected) #assert(actual != expected) #assert(a > b) #assert(a >= b) #assert(actual === expected) #assert(actual !== expected)

Slide 201

Slide 201 text

&YFSDJTFT4PVSDF&EJUPS&YUFOTJPOT $POWFSU9$5"TTFSU'VODUJPOTUP1PXFS"TTFSU.BDSPT r 9$5"TTFSUؔ਺ΛBTTFSU ϚΫϩʹม׵͢Δ r ςετͷ࣮ߦ݁Ռ͕มΘΒͳ͍Α͏ʹ͢Δ r NFTTBHFɺ fi MFɺMJOFͷσϑΥϧτҾ਺ʹ஫ҙ͢Δ r ුಈখ਺Λൺֱ͢Δ9$5"TTFSU&RVBM @@BDDVSBDZ@ fi MFMJOF ؔ਺͸ର৅֎ r ෆ׬શͳιʔείʔυ͕౉ͬͯ͘Δ৔߹͕͋Δ r ղ౴ྫ IUUQTHJUIVCDPNLJTIJLBXBLBUTVNJTXJGUQPXFSBTTFSUQVMM

Slide 202

Slide 202 text

1VTI:PVS-JNJUT 4XJGU4ZOUBYΛϚελʔ͢ΔͨΊʹ r 4XJGU-JOUͷϧʔϧΛ4XJGU4ZOUBYΛ࢖ͬͯॻ͖׵͑Δ r 4XJGUϚΫϩΛ࡞ͬͯΈΔ r 4XJGU4ZOUBYΛ࢖ͬͯ9DPEF4PVSDF&EJUPS&YUFOTJPOΛ࡞Δ r 4XJGU"45&YQMPSFSͷ։ൃʹڠྗ͢Δ r 4XJGU1PXFS"TTFSUͷ։ൃʹڠྗ͢Δ

Slide 203

Slide 203 text

8SBQ6Q r 4XJGU1BSTFSͰιʔείʔυΛߏจղੳ͠ɺ4ZOUBY5SFFΛ୳ࡧ͢Δ r 4ZOUBY5SFFΛม׵ͯ͠ιʔείʔυΛॻ͖׵͑Δ r ϚΫϩɺ-JOUɺ'PSNBUUFSɺ9DPEF&YUFOTJPOɺͳͲ͕࡞ΕΔ r 4ZOUBY3FXSJUFS΍4PVSDF-PDBUJPO$POWFSUFSͳͲಠಛͷ"1*ʹ׳ΕΕ͹ҙ֎ ͱγϯϓϧʹॻ͚Δ r ίϯύΠϥͰ͸ͳ͍ͷͰܕ৘ใͳͲߏจ͔ΒಡΈऔΕͳ͍΋ͷ͸ѻ͑ͳ͍ r 4XJGU4ZOUBYΛ༗ޮʹ࢖͏ʹ͸4XJGUʹؔ͢Δ෯޿͍஌͕ࣝॏཁ

Slide 204

Slide 204 text

3FGFSFODFT r 4BNQMF$PEF IUUQTHJUIVCDPNLJTIJLBXBLBUTVNJJPTEDTBNQMFT r 4XJGU4ZOUBY IUUQTHJUIVCDPNBQQMFTXJGUTZOUBY r 4XJGU"45&YQMPSFS IUUQTTXJGUBTUFYQMPSFSDPN r 4XJGU-BOHVBHF3FGFSFODF IUUQTEPDTTXJGUPSHTXJGUCPPLEPDVNFOUBUJPOUIFTXJGUQSPHSBNNJOHMBOHVBHFBCPVUUIFMBOHVBHFSFGFSFODF r 4XJGU.BDSPT IUUQTHJUIVCDPNLS[ZT[UPG[BCMPDLJ4XJGU.BDSPT