@@ -32,30 +32,37 @@ public class BasicMacroExpansionContext {
32
32
}
33
33
}
34
34
35
- /// Create a new macro evaluation context.
36
- public init (
37
- expansionDiscriminator: String = " __macro_local_ " ,
38
- sourceFiles: [ SourceFileSyntax : KnownSourceFile ] = [ : ]
39
- ) {
40
- self . expansionDiscriminator = expansionDiscriminator
41
- self . sourceFiles = sourceFiles
35
+ /// Describes state that is shared amongst all instances of the basic
36
+ /// macro expansion context.
37
+ private class SharedState {
38
+ /// The set of diagnostics that were emitted as part of expanding the
39
+ /// macro.
40
+ var diagnostics : [ Diagnostic ] = [ ]
41
+
42
+ /// Mapping from the root source file syntax nodes to the known source-file
43
+ /// information about that source file.
44
+ var sourceFiles : [ SourceFileSyntax : KnownSourceFile ] = [ : ]
45
+
46
+ /// Mapping from intentionally-disconnected syntax nodes to the corresponding
47
+ /// nodes in the original source file.
48
+ ///
49
+ /// This is used to establish the link between a node that been intentionally
50
+ /// disconnected from a source file to hide information from the macro
51
+ /// implementation.
52
+ var detachedNodes : [ Syntax : Syntax ] = [ : ]
53
+
54
+ /// Counter for each of the uniqued names.
55
+ ///
56
+ /// Used in conjunction with `expansionDiscriminator`.
57
+ var uniqueNames : [ String : Int ] = [ : ]
42
58
}
43
59
44
- /// The set of diagnostics that were emitted as part of expanding the
45
- /// macro.
46
- public private( set) var diagnostics : [ Diagnostic ] = [ ]
47
-
48
- /// Mapping from the root source file syntax nodes to the known source-file
49
- /// information about that source file.
50
- private var sourceFiles : [ SourceFileSyntax : KnownSourceFile ] = [ : ]
60
+ /// State shared by different instances of the macro expansion context,
61
+ /// which includes information about detached nodes and source file names.
62
+ private var sharedState : SharedState
51
63
52
- /// Mapping from intentionally-disconnected syntax nodes to the corresponding
53
- /// nodes in the original source file.
54
- ///
55
- /// This is used to establish the link between a node that been intentionally
56
- /// disconnected from a source file to hide information from the macro
57
- /// implementation.
58
- private var detachedNodes : [ Syntax : Syntax ] = [ : ]
64
+ /// The lexical context of the macro expansion described by this context.
65
+ public let lexicalContext : [ Syntax ]
59
66
60
67
/// The macro expansion discriminator, which is used to form unique names
61
68
/// when requested.
@@ -64,18 +71,41 @@ public class BasicMacroExpansionContext {
64
71
/// to produce unique names.
65
72
private var expansionDiscriminator : String = " "
66
73
67
- /// Counter for each of the uniqued names.
68
- ///
69
- /// Used in conjunction with `expansionDiscriminator`.
70
- private var uniqueNames : [ String : Int ] = [ : ]
74
+ /// Create a new macro evaluation context.
75
+ public init (
76
+ lexicalContext: [ Syntax ] ,
77
+ expansionDiscriminator: String = " __macro_local_ " ,
78
+ sourceFiles: [ SourceFileSyntax : KnownSourceFile ] = [ : ]
79
+ ) {
80
+ self . sharedState = SharedState ( )
81
+ self . lexicalContext = lexicalContext
82
+ self . expansionDiscriminator = expansionDiscriminator
83
+ self . sharedState. sourceFiles = sourceFiles
84
+ }
85
+
86
+ /// Create a new macro evaluation context that shares most of its global
87
+ /// state (detached nodes, diagnostics, etc.) with the given context.
88
+ public init ( sharingWith context: BasicMacroExpansionContext , lexicalContext: [ Syntax ] ) {
89
+ self . sharedState = context. sharedState
90
+ self . lexicalContext = lexicalContext
91
+ self . expansionDiscriminator = context. expansionDiscriminator
92
+ }
93
+ }
71
94
95
+ extension BasicMacroExpansionContext {
96
+ /// The set of diagnostics that were emitted as part of expanding the
97
+ /// macro.
98
+ public private( set) var diagnostics : [ Diagnostic ] {
99
+ get { sharedState. diagnostics }
100
+ set { sharedState. diagnostics = newValue }
101
+ }
72
102
}
73
103
74
104
extension BasicMacroExpansionContext {
75
105
/// Detach the given node, and record where it came from.
76
106
public func detach< Node: SyntaxProtocol > ( _ node: Node ) -> Node {
77
107
let detached = node. detached
78
- detachedNodes [ Syntax ( detached) ] = Syntax ( node)
108
+ sharedState . detachedNodes [ Syntax ( detached) ] = Syntax ( node)
79
109
return detached
80
110
}
81
111
@@ -88,7 +118,7 @@ extension BasicMacroExpansionContext {
88
118
{
89
119
// Folding operators doesn't change the source file and its associated locations
90
120
// Record the `KnownSourceFile` information for the folded tree.
91
- sourceFiles [ newSourceFile] = sourceFiles [ originalSourceFile]
121
+ sharedState . sourceFiles [ newSourceFile] = sharedState . sourceFiles [ originalSourceFile]
92
122
}
93
123
return folded
94
124
}
@@ -113,8 +143,8 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
113
143
let name = providedName. isEmpty ? " __local " : providedName
114
144
115
145
// Grab a unique index value for this name.
116
- let uniqueIndex = uniqueNames [ name, default: 0 ]
117
- uniqueNames [ name] = uniqueIndex + 1
146
+ let uniqueIndex = sharedState . uniqueNames [ name, default: 0 ]
147
+ sharedState . uniqueNames [ name] = uniqueIndex + 1
118
148
119
149
// Start with the expansion discriminator.
120
150
var resultString = expansionDiscriminator
@@ -153,7 +183,7 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
153
183
anchoredAt node: Syntax ,
154
184
fileName: String
155
185
) -> SourceLocation {
156
- guard let nodeInOriginalTree = detachedNodes [ node. root] else {
186
+ guard let nodeInOriginalTree = sharedState . detachedNodes [ node. root] else {
157
187
return SourceLocationConverter ( fileName: fileName, tree: node. root) . location ( for: position)
158
188
}
159
189
let adjustedPosition = position + SourceLength( utf8Length: nodeInOriginalTree. position. utf8Offset)
@@ -173,15 +203,15 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
173
203
// The syntax node came from the source file itself.
174
204
rootSourceFile = directRootSourceFile
175
205
offsetAdjustment = . zero
176
- } else if let nodeInOriginalTree = detachedNodes [ Syntax ( node) ] {
206
+ } else if let nodeInOriginalTree = sharedState . detachedNodes [ Syntax ( node) ] {
177
207
// The syntax node came from a disconnected root, so adjust for that.
178
208
rootSourceFile = nodeInOriginalTree. root. as ( SourceFileSyntax . self)
179
209
offsetAdjustment = SourceLength ( utf8Length: nodeInOriginalTree. position. utf8Offset)
180
210
} else {
181
211
return nil
182
212
}
183
213
184
- guard let rootSourceFile, let knownRoot = sourceFiles [ rootSourceFile] else {
214
+ guard let rootSourceFile, let knownRoot = sharedState . sourceFiles [ rootSourceFile] else {
185
215
return nil
186
216
}
187
217
0 commit comments