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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
use std::ops::Range;
use crate::{Tree, ffi};
/// A zero-based source position with a byte column, matching tree-sitter.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Point {
/// Zero-based row, counted by LF bytes.
pub row: u32,
/// Zero-based byte column within the row.
pub column: u32,
}
/// A checked reference into a particular immutable tree.
#[derive(Clone, Copy)]
pub struct Node<'tree> {
pub(crate) tree: &'tree Tree<'tree>,
pub(crate) id: u32,
}
impl<'tree> Node<'tree> {
/// The grammar's exact node-kind spelling.
pub fn kind(self) -> &'tree [u8] {
let mut len = 0;
// SAFETY: construction validated id; the tree's parser owns the name
// for at least 'tree and cannot be freed through a live node borrow.
unsafe {
let pointer = ffi::jnt_node_name(self.tree.raw.as_ptr(), self.id, &mut len);
ffi::bytes(pointer, len)
}
}
/// Whether queries can match this node by kind rather than its literal.
pub fn is_named(self) -> bool {
// SAFETY: this ref was validated and its immutable owner remains live.
unsafe { ffi::jnt_node_named(self.tree.raw.as_ptr(), self.id) != 0 }
}
/// The source byte span, with an exclusive end.
pub fn byte_range(self) -> Range<u32> {
// SAFETY: scalar reads on a validated node in a live immutable tree.
unsafe {
ffi::jnt_node_start(self.tree.raw.as_ptr(), self.id)
..ffi::jnt_node_end(self.tree.raw.as_ptr(), self.id)
}
}
/// Original source bytes in this node's span, absent for an invalid span.
pub fn text(self) -> Option<&'tree [u8]> {
let span = self.byte_range();
self.tree
.source()
.get(span.start as usize..span.end as usize)
}
/// Position of the first byte, absent for a span beyond the source.
pub fn start_point(self) -> Option<Point> {
self.tree.point_at(self.byte_range().start)
}
/// Position immediately after the last byte, absent beyond the source.
pub fn end_point(self) -> Option<Point> {
self.tree.point_at(self.byte_range().end)
}
/// This node's field in its parent, absent when the grammar did not file it.
pub fn field(self) -> Option<&'tree [u8]> {
let mut len = 0;
// SAFETY: a non-null name belongs to this node's live parser/bank.
unsafe {
let pointer = ffi::jnt_node_field(self.tree.raw.as_ptr(), self.id, &mut len);
(!pointer.is_null()).then(|| ffi::bytes(pointer, len))
}
}
/// Number of children, including anonymous nodes and comments.
pub fn child_count(self) -> u32 {
// SAFETY: a scalar read on this validated live node.
unsafe { ffi::jnt_node_kids(self.tree.raw.as_ptr(), self.id) }
}
/// Child `index`, absent past the end.
pub fn child(self, index: u32) -> Option<Self> {
// SAFETY: the native accessor bounds-checks the child index.
self.tree
.node(unsafe { ffi::jnt_node_kid(self.tree.raw.as_ptr(), self.id, index) })
}
/// All children in source order, including anonymous nodes.
pub fn children(self) -> impl ExactSizeIterator<Item = Self> {
(0..self.child_count()).map(move |i| self.child(i).expect("native child exists"))
}
/// Children that queries can match by kind.
pub fn named_children(self) -> impl Iterator<Item = Self> {
self.children().filter(|node| node.is_named())
}
/// The first child filed under this exact field spelling.
pub fn child_by_field(self, field: impl AsRef<[u8]>) -> Option<Self> {
let field = field.as_ref();
// SAFETY: field covers len readable bytes for this call, and lookup
// is bounds-checked against a validated node in a live tree.
self.tree.node(unsafe {
ffi::jnt_node_by_field(
self.tree.raw.as_ptr(),
self.id,
field.as_ptr().cast(),
field.len(),
)
})
}
/// Parent node; roots in a partial forest have none.
pub fn parent(self) -> Option<Self> {
// SAFETY: native neighbourhood lookups bounds-check validated refs.
self.tree
.node(unsafe { ffi::jnt_node_parent(self.tree.raw.as_ptr(), self.id) })
}
/// Next sibling, including anonymous nodes.
pub fn next_sibling(self) -> Option<Self> {
// SAFETY: native neighbourhood lookups bounds-check validated refs.
self.tree
.node(unsafe { ffi::jnt_node_next(self.tree.raw.as_ptr(), self.id) })
}
/// Previous sibling, including anonymous nodes.
pub fn previous_sibling(self) -> Option<Self> {
// SAFETY: native neighbourhood lookups bounds-check validated refs.
self.tree
.node(unsafe { ffi::jnt_node_prev(self.tree.raw.as_ptr(), self.id) })
}
/// Next named sibling, including comments.
pub fn next_named_sibling(self) -> Option<Self> {
// SAFETY: native neighbourhood lookups bounds-check validated refs.
self.tree
.node(unsafe { ffi::jnt_node_next_named(self.tree.raw.as_ptr(), self.id) })
}
/// Previous named sibling, including comments.
pub fn previous_named_sibling(self) -> Option<Self> {
// SAFETY: native neighbourhood lookups bounds-check validated refs.
self.tree
.node(unsafe { ffi::jnt_node_prev_named(self.tree.raw.as_ptr(), self.id) })
}
/// Parent hops to a root; every root has depth zero.
pub fn depth(self) -> u32 {
// SAFETY: native depth lookup bounds-checks this validated live ref.
unsafe { ffi::jnt_node_depth(self.tree.raw.as_ptr(), self.id) }
}
}
impl PartialEq for Node<'_> {
fn eq(&self, other: &Self) -> bool {
self.tree.raw == other.tree.raw && self.id == other.id
}
}
impl Eq for Node<'_> {}
impl std::fmt::Debug for Node<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Node")
.field("kind", &self.kind())
.field("span", &self.byte_range())
.finish()
}
}