rust_sitter/
lib.rs

1pub mod __private;
2
3use std::ops::Deref;
4
5pub use rust_sitter_macro::*;
6
7#[cfg(feature = "tree-sitter-standard")]
8pub use tree_sitter_runtime_standard as tree_sitter;
9
10#[cfg(feature = "tree-sitter-c2rust")]
11pub use tree_sitter_runtime_c2rust as tree_sitter;
12
13/// Defines the logic used to convert a node in a Tree Sitter tree to
14/// the corresponding Rust type.
15pub trait Extract<Output> {
16    type LeafFn: ?Sized;
17    fn extract(
18        node: Option<tree_sitter::Node>,
19        source: &[u8],
20        last_idx: usize,
21        leaf_fn: Option<&Self::LeafFn>,
22    ) -> Output;
23}
24
25pub struct WithLeaf<L> {
26    _phantom: std::marker::PhantomData<L>,
27}
28
29impl<L> Extract<L> for WithLeaf<L> {
30    type LeafFn = dyn Fn(&str) -> L;
31
32    fn extract(
33        node: Option<tree_sitter::Node>,
34        source: &[u8],
35        _last_idx: usize,
36        leaf_fn: Option<&Self::LeafFn>,
37    ) -> L {
38        node.and_then(|n| n.utf8_text(source).ok())
39            .map(|s| leaf_fn.unwrap()(s))
40            .unwrap()
41    }
42}
43
44impl Extract<()> for () {
45    type LeafFn = ();
46    fn extract(
47        _node: Option<tree_sitter::Node>,
48        _source: &[u8],
49        _last_idx: usize,
50        _leaf_fn: Option<&Self::LeafFn>,
51    ) {
52    }
53}
54
55impl<T: Extract<U>, U> Extract<Option<U>> for Option<T> {
56    type LeafFn = T::LeafFn;
57    fn extract(
58        node: Option<tree_sitter::Node>,
59        source: &[u8],
60        last_idx: usize,
61        leaf_fn: Option<&Self::LeafFn>,
62    ) -> Option<U> {
63        node.map(|n| T::extract(Some(n), source, last_idx, leaf_fn))
64    }
65}
66
67impl<T: Extract<U>, U> Extract<Box<U>> for Box<T> {
68    type LeafFn = T::LeafFn;
69    fn extract(
70        node: Option<tree_sitter::Node>,
71        source: &[u8],
72        last_idx: usize,
73        leaf_fn: Option<&Self::LeafFn>,
74    ) -> Box<U> {
75        Box::new(T::extract(node, source, last_idx, leaf_fn))
76    }
77}
78
79impl<T: Extract<U>, U> Extract<Vec<U>> for Vec<T> {
80    type LeafFn = T::LeafFn;
81    fn extract(
82        node: Option<tree_sitter::Node>,
83        source: &[u8],
84        mut last_idx: usize,
85        leaf_fn: Option<&Self::LeafFn>,
86    ) -> Vec<U> {
87        node.map(|node| {
88            let mut cursor = node.walk();
89            let mut out = vec![];
90            if cursor.goto_first_child() {
91                loop {
92                    let n = cursor.node();
93                    if cursor.field_name().is_some() {
94                        out.push(T::extract(Some(n), source, last_idx, leaf_fn));
95                    }
96
97                    last_idx = n.end_byte();
98
99                    if !cursor.goto_next_sibling() {
100                        break;
101                    }
102                }
103            }
104
105            out
106        })
107        .unwrap_or_default()
108    }
109}
110
111#[derive(Clone, Debug)]
112/// A wrapper around a value that also contains the span of the value in the source.
113pub struct Spanned<T> {
114    /// The underlying parsed node.
115    pub value: T,
116    /// The span of the node in the source. The first value is the inclusive start
117    /// of the span, and the second value is the exclusive end of the span.
118    pub span: (usize, usize),
119}
120
121impl<T> Deref for Spanned<T> {
122    type Target = T;
123
124    fn deref(&self) -> &T {
125        &self.value
126    }
127}
128
129impl<T: Extract<U>, U> Extract<Spanned<U>> for Spanned<T> {
130    type LeafFn = T::LeafFn;
131    fn extract(
132        node: Option<tree_sitter::Node>,
133        source: &[u8],
134        last_idx: usize,
135        leaf_fn: Option<&Self::LeafFn>,
136    ) -> Spanned<U> {
137        Spanned {
138            value: T::extract(node, source, last_idx, leaf_fn),
139            span: node
140                .map(|n| (n.start_byte(), n.end_byte()))
141                .unwrap_or((last_idx, last_idx)),
142        }
143    }
144}
145
146pub mod errors {
147    #[cfg(feature = "tree-sitter-standard")]
148    use tree_sitter_runtime_standard as tree_sitter;
149
150    #[cfg(feature = "tree-sitter-c2rust")]
151    use tree_sitter_runtime_c2rust as tree_sitter;
152
153    #[derive(Debug)]
154    /// An explanation for an error that occurred during parsing.
155    pub enum ParseErrorReason {
156        /// The parser did not expect to see some token.
157        UnexpectedToken(String),
158        /// Tree Sitter failed to parse a specific intermediate node.
159        /// The underlying failures are in the vector.
160        FailedNode(Vec<ParseError>),
161        /// The parser expected a specific token, but it was not found.
162        MissingToken(String),
163    }
164
165    #[derive(Debug)]
166    /// An error that occurred during parsing.
167    pub struct ParseError {
168        pub reason: ParseErrorReason,
169        /// Inclusive start of the error.
170        pub start: usize,
171        /// Exclusive end of the error.
172        pub end: usize,
173    }
174
175    /// Given the root node of a Tree Sitter parsing result, accumulates all
176    /// errors that were emitted.
177    pub fn collect_parsing_errors(
178        node: &tree_sitter::Node,
179        source: &[u8],
180        errors: &mut Vec<ParseError>,
181    ) {
182        if node.is_error() {
183            if node.child(0).is_some() {
184                // we managed to parse some children, so collect underlying errors for this node
185                let mut inner_errors = vec![];
186                let mut cursor = node.walk();
187                node.children(&mut cursor)
188                    .for_each(|c| collect_parsing_errors(&c, source, &mut inner_errors));
189
190                errors.push(ParseError {
191                    reason: ParseErrorReason::FailedNode(inner_errors),
192                    start: node.start_byte(),
193                    end: node.end_byte(),
194                })
195            } else {
196                let contents = node.utf8_text(source).unwrap();
197                if !contents.is_empty() {
198                    errors.push(ParseError {
199                        reason: ParseErrorReason::UnexpectedToken(contents.to_string()),
200                        start: node.start_byte(),
201                        end: node.end_byte(),
202                    })
203                } else {
204                    errors.push(ParseError {
205                        reason: ParseErrorReason::FailedNode(vec![]),
206                        start: node.start_byte(),
207                        end: node.end_byte(),
208                    })
209                }
210            }
211        } else if node.is_missing() {
212            errors.push(ParseError {
213                reason: ParseErrorReason::MissingToken(node.kind().to_string()),
214                start: node.start_byte(),
215                end: node.end_byte(),
216            })
217        } else if node.has_error() {
218            let mut cursor = node.walk();
219            node.children(&mut cursor)
220                .for_each(|c| collect_parsing_errors(&c, source, errors));
221        }
222    }
223}