@@ -17,11 +17,13 @@ import SwiftSyntax
17
17
import SwiftSyntaxBuilder
18
18
import Utils
19
19
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]
25
27
private let BASE_KIND_FILES = [
26
28
" Decl " : " SyntaxDeclNodes.swift " ,
27
29
" Expr " : " SyntaxExprNodes.swift " ,
@@ -31,6 +33,23 @@ private let BASE_KIND_FILES = [
31
33
" Type " : " SyntaxTypeNodes.swift " ,
32
34
]
33
35
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
+
34
53
struct TemplateSpec {
35
54
let sourceFileGenerator : ( ) -> SourceFileSyntax
36
55
var sourceFile : SourceFileSyntax {
@@ -55,49 +74,51 @@ struct GenerateSwiftSyntax: ParsableCommand {
55
74
var verbose : Bool = false
56
75
57
76
func run( ) throws {
58
- let templates : [ TemplateSpec ] =
77
+ let fileSpecs : [ GeneratedFileSpec ] =
59
78
[
60
79
// SwiftBasicFormat
61
- TemplateSpec ( sourceFile : basicFormatFile , module : swiftBasicFormatDir , filename : " BasicFormat.swift " ) ,
80
+ GeneratedFileSpec ( swiftBasicFormatGeneratedDir + [ " BasicFormat.swift " ] , basicFormatFile ) ,
62
81
63
82
// IDEUtils
64
- TemplateSpec ( sourceFile : syntaxClassificationFile , module : ideUtilsDir , filename : " SyntaxClassification.swift " ) ,
83
+ GeneratedFileSpec ( ideUtilsGeneratedDir + [ " SyntaxClassification.swift " ] , syntaxClassificationFile ) ,
65
84
66
85
// 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 ) ,
71
90
72
91
// 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 ) ,
89
108
90
109
// 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 ) ,
95
114
]
96
115
+ 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
+ ]
99
120
100
- let modules = Set ( templates . map ( \ . module ) )
121
+ let modules = Set ( fileSpecs . compactMap { $0 . pathComponents . first } )
101
122
102
123
let previouslyGeneratedFilesLock = NSLock ( )
103
124
var previouslyGeneratedFiles = Set (
@@ -108,25 +129,25 @@ struct GenerateSwiftSyntax: ParsableCommand {
108
129
return FileManager . default
109
130
. enumerator ( at: generatedDir, includingPropertiesForKeys: nil ) !
110
131
. compactMap { $0 as? URL }
111
- . filter { $0. pathExtension == " swift " }
132
+ . filter { ! $0. hasDirectoryPath }
112
133
}
113
134
)
114
135
115
136
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]
118
139
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
+ }
123
144
124
145
previouslyGeneratedFilesLock. lock ( ) ;
125
146
_ = previouslyGeneratedFiles. remove ( destination)
126
147
previouslyGeneratedFilesLock. unlock ( )
127
148
128
- try generateTemplate (
129
- sourceFile : template . sourceFile ,
149
+ try generateFile (
150
+ contents : fileSpec . contents ,
130
151
destination: destination,
131
152
verbose: verbose
132
153
)
@@ -147,8 +168,8 @@ struct GenerateSwiftSyntax: ParsableCommand {
147
168
}
148
169
}
149
170
150
- private func generateTemplate (
151
- sourceFile : SourceFileSyntax ,
171
+ private func generateFile (
172
+ contents : @autoclosure ( ) -> String ,
152
173
destination: URL ,
153
174
verbose: Bool
154
175
) throws {
@@ -161,7 +182,10 @@ struct GenerateSwiftSyntax: ParsableCommand {
161
182
if verbose {
162
183
print ( " Generating \( destination. path) ... " )
163
184
}
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
+ }
166
190
}
167
191
}
0 commit comments