@@ -24,6 +24,49 @@ import SwiftSyntax
2424import SwiftSyntaxMacros
2525#endif
2626
27+ /// Caching parser for PluginMessage.Syntax
28+ class ParsedSyntaxRegistry {
29+ struct Key : Hashable {
30+ let source : String
31+ let kind : PluginMessage . Syntax . Kind
32+ }
33+
34+ private var storage : [ Key : Syntax ] = [ : ]
35+
36+ private func parse( source: String , kind: PluginMessage . Syntax . Kind ) -> Syntax {
37+ var parser = Parser ( source)
38+ switch kind {
39+ case . declaration:
40+ return Syntax ( DeclSyntax . parse ( from: & parser) )
41+ case . statement:
42+ return Syntax ( StmtSyntax . parse ( from: & parser) )
43+ case . expression:
44+ return Syntax ( ExprSyntax . parse ( from: & parser) )
45+ case . type:
46+ return Syntax ( TypeSyntax . parse ( from: & parser) )
47+ case . pattern:
48+ return Syntax ( PatternSyntax . parse ( from: & parser) )
49+ case . attribute:
50+ return Syntax ( AttributeSyntax . parse ( from: & parser) )
51+ }
52+ }
53+
54+ func get( source: String , kind: PluginMessage . Syntax . Kind ) -> Syntax {
55+ let key = Key ( source: source, kind: kind)
56+ if let cached = storage [ key] {
57+ return cached
58+ }
59+
60+ let node = parse ( source: source, kind: kind)
61+ storage [ key] = node
62+ return node
63+ }
64+
65+ func clear( ) {
66+ storage = [ : ]
67+ }
68+ }
69+
2770/// Manages known source code combined with their filename/fileID. This can be
2871/// used to get line/column from a syntax node in the managed source code.
2972class SourceManager {
@@ -67,32 +110,24 @@ class SourceManager {
67110 var endUTF8Offset : Int
68111 }
69112
113+ /// Caching syntax parser.
114+ private let syntaxRegistry : ParsedSyntaxRegistry
115+
70116 /// Syntax added by `add(_:)` method. Keyed by the `id` of the node.
71117 private var knownSourceSyntax : [ Syntax . ID : KnownSourceSyntax ] = [ : ]
72118
119+ init ( syntaxRegistry: ParsedSyntaxRegistry ) {
120+ self . syntaxRegistry = syntaxRegistry
121+ }
122+
73123 /// Convert syntax information to a ``Syntax`` node. The location informations
74124 /// are cached in the source manager to provide `location(of:)` et al.
75125 func add(
76126 _ syntaxInfo: PluginMessage . Syntax ,
77127 foldingWith operatorTable: OperatorTable ? = nil
78128 ) -> Syntax {
79129
80- var node : Syntax
81- var parser = Parser ( syntaxInfo. source)
82- switch syntaxInfo. kind {
83- case . declaration:
84- node = Syntax ( DeclSyntax . parse ( from: & parser) )
85- case . statement:
86- node = Syntax ( StmtSyntax . parse ( from: & parser) )
87- case . expression:
88- node = Syntax ( ExprSyntax . parse ( from: & parser) )
89- case . type:
90- node = Syntax ( TypeSyntax . parse ( from: & parser) )
91- case . pattern:
92- node = Syntax ( PatternSyntax . parse ( from: & parser) )
93- case . attribute:
94- node = Syntax ( AttributeSyntax . parse ( from: & parser) )
95- }
130+ var node = syntaxRegistry. get ( source: syntaxInfo. source, kind: syntaxInfo. kind)
96131 if let operatorTable {
97132 node = operatorTable. foldAll ( node, errorHandler: { _ in /*ignore*/ } )
98133 }
0 commit comments