1use std::borrow::Cow;
8use std::error::Error;
9use std::fmt::{Display, Formatter};
10use std::vec::IntoIter;
11
12use crate::{
13 CSTNodeClassLabel, CellStream, ExternalCstChild, ExternalCstNode, LexError, Parser,
14 ReconstructError, SourceFile, SourceId, Span, Spanned, TextPoint, TextRange, TokenStream,
15 lex_str, reconstruct,
16};
17
18#[derive(Debug)]
19pub enum ParseError {
20 Lex(LexError),
21 Language(tree_sitter::LanguageError),
22 Cancelled,
23 InvalidSyntax(Span),
24 Reconstruct(ReconstructError),
25}
26
27impl Display for ParseError {
28 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Self::Lex(error) => error.fmt(formatter),
31 Self::Language(error) => error.fmt(formatter),
32 Self::Cancelled => formatter.write_str("Tree-sitter parsing was cancelled"),
33 Self::InvalidSyntax(span) => match span.range() {
34 Ok(range) => write!(
35 formatter,
36 "invalid Macaulay2 syntax at byte {}",
37 range.start().map_or(0, |point| point.byte)
38 ),
39 Err(_) => formatter.write_str("invalid Macaulay2 syntax"),
40 },
41 Self::Reconstruct(error) => error.fmt(formatter),
42 }
43 }
44}
45
46impl Error for ParseError {
47 fn source(&self) -> Option<&(dyn Error + 'static)> {
48 match self {
49 Self::Lex(error) => Some(error),
50 Self::Language(error) => Some(error),
51 Self::Reconstruct(error) => Some(error),
52 Self::Cancelled | Self::InvalidSyntax(_) => None,
53 }
54 }
55}
56
57impl From<ReconstructError> for ParseError {
58 fn from(error: ReconstructError) -> Self {
59 Self::Reconstruct(error)
60 }
61}
62
63impl From<LexError> for ParseError {
64 fn from(error: LexError) -> Self {
65 Self::Lex(error)
66 }
67}
68
69pub struct TreeSitterParser {
70 parser: tree_sitter::Parser,
71}
72
73impl TreeSitterParser {
74 pub fn new() -> Result<Self, ParseError> {
75 let mut parser = tree_sitter::Parser::new();
76 parser
77 .set_language(&tree_sitter_macaulay2::language())
78 .map_err(ParseError::Language)?;
79 Ok(Self { parser })
80 }
81}
82
83impl Parser for TreeSitterParser {
84 type Error = ParseError;
85
86 fn parse_cells(&mut self, tokens: CellStream) -> Result<SourceFile, Self::Error> {
87 let source_id = tokens.source_id();
88 let source = tokens.to_string();
89 let tree = self
90 .parser
91 .parse(&source, None)
92 .ok_or(ParseError::Cancelled)?;
93 if let Some(error) = first_error(tree.root_node()) {
94 return Err(ParseError::InvalidSyntax(
95 TreeSitterNode::new(error, source.as_bytes(), source_id).span(),
96 ));
97 }
98 reconstruct(TreeSitterNode::new(
99 tree.root_node(),
100 source.as_bytes(),
101 source_id,
102 ))
103 .map_err(Into::into)
104 }
105}
106
107pub fn parse_file(source: &str, source_id: SourceId) -> Result<SourceFile, ParseError> {
108 let mut parser = TreeSitterParser::new()?;
109 parser.parse_cells(lex_str(source, source_id)?)
110}
111
112pub fn parse_tokens(tokens: &TokenStream, source_id: SourceId) -> Result<SourceFile, ParseError> {
114 parse_file(&tokens.to_string(), source_id)
115}
116
117fn first_error(root: tree_sitter::Node<'_>) -> Option<tree_sitter::Node<'_>> {
118 let mut pending = vec![root];
119 while let Some(node) = pending.pop() {
120 if node.is_error() || node.is_missing() {
121 return Some(node);
122 }
123 pending.extend((0..node.child_count()).rev().filter_map(|index| {
124 node.child(u32::try_from(index).expect("Tree-sitter child count fits u32"))
125 }));
126 }
127 None
128}
129
130#[derive(Clone, Copy)]
131pub struct TreeSitterNode<'tree, 'source> {
132 node: tree_sitter::Node<'tree>,
133 source: &'source [u8],
134 source_id: SourceId,
135}
136
137impl<'tree, 'source> TreeSitterNode<'tree, 'source> {
138 pub fn new(node: tree_sitter::Node<'tree>, source: &'source [u8], source_id: SourceId) -> Self {
139 Self {
140 node,
141 source,
142 source_id,
143 }
144 }
145
146 pub fn raw(self) -> tree_sitter::Node<'tree> {
147 self.node
148 }
149
150 fn normalized_node(self) -> tree_sitter::Node<'tree> {
151 if self.node.kind() != "cell" {
152 return self.node;
153 }
154
155 let mut named_children = (0..self.node.named_child_count())
159 .filter_map(|index| self.node.named_child(index as u32));
160 match (named_children.next(), named_children.next()) {
161 (Some(child), None) if child.kind() == "muted" => child,
162 _ => self.node,
163 }
164 }
165}
166
167impl ExternalCstNode for TreeSitterNode<'_, '_> {
168 type Children<'syntax>
169 = IntoIter<ExternalCstChild<Self>>
170 where
171 Self: 'syntax;
172
173 fn identity(&self) -> CSTNodeClassLabel<'_> {
174 let node = self.normalized_node();
175 CSTNodeClassLabel::new(node.kind(), node.is_named())
176 }
177
178 fn children(&self) -> Self::Children<'_> {
179 let parent = self.normalized_node();
180 (0..parent.child_count())
181 .filter_map(|index| {
182 let index = u32::try_from(index).expect("Tree-sitter child count fits u32");
183 parent.child(index).map(|node| ExternalCstChild {
184 field: parent.field_name_for_child(index),
185 node: Self::new(node, self.source, self.source_id),
186 })
187 })
188 .collect::<Vec<_>>()
189 .into_iter()
190 }
191
192 fn text(&self) -> Cow<'_, str> {
193 String::from_utf8_lossy(&self.source[self.normalized_node().byte_range()])
194 }
195
196 fn is_extra(&self) -> bool {
197 self.node.is_extra()
198 }
199}
200
201impl Spanned for TreeSitterNode<'_, '_> {
202 fn span(&self) -> Span {
203 let node = self.normalized_node();
204 let range = TextRange::new(
205 TextPoint::new(
206 node.start_position().row as u32,
207 node.start_position().column as u32,
208 node.start_byte(),
209 ),
210 TextPoint::new(
211 node.end_position().row as u32,
212 node.end_position().column as u32,
213 node.end_byte(),
214 ),
215 );
216 Span::new(self.source_id, range)
217 }
218}