Skip to main content

xidl_parser/
parser.rs

1mod doc_comments;
2mod normalize;
3
4use crate::error::ParserResult;
5use std::collections::{HashMap, HashSet};
6use tree_sitter::Node;
7
8pub struct ParseContext<'a> {
9    pub source: &'a [u8],
10    pub symbols: HashMap<String, String>,
11    doc_consumed: HashSet<usize>,
12}
13
14impl<'a> ParseContext<'a> {
15    pub fn new(source: &'a [u8]) -> Self {
16        Self {
17            source,
18            symbols: HashMap::new(),
19            doc_consumed: HashSet::new(),
20        }
21    }
22
23    pub fn node_text(&self, node: &Node) -> ParserResult<&str> {
24        Ok(node.utf8_text(self.source)?)
25    }
26
27    pub fn take_doc_comment(&mut self, node: &Node) -> Option<String> {
28        let start = node.start_byte();
29        if self.doc_consumed.contains(&start) {
30            return None;
31        }
32        let doc = doc_comments::extract(self.source, start);
33        if doc.is_some() {
34            self.doc_consumed.insert(start);
35        }
36        doc
37    }
38}
39
40pub trait FromTreeSitter<'a>: Sized {
41    fn from_node(node: Node<'a>, context: &mut ParseContext<'a>) -> ParserResult<Self>;
42}
43
44impl<'a> FromTreeSitter<'a> for String {
45    fn from_node(node: Node<'a>, context: &mut ParseContext<'a>) -> ParserResult<Self> {
46        Ok(context.node_text(&node)?.to_string())
47    }
48}
49
50impl<'a, T> FromTreeSitter<'a> for Box<T>
51where
52    T: FromTreeSitter<'a>,
53{
54    fn from_node(node: Node<'a>, context: &mut ParseContext<'a>) -> ParserResult<Self> {
55        Ok(Box::new(T::from_node(node, context)?))
56    }
57}
58
59pub fn parser_text(text: &str) -> ParserResult<crate::typed_ast::Specification> {
60    use crate::typed_ast::Specification;
61
62    let mut parser = tree_sitter::Parser::new();
63    parser.set_language(&tree_sitter_idl::language()).unwrap();
64
65    let normalized = normalize::source(text);
66
67    let tree = parser.parse(normalized.as_ref(), None).ok_or_else(|| {
68        crate::error::ParseError::TreeSitterError("Failed to parse text".to_string())
69    })?;
70
71    let root_node = tree.root_node();
72    if root_node.has_error() {
73        return Err(crate::error::ParseError::TreeSitterError(
74            "Failed to parse text".to_string(),
75        ));
76    }
77    let mut context = ParseContext::new(text.as_bytes());
78
79    Specification::from_node(root_node, &mut context)
80}
81
82pub fn normalize_source_for_tree_sitter(text: &str) -> std::borrow::Cow<'_, str> {
83    normalize::source(text)
84}
85
86#[cfg(test)]
87mod tests;