type_sitter_lib/node/
parser.rs

1#[cfg(feature = "yak-sitter")]
2use crate::TreeParseError;
3use crate::{raw, IncludedRangesError, Language, LanguageError, Node, Range, Tree};
4use std::marker::PhantomData;
5#[cfg(feature = "yak-sitter")]
6use std::path::Path;
7
8/// A stateful object that this is used to produce a tree based on some source code.
9#[repr(transparent)]
10pub struct Parser<Root: Node<'static>>(pub raw::Parser, PhantomData<Root>);
11
12impl<Root: Node<'static>> Parser<Root> {
13    /// Convert a tree-sitter parser into a typed parser by specifying the correct root node type.
14    ///
15    /// This will succeed even if `Root` is not the language's root node, because
16    /// [`Tree::root_node`] checks that the root node is the correct type.
17    pub fn wrap(parser: raw::Parser) -> Self {
18        Self(parser, PhantomData)
19    }
20
21    /// Version of [`wrap`](Self::wrap) for an immutable reference.
22    pub fn wrap_ref(parser: &raw::Parser) -> &Self {
23        // SAFETY: Same repr
24        unsafe { &*(parser as *const raw::Parser as *const Self) }
25    }
26
27    /// Version of [`wrap`](Self::wrap) for a mutable reference.
28    pub fn wrap_mut(parser: &mut raw::Parser) -> &mut Self {
29        // SAFETY: Same repr
30        unsafe { &mut *(parser as *mut raw::Parser as *mut Self) }
31    }
32
33    /// Create a new parser for the given language. See
34    /// [tree-sitter's `Parser::set_language`](tree_sitter::Parser::set_language).
35    ///
36    /// This will succeed even if `Root` is not the language's root node, because
37    /// [`Tree::root_node`] checks that the root node is the correct type.
38    ///
39    /// If the language changes, the root node should change as well, so `set_language` isn't
40    /// exposed by this wrapper. Instead, unwrap the parser, call `set_language`, and re-wrap.
41    #[inline]
42    #[cfg(feature = "yak-sitter")]
43    pub fn new(language: &Language) -> Result<Self, LanguageError> {
44        Ok(Self(raw::Parser::new(language)?, PhantomData))
45    }
46
47    /// Create a new parser for the given language. See [`tree_sitter::Parser::set_language`]
48    #[inline]
49    #[cfg(not(feature = "yak-sitter"))]
50    pub fn new(language: &Language) -> Result<Self, LanguageError> {
51        let mut parser = raw::Parser::new();
52        parser.set_language(language)?;
53        Ok(Self(parser, PhantomData))
54    }
55
56    /// Set the ranges of text the parser should include when parsing. See
57    /// [`tree_sitter::Parser::set_included_ranges`]
58    #[inline]
59    pub fn set_included_ranges(&mut self, ranges: &[Range]) -> Result<(), IncludedRangesError> {
60        self.0.set_included_ranges(ranges)
61    }
62
63    /// Parse a file. See [`tree_sitter::Parser::parse`].
64    ///
65    /// Additionally, file must be valid utf-8 or this will return `Err`. The file's path is used
66    /// for stable node comparison between trees.
67    #[inline]
68    #[cfg(feature = "yak-sitter")]
69    pub fn parse_file(
70        &mut self,
71        path: &Path,
72        old_tree: Option<&Tree<Root>>,
73    ) -> Result<Tree<Root>, TreeParseError> {
74        self.0
75            .parse_file(path, old_tree.map(|t| &t.0))
76            .map(Tree::wrap)
77    }
78
79    /// Parse a string. See [`tree_sitter::Parser::parse`].
80    ///
81    /// The path is stored as metadata that can be accessed from nodes. If you don't need this, pass
82    /// `None`.
83    #[inline]
84    #[cfg(feature = "yak-sitter")]
85    pub fn parse_string(
86        &mut self,
87        text: String,
88        path: Option<&Path>,
89        old_tree: Option<&Tree<Root>>,
90    ) -> Result<Tree<Root>, TreeParseError> {
91        self.0
92            .parse_string(text, path, old_tree.map(|t| &t.0))
93            .map(Tree::wrap)
94    }
95
96    /// Parse a byte string. See [`tree_sitter::Parser::parse`].
97    ///
98    /// Note that the wrappers expect and assume UTF-8, so this will fail if the text is not valid
99    /// UTF-8.
100    ///
101    /// The path is stored as metadata that can be accessed from nodes. If you don't need this, pass
102    /// `None`.
103    #[inline]
104    #[cfg(feature = "yak-sitter")]
105    pub fn parse_bytes(
106        &mut self,
107        byte_text: Vec<u8>,
108        path: Option<&Path>,
109        old_tree: Option<&Tree<Root>>,
110    ) -> Result<Tree<Root>, TreeParseError> {
111        self.0
112            .parse_bytes(byte_text, path, old_tree.map(|t| &t.0))
113            .map(Tree::wrap)
114    }
115
116    /// Parse a byte string. See [`tree_sitter::Parser::parse`]
117    #[inline]
118    #[cfg(not(feature = "yak-sitter"))]
119    pub fn parse(
120        &mut self,
121        text: impl AsRef<[u8]>,
122        old_tree: Option<&Tree<Root>>,
123    ) -> Result<Tree<Root>, ()> {
124        self.0
125            .parse(text, old_tree.map(|t| &t.0))
126            .ok_or(())
127            .map(Tree::wrap)
128    }
129}