wip: converting generate_tags to return an iterator

This commit is contained in:
Max Brunsfeld 2020-03-10 11:45:31 -07:00
parent 157258d881
commit 0eb162c685
2 changed files with 60 additions and 25 deletions

View file

@ -27,9 +27,10 @@ fn test_tags_javascript() {
.unwrap();
let mut tag_context = TagsContext::new();
let tags = tag_context.generate_tags(
&tags_config,
br#"
let tags = tag_context
.generate_tags(
&tags_config,
br#"
class Customer:
'''
Data about a customer
@ -42,7 +43,8 @@ fn test_tags_javascript() {
compute_age(self.id);
}
"#,
);
)
.collect::<Vec<_>>();
assert_eq!(
tags.iter().map(|t| (t.name, t.kind)).collect::<Vec<_>>(),

View file

@ -1,8 +1,8 @@
use regex::Regex;
use serde::{Serialize, Serializer};
use std::collections::{hash_map, HashMap};
use std::{ops, str};
use tree_sitter::{Language, Node, Parser, Query, QueryCursor, QueryError};
use std::{mem, ops, str};
use tree_sitter::{Language, Node, Parser, Query, QueryCursor, QueryError, Tree};
/// Contains the data neeeded to compute tags for code written in a
/// particular language.
@ -24,6 +24,17 @@ pub struct TagsContext {
cursor: QueryCursor,
}
struct TagsIter<'a, I>
where
I: Iterator<Item = tree_sitter::QueryMatch<'a>>,
{
matches: I,
tree: Tree,
source: &'a [u8],
config: &'a TagsConfiguration,
tags: Vec<(Node<'a>, usize, Tag<'a>)>,
}
#[derive(Debug, Serialize, Clone)]
pub struct Loc {
pub byte_range: ops::Range<usize>,
@ -134,10 +145,10 @@ impl TagsContext {
// TODO: This should return an iterator rather than build up a vector
pub fn generate_tags<'a>(
&mut self,
config: &TagsConfiguration,
&'a mut self,
config: &'a TagsConfiguration,
source: &'a [u8],
) -> Vec<Tag<'a>> {
) -> impl Iterator<Item = Tag<'a>> + 'a {
self.parser
.set_language(config.language)
.expect("Incompatible language");
@ -145,14 +156,30 @@ impl TagsContext {
.parser
.parse(source, None)
.expect("Parsing failed unexpectedly");
let tree_ref = unsafe { mem::transmute::<_, &'static Tree>(&tree) };
let matches = self
.cursor
.matches(&config.query, tree.root_node(), |node| {
.matches(&config.query, tree_ref.root_node(), move |node| {
&source[node.byte_range()]
});
let mut neighbor_map: HashMap<tree_sitter::Node, (Tag<'a>, usize)> = HashMap::new();
TagsIter {
matches,
tree,
source,
config,
tags: Vec::new(),
}
}
}
for mat in matches {
impl<'a, I> Iterator for TagsIter<'a, I>
where
I: Iterator<Item = tree_sitter::QueryMatch<'a>>,
{
type Item = Tag<'a>;
fn next(&mut self) -> Option<Tag<'a>> {
if let Some(mat) = self.matches.next() {
let mut call_node = None;
let mut doc_node = None;
let mut class_node = None;
@ -163,21 +190,23 @@ impl TagsContext {
for capture in mat.captures {
let index = Some(capture.index);
let node = Some(capture.node);
if index == config.call_capture_index {
if index == self.config.call_capture_index {
call_node = node;
} else if index == config.class_capture_index {
} else if index == self.config.class_capture_index {
class_node = node;
} else if index == config.doc_capture_index {
} else if index == self.config.doc_capture_index {
doc_node = node;
} else if index == config.function_capture_index {
} else if index == self.config.function_capture_index {
function_node = node;
} else if index == config.module_capture_index {
} else if index == self.config.module_capture_index {
module_node = node;
} else if index == config.name_capture_index {
} else if index == self.config.name_capture_index {
name_node = node;
}
}
let source = &self.source;
let config = &self.config;
let tag_from_node = |node: Node, kind: TagKind| -> Option<Tag> {
let name = str::from_utf8(&source[name_node?.byte_range()]).ok()?;
let docs = doc_node
@ -208,9 +237,13 @@ impl TagsContext {
.cloned()
{
if let Some(found) = tag_node {
match neighbor_map.entry(found) {
hash_map::Entry::Occupied(mut entry) => {
let (tag, old_idx) = entry.get_mut();
match self
.tags
.binary_search_by_key(&(found.end_byte(), found.id()), |(node, _, _)| {
(node.end_byte(), node.id())
}) {
Ok(i) => {
let (_, old_idx, tag) = &mut self.tags[i];
if *old_idx > mat.pattern_index {
if let Some(new_tag) = tag_from_node(found, tag_kind) {
*tag = new_tag;
@ -218,17 +251,17 @@ impl TagsContext {
}
}
}
hash_map::Entry::Vacant(entry) => {
Err(i) => {
if let Some(tag) = tag_from_node(found, tag_kind) {
entry.insert((tag, mat.pattern_index));
self.tags.insert(i, (found, mat.pattern_index, tag))
}
}
}
}
}
} else {
}
return neighbor_map.into_iter().map(|t| (t.1).0).collect();
None
}
}