Skip to content

Commit f0db832

Browse files
authored
Merge pull request #2939 from rintaro/perf-token-sequence
[Perf] Optimize TokenSequence
2 parents 00f5b14 + 090945d commit f0db832

File tree

3 files changed

+69
-47
lines changed

3 files changed

+69
-47
lines changed

Diff for: Sources/SwiftSyntax/Syntax.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
3636
self.dataRef = dataRef
3737
}
3838

39-
private var data: SyntaxData {
39+
var data: SyntaxData {
4040
@_transparent unsafeAddress { dataRef.pointer }
4141
}
4242

Diff for: Sources/SwiftSyntax/SyntaxProtocol.swift

+4-46
Original file line numberDiff line numberDiff line change
@@ -253,20 +253,7 @@ extension SyntaxProtocol {
253253
/// Recursively walks through the tree to find the token semantically before
254254
/// this node.
255255
public func previousToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
256-
guard let parent = self.parent else {
257-
return nil
258-
}
259-
let siblings = parent.children(viewMode: viewMode)
260-
// `self` could be a missing node at index 0 and `viewMode` be `.sourceAccurate`.
261-
// In that case `siblings` skips over the missing `self` node and has a `startIndex > 0`.
262-
if siblings.startIndex < self.indexInParent {
263-
for child in siblings[..<self.indexInParent].reversed() {
264-
if let token = child.lastToken(viewMode: viewMode) {
265-
return token
266-
}
267-
}
268-
}
269-
return parent.previousToken(viewMode: viewMode)
256+
return self._syntaxNode.previousToken(viewMode: viewMode)
270257
}
271258

272259
@available(*, deprecated, message: "Use nextToken(viewMode:) instead")
@@ -277,16 +264,7 @@ extension SyntaxProtocol {
277264
/// Recursively walks through the tree to find the next token semantically
278265
/// after this node.
279266
public func nextToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
280-
guard let parent = self.parent else {
281-
return nil
282-
}
283-
let siblings = parent.children(viewMode: viewMode)
284-
for child in siblings[siblings.index(after: self.indexInParent)...] {
285-
if let token = child.firstToken(viewMode: viewMode) {
286-
return token
287-
}
288-
}
289-
return parent.nextToken(viewMode: viewMode)
267+
return self._syntaxNode.nextToken(viewMode: viewMode)
290268
}
291269

292270
@available(*, deprecated, message: "Use firstToken(viewMode: .sourceAccurate) instead")
@@ -296,17 +274,7 @@ extension SyntaxProtocol {
296274

297275
/// Returns the first token node that is part of this syntax node.
298276
public func firstToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
299-
guard viewMode.shouldTraverse(node: raw) else { return nil }
300-
if let token = _syntaxNode.as(TokenSyntax.self) {
301-
return token
302-
}
303-
304-
for child in children(viewMode: viewMode) {
305-
if let token = child.firstToken(viewMode: viewMode) {
306-
return token
307-
}
308-
}
309-
return nil
277+
return self._syntaxNode.firstToken(viewMode: viewMode)
310278
}
311279

312280
@available(*, deprecated, message: "Use lastToken(viewMode: .sourceAccurate) instead")
@@ -316,17 +284,7 @@ extension SyntaxProtocol {
316284

317285
/// Returns the last token node that is part of this syntax node.
318286
public func lastToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
319-
guard viewMode.shouldTraverse(node: raw) else { return nil }
320-
if let token = _syntaxNode.as(TokenSyntax.self) {
321-
return token
322-
}
323-
324-
for child in children(viewMode: viewMode).reversed() {
325-
if let tok = child.lastToken(viewMode: viewMode) {
326-
return tok
327-
}
328-
}
329-
return nil
287+
return self._syntaxNode.lastToken(viewMode: viewMode)
330288
}
331289

332290
/// Sequence of tokens that are part of this Syntax node.

Diff for: Sources/SwiftSyntax/TokenSequence.swift

+64
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,70 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
extension Syntax {
14+
/// Implementation of 'SyntaxProtocol.previousToken(viewMode:)'
15+
func previousToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
16+
guard let parentDataRef = data.parent else {
17+
return nil
18+
}
19+
for case let childDataRef? in arena.layout(for: parentDataRef)[..<layoutIndexInParent].reversed() {
20+
if let token = Syntax(arena: arena, dataRef: childDataRef).lastToken(viewMode: viewMode) {
21+
return token
22+
}
23+
}
24+
return Syntax(arena: arena, dataRef: parentDataRef).previousToken(viewMode: viewMode)
25+
}
26+
27+
/// Implementation of 'SyntaxProtocol.nextToken(viewMode:)'
28+
func nextToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
29+
guard let parentDataRef = data.parent else {
30+
return nil
31+
}
32+
for case let childDataRef? in arena.layout(for: parentDataRef)[(layoutIndexInParent &+ 1)...] {
33+
if let token = Syntax(arena: arena, dataRef: childDataRef).firstToken(viewMode: viewMode) {
34+
return token
35+
}
36+
}
37+
return Syntax(arena: arena, dataRef: parentDataRef).nextToken(viewMode: viewMode)
38+
}
39+
40+
/// Implementation of 'SyntaxProtocol.firstToken(viewMode:)'
41+
///
42+
/// - Note: Can't use 'RawSyntax.firstToken(viewMode:)' because it loses absolute info.
43+
func firstToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
44+
guard viewMode.shouldTraverse(node: raw) else {
45+
return nil
46+
}
47+
if raw.isToken {
48+
return TokenSyntax(self)!
49+
}
50+
for case let childDataRef? in layoutBuffer {
51+
if let token = Syntax(arena: arena, dataRef: childDataRef).firstToken(viewMode: viewMode) {
52+
return token
53+
}
54+
}
55+
return nil
56+
}
57+
58+
/// Implementation of 'SyntaxProtocol.lastToken(viewMode:)'
59+
///
60+
/// - Note: Can't use 'RawSyntax.lastToken(viewMode:)' because it loses absolute info.
61+
func lastToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
62+
guard viewMode.shouldTraverse(node: raw) else {
63+
return nil
64+
}
65+
if raw.isToken {
66+
return TokenSyntax(self)!
67+
}
68+
for case let childDataRef? in layoutBuffer.reversed() {
69+
if let token = Syntax(arena: arena, dataRef: childDataRef).lastToken(viewMode: viewMode) {
70+
return token
71+
}
72+
}
73+
return nil
74+
}
75+
}
76+
1377
/// Sequence of tokens that are part of the provided Syntax node.
1478
public struct TokenSequence: Sequence, Sendable {
1579
/// Iterates over a ``TokenSequence``.

0 commit comments

Comments
 (0)