@@ -32,30 +32,37 @@ public class BasicMacroExpansionContext {
3232 }
3333 }
3434
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 ] = [ : ]
4258 }
4359
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
5163
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 ]
5966
6067 /// The macro expansion discriminator, which is used to form unique names
6168 /// when requested.
@@ -64,18 +71,41 @@ public class BasicMacroExpansionContext {
6471 /// to produce unique names.
6572 private var expansionDiscriminator : String = " "
6673
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+ }
7194
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+ }
72102}
73103
74104extension BasicMacroExpansionContext {
75105 /// Detach the given node, and record where it came from.
76106 public func detach< Node: SyntaxProtocol > ( _ node: Node ) -> Node {
77107 let detached = node. detached
78- detachedNodes [ Syntax ( detached) ] = Syntax ( node)
108+ sharedState . detachedNodes [ Syntax ( detached) ] = Syntax ( node)
79109 return detached
80110 }
81111
@@ -88,7 +118,7 @@ extension BasicMacroExpansionContext {
88118 {
89119 // Folding operators doesn't change the source file and its associated locations
90120 // Record the `KnownSourceFile` information for the folded tree.
91- sourceFiles [ newSourceFile] = sourceFiles [ originalSourceFile]
121+ sharedState . sourceFiles [ newSourceFile] = sharedState . sourceFiles [ originalSourceFile]
92122 }
93123 return folded
94124 }
@@ -113,8 +143,8 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
113143 let name = providedName. isEmpty ? " __local " : providedName
114144
115145 // 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
118148
119149 // Start with the expansion discriminator.
120150 var resultString = expansionDiscriminator
@@ -153,7 +183,7 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
153183 anchoredAt node: Syntax ,
154184 fileName: String
155185 ) -> SourceLocation {
156- guard let nodeInOriginalTree = detachedNodes [ node. root] else {
186+ guard let nodeInOriginalTree = sharedState . detachedNodes [ node. root] else {
157187 return SourceLocationConverter ( fileName: fileName, tree: node. root) . location ( for: position)
158188 }
159189 let adjustedPosition = position + SourceLength( utf8Length: nodeInOriginalTree. position. utf8Offset)
@@ -173,15 +203,15 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
173203 // The syntax node came from the source file itself.
174204 rootSourceFile = directRootSourceFile
175205 offsetAdjustment = . zero
176- } else if let nodeInOriginalTree = detachedNodes [ Syntax ( node) ] {
206+ } else if let nodeInOriginalTree = sharedState . detachedNodes [ Syntax ( node) ] {
177207 // The syntax node came from a disconnected root, so adjust for that.
178208 rootSourceFile = nodeInOriginalTree. root. as ( SourceFileSyntax . self)
179209 offsetAdjustment = SourceLength ( utf8Length: nodeInOriginalTree. position. utf8Offset)
180210 } else {
181211 return nil
182212 }
183213
184- guard let rootSourceFile, let knownRoot = sourceFiles [ rootSourceFile] else {
214+ guard let rootSourceFile, let knownRoot = sharedState . sourceFiles [ rootSourceFile] else {
185215 return nil
186216 }
187217
0 commit comments