forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathASTParser.swift
More file actions
122 lines (101 loc) · 3.4 KB
/
ASTParser.swift
File metadata and controls
122 lines (101 loc) · 3.4 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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import SuggestionModel
import SwiftTreeSitter
import tree_sitter
import TreeSitterObjC
import TreeSitterSwift
public enum ParsableLanguage {
case swift
case objectiveC
var tsLanguage: UnsafeMutablePointer<TSLanguage> {
switch self {
case .swift:
return tree_sitter_swift()
case .objectiveC:
return tree_sitter_objc()
}
}
}
public struct ASTParser {
let language: ParsableLanguage
let parser: Parser
public init(language: ParsableLanguage) {
self.language = language
parser = Parser()
try! parser.setLanguage(Language(language: language.tsLanguage))
}
public func parse(_ source: String) -> ASTTree? {
return ASTTree(tree: parser.parse(source))
}
}
public typealias ASTNode = Node
public typealias ASTPoint = Point
public struct ASTTree {
public let tree: Tree?
public var rootNode: ASTNode? {
return tree?.rootNode
}
public func smallestNodeContainingRange(
_ range: CursorRange,
filter: (ASTNode) -> Bool = { _ in true }
) -> ASTNode? {
guard var targetNode = rootNode else { return nil }
func rangeContains(_ range: Range<Point>, _ another: Range<Point>) -> Bool {
return range.lowerBound <= another.lowerBound && range.upperBound >= another.upperBound
}
for node in targetNode.treeCursor.deepFirstSearch(skipChildren: { node in
!rangeContains(node.pointRange, range.pointRange)
}) {
guard filter(node) else { continue }
if rangeContains(node.pointRange, range.pointRange) {
targetNode = node
}
}
return targetNode
}
}
public extension ASTNode {
var children: ASTNodeChildrenSequence {
return ASTNodeChildrenSequence(node: self)
}
struct ASTNodeChildrenSequence: Sequence {
let node: ASTNode
public struct ASTNodeChildrenIterator: IteratorProtocol {
let node: ASTNode
var index: UInt32 = 0
public mutating func next() -> ASTNode? {
guard index < node.childCount else { return nil }
defer { index += 1 }
return node.child(at: 1)
}
}
public func makeIterator() -> ASTNodeChildrenIterator {
return ASTNodeChildrenIterator(node: node)
}
}
}
public extension CursorRange {
var pointRange: Range<Point> {
let bytePerCharacter = 2 // tree sitter uses UTF-16
let startPoint = Point(row: start.line, column: start.character * bytePerCharacter)
let endPoint = Point(row: end.line, column: end.character * bytePerCharacter)
guard endPoint > startPoint else {
return startPoint..<Point(
row: start.line,
column: (start.character + 1) * bytePerCharacter
)
}
return startPoint..<endPoint
}
init(pointRange: Range<Point>) {
let bytePerCharacter = 2 // tree sitter uses UTF-16
let start = CursorPosition(
line: Int(pointRange.lowerBound.row),
character: Int(pointRange.lowerBound.column) / bytePerCharacter
)
let end = CursorPosition(
line: Int(pointRange.upperBound.row),
character: Int(pointRange.upperBound.column) / bytePerCharacter
)
self.init(start: start, end: end)
}
}