@@ -24,6 +24,49 @@ import SwiftSyntax
24
24
import SwiftSyntaxMacros
25
25
#endif
26
26
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
+
27
70
/// Manages known source code combined with their filename/fileID. This can be
28
71
/// used to get line/column from a syntax node in the managed source code.
29
72
class SourceManager {
@@ -67,32 +110,24 @@ class SourceManager {
67
110
var endUTF8Offset : Int
68
111
}
69
112
113
+ /// Caching syntax parser.
114
+ private let syntaxRegistry : ParsedSyntaxRegistry
115
+
70
116
/// Syntax added by `add(_:)` method. Keyed by the `id` of the node.
71
117
private var knownSourceSyntax : [ Syntax . ID : KnownSourceSyntax ] = [ : ]
72
118
119
+ init ( syntaxrRegistry: ParsedSyntaxRegistry ) {
120
+ self . syntaxRegistry = syntaxrRegistry
121
+ }
122
+
73
123
/// Convert syntax information to a ``Syntax`` node. The location informations
74
124
/// are cached in the source manager to provide `location(of:)` et al.
75
125
func add(
76
126
_ syntaxInfo: PluginMessage . Syntax ,
77
127
foldingWith operatorTable: OperatorTable ? = nil
78
128
) -> Syntax {
79
129
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)
96
131
if let operatorTable {
97
132
node = operatorTable. foldAll ( node, errorHandler: { _ in /*ignore*/ } )
98
133
}
0 commit comments