feat: reverse iteration through node parents (#3214)
This commit is contained in:
parent
0f125e2d09
commit
90e0e28b95
5 changed files with 84 additions and 24 deletions
|
|
@ -168,6 +168,22 @@ fn test_node_child() {
|
|||
assert_eq!(object_node.parent().unwrap(), array_node);
|
||||
assert_eq!(array_node.parent().unwrap(), tree.root_node());
|
||||
assert_eq!(tree.root_node().parent(), None);
|
||||
|
||||
assert_eq!(
|
||||
tree.root_node()
|
||||
.child_containing_descendant(null_node)
|
||||
.unwrap(),
|
||||
array_node
|
||||
);
|
||||
assert_eq!(
|
||||
array_node.child_containing_descendant(null_node).unwrap(),
|
||||
object_node
|
||||
);
|
||||
assert_eq!(
|
||||
object_node.child_containing_descendant(null_node).unwrap(),
|
||||
pair_node
|
||||
);
|
||||
assert_eq!(pair_node.child_containing_descendant(null_node), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -267,6 +283,12 @@ fn test_parent_of_zero_width_node() {
|
|||
assert_eq!(block.to_string(), "(block)");
|
||||
assert_eq!(block_parent.kind(), "function_definition");
|
||||
assert_eq!(block_parent.to_string(), "(function_definition name: (identifier) parameters: (parameters (identifier)) body: (block))");
|
||||
|
||||
assert_eq!(
|
||||
root.child_containing_descendant(block).unwrap(),
|
||||
function_definition
|
||||
);
|
||||
assert_eq!(function_definition.child_containing_descendant(block), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -385,6 +407,22 @@ fn test_node_named_child() {
|
|||
assert_eq!(object_node.parent().unwrap(), array_node);
|
||||
assert_eq!(array_node.parent().unwrap(), tree.root_node());
|
||||
assert_eq!(tree.root_node().parent(), None);
|
||||
|
||||
assert_eq!(
|
||||
tree.root_node()
|
||||
.child_containing_descendant(null_node)
|
||||
.unwrap(),
|
||||
array_node
|
||||
);
|
||||
assert_eq!(
|
||||
array_node.child_containing_descendant(null_node).unwrap(),
|
||||
object_node
|
||||
);
|
||||
assert_eq!(
|
||||
object_node.child_containing_descendant(null_node).unwrap(),
|
||||
pair_node
|
||||
);
|
||||
assert_eq!(pair_node.child_containing_descendant(null_node), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -355,9 +355,13 @@ extern "C" {
|
|||
pub fn ts_node_next_parse_state(self_: TSNode) -> TSStateId;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Get the node's immediate parent."]
|
||||
#[doc = " Get the node's immediate parent.\n Prefer [`ts_node_child_containing_descendant`] for\n iterating over the node's ancestors."]
|
||||
pub fn ts_node_parent(self_: TSNode) -> TSNode;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Get the node's child that contains `descendant`."]
|
||||
pub fn ts_node_child_containing_descendant(self_: TSNode, descendant: TSNode) -> TSNode;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Get the node's child at the given index, where zero represents the first\n child."]
|
||||
pub fn ts_node_child(self_: TSNode, child_index: u32) -> TSNode;
|
||||
|
|
|
|||
|
|
@ -1331,12 +1331,21 @@ impl<'tree> Node<'tree> {
|
|||
}
|
||||
|
||||
/// Get this node's immediate parent.
|
||||
/// Prefer [`child_containing_descendant`](Node::child_containing_descendant)
|
||||
/// for iterating over this node's ancestors.
|
||||
#[doc(alias = "ts_node_parent")]
|
||||
#[must_use]
|
||||
pub fn parent(&self) -> Option<Self> {
|
||||
Self::new(unsafe { ffi::ts_node_parent(self.0) })
|
||||
}
|
||||
|
||||
/// Get this node's child that contains `descendant`.
|
||||
#[doc(alias = "ts_node_child_containing_descendant")]
|
||||
#[must_use]
|
||||
pub fn child_containing_descendant(&self, descendant: Self) -> Option<Self> {
|
||||
Self::new(unsafe { ffi::ts_node_child_containing_descendant(self.0, descendant.0) })
|
||||
}
|
||||
|
||||
/// Get this node's next sibling.
|
||||
#[doc(alias = "ts_node_next_sibling")]
|
||||
#[must_use]
|
||||
|
|
|
|||
|
|
@ -548,9 +548,16 @@ TSStateId ts_node_next_parse_state(TSNode self);
|
|||
|
||||
/**
|
||||
* Get the node's immediate parent.
|
||||
* Prefer [`ts_node_child_containing_descendant`] for
|
||||
* iterating over the node's ancestors.
|
||||
*/
|
||||
TSNode ts_node_parent(TSNode self);
|
||||
|
||||
/**
|
||||
* Get the node's child that contains `descendant`.
|
||||
*/
|
||||
TSNode ts_node_child_containing_descendant(TSNode self, TSNode descendant);
|
||||
|
||||
/**
|
||||
* Get the node's child at the given index, where zero represents the first
|
||||
* child.
|
||||
|
|
|
|||
|
|
@ -505,33 +505,35 @@ TSStateId ts_node_next_parse_state(TSNode self) {
|
|||
|
||||
TSNode ts_node_parent(TSNode self) {
|
||||
TSNode node = ts_tree_root_node(self.tree);
|
||||
uint32_t end_byte = ts_node_end_byte(self);
|
||||
if (node.id == self.id) return ts_node__null();
|
||||
|
||||
TSNode last_visible_node = node;
|
||||
bool did_descend = true;
|
||||
while (did_descend) {
|
||||
did_descend = false;
|
||||
|
||||
TSNode child;
|
||||
NodeChildIterator iterator = ts_node_iterate_children(&node);
|
||||
while (ts_node_child_iterator_next(&iterator, &child)) {
|
||||
if (
|
||||
ts_node_start_byte(child) > ts_node_start_byte(self) ||
|
||||
child.id == self.id
|
||||
) break;
|
||||
if (iterator.position.bytes >= end_byte && ts_node_child_count(child) > 0) {
|
||||
node = child;
|
||||
if (ts_node__is_relevant(child, true)) {
|
||||
last_visible_node = node;
|
||||
}
|
||||
did_descend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
TSNode next_node = ts_node_child_containing_descendant(node, self);
|
||||
if (ts_node_is_null(next_node)) break;
|
||||
node = next_node;
|
||||
}
|
||||
|
||||
return last_visible_node;
|
||||
return node;
|
||||
}
|
||||
|
||||
TSNode ts_node_child_containing_descendant(TSNode self, TSNode subnode) {
|
||||
uint32_t start_byte = ts_node_start_byte(subnode);
|
||||
uint32_t end_byte = ts_node_end_byte(subnode);
|
||||
|
||||
do {
|
||||
NodeChildIterator iter = ts_node_iterate_children(&self);
|
||||
do {
|
||||
if (
|
||||
!ts_node_child_iterator_next(&iter, &self)
|
||||
|| ts_node_start_byte(self) > start_byte
|
||||
|| self.id == subnode.id
|
||||
) {
|
||||
return ts_node__null();
|
||||
}
|
||||
} while (iter.position.bytes < end_byte || ts_node_child_count(self) == 0);
|
||||
} while (!ts_node__is_relevant(self, true));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
TSNode ts_node_child(TSNode self, uint32_t child_index) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue