forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTreeCursor.swift
More file actions
71 lines (60 loc) · 1.84 KB
/
TreeCursor.swift
File metadata and controls
71 lines (60 loc) · 1.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import Foundation
import SwiftTreeSitter
extension TreeCursor {
/// Deep first search nodes.
/// - Parameter skipChildren: Check if children of a `Node` should be skipped.
func deepFirstSearch(
skipChildren: @escaping (Node) -> Bool
) -> CursorDeepFirstSearchSequence<TreeCursor> {
return CursorDeepFirstSearchSequence(cursor: self, skipChildren: skipChildren)
}
}
// MARK: - Search
protocol Cursor {
associatedtype Node
var currentNode: Node? { get }
func goToFirstChild() -> Bool
func goToNextSibling() -> Bool
func goToParent() -> Bool
}
extension TreeCursor: Cursor {
func goToNextSibling() -> Bool {
gotoNextSibling()
}
func goToParent() -> Bool {
gotoParent()
}
}
struct CursorDeepFirstSearchSequence<C: Cursor>: Sequence {
let cursor: C
let skipChildren: (C.Node) -> Bool
func makeIterator() -> CursorDeepFirstSearchIterator<C> {
return CursorDeepFirstSearchIterator(
cursor: cursor,
skipChildren: skipChildren
)
}
struct CursorDeepFirstSearchIterator<C: Cursor>: IteratorProtocol {
let cursor: C
let skipChildren: (C.Node) -> Bool
var isEnded = false
mutating func next() -> C.Node? {
guard !isEnded else { return nil }
let currentNode = cursor.currentNode
let hasChild = {
guard let n = currentNode else { return false }
if skipChildren(n) { return false }
return cursor.goToFirstChild()
}()
if !hasChild {
while !cursor.goToNextSibling() {
if !cursor.goToParent() {
isEnded = true
break
}
}
}
return currentNode
}
}
}