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
use crate::ExtractionError;
use std::ops::Range;
use tree_sitter::{Node, Parser, Query, QueryCursor, QueryMatches, Tree};
/// A parsed source file with its tree-sitter parse tree and original source code.
pub struct ParsedFile<'a> {
root_tree: Tree,
source_code: &'a str,
}
impl<'a> ParsedFile<'a> {
/// Parse source code into a tree-sitter parse tree.
///
/// # Parameters
/// * `source_code` - The source code to parse
/// * `parser` - A mutable reference to a configured tree-sitter parser
///
/// # Returns
/// A new `ParsedFile` instance or an `ExtractionError` if parsing fails
pub fn parse(source_code: &'a str, parser: &mut Parser) -> Result<Self, ExtractionError> {
let root_tree = parser
.parse(source_code, None)
.ok_or_else(|| ExtractionError::Malformed("Failed to parse source file".to_string()))?;
if root_tree.root_node().has_error() {
return Err(ExtractionError::Malformed(
"Failed to parse source file".to_string(),
));
}
Ok(Self {
root_tree,
source_code,
})
}
/// Return the root node of the parse tree.
///
/// # Returns
/// The root node of the parsed source file
pub fn root_node(&'a self) -> Node<'a> {
self.root_tree.root_node()
}
/// Return a tree-sitter node's text content.
///
/// # Parameters
/// * `node` - The tree-sitter node to render
///
/// # Returns
/// The text content of the node or an `ExtractionError` if rendering fails
pub fn render_node(&self, node: Node) -> Result<String, ExtractionError> {
node.utf8_text(self.source_code.as_bytes())
.map(|s| s.to_string())
.map_err(|_| ExtractionError::Malformed("Failed to render node".to_string()))
}
/// Return text content from a byte range in the source code.
///
/// # Parameters
/// * `range` - The byte range to extract from the source code
///
/// # Returns
/// The text content within the specified range
pub fn render(&self, range: Range<usize>) -> String {
self.source_code[range].to_string()
}
/// Create a new tree-sitter query from a query string.
///
/// # Parameters
/// * `query` - The query string in tree-sitter query language
///
/// # Returns
/// A compiled query or an `ExtractionError` if query creation fails
pub fn make_query(&self, query: &str) -> Result<Query, ExtractionError> {
Query::new(&self.root_tree.language(), query)
.map_err(|_| ExtractionError::Malformed("Failed to create query".to_string()))
}
/// Execute a tree-sitter query on a specific node.
///
/// # Parameters
/// * `query` - The compiled tree-sitter query to execute
/// * `node` - The node to search within
/// * `cursor` - A mutable reference to a query cursor for tracking query state
///
/// # Returns
/// An iterator over the query matches
pub fn exec_query<'b>(
&'b self,
query: &'b Query,
node: Node<'b>,
cursor: &'b mut QueryCursor,
) -> QueryMatches<'b, 'b, &'b [u8], &'b [u8]> {
cursor.matches(query, node, self.source_code.as_bytes())
}
}