Merge pull request #1072 from ahlinc/feat/separate-nodes-lifetime
feat(binding_rust): separate nodes lifetime from QueryCursor / QueryCaptures. Supersedes #1065
This commit is contained in:
commit
f2495aba77
3 changed files with 77 additions and 21 deletions
|
|
@ -3036,6 +3036,62 @@ fn test_query_capture_names() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_lifetime_is_separate_from_nodes_lifetime() {
|
||||
allocations::record(|| {
|
||||
let query = r#"(call_expression) @call"#;
|
||||
let source = "a(1); b(2);";
|
||||
|
||||
let language = get_language("javascript");
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
|
||||
fn take_first_node_from_captures<'tree>(
|
||||
source: &str,
|
||||
query: &str,
|
||||
node: Node<'tree>,
|
||||
) -> Node<'tree> {
|
||||
// Following 2 lines are redundant but needed to demonstrate
|
||||
// more understandable compiler error message
|
||||
let language = get_language("javascript");
|
||||
let query = Query::new(language, query).unwrap();
|
||||
let mut cursor = QueryCursor::new();
|
||||
let node = cursor
|
||||
.matches(&query, node, to_callback(source))
|
||||
.next()
|
||||
.unwrap()
|
||||
.captures[0]
|
||||
.node;
|
||||
node
|
||||
}
|
||||
|
||||
let node = take_first_node_from_captures(source, query, tree.root_node());
|
||||
assert_eq!(node.kind(), "call_expression");
|
||||
|
||||
fn take_first_node_from_matches<'tree>(
|
||||
source: &str,
|
||||
query: &str,
|
||||
node: Node<'tree>,
|
||||
) -> Node<'tree> {
|
||||
let language = get_language("javascript");
|
||||
let query = Query::new(language, query).unwrap();
|
||||
let mut cursor = QueryCursor::new();
|
||||
let node = cursor
|
||||
.captures(&query, node, to_callback(source))
|
||||
.next()
|
||||
.unwrap()
|
||||
.0
|
||||
.captures[0]
|
||||
.node;
|
||||
node
|
||||
}
|
||||
|
||||
let node = take_first_node_from_matches(source, query, tree.root_node());
|
||||
assert_eq!(node.kind(), "call_expression");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_with_no_patterns() {
|
||||
allocations::record(|| {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ struct LocalScope<'a> {
|
|||
local_defs: Vec<LocalDef<'a>>,
|
||||
}
|
||||
|
||||
struct HighlightIter<'a, F>
|
||||
struct HighlightIter<'a, 'tree: 'a, F>
|
||||
where
|
||||
F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a,
|
||||
{
|
||||
|
|
@ -92,16 +92,16 @@ where
|
|||
highlighter: &'a mut Highlighter,
|
||||
injection_callback: F,
|
||||
cancellation_flag: Option<&'a AtomicUsize>,
|
||||
layers: Vec<HighlightIterLayer<'a>>,
|
||||
layers: Vec<HighlightIterLayer<'a, 'tree>>,
|
||||
iter_count: usize,
|
||||
next_event: Option<HighlightEvent>,
|
||||
last_highlight_range: Option<(usize, usize, usize)>,
|
||||
}
|
||||
|
||||
struct HighlightIterLayer<'a> {
|
||||
struct HighlightIterLayer<'a, 'tree: 'a> {
|
||||
_tree: Tree,
|
||||
cursor: QueryCursor,
|
||||
captures: iter::Peekable<QueryCaptures<'a, &'a [u8]>>,
|
||||
captures: iter::Peekable<QueryCaptures<'a, 'tree, &'a [u8]>>,
|
||||
config: &'a HighlightConfiguration,
|
||||
highlight_end_stack: Vec<usize>,
|
||||
scope_stack: Vec<LocalScope<'a>>,
|
||||
|
|
@ -319,7 +319,7 @@ impl HighlightConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> HighlightIterLayer<'a> {
|
||||
impl<'a, 'tree: 'a> HighlightIterLayer<'a, 'tree> {
|
||||
/// Create a new 'layer' of highlighting for this document.
|
||||
///
|
||||
/// In the even that the new layer contains "combined injections" (injections where multiple
|
||||
|
|
@ -548,7 +548,7 @@ impl<'a> HighlightIterLayer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, F> HighlightIter<'a, F>
|
||||
impl<'a, 'tree: 'a, F> HighlightIter<'a, 'tree, F>
|
||||
where
|
||||
F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a,
|
||||
{
|
||||
|
|
@ -596,7 +596,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_layer(&mut self, mut layer: HighlightIterLayer<'a>) {
|
||||
fn insert_layer(&mut self, mut layer: HighlightIterLayer<'a, 'tree>) {
|
||||
if let Some(sort_key) = layer.sort_key() {
|
||||
let mut i = 1;
|
||||
while i < self.layers.len() {
|
||||
|
|
@ -615,7 +615,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, F> Iterator for HighlightIter<'a, F>
|
||||
impl<'a, 'tree: 'a, F> Iterator for HighlightIter<'a, 'tree, F>
|
||||
where
|
||||
F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -134,10 +134,10 @@ pub struct QueryMatch<'a> {
|
|||
}
|
||||
|
||||
/// A sequence of `QueryCapture`s within a `QueryMatch`.
|
||||
pub struct QueryCaptures<'a, T: AsRef<[u8]>> {
|
||||
pub struct QueryCaptures<'a, 'tree: 'a, T: AsRef<[u8]>> {
|
||||
ptr: *mut ffi::TSQueryCursor,
|
||||
query: &'a Query,
|
||||
text_callback: Box<dyn FnMut(Node<'a>) -> T + 'a>,
|
||||
text_callback: Box<dyn FnMut(Node<'tree>) -> T + 'a>,
|
||||
}
|
||||
|
||||
/// A particular `Node` that has been captured with a particular name within a `Query`.
|
||||
|
|
@ -1587,7 +1587,7 @@ impl Query {
|
|||
}
|
||||
}
|
||||
|
||||
impl QueryCursor {
|
||||
impl<'a> QueryCursor {
|
||||
/// Create a new cursor for executing a given query.
|
||||
///
|
||||
/// The cursor stores the state that is needed to iteratively search for matches.
|
||||
|
|
@ -1606,12 +1606,12 @@ impl QueryCursor {
|
|||
/// Each match contains the index of the pattern that matched, and a list of captures.
|
||||
/// Because multiple patterns can match the same set of nodes, one match may contain
|
||||
/// captures that appear *before* some of the captures from a previous match.
|
||||
pub fn matches<'a, T: AsRef<[u8]>>(
|
||||
pub fn matches<'tree: 'a, T: AsRef<[u8]>>(
|
||||
&'a mut self,
|
||||
query: &'a Query,
|
||||
node: Node<'a>,
|
||||
mut text_callback: impl FnMut(Node<'a>) -> T + 'a,
|
||||
) -> impl Iterator<Item = QueryMatch<'a>> + 'a {
|
||||
node: Node<'tree>,
|
||||
mut text_callback: impl FnMut(Node<'tree>) -> T + 'a,
|
||||
) -> impl Iterator<Item = QueryMatch<'tree>> + 'a {
|
||||
let ptr = self.0.as_ptr();
|
||||
unsafe { ffi::ts_query_cursor_exec(ptr, query.ptr.as_ptr(), node.0) };
|
||||
std::iter::from_fn(move || loop {
|
||||
|
|
@ -1633,12 +1633,12 @@ impl QueryCursor {
|
|||
///
|
||||
/// This is useful if don't care about which pattern matched, and just want a single,
|
||||
/// ordered sequence of captures.
|
||||
pub fn captures<'a, T: AsRef<[u8]>>(
|
||||
pub fn captures<'tree, T: AsRef<[u8]>>(
|
||||
&'a mut self,
|
||||
query: &'a Query,
|
||||
node: Node<'a>,
|
||||
text_callback: impl FnMut(Node<'a>) -> T + 'a,
|
||||
) -> QueryCaptures<'a, T> {
|
||||
node: Node<'tree>,
|
||||
text_callback: impl FnMut(Node<'tree>) -> T + 'a,
|
||||
) -> QueryCaptures<'a, 'tree, T> {
|
||||
let ptr = self.0.as_ptr();
|
||||
unsafe { ffi::ts_query_cursor_exec(ptr, query.ptr.as_ptr(), node.0) };
|
||||
QueryCaptures {
|
||||
|
|
@ -1732,8 +1732,8 @@ impl QueryProperty {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsRef<[u8]>> Iterator for QueryCaptures<'a, T> {
|
||||
type Item = (QueryMatch<'a>, usize);
|
||||
impl<'a, 'tree: 'a, T: AsRef<[u8]>> Iterator for QueryCaptures<'a, 'tree, T> {
|
||||
type Item = (QueryMatch<'tree>, usize);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue