11
11
//===----------------------------------------------------------------------===//
12
12
13
13
@_spi ( RawSyntax) import SwiftSyntax
14
+
15
+ extension Parser {
16
+ mutating func loadCurrentSyntaxNodeFromCache( for kind: SyntaxKind ) -> Syntax ? {
17
+ guard parseLookup != nil else {
18
+ return nil
19
+ }
20
+
21
+ let currentOffset = self . lexemes. getOffsetToStart ( self . currentToken)
22
+ if let node = parseLookup!. lookUp ( currentOffset, kind: kind) {
23
+ self . lexemes. advance ( by: node. byteSize, currentToken: & self . currentToken)
24
+ return node
25
+ }
26
+
27
+ return nil
28
+ }
29
+
30
+ mutating func registerNodeForIncrementalParse( node: RawSyntax , startToken: Lexer . Lexeme ) {
31
+ lookaheadRanges. registerNodeForIncrementalParse (
32
+ node: node,
33
+ lookaheadLength: lexemes. lookaheadTracker. pointee. furthestOffset - self . lexemes. getOffsetToStart ( startToken)
34
+ )
35
+ }
36
+ }
37
+
14
38
/// Accepts the re-used ``Syntax`` nodes that `IncrementalParseTransition`
15
39
/// determined they should be re-used for a parse invocation.
16
40
///
20
44
/// This is also used for testing purposes to ensure incremental reparsing
21
45
/// worked as expected.
22
46
public protocol IncrementalParseReusedNodeDelegate {
23
- /// Accepts the range and ``Syntax`` node of skipped source region.
47
+ /// Accepts ``Syntax`` node of skipped source region.
24
48
///
25
49
/// - Parameters:
26
- /// - range: The source region of the currently parsed source.
27
50
/// - previousNode: The node from the previous tree that is associated with
28
51
/// the skipped source region.
29
- func parserReusedNode( range : ByteSourceRange , previousNode: Syntax )
52
+ func parserReusedNode( previousNode: Syntax )
30
53
}
31
54
32
55
/// An implementation of `IncrementalParseReusedNodeDelegate` that just collects
33
56
/// the range and re-used node into an array.
34
57
public final class IncrementalParseReusedNodeCollector :
35
58
IncrementalParseReusedNodeDelegate
36
59
{
37
- public var rangeAndNodes : [ ( ByteSourceRange , Syntax ) ] = [ ]
60
+ public var nodes : [ Syntax ] = [ ]
38
61
39
62
public init ( ) { }
40
63
41
- public func parserReusedNode( range : ByteSourceRange , previousNode: Syntax ) {
42
- rangeAndNodes . append ( ( range , previousNode) )
64
+ public func parserReusedNode( previousNode: Syntax ) {
65
+ nodes . append ( previousNode)
43
66
}
44
67
}
45
68
@@ -48,6 +71,7 @@ public final class IncrementalParseReusedNodeCollector:
48
71
public final class IncrementalParseTransition {
49
72
fileprivate let previousTree : SourceFileSyntax
50
73
fileprivate let edits : ConcurrentEdits
74
+ fileprivate let lookaheadRanges : LookaheadRanges
51
75
fileprivate let reusedDelegate : IncrementalParseReusedNodeDelegate ?
52
76
53
77
/// - Parameters:
@@ -59,17 +83,19 @@ public final class IncrementalParseTransition {
59
83
public init (
60
84
previousTree: SourceFileSyntax ,
61
85
edits: ConcurrentEdits ,
86
+ lookaheadRanges: LookaheadRanges ,
62
87
reusedNodeDelegate: IncrementalParseReusedNodeDelegate ? = nil
63
88
) {
64
89
self . previousTree = previousTree
65
90
self . edits = edits
91
+ self . lookaheadRanges = lookaheadRanges
66
92
self . reusedDelegate = reusedNodeDelegate
67
93
}
68
94
}
69
95
70
96
/// Provides a mechanism for the parser to skip regions of an incrementally
71
97
/// updated source that was already parsed during a previous parse invocation.
72
- public struct IncrementalParseLookup {
98
+ struct IncrementalParseLookup {
73
99
fileprivate let transition : IncrementalParseTransition
74
100
fileprivate var cursor : SyntaxCursor
75
101
@@ -100,23 +126,21 @@ public struct IncrementalParseLookup {
100
126
/// - Returns: A ``Syntax`` node from the previous parse invocation,
101
127
/// representing the contents of this region, if it is still valid
102
128
/// to re-use. `nil` otherwise.
103
- @_spi ( RawSyntax)
104
- public mutating func lookUp( _ newOffset: Int , kind: SyntaxKind ) -> Syntax ? {
129
+ fileprivate mutating func lookUp( _ newOffset: Int , kind: SyntaxKind ) -> Syntax ? {
105
130
guard let prevOffset = translateToPreEditOffset ( newOffset) else {
106
131
return nil
107
132
}
108
133
let prevPosition = AbsolutePosition ( utf8Offset: prevOffset)
109
134
let node = cursorLookup ( prevPosition: prevPosition, kind: kind)
110
135
if let delegate = reusedDelegate, let node {
111
136
delegate. parserReusedNode (
112
- range: ByteSourceRange ( offset: newOffset, length: node. byteSize) ,
113
137
previousNode: node
114
138
)
115
139
}
116
140
return node
117
141
}
118
142
119
- mutating fileprivate func cursorLookup(
143
+ fileprivate mutating func cursorLookup(
120
144
prevPosition: AbsolutePosition ,
121
145
kind: SyntaxKind
122
146
) -> Syntax ? {
@@ -148,24 +172,13 @@ public struct IncrementalParseLookup {
148
172
return true
149
173
}
150
174
151
- // Node can also not be reused if an edit has been made in the next token's
152
- // text, e.g. because `private struct Foo {}` parses as a CodeBlockItem with
153
- // a StructDecl inside and `private struc Foo {}` parses as two
154
- // CodeBlockItems one for `private` and one for `struc Foo {}`
155
- var nextLeafNodeLength : SourceLength = . zero
156
- if let nextSibling = cursor. nextSibling {
157
- // Fast path check: if next sibling is before all the edits then we can
158
- // re-use the node.
159
- if !edits. edits. isEmpty && edits. edits. first!. range. offset > nextSibling. endPosition. utf8Offset {
160
- return true
161
- }
162
- if let nextToken = nextSibling. firstToken ( viewMode: . sourceAccurate) {
163
- nextLeafNodeLength = nextToken. leadingTriviaLength + nextToken. contentLength
164
- }
175
+ guard let nodeAffectRangeLength = transition. lookaheadRanges. lookaheadRanges [ node. raw. id] else {
176
+ return false
165
177
}
178
+
166
179
let nodeAffectRange = ByteSourceRange (
167
180
offset: node. position. utf8Offset,
168
- length: ( node . totalLength + nextLeafNodeLength ) . utf8Length
181
+ length: nodeAffectRangeLength
169
182
)
170
183
171
184
for edit in edits. edits {
0 commit comments