1111//===----------------------------------------------------------------------===//
1212
1313@_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+
1438/// Accepts the re-used ``Syntax`` nodes that `IncrementalParseTransition`
1539/// determined they should be re-used for a parse invocation.
1640///
2044/// This is also used for testing purposes to ensure incremental reparsing
2145/// worked as expected.
2246public protocol IncrementalParseReusedNodeDelegate {
23- /// Accepts the range and ``Syntax`` node of skipped source region.
47+ /// Accepts ``Syntax`` node of skipped source region.
2448 ///
2549 /// - Parameters:
26- /// - range: The source region of the currently parsed source.
2750 /// - previousNode: The node from the previous tree that is associated with
2851 /// the skipped source region.
29- func parserReusedNode( range : ByteSourceRange , previousNode: Syntax )
52+ func parserReusedNode( previousNode: Syntax )
3053}
3154
3255/// An implementation of `IncrementalParseReusedNodeDelegate` that just collects
3356/// the range and re-used node into an array.
3457public final class IncrementalParseReusedNodeCollector :
3558 IncrementalParseReusedNodeDelegate
3659{
37- public var rangeAndNodes : [ ( ByteSourceRange , Syntax ) ] = [ ]
60+ public var nodes : [ Syntax ] = [ ]
3861
3962 public init ( ) { }
4063
41- public func parserReusedNode( range : ByteSourceRange , previousNode: Syntax ) {
42- rangeAndNodes . append ( ( range , previousNode) )
64+ public func parserReusedNode( previousNode: Syntax ) {
65+ nodes . append ( previousNode)
4366 }
4467}
4568
@@ -48,6 +71,7 @@ public final class IncrementalParseReusedNodeCollector:
4871public final class IncrementalParseTransition {
4972 fileprivate let previousTree : SourceFileSyntax
5073 fileprivate let edits : ConcurrentEdits
74+ fileprivate let lookaheadRanges : LookaheadRanges
5175 fileprivate let reusedDelegate : IncrementalParseReusedNodeDelegate ?
5276
5377 /// - Parameters:
@@ -59,17 +83,19 @@ public final class IncrementalParseTransition {
5983 public init (
6084 previousTree: SourceFileSyntax ,
6185 edits: ConcurrentEdits ,
86+ lookaheadRanges: LookaheadRanges ,
6287 reusedNodeDelegate: IncrementalParseReusedNodeDelegate ? = nil
6388 ) {
6489 self . previousTree = previousTree
6590 self . edits = edits
91+ self . lookaheadRanges = lookaheadRanges
6692 self . reusedDelegate = reusedNodeDelegate
6793 }
6894}
6995
7096/// Provides a mechanism for the parser to skip regions of an incrementally
7197/// updated source that was already parsed during a previous parse invocation.
72- public struct IncrementalParseLookup {
98+ struct IncrementalParseLookup {
7399 fileprivate let transition : IncrementalParseTransition
74100 fileprivate var cursor : SyntaxCursor
75101
@@ -100,23 +126,21 @@ public struct IncrementalParseLookup {
100126 /// - Returns: A ``Syntax`` node from the previous parse invocation,
101127 /// representing the contents of this region, if it is still valid
102128 /// 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 ? {
105130 guard let prevOffset = translateToPreEditOffset ( newOffset) else {
106131 return nil
107132 }
108133 let prevPosition = AbsolutePosition ( utf8Offset: prevOffset)
109134 let node = cursorLookup ( prevPosition: prevPosition, kind: kind)
110135 if let delegate = reusedDelegate, let node {
111136 delegate. parserReusedNode (
112- range: ByteSourceRange ( offset: newOffset, length: node. byteSize) ,
113137 previousNode: node
114138 )
115139 }
116140 return node
117141 }
118142
119- mutating fileprivate func cursorLookup(
143+ fileprivate mutating func cursorLookup(
120144 prevPosition: AbsolutePosition ,
121145 kind: SyntaxKind
122146 ) -> Syntax ? {
@@ -148,24 +172,13 @@ public struct IncrementalParseLookup {
148172 return true
149173 }
150174
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
165177 }
178+
166179 let nodeAffectRange = ByteSourceRange (
167180 offset: node. position. utf8Offset,
168- length: ( node . totalLength + nextLeafNodeLength ) . utf8Length
181+ length: nodeAffectRangeLength
169182 )
170183
171184 for edit in edits. edits {
0 commit comments