@@ -17,11 +17,13 @@ import SwiftSyntax
1717import SwiftSyntaxBuilder
1818import Utils
1919
20- private let swiftBasicFormatDir : String = " SwiftBasicFormat "
21- private let ideUtilsDir : String = " IDEUtils "
22- private let swiftParserDir : String = " SwiftParser "
23- private let swiftSyntaxDir : String = " SwiftSyntax "
24- private let swiftSyntaxBuilderDir : String = " SwiftSyntaxBuilder "
20+ private let generatedDirName = " generated "
21+
22+ private let swiftBasicFormatGeneratedDir = [ " SwiftBasicFormat " , generatedDirName]
23+ private let ideUtilsGeneratedDir = [ " IDEUtils " , generatedDirName]
24+ private let swiftParserGeneratedDir = [ " SwiftParser " , generatedDirName]
25+ private let swiftSyntaxGeneratedDir = [ " SwiftSyntax " , generatedDirName]
26+ private let swiftSyntaxBuilderGeneratedDir = [ " SwiftSyntaxBuilder " , generatedDirName]
2527private let BASE_KIND_FILES = [
2628 " Decl " : " SyntaxDeclNodes.swift " ,
2729 " Expr " : " SyntaxExprNodes.swift " ,
@@ -31,6 +33,23 @@ private let BASE_KIND_FILES = [
3133 " Type " : " SyntaxTypeNodes.swift " ,
3234]
3335
36+ struct GeneratedFileSpec {
37+ let pathComponents : [ String ]
38+ private let contentsGenerator : ( ) -> String
39+ var contents : String {
40+ return self . contentsGenerator ( )
41+ }
42+
43+ init ( _ pathComponents: [ String ] , _ contents: @escaping @autoclosure ( ) -> String ) {
44+ self . pathComponents = pathComponents
45+ self . contentsGenerator = contents
46+ }
47+
48+ init ( _ pathComponents: [ String ] , _ contents: @escaping @autoclosure ( ) -> SourceFileSyntax ) {
49+ self . init ( pathComponents, " \( contents ( ) . formatted ( using: CodeGenerationFormat ( ) ) ) \n " )
50+ }
51+ }
52+
3453struct TemplateSpec {
3554 let sourceFileGenerator : ( ) -> SourceFileSyntax
3655 var sourceFile : SourceFileSyntax {
@@ -55,49 +74,51 @@ struct GenerateSwiftSyntax: ParsableCommand {
5574 var verbose : Bool = false
5675
5776 func run( ) throws {
58- let templates : [ TemplateSpec ] =
77+ let fileSpecs : [ GeneratedFileSpec ] =
5978 [
6079 // SwiftBasicFormat
61- TemplateSpec ( sourceFile : basicFormatFile , module : swiftBasicFormatDir , filename : " BasicFormat.swift " ) ,
80+ GeneratedFileSpec ( swiftBasicFormatGeneratedDir + [ " BasicFormat.swift " ] , basicFormatFile ) ,
6281
6382 // IDEUtils
64- TemplateSpec ( sourceFile : syntaxClassificationFile , module : ideUtilsDir , filename : " SyntaxClassification.swift " ) ,
83+ GeneratedFileSpec ( ideUtilsGeneratedDir + [ " SyntaxClassification.swift " ] , syntaxClassificationFile ) ,
6584
6685 // SwiftParser
67- TemplateSpec ( sourceFile : declarationModifierFile , module : swiftParserDir , filename : " DeclarationModifier.swift " ) ,
68- TemplateSpec ( sourceFile : parserEntryFile , module : swiftParserDir , filename : " Parser+Entry.swift " ) ,
69- TemplateSpec ( sourceFile : tokenSpecStaticMembersFile , module : swiftParserDir , filename : " TokenSpecStaticMembers.swift " ) ,
70- TemplateSpec ( sourceFile : typeAttributeFile , module : swiftParserDir , filename : " TypeAttribute.swift " ) ,
86+ GeneratedFileSpec ( swiftParserGeneratedDir + [ " DeclarationModifier.swift " ] , declarationModifierFile ) ,
87+ GeneratedFileSpec ( swiftParserGeneratedDir + [ " Parser+Entry.swift " ] , parserEntryFile ) ,
88+ GeneratedFileSpec ( swiftParserGeneratedDir + [ " TokenSpecStaticMembers.swift " ] , tokenSpecStaticMembersFile ) ,
89+ GeneratedFileSpec ( swiftParserGeneratedDir + [ " TypeAttribute.swift " ] , typeAttributeFile ) ,
7190
7291 // SwiftSyntax
73- TemplateSpec ( sourceFile : keywordFile , module : swiftSyntaxDir , filename : " Keyword.swift " ) ,
74- TemplateSpec ( sourceFile : miscFile , module : swiftSyntaxDir , filename : " Misc.swift " ) ,
75- TemplateSpec ( sourceFile : rawSyntaxNodesFile , module : swiftSyntaxDir , filename : " raw/ RawSyntaxNodes.swift" ) ,
76- TemplateSpec ( sourceFile : rawSyntaxValidationFile , module : swiftSyntaxDir , filename : " raw/ RawSyntaxValidation.swift" ) ,
77- TemplateSpec ( sourceFile : syntaxAnyVisitorFile , module : swiftSyntaxDir , filename : " SyntaxAnyVisitor.swift " ) ,
78- TemplateSpec ( sourceFile : syntaxBaseNodesFile , module : swiftSyntaxDir , filename : " SyntaxBaseNodes.swift " ) ,
79- TemplateSpec ( sourceFile : syntaxCollectionsFile , module : swiftSyntaxDir , filename : " SyntaxCollections.swift " ) ,
80- TemplateSpec ( sourceFile : syntaxEnumFile , module : swiftSyntaxDir , filename : " SyntaxEnum.swift " ) ,
81- TemplateSpec ( sourceFile : syntaxKindFile , module : swiftSyntaxDir , filename : " SyntaxKind.swift " ) ,
82- TemplateSpec ( sourceFile : syntaxRewriterFile , module : swiftSyntaxDir , filename : " SyntaxRewriter.swift " ) ,
83- TemplateSpec ( sourceFile : syntaxTraitsFile , module : swiftSyntaxDir , filename : " SyntaxTraits.swift " ) ,
84- TemplateSpec ( sourceFile : syntaxTransformFile , module : swiftSyntaxDir , filename : " SyntaxTransform.swift " ) ,
85- TemplateSpec ( sourceFile : syntaxVisitorFile , module : swiftSyntaxDir , filename : " SyntaxVisitor.swift " ) ,
86- TemplateSpec ( sourceFile : tokenKindFile , module : swiftSyntaxDir , filename : " TokenKind.swift " ) ,
87- TemplateSpec ( sourceFile : tokensFile , module : swiftSyntaxDir , filename : " Tokens.swift " ) ,
88- TemplateSpec ( sourceFile : triviaFile , module : swiftSyntaxDir , filename : " Trivia.swift " ) ,
92+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " Keyword.swift " ] , keywordFile ) ,
93+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " Misc.swift " ] , miscFile ) ,
94+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " raw " , " RawSyntaxNodes.swift " ] , rawSyntaxNodesFile ) ,
95+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " raw " , " RawSyntaxValidation.swift " ] , rawSyntaxValidationFile ) ,
96+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxAnyVisitor.swift " ] , syntaxAnyVisitorFile ) ,
97+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxBaseNodes.swift " ] , syntaxBaseNodesFile ) ,
98+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxCollections.swift " ] , syntaxCollectionsFile ) ,
99+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxEnum.swift " ] , syntaxEnumFile ) ,
100+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxKind.swift " ] , syntaxKindFile ) ,
101+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxRewriter.swift " ] , syntaxRewriterFile ) ,
102+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxTraits.swift " ] , syntaxTraitsFile ) ,
103+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxTransform.swift " ] , syntaxTransformFile ) ,
104+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " SyntaxVisitor.swift " ] , syntaxVisitorFile ) ,
105+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " TokenKind.swift " ] , tokenKindFile ) ,
106+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " Tokens.swift " ] , tokensFile ) ,
107+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " Trivia.swift " ] , triviaFile ) ,
89108
90109 // SwiftSyntaxBuilder
91- TemplateSpec ( sourceFile : buildableCollectionNodesFile , module : swiftSyntaxBuilderDir , filename : " BuildableCollectionNodes.swift " ) ,
92- TemplateSpec ( sourceFile : buildableNodesFile , module : swiftSyntaxBuilderDir , filename : " BuildableNodes.swift " ) ,
93- TemplateSpec ( sourceFile : resultBuildersFile , module : swiftSyntaxBuilderDir , filename : " ResultBuilders.swift " ) ,
94- TemplateSpec ( sourceFile : syntaxExpressibleByStringInterpolationConformancesFile , module : swiftSyntaxBuilderDir , filename : " SyntaxExpressibleByStringInterpolationConformances.swift " ) ,
110+ GeneratedFileSpec ( swiftSyntaxBuilderGeneratedDir + [ " BuildableCollectionNodes.swift " ] , buildableCollectionNodesFile ) ,
111+ GeneratedFileSpec ( swiftSyntaxBuilderGeneratedDir + [ " BuildableNodes.swift " ] , buildableNodesFile ) ,
112+ GeneratedFileSpec ( swiftSyntaxBuilderGeneratedDir + [ " ResultBuilders.swift " ] , resultBuildersFile ) ,
113+ GeneratedFileSpec ( swiftSyntaxBuilderGeneratedDir + [ " SyntaxExpressibleByStringInterpolationConformances.swift " ] , syntaxExpressibleByStringInterpolationConformancesFile ) ,
95114 ]
96115 + BASE_KIND_FILES. map { baseKind in
97- TemplateSpec ( sourceFile: syntaxNode ( emitKind: baseKind. key) , module: swiftSyntaxDir, filename: " syntaxNodes/ \( baseKind. value) " )
98- }
116+ GeneratedFileSpec ( swiftSyntaxGeneratedDir + [ " syntaxNodes " , baseKind. value] , syntaxNode ( emitKind: baseKind. key) )
117+ } + [
118+ GeneratedFileSpec ( [ " SwiftSyntax " , " Documentation.docc " , " generated " , " SwiftSyntax.md " ] , swiftSyntaxDoccIndex)
119+ ]
99120
100- let modules = Set ( templates . map ( \ . module ) )
121+ let modules = Set ( fileSpecs . compactMap { $0 . pathComponents . first } )
101122
102123 let previouslyGeneratedFilesLock = NSLock ( )
103124 var previouslyGeneratedFiles = Set (
@@ -108,25 +129,25 @@ struct GenerateSwiftSyntax: ParsableCommand {
108129 return FileManager . default
109130 . enumerator ( at: generatedDir, includingPropertiesForKeys: nil ) !
110131 . compactMap { $0 as? URL }
111- . filter { $0. pathExtension == " swift " }
132+ . filter { ! $0. hasDirectoryPath }
112133 }
113134 )
114135
115136 var errors : [ Error ] = [ ]
116- DispatchQueue . concurrentPerform ( iterations: templates . count) { index in
117- let template = templates [ index]
137+ DispatchQueue . concurrentPerform ( iterations: fileSpecs . count) { index in
138+ let fileSpec = fileSpecs [ index]
118139 do {
119- let destination = URL ( fileURLWithPath: destination)
120- . appendingPathComponent ( template . module )
121- . appendingPathComponent ( " generated " )
122- . appendingPathComponent ( template . filename )
140+ var destination = URL ( fileURLWithPath: destination)
141+ for component in fileSpec . pathComponents {
142+ destination = destination . appendingPathComponent ( component )
143+ }
123144
124145 previouslyGeneratedFilesLock. lock ( ) ;
125146 _ = previouslyGeneratedFiles. remove ( destination)
126147 previouslyGeneratedFilesLock. unlock ( )
127148
128- try generateTemplate (
129- sourceFile : template . sourceFile ,
149+ try generateFile (
150+ contents : fileSpec . contents ,
130151 destination: destination,
131152 verbose: verbose
132153 )
@@ -147,8 +168,8 @@ struct GenerateSwiftSyntax: ParsableCommand {
147168 }
148169 }
149170
150- private func generateTemplate (
151- sourceFile : SourceFileSyntax ,
171+ private func generateFile (
172+ contents : @autoclosure ( ) -> String ,
152173 destination: URL ,
153174 verbose: Bool
154175 ) throws {
@@ -161,7 +182,10 @@ struct GenerateSwiftSyntax: ParsableCommand {
161182 if verbose {
162183 print ( " Generating \( destination. path) ... " )
163184 }
164- let syntax = sourceFile. formatted ( using: CodeGenerationFormat ( ) )
165- try " \( syntax) \n " . write ( to: destination, atomically: true , encoding: . utf8)
185+ let start = Date ( )
186+ try contents ( ) . write ( to: destination, atomically: true , encoding: . utf8)
187+ if verbose {
188+ print ( " Generated \( destination. path) in \( ( Date ( ) . timeIntervalSince ( start) * 1000 ) . rounded ( ) / 1000 ) s " )
189+ }
166190 }
167191}
0 commit comments