r 4XJGUιʔείʔυͷߏจղੳɺݕࠪɺॻ͖͑ɺιʔείʔυͷੜΛ͓͜ͳ ͏4XJGUϥΠϒϥϦ r 4XJGUϓϩδΣΫτͷҰ෦ͱͯ͠"QQMF͔Βఏڙ͞Ε͍ͯΔެࣜπʔϧ IUUQTHJUIVCDPNBQQMFTXJGUTZOUBY r ΦʔϓϯιʔειϑτΣΞ 8IBUJT4XJGU4ZOUBY 4XJGU4ZOUBYͱԿ͔
r SFBMN4XJGU-JOU IUUQTHJUIVCDPNSFBMN4XJGU-JOU r BQQMFTXJGUGPSNBU IUUQTHJUIVCDPNBQQMFTXJGUGPSNBU r LS[ZT[UPG[BCMPDLJ4PVSDFSZ IUUQTHJUIVCDPNLS[ZT[UPG[BCMPDLJ4PVSDFSZ r VCFSNPDLPMP IUUQTHJUIVCDPNVCFSNPDLPMP 8IPVTF4XJGU4ZOUBY 4XJGU4ZOUBYͷར༻ྫ
let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let 4ZOUBY5SFF
let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let
let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let
let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let
let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let
let number = 100 SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let
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 πϦʔͷܗΛߏతʹϚονϯά͢Δ
SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100
@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
@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
4XJGU4ZOUBY0WFSWJFX r 1BSTFSιʔείʔυ͔Β4ZOUBY5SFFΛੜ͢Δ r 4ZOUBY5SFFιʔείʔυΛҰఆͷߏͱͯ͠ѻ͑Δ r ۭനվߦɺίϝϯτ5SJWJBͱͯ͠4ZOUBY5SFFΛߏ͢Δ r ಛఆͷมΘΒͳ͍ܗΛݟ͚ͭͯߏతʹϚονϯά͢Δ r 4XJGU4ZOUBYΛͬͯ4ZOUBY5SFFΛ෦తʹॻ͖͑ΒΕΔ
SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100 5PLFO
SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100 5PLFO
SourceFileSyntax CodeBlockItemListSyntax CodeBlockItemSyntax VariableDeclSyntax PatternBindingListSyntax PatternBindingSyntax IdentifierPatternSyntax InitializerClauseSyntax IntegerLiteralExprSyntax endOfFile number = 100 let let number = 100 5PLFO
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) ... }
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ؔΛΦʔόʔϥΠυ͢Δ
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 ...
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
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
1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT SyntaxVisitor(viewMode: .sourceAccurate) enum SyntaxTreeViewMode { case sourceAccurate case fixedUp case all } ιʔείʔυʹදࣔ͞ΕΔτʔΫϯͷΈ 1BSTFS͕ิͨ͠τʔΫϯ८ճ͢Δ 1BSTFS͕ิͨ͠τʔΫϯ͓Αͼ༧ظ͠ͳ͍ϊʔυ८ճ͢Δ
1BSTFS3FTJMJFODZ 1BSTFS/FWFS'BJMT r จ๏Τϥʔ͕͋ͬͯࣗಈతʹͭͭ͡·ͷ߹͏τʔΫϯΛՃͯ͠ଓߦ͢Δ r ਖ਼͘͠ͳ͍จ๏ɺίϯύΠϧͰ͖ͳ͍ιʔείʔυͰ1BSTFͰ͖Δ r ϚΫϩʹίϯύΠϥͷνΣοΫޙͷΤϥʔͷͳ͍4ZOUBY5SFF͕͞ΕΔ r ෆશͳίʔυɺΤϥʔΛؚΉ4ZOUBY5SFF IBT&SSPSϓϩύςΟΛνΣοΫ
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? }
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 }
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? }
'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
'PMEJOH4FRVFODF&YQSFTTJPOT 4XJGU0QFSBUPST r ԋࢉࢠͷ༏ઌॱҐʹैͬͯ4ZOUBY5SFFΛʮંΓͨͨΉʯ r ԋࢉࢠͷ༏ઌॱҐͷ௨Γʹ८ճͰ͖ΔπϦʔߏ͕ੜ͞ΕΔ r ԋࢉࢠͷ༏ઌॱҐԋࢉࢠςʔϒϧʹ͋Β͔͡Ίొ͢Δ r ະͷԋࢉࢠ ಠࣗఆٛͷԋࢉࢠ ͕ԋࢉࢠ͕͋Δͱࣦഊ͢Δ r ϚΫϩͷ߹ɺࣗಈͰંΓͨͨΜͩ4ZOUBY5SFF͕͞ΕΔ ‣ ࣗͰ1BSTFͨ͠4ZOUBY5SFFͱҟͳ͍ͬͯͯ͋Θͯͳ͍ r ϚΫϩͷ߹ɺಠࣗఆٛͷԋࢉࢠ͕͋ͬͯڧҾʹંΓͨͨΉ ‣ ༏ઌॱҐ͕ؒҧͬͯંΓͨͨ·ΕΔ ߹͕͋Δ
*OJU.BDSP "EWBODFE&YFSDJTFT r $MBTTɺ4USVDUɺ"DUPSҎ֎ͷܕʹద༻͠ͳ͍ r ܕʹͭ͘ΞΫηεम০ࢠ QVCMJDɺQSJWBUFͳͲ ͱΠχγϟϥΠβͷΞΫηεϨ ϕϧΛҰகͤ͞Δ r $PNQVUFE1SPQFSUZΛআ֎͢Δ r ؔܕͷϓϩύςΟʹରԠ͢Δ r αϯϓϧίʔυ IUUQTHJUIVCDPNLJTIJLBXBLBUTVNJJPTEDTBNQMFT
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 { }
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จରɻଞʹʁ
-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
-BOHVBHF3FGFSFODF "CPVUUIF-BOHVBHF3FGFSFODF r ҹ ˠ ߏจΛࣔ͠ɺʮࠨลӈลͷʓʓͰߏ͞ΕΔʯͱಡΈ·͢ r ߏจΧςΰϦΠλϦοΫͷςΩετͰࣔ͞Εɺߏจϧʔϧͷ྆ଆʹݱΕ·͢ r ୯ޠϦςϥϧͱه߸ɺଠࣈͰ෯ͷॻମͰࣔ͞ΕɺߏจϧʔϧͷӈଆʹͷΈݱΕ ·͢ r ෳͷॻ͖ํ͕͋ΔߏจύΠϓ c Ͱ۠ΒΕ·͢ɻԣʹ͘ಡΈʹ͘͘ͳΔ߹ ৽͍͠ߦͰෳͷߏจϧʔϧʹׂ͞Ε·͢ r ௨ৗͷॻମΛ༻ͯ͠จ๏نଇͷӈଆΛهड़͢Δ͜ͱ͕͋Γ·͢ r ඞਢͰͳ͍ߏจΧςΰϦͱϦςϥϧɺඌʹΫΤενϣϯϚʔΫA A͕͖·͢
-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r มએݴ r $PNQVUFE1SPQFSUZ r HFUUFSTFUUFS r XJMM4FUEJE4FU r GPSJOXIJMFSFQFBUXIJMFJGHVBSETXJUDI r EFGFS r EPEPDBUDI
-BOHVBHF3FGFSFODF 4VNNBSZPGUIF(SBNNBS r มએݴ r $PNQVUFE1SPQFSUZ r HFUUFSTFUUFS r XJMM4FUEJE4FU r GPSJOXIJMFSFQFBUXIJMFJGHVBSETXJUDI r EFGFS r EPEPDBUDI r FOVNTUSVDUDMBTTBDUPSQSPUPDPMFYUFOTJPOએݴ r QSFDFEFODFHSPVQએݴ r $MPTVSF
-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
4XJGU-JOU0QFOJOH#SBDF4QBDJOH3VMF -FTTPOT-FBSOFE r 4ZOUBY7JTJUPSΛͬͯҧΛνΣοΫ r 4ZOUBY3FXSJUFSΛͬͯҧΛνΣοΫˍࣗಈमਖ਼ r 1SPUPDPM&YUFOTJPOΛͬͯॲཧΛ·ͱΊΔ r 4XJGU-BOHVBHF3FGFSFODF r 1VMM3FRVFTU IUUQTHJUIVCDPNSFBMN4XJGU-JOUQVMM
&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
1VTI:PVS-JNJUT 4XJGU4ZOUBYΛϚελʔ͢ΔͨΊʹ r 4XJGU-JOUͷϧʔϧΛ4XJGU4ZOUBYΛͬͯॻ͖͑Δ r 4XJGUϚΫϩΛ࡞ͬͯΈΔ r 4XJGU4ZOUBYΛͬͯ9DPEF4PVSDF&EJUPS&YUFOTJPOΛ࡞Δ r 4XJGU"45&YQMPSFSͷ։ൃʹڠྗ͢Δ r 4XJGU1PXFS"TTFSUͷ։ൃʹڠྗ͢Δ
8SBQ6Q r 4XJGU1BSTFSͰιʔείʔυΛߏจղੳ͠ɺ4ZOUBY5SFFΛ୳ࡧ͢Δ r 4ZOUBY5SFFΛมͯ͠ιʔείʔυΛॻ͖͑Δ r ϚΫϩɺ-JOUɺ'PSNBUUFSɺ9DPEF&YUFOTJPOɺͳͲ͕࡞ΕΔ r 4ZOUBY3FXSJUFS4PVSDF-PDBUJPO$POWFSUFSͳͲಠಛͷ"1*ʹ׳ΕΕҙ֎ ͱγϯϓϧʹॻ͚Δ r ίϯύΠϥͰͳ͍ͷͰܕใͳͲߏจ͔ΒಡΈऔΕͳ͍ͷѻ͑ͳ͍ r 4XJGU4ZOUBYΛ༗ޮʹ͏ʹ4XJGUʹؔ͢Δ෯͍͕ࣝॏཁ
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