Skip to main content

m2_syn/cst/
treesitter.rs

1//! Tree-sitter parser adapter.
2//!
3//! Tree-sitter nodes remain backend-local. Complete-file parsing lowers the
4//! grammar's concrete nodes directly into the generated typed graph; it never
5//! reparses their source through the native precedence engine.
6//! [`TreeSitterNode`] is also the generic [`ExternalCstNode`] adapter used for
7//! reconstructing leaves, operators, and tokens with the generated machinery.
8
9use std::borrow::Cow;
10use std::error::Error;
11use std::fmt::{Display, Formatter};
12use std::ops::Range;
13use std::vec::IntoIter;
14
15use crate::native::{assignment_pack, installation_value, lambda_parameters};
16use crate::nodes::*;
17use crate::{
18    CSTNodeClassLabel, DelimiterKind, DelimiterToken, DoubleSpan, ExternalCstChild,
19    ExternalCstNode, LexError, Parser, Punctuated, Reconstruct, ReconstructError, Recovered,
20    SourceFile, Span, Spanned, TextEdit, TokenStream, TokenTree, lex_str, lex_str_recovering,
21};
22
23#[derive(Debug)]
24/// A failure while parsing or reconstructing a Tree-sitter syntax tree.
25pub enum ParseError {
26    /// The renaming hook could not inspect the source token stream.
27    Lex(LexError),
28    /// The bundled grammar could not be installed in the parser.
29    Language(tree_sitter::LanguageError),
30    /// Tree-sitter returned no tree.
31    Cancelled,
32    /// A requested source edit did not lie on valid boundaries of the buffer.
33    InvalidEdit,
34    /// Tree-sitter produced an error or missing node at this span.
35    InvalidSyntax(Span),
36    /// The untyped Tree-sitter node could not reconstruct typed syntax.
37    Reconstruct(ReconstructError),
38    /// A valid concrete node has no representation in the typed schema.
39    UnsupportedNode {
40        /// The Tree-sitter node kind that could not be lowered.
41        kind: String,
42        /// The complete node range.
43        span: Span,
44    },
45}
46
47impl Display for ParseError {
48    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
49        match self {
50            Self::Lex(error) => error.fmt(formatter),
51            Self::Language(error) => error.fmt(formatter),
52            Self::Cancelled => formatter.write_str("Tree-sitter parsing was cancelled"),
53            Self::InvalidEdit => formatter.write_str("source edit is outside the current buffer"),
54            Self::InvalidSyntax(span) => match span.start() {
55                Some(start) => write!(formatter, "invalid Macaulay2 syntax at byte {start}"),
56                None => formatter.write_str("invalid Macaulay2 syntax"),
57            },
58            Self::Reconstruct(error) => error.fmt(formatter),
59            Self::UnsupportedNode { kind, .. } => {
60                write!(
61                    formatter,
62                    "Tree-sitter node `{kind}` has no typed representation"
63                )
64            }
65        }
66    }
67}
68
69impl Error for ParseError {
70    fn source(&self) -> Option<&(dyn Error + 'static)> {
71        match self {
72            Self::Lex(error) => Some(error),
73            Self::Language(error) => Some(error),
74            Self::Reconstruct(error) => Some(error),
75            Self::Cancelled
76            | Self::InvalidEdit
77            | Self::InvalidSyntax(_)
78            | Self::UnsupportedNode { .. } => None,
79        }
80    }
81}
82
83impl From<ReconstructError> for ParseError {
84    fn from(error: ReconstructError) -> Self {
85        Self::Reconstruct(error)
86    }
87}
88
89impl From<LexError> for ParseError {
90    fn from(error: LexError) -> Self {
91        Self::Lex(error)
92    }
93}
94
95/// A reusable Tree-sitter parser and direct typed-CST lowerer.
96pub struct TreeSitterParser {
97    parser: tree_sitter::Parser,
98}
99
100/// An incrementally updated Tree-sitter parse for editor-style source changes.
101///
102/// The parser retains its previous Tree-sitter tree, applies each [`TextEdit`]
103/// to that tree, and supplies it to the next parse. Typed syntax is lowered
104/// afresh from the incrementally produced tree, so every public node and span
105/// describes the current source snapshot. Missing group closers are recoverable
106/// and remain available through [`Self::diagnostics`].
107pub struct RealtimeParser {
108    parser: tree_sitter::Parser,
109    source: String,
110    parse_view: String,
111    tree: tree_sitter::Tree,
112    syntax: SourceFile,
113    diagnostics: Vec<LexError>,
114    changed_ranges: Vec<Span>,
115}
116
117impl RealtimeParser {
118    /// Creates a retained parse of the initial source snapshot.
119    ///
120    /// # Errors
121    ///
122    /// Returns [`ParseError`] when the grammar cannot parse and lower the
123    /// source, apart from recoverable missing group closers.
124    pub fn new(source: impl Into<String>) -> Result<Self, ParseError> {
125        let source = source.into();
126        let mut parser = TreeSitterParser::new()?.parser;
127        let ParsedTree {
128            parse_view,
129            tree,
130            syntax,
131            diagnostics,
132        } = parse_recovered_tree(&mut parser, &source, None)?;
133        Ok(Self {
134            parser,
135            source,
136            parse_view,
137            tree,
138            syntax,
139            diagnostics,
140            changed_ranges: Vec::new(),
141        })
142    }
143
144    /// Applies one source edit and incrementally refreshes the typed syntax.
145    ///
146    /// The update is transactional: a failed edit or parse leaves the previous
147    /// source, tree, syntax, and diagnostics unchanged.
148    ///
149    /// # Errors
150    ///
151    /// Returns [`ParseError::InvalidEdit`] when the edit is outside the current
152    /// UTF-8 buffer, or another [`ParseError`] when the edited source cannot be
153    /// recovered and lowered.
154    pub fn apply_edit(&mut self, edit: &TextEdit) -> Result<(), ParseError> {
155        let source = edit.apply(&self.source).ok_or(ParseError::InvalidEdit)?;
156        let (view, aliases, diagnostics) = renamed_source_recovering(&source)?;
157        let parse_view = view.into_owned();
158
159        let mut edited_tree = self.tree.clone();
160        edited_tree.edit(&input_edit_between(&self.parse_view, &parse_view));
161        let tree = self
162            .parser
163            .parse(parse_view.as_bytes(), Some(&edited_tree))
164            .ok_or(ParseError::Cancelled)?;
165        if let Some(error) = first_error(tree.root_node()) {
166            return Err(ParseError::InvalidSyntax(Span::new(
167                error.start_byte().min(source.len()),
168                error.end_byte().min(source.len()),
169            )));
170        }
171        let syntax = Lowerer::new(&source, aliases).source_file(tree.root_node())?;
172        let changed_ranges = edited_tree
173            .changed_ranges(&tree)
174            .map(|range| {
175                Span::new(
176                    range.start_byte.min(source.len()),
177                    range.end_byte.min(source.len()),
178                )
179            })
180            .collect();
181
182        self.source = source;
183        self.parse_view = parse_view;
184        self.tree = tree;
185        self.syntax = syntax;
186        self.diagnostics = diagnostics;
187        self.changed_ranges = changed_ranges;
188        Ok(())
189    }
190
191    /// Returns the current source snapshot.
192    pub fn source(&self) -> &str {
193        &self.source
194    }
195
196    /// Returns the typed syntax for the current snapshot.
197    pub fn syntax(&self) -> &SourceFile {
198        &self.syntax
199    }
200
201    /// Returns the recoverable diagnostics for the current snapshot.
202    pub fn diagnostics(&self) -> &[LexError] {
203        &self.diagnostics
204    }
205
206    /// Returns structural ranges changed by the most recent incremental parse.
207    pub fn changed_ranges(&self) -> &[Span] {
208        &self.changed_ranges
209    }
210
211    /// Consumes the retained parser and returns its current typed syntax.
212    pub fn into_syntax(self) -> SourceFile {
213        self.syntax
214    }
215}
216
217struct ParsedTree {
218    parse_view: String,
219    tree: tree_sitter::Tree,
220    syntax: SourceFile,
221    diagnostics: Vec<LexError>,
222}
223
224fn parse_recovered_tree(
225    parser: &mut tree_sitter::Parser,
226    source: &str,
227    old_tree: Option<&tree_sitter::Tree>,
228) -> Result<ParsedTree, ParseError> {
229    let (view, aliases, diagnostics) = renamed_source_recovering(source)?;
230    let parse_view = view.into_owned();
231    let tree = parser
232        .parse(parse_view.as_bytes(), old_tree)
233        .ok_or(ParseError::Cancelled)?;
234    if let Some(error) = first_error(tree.root_node()) {
235        return Err(ParseError::InvalidSyntax(Span::new(
236            error.start_byte().min(source.len()),
237            error.end_byte().min(source.len()),
238        )));
239    }
240    let syntax = Lowerer::new(source, aliases).source_file(tree.root_node())?;
241    Ok(ParsedTree {
242        parse_view,
243        tree,
244        syntax,
245        diagnostics,
246    })
247}
248
249fn input_edit_between(old: &str, new: &str) -> tree_sitter::InputEdit {
250    let mut start = old
251        .as_bytes()
252        .iter()
253        .zip(new.as_bytes())
254        .take_while(|(old, new)| old == new)
255        .count();
256    while !old.is_char_boundary(start) || !new.is_char_boundary(start) {
257        start -= 1;
258    }
259
260    let available_suffix = old.len().min(new.len()).saturating_sub(start);
261    let mut suffix = old
262        .as_bytes()
263        .iter()
264        .rev()
265        .zip(new.as_bytes().iter().rev())
266        .take(available_suffix)
267        .take_while(|(old, new)| old == new)
268        .count();
269    while !old.is_char_boundary(old.len() - suffix) || !new.is_char_boundary(new.len() - suffix) {
270        suffix -= 1;
271    }
272
273    let old_end = old.len() - suffix;
274    let new_end = new.len() - suffix;
275    tree_sitter::InputEdit {
276        start_byte: start,
277        old_end_byte: old_end,
278        new_end_byte: new_end,
279        start_position: point_at(old, start),
280        old_end_position: point_at(old, old_end),
281        new_end_position: point_at(new, new_end),
282    }
283}
284
285fn point_at(source: &str, offset: usize) -> tree_sitter::Point {
286    let before = &source[..offset];
287    let row = before.bytes().filter(|byte| *byte == b'\n').count();
288    let column = before
289        .as_bytes()
290        .iter()
291        .rposition(|byte| *byte == b'\n')
292        .map_or(before.len(), |newline| before.len() - newline - 1);
293    tree_sitter::Point { row, column }
294}
295
296impl TreeSitterParser {
297    /// Creates a parser loaded with the bundled Macaulay2 grammar.
298    ///
299    /// # Errors
300    ///
301    /// Returns [`ParseError::Language`] if Tree-sitter rejects the bundled
302    /// language definition.
303    pub fn new() -> Result<Self, ParseError> {
304        let mut parser = tree_sitter::Parser::new();
305        parser
306            .set_language(&tree_sitter_macaulay2::language())
307            .map_err(ParseError::Language)?;
308        Ok(Self { parser })
309    }
310
311    fn parse_source(&mut self, source: &str) -> Result<SourceFile, ParseError> {
312        let (renamed, aliases) = renamed_source(source)?;
313        let tree = self
314            .parser
315            .parse(renamed.as_bytes(), None)
316            .ok_or(ParseError::Cancelled)?;
317        if let Some(error) = first_error(tree.root_node()) {
318            return Err(ParseError::InvalidSyntax(
319                TreeSitterNode::new(error, source.as_bytes()).span(),
320            ));
321        }
322        Lowerer::new(source, aliases).source_file(tree.root_node())
323    }
324
325    /// Parses incomplete source while retaining syntax inside unclosed groups.
326    ///
327    /// The parsing view is completed only for Tree-sitter; reconstructed nodes
328    /// retain the original source spans and zero-width missing closers.
329    ///
330    /// # Errors
331    ///
332    /// Returns [`ParseError`] when source has a non-recoverable lexical or
333    /// grammatical failure, parsing is cancelled, or lowering fails.
334    pub fn parse_recovering(
335        &mut self,
336        source: &str,
337    ) -> Result<Recovered<SourceFile, LexError>, ParseError> {
338        let (renamed, aliases, diagnostics) = renamed_source_recovering(source)?;
339        let tree = self
340            .parser
341            .parse(renamed.as_bytes(), None)
342            .ok_or(ParseError::Cancelled)?;
343        if let Some(error) = first_error(tree.root_node()) {
344            return Err(ParseError::InvalidSyntax(Span::new(
345                error.start_byte().min(source.len()),
346                error.end_byte().min(source.len()),
347            )));
348        }
349        let syntax = Lowerer::new(source, aliases).source_file(tree.root_node())?;
350        Ok(Recovered::new(syntax, diagnostics))
351    }
352}
353
354impl Parser for TreeSitterParser {
355    type Error = ParseError;
356
357    fn parse_stream(&mut self, tokens: TokenStream) -> Result<SourceFile, Self::Error> {
358        let source = tokens.to_string();
359        self.parse_source(&source)
360    }
361}
362
363/// Parses source with Tree-sitter and lowers its CST into the typed syntax tree.
364///
365/// # Errors
366///
367/// Returns [`ParseError`] when parsing or typed reconstruction fails.
368pub fn parse_file(source: &str) -> Result<SourceFile, ParseError> {
369    let mut parser = TreeSitterParser::new()?;
370    parser.parse_source(source)
371}
372
373/// Parses incomplete source while retaining syntax inside unclosed groups.
374///
375/// # Errors
376///
377/// Returns [`ParseError`] for failures other than missing closing delimiters or
378/// when the recovered Tree-sitter CST cannot be lowered.
379pub fn parse_file_recovering(source: &str) -> Result<Recovered<SourceFile, LexError>, ParseError> {
380    TreeSitterParser::new()?.parse_recovering(source)
381}
382
383/// Parses an emitted M2 token stream into the complete typed source file.
384///
385/// # Errors
386///
387/// Returns [`ParseError`] when the emitted source is invalid or reconstruction
388/// fails.
389pub fn parse_tokens(tokens: &TokenStream) -> Result<SourceFile, ParseError> {
390    parse_file(&tokens.to_string())
391}
392
393fn first_error(root: tree_sitter::Node<'_>) -> Option<tree_sitter::Node<'_>> {
394    let mut pending = vec![root];
395    while let Some(node) = pending.pop() {
396        if node.is_error() || node.is_missing() {
397            return Some(node);
398        }
399        pending.extend((0..node.child_count()).rev().filter_map(|index| {
400            node.child(u32::try_from(index).expect("Tree-sitter child count fits u32"))
401        }));
402    }
403    None
404}
405
406struct Lowerer<'source> {
407    source: &'source [u8],
408    source_span: Span,
409    aliases: Vec<CoreAlias>,
410}
411
412impl<'source> Lowerer<'source> {
413    fn new(source: &'source str, aliases: Vec<CoreAlias>) -> Self {
414        Self {
415            source: source.as_bytes(),
416            source_span: Span::source(source),
417            aliases,
418        }
419    }
420
421    fn source_file(&self, root: tree_sitter::Node<'_>) -> Result<SourceFile, ParseError> {
422        let mut cells = Vec::new();
423        let raw_cells = self.semantic_children(root);
424        for (index, child) in raw_cells.iter().copied().enumerate() {
425            match child.kind() {
426                "cell" | "muted" => {
427                    let next = raw_cells.get(index + 1).copied();
428                    cells.push(self.cell(child, self.eoc_offset(child, next))?);
429                }
430                kind => return Err(self.unsupported(kind, child)),
431            }
432        }
433        Ok(SourceFile::new(
434            cells,
435            Eof::new("", Span::from_offset(self.source.len())),
436        ))
437    }
438
439    fn cell(&self, node: tree_sitter::Node<'_>, eoc_offset: usize) -> Result<Cell, ParseError> {
440        let (content, semicolon) = if node.kind() == "muted" {
441            let semicolon = self.required_kind(node, ";")?;
442            (
443                self.expr_pack(self.children(node))?,
444                Some(self.reconstruct(semicolon)?),
445            )
446        } else {
447            let child = self.only_semantic_child(node)?;
448            let pack = if child.kind() == "naked_sequence" {
449                self.expr_pack(self.children(child))?
450            } else {
451                ExprPack::new(Punctuated::from_single(Component::Expr(Box::new(
452                    self.expr(child)?,
453                ))))
454            };
455            (pack, None)
456        };
457        Ok(Cell::new(
458            content,
459            semicolon,
460            Eoc::new("", Span::from_offset(eoc_offset)),
461        ))
462    }
463
464    fn eoc_offset(
465        &self,
466        node: tree_sitter::Node<'_>,
467        next: Option<tree_sitter::Node<'_>>,
468    ) -> usize {
469        if node.kind() == "muted" {
470            return node.end_byte().min(self.source.len());
471        }
472        let start = node.end_byte().min(self.source.len());
473        let end = next
474            .map_or(self.source.len(), |next| next.start_byte())
475            .min(self.source.len());
476        self.source[start..end]
477            .iter()
478            .position(|byte| *byte == b'\n')
479            .map_or(end, |relative| start + relative + 1)
480    }
481
482    fn expr_pack(&self, nodes: Vec<tree_sitter::Node<'_>>) -> Result<ExprPack, ParseError> {
483        let pack_span = nodes
484            .iter()
485            .fold(Span::detached(), |span, node| span.join(self.span(*node)));
486        let mut values = Vec::new();
487        let mut commas = Vec::new();
488        for node in nodes.into_iter().filter(|node| !node.is_extra()) {
489            match node.kind() {
490                "," => commas.push(self.reconstruct::<Token![,]>(node)?),
491                "empty_component" => values.push(Component::Empty(Empty::new("", self.span(node)))),
492                ";" | "(" | ")" | "[" | "]" | "{" | "}" | "<|" | "|>" | "muted" => {}
493                _ if node.is_named() => values.push(Component::Expr(Box::new(self.expr(node)?))),
494                _ => {}
495            }
496        }
497        let mut values = values.into_iter();
498        let Some(first) = values.next() else {
499            return Err(self.unsupported_span("empty expression pack", pack_span));
500        };
501        let value_count = values.len() + 1;
502        let comma_count = commas.len();
503        if value_count != comma_count + 1 {
504            return Err(self.unsupported_span("invalid expression pack", pack_span));
505        }
506        let rest = commas
507            .into_iter()
508            .zip(values)
509            .collect::<Vec<(Token![,], Component)>>();
510        Ok(ExprPack::new(Punctuated::new(first, rest)))
511    }
512
513    fn expr(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
514        match node.kind() {
515            "symbol" => Ok(self.reconstruct::<Symbol>(node)?.into()),
516            "integer_literal" if self.text(node).contains('p') => {
517                Ok(FloatLiteral::new(self.text(node), self.span(node)).into())
518            }
519            "integer_literal" => Ok(self.reconstruct::<IntegerLiteral>(node)?.into()),
520            "float_literal" => Ok(self.reconstruct::<FloatLiteral>(node)?.into()),
521            "string_literal" => self.string_literal(node),
522            "raw_string_literal" => self.raw_string_literal(node),
523            "array" | "list" | "angle_bar_list" | "sequence" | "parenthesized_expression" => {
524                self.collection(node)
525            }
526            "binary_expression" => self.binary_expr(node),
527            "prefix_expression" => self.prefix_expr(node),
528            "postfix_expression" => self.postfix_expr(node),
529            "lambda_expression" => self.lambda_expression(node),
530            "assignment"
531            | "local_assignment"
532            | "binary_assignment"
533            | "prefix_assignment"
534            | "postfix_assignment"
535            | "binary_installation"
536            | "prefix_installation"
537            | "postfix_installation"
538            | "structured_binding"
539            | "local_structured_binding" => self.assignment(node),
540            "evaluated_assignment" => Ok(EvaluatedAssignment::new(
541                self.expr(self.required_field(node, "left")?)?,
542                self.reconstruct(self.required_field(node, "operator")?)?,
543                self.expr(self.required_field(node, "right")?)?,
544            )
545            .into()),
546            "option" => Ok(OptionExpression::new(
547                self.expr(self.required_field(node, "left")?)?,
548                self.reconstruct(self.required_field(node, "operator")?)?,
549                self.expr(self.required_field(node, "right")?)?,
550            )
551            .into()),
552            "if_statement" => self.if_statement(node),
553            "for_loop" => self.for_loop(node),
554            "while_loop" => self.while_loop(node),
555            "try_statement" => self.try_statement(node),
556            "quote_expression" => self.quote_expression(node),
557            "new_statement" => self.new_statement(node),
558            "break_statement" => Ok(BreakExpr::new(
559                self.reconstruct(self.required_kind(node, "break")?)?,
560                self.first_expression_child(node)
561                    .map(|child| self.expr(child))
562                    .transpose()?,
563            )
564            .into()),
565            "continue_statement" => Ok(ContinueExpr::new(
566                self.reconstruct(self.required_kind(node, "continue")?)?,
567                self.first_expression_child(node)
568                    .map(|child| self.expr(child))
569                    .transpose()?,
570            )
571            .into()),
572            "return_statement" => Ok(ReturnExpr::new(
573                self.reconstruct(self.required_kind(node, "return")?)?,
574                self.first_expression_child(node)
575                    .map(|child| self.expr(child))
576                    .transpose()?,
577            )
578            .into()),
579            "catch_statement" => Ok(Catch::new(
580                self.reconstruct(self.required_kind(node, "catch")?)?,
581                self.expr(self.required_expression_child(node)?)?,
582            )
583            .into()),
584            "throw_statement" => Ok(Throw::new(
585                self.reconstruct(self.required_kind(node, "throw")?)?,
586                self.expr(self.required_expression_child(node)?)?,
587            )
588            .into()),
589            "trap_statement" => Ok(Trap::new(
590                self.reconstruct(self.required_kind(node, "trap")?)?,
591                self.expr(self.required_expression_child(node)?)?,
592            )
593            .into()),
594            "debug_clause" => self.debug_clause(node),
595            kind => Err(self.unsupported(kind, node)),
596        }
597    }
598
599    fn collection(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
600        let spans = self.delimiter_spans(node)?;
601        let statements = self
602            .semantic_children(node)
603            .into_iter()
604            .filter(|child| child.kind() == "muted")
605            .map(|child| self.statement(child))
606            .collect::<Result<Vec<_>, _>>()?;
607
608        if node.kind() == "parenthesized_expression" {
609            let value = self
610                .semantic_children(node)
611                .into_iter()
612                .find(|child| child.kind() != "muted")
613                .map(|child| self.expr(child))
614                .transpose()?;
615            let mut holder = Holder::new(statements, value);
616            holder.delimiter = <Delimiter![()] as DelimiterToken>::new(spans);
617            return Ok(holder.into());
618        }
619
620        let has_elements = self.children(node).into_iter().any(|child| {
621            !child.is_extra()
622                && (child.kind() == ","
623                    || child.kind() == "empty_component"
624                    || (child.is_named() && child.kind() != "muted"))
625        });
626        let elements = has_elements
627            .then(|| self.expr_pack(self.children(node)))
628            .transpose()?;
629        Ok(match node.kind() {
630            "array" => {
631                let mut value = Array::new(statements, elements);
632                value.delimiter = <Delimiter![[]] as DelimiterToken>::new(spans);
633                value.into()
634            }
635            "list" => {
636                let mut value = List::new(statements, elements);
637                value.delimiter = <Delimiter![{}] as DelimiterToken>::new(spans);
638                value.into()
639            }
640            "angle_bar_list" => {
641                let mut value = AngleBarList::new(statements, elements);
642                value.delimiter = <Delimiter![<| |>] as DelimiterToken>::new(spans);
643                value.into()
644            }
645            "sequence" => {
646                let mut value = Sequence::new(statements, elements);
647                value.delimiter = <Delimiter![()] as DelimiterToken>::new(spans);
648                value.into()
649            }
650            kind => return Err(self.unsupported(kind, node)),
651        })
652    }
653
654    fn statement(&self, node: tree_sitter::Node<'_>) -> Result<Statement, ParseError> {
655        Ok(Statement::new(
656            self.expr_pack(self.children(node))?,
657            self.reconstruct(self.required_kind(node, ";")?)?,
658        ))
659    }
660
661    fn string_literal(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
662        let elements = self
663            .children(node)
664            .into_iter()
665            .filter(|child| child.kind() != "\"")
666            .filter(|child| !child.is_extra())
667            .map(|child| match child.kind() {
668                "escape_sequence" => self.reconstruct(child).map(StringElement::EscapeSequence),
669                "string_content" => self.reconstruct(child).map(StringElement::StringContent),
670                _ => Ok(StringElement::StringContent(StringContent::new(
671                    self.text(child),
672                    self.span(child),
673                ))),
674            })
675            .collect::<Result<Vec<_>, ParseError>>()?;
676        Ok(StringLiteral::new(elements, self.span(node)).into())
677    }
678
679    fn raw_string_literal(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
680        let elements = self
681            .children(node)
682            .into_iter()
683            .filter(|child| child.kind() != "///")
684            .filter(|child| !child.is_extra())
685            .map(|child| match child.kind() {
686                "escape_sequence" => self
687                    .reconstruct(child)
688                    .map(RawStringElement::EscapeSequence),
689                "raw_string_content" => self
690                    .reconstruct(child)
691                    .map(RawStringElement::RawStringContent),
692                kind => Err(self.unsupported(kind, child)),
693            })
694            .collect::<Result<Vec<_>, ParseError>>()?;
695        Ok(RawStringLiteral::new(elements, self.span(node)).into())
696    }
697
698    fn binary_expr(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
699        let left = self.expr(self.required_field(node, "left")?)?;
700        let operator = self.required_field(node, "operator")?;
701        let right = self.expr(self.required_field(node, "right")?)?;
702        if operator.kind() == "SPACE" {
703            Ok(AdjacentExpr::new(left, Adj::new("", self.span(operator)), right).into())
704        } else {
705            Ok(BinaryExpr::new(left, self.reconstruct(operator)?, right).into())
706        }
707    }
708
709    fn prefix_expr(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
710        Ok(PrefixExpr::new(
711            self.reconstruct(self.required_field(node, "operator")?)?,
712            self.expr(self.required_field(node, "operand")?)?,
713        )
714        .into())
715    }
716
717    fn postfix_expr(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
718        Ok(PostfixExpr::new(
719            self.expr(self.required_field(node, "operand")?)?,
720            self.reconstruct(self.required_field(node, "operator")?)?,
721        )
722        .into())
723    }
724
725    fn lambda_expression(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
726        let parameter_expr = self.expr(self.required_field(node, "parameters")?)?;
727        let parameters = lambda_parameters(parameter_expr)
728            .ok_or_else(|| self.unsupported("lambda parameters", node))?;
729        Ok(LambdaExpression::new(
730            parameters,
731            self.reconstruct(self.required_field(node, "operator")?)?,
732            self.expr(self.required_field(node, "body")?)?,
733        )
734        .into())
735    }
736
737    fn assignment(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
738        let right = self.expr(self.required_field(node, "right")?)?;
739        Ok(match node.kind() {
740            "assignment" => GlobalBinding::new(
741                self.reconstruct(self.required_field(node, "left")?)?,
742                self.reconstruct(self.required_field(node, "operator")?)?,
743                right,
744            )
745            .into(),
746            "local_assignment" => LocalBinding::new(
747                self.reconstruct(self.required_field(node, "left")?)?,
748                self.reconstruct(self.required_field(node, "operator")?)?,
749                right,
750            )
751            .into(),
752            "binary_assignment" | "prefix_assignment" | "postfix_assignment" => {
753                let Expr::OperatorExpr(left) = self.expr(self.required_field(node, "left")?)?
754                else {
755                    return Err(self.unsupported("operator assignment target", node));
756                };
757                OperatorAssignment::new(
758                    left,
759                    self.reconstruct(self.required_field(node, "operator")?)?,
760                    right,
761                )
762                .into()
763            }
764            "binary_installation" | "prefix_installation" | "postfix_installation" => {
765                let Expr::OperatorExpr(left) = self.expr(self.required_field(node, "left")?)?
766                else {
767                    return Err(self.unsupported("operator installation target", node));
768                };
769                let (typical_value, function) = installation_value(right);
770                match left {
771                    OperatorExpr::AdjacentExpr(application) => MethodInstallation::new(
772                        *application.left_operand,
773                        *application.right_operand,
774                        self.reconstruct(self.required_field(node, "operator")?)?,
775                        typical_value,
776                        function,
777                    )
778                    .into(),
779                    domain => OperatorInstallation::new(
780                        domain,
781                        self.reconstruct(self.required_field(node, "operator")?)?,
782                        typical_value,
783                        function,
784                    )
785                    .into(),
786                }
787            }
788            "structured_binding" | "local_structured_binding" => {
789                let pack_expr = self.expr(self.required_field(node, "binding_pack")?)?;
790                let pack = assignment_pack(pack_expr)
791                    .ok_or_else(|| self.unsupported("assignment pack", node))?;
792                if node.kind() == "local_structured_binding" {
793                    LocalParallelAssignment::new(
794                        pack,
795                        self.reconstruct(self.required_field(node, "operator")?)?,
796                        right,
797                    )
798                    .into()
799                } else {
800                    GlobalParallelAssignment::new(
801                        pack,
802                        self.reconstruct(self.required_field(node, "operator")?)?,
803                        right,
804                    )
805                    .into()
806                }
807            }
808            kind => return Err(self.unsupported(kind, node)),
809        })
810    }
811
812    fn then_clause(&self, node: tree_sitter::Node<'_>) -> Result<ThenClause, ParseError> {
813        Ok(ThenClause::new(
814            self.reconstruct(self.required_kind(node, "then")?)?,
815            self.expr(self.required_expression_child(node)?)?,
816        ))
817    }
818
819    fn else_clause(&self, node: tree_sitter::Node<'_>) -> Result<ElseClause, ParseError> {
820        Ok(ElseClause::new(
821            self.reconstruct(self.required_kind(node, "else")?)?,
822            self.expr(self.required_expression_child(node)?)?,
823        ))
824    }
825
826    fn if_statement(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
827        Ok(IfStatement::new(
828            self.reconstruct(self.required_kind(node, "if")?)?,
829            self.expr(self.required_field(node, "condition")?)?,
830            self.then_clause(self.required_kind(node, "then_clause")?)?,
831            self.optional_kind(node, "else_clause")
832                .map(|child| self.else_clause(child))
833                .transpose()?,
834        )
835        .into())
836    }
837
838    fn loop_body(&self, node: tree_sitter::Node<'_>) -> Result<LoopBody, ParseError> {
839        let list_step = self
840            .optional_kind(node, "list")
841            .map(|token| {
842                Ok::<_, ParseError>(ListStep::new(
843                    self.reconstruct(token)?,
844                    self.expr(self.required_field(node, "listed_value")?)?,
845                ))
846            })
847            .transpose()?;
848        let do_step = self
849            .optional_kind(node, "do")
850            .map(|token| {
851                Ok::<_, ParseError>(DoStep::new(
852                    self.reconstruct(token)?,
853                    self.expr(self.required_field(node, "ignored_value")?)?,
854                ))
855            })
856            .transpose()?;
857        Ok(LoopBody::new(list_step, do_step))
858    }
859
860    fn for_loop(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
861        let iteration_domain = self
862            .optional_kind(node, "iteration_range")
863            .map(|range| self.iteration_domain(range))
864            .transpose()?;
865        let when_condition = self
866            .optional_kind(node, "when")
867            .map(|token| {
868                Ok::<_, ParseError>(WhenCondition::new(
869                    self.reconstruct(token)?,
870                    self.expr(self.required_field(node, "filter")?)?,
871                ))
872            })
873            .transpose()?;
874        Ok(ForLoop::new(
875            self.reconstruct(self.required_kind(node, "for")?)?,
876            self.reconstruct(self.required_field(node, "variable")?)?,
877            iteration_domain,
878            when_condition,
879            self.loop_body(self.required_kind(node, "loop_body")?)?,
880        )
881        .into())
882    }
883
884    fn iteration_domain(&self, node: tree_sitter::Node<'_>) -> Result<IterationDomain, ParseError> {
885        if let Some(token) = self.optional_kind(node, "in") {
886            return Ok(IterIn::new(
887                self.reconstruct(token)?,
888                self.expr(self.required_field(node, "iterated_collection")?)?,
889            )
890            .into());
891        }
892        let lower_bound = self
893            .optional_kind(node, "from")
894            .map(|token| {
895                Ok::<_, ParseError>(RangeBoundFrom::new(
896                    self.reconstruct(token)?,
897                    self.expr(self.required_field(node, "range_start")?)?,
898                ))
899            })
900            .transpose()?;
901        let upper_bound = self
902            .optional_kind(node, "to")
903            .map(|token| {
904                Ok::<_, ParseError>(RangeBoundTo::new(
905                    self.reconstruct(token)?,
906                    self.expr(self.required_field(node, "range_end")?)?,
907                ))
908            })
909            .transpose()?;
910        Ok(IterRange::new(lower_bound, upper_bound).into())
911    }
912
913    fn while_loop(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
914        Ok(WhileLoop::new(
915            self.reconstruct(self.required_kind(node, "while")?)?,
916            self.expr(self.required_field(node, "condition")?)?,
917            self.loop_body(self.required_kind(node, "loop_body")?)?,
918        )
919        .into())
920    }
921
922    fn new_statement(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
923        let mut installation = None;
924        let class =
925            self.new_statement_element(self.required_field(node, "class")?, &mut installation)?;
926        let parent_class = self
927            .optional_kind(node, "of")
928            .map(|token| {
929                Ok::<_, ParseError>(OfClass::new(
930                    self.reconstruct(token)?,
931                    self.new_statement_element(
932                        self.required_field(node, "parent")?,
933                        &mut installation,
934                    )?,
935                ))
936            })
937            .transpose()?;
938        let instance = self
939            .optional_kind(node, "from")
940            .map(|token| {
941                Ok::<_, ParseError>(FromInstance::new(
942                    self.reconstruct(token)?,
943                    self.new_statement_element(
944                        self.required_field(node, "instance")?,
945                        &mut installation,
946                    )?,
947                ))
948            })
949            .transpose()?;
950        let statement = NewStatement::new(
951            self.reconstruct(self.required_kind(node, "new")?)?,
952            class,
953            parent_class,
954            instance,
955        );
956        Ok(match installation {
957            Some((operator, function)) => {
958                NewInstallation::new(statement, operator, function).into()
959            }
960            None => statement.into(),
961        })
962    }
963
964    fn new_statement_element(
965        &self,
966        node: tree_sitter::Node<'_>,
967        installation: &mut Option<(Token![:=], Expr)>,
968    ) -> Result<Expr, ParseError> {
969        match node.kind() {
970            "assignment" => return Err(self.unsupported("`new` assignment with `=`", node)),
971            "local_assignment" => {}
972            _ => return self.expr(node),
973        }
974        *installation = Some((
975            self.reconstruct(self.required_field(node, "operator")?)?,
976            self.expr(self.required_field(node, "right")?)?,
977        ));
978        self.expr(self.required_field(node, "left")?)
979    }
980
981    fn try_statement(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
982        let value = self
983            .semantic_children(node)
984            .into_iter()
985            .find(|child| {
986                child.kind() != "then_clause"
987                    && child.kind() != "else_clause"
988                    && child.kind() != "except_clause"
989            })
990            .ok_or_else(|| self.unsupported("try value", node))?;
991        let on_success = self
992            .optional_kind(node, "then_clause")
993            .map(|child| self.then_clause(child))
994            .transpose()?;
995        let fallback = self
996            .child_by_field(node, "fallback")
997            .map(|child| match child.kind() {
998                "else_clause" => self.else_clause(child).map(TryFallback::ElseClause),
999                "except_clause" => self.except_do(child).map(TryFallback::ExceptDo),
1000                kind => Err(self.unsupported(kind, child)),
1001            })
1002            .transpose()?;
1003        Ok(TryStatement::new(
1004            self.reconstruct(self.required_kind(node, "try")?)?,
1005            self.expr(value)?,
1006            on_success,
1007            fallback,
1008        )
1009        .into())
1010    }
1011
1012    fn except_do(&self, node: tree_sitter::Node<'_>) -> Result<ExceptDo, ParseError> {
1013        Ok(ExceptDo::new(
1014            self.reconstruct(self.required_kind(node, "except")?)?,
1015            self.reconstruct(self.required_field(node, "exception")?)?,
1016            self.reconstruct(self.required_kind(node, "do")?)?,
1017            self.expr(self.required_expression_child(node)?)?,
1018        ))
1019    }
1020
1021    fn quote_expression(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
1022        let token = self
1023            .children(node)
1024            .into_iter()
1025            .find(|child| {
1026                matches!(
1027                    child.kind(),
1028                    "symbol" | "local" | "global" | "threadVariable" | "threadLocal"
1029                ) && self.child_by_field(node, "token") != Some(*child)
1030            })
1031            .ok_or_else(|| self.unsupported("quote specifier", node))?;
1032        let specifier = match token.kind() {
1033            "symbol" => QuoteSpecifier::Symbol(self.reconstruct(token)?),
1034            "local" => QuoteSpecifier::Local(self.reconstruct(token)?),
1035            "global" => QuoteSpecifier::Global(self.reconstruct(token)?),
1036            "threadVariable" => QuoteSpecifier::ThreadVariable(self.reconstruct(token)?),
1037            "threadLocal" => QuoteSpecifier::ThreadLocal(self.reconstruct(token)?),
1038            kind => return Err(self.unsupported(kind, token)),
1039        };
1040        let quoted = self.required_field(node, "token")?;
1041        Ok(
1042            QuoteExpression::new(specifier, Symbol::new(self.text(quoted), self.span(quoted)))
1043                .into(),
1044        )
1045    }
1046
1047    fn debug_clause(&self, node: tree_sitter::Node<'_>) -> Result<Expr, ParseError> {
1048        let keyword = self.required_field(node, "keyword")?;
1049        let value = self
1050            .first_expression_child(node)
1051            .map(|child| self.expr(child))
1052            .transpose()?;
1053        Ok(match keyword.kind() {
1054            "elapsedTime" => ProfilingExpr::new(
1055                ProfilingModifier::ElapsedTime(self.reconstruct(keyword)?),
1056                value.ok_or_else(|| self.unsupported("profiling operand", node))?,
1057            )
1058            .into(),
1059            "elapsedTiming" => ProfilingExpr::new(
1060                ProfilingModifier::ElapsedTiming(self.reconstruct(keyword)?),
1061                value.ok_or_else(|| self.unsupported("profiling operand", node))?,
1062            )
1063            .into(),
1064            "profile" => ProfilingExpr::new(
1065                ProfilingModifier::Profile(self.reconstruct(keyword)?),
1066                value.ok_or_else(|| self.unsupported("profiling operand", node))?,
1067            )
1068            .into(),
1069            "time" => ProfilingExpr::new(
1070                ProfilingModifier::Time(self.reconstruct(keyword)?),
1071                value.ok_or_else(|| self.unsupported("profiling operand", node))?,
1072            )
1073            .into(),
1074            "timing" => ProfilingExpr::new(
1075                ProfilingModifier::Timing(self.reconstruct(keyword)?),
1076                value.ok_or_else(|| self.unsupported("profiling operand", node))?,
1077            )
1078            .into(),
1079            "TEST" => DebugExpr::new(DebugKeyword::Test(self.reconstruct(keyword)?), value).into(),
1080            "step" => DebugExpr::new(DebugKeyword::Step(self.reconstruct(keyword)?), value).into(),
1081            "finish" => {
1082                DebugExpr::new(DebugKeyword::Finish(self.reconstruct(keyword)?), value).into()
1083            }
1084            "shield" => {
1085                DebugExpr::new(DebugKeyword::Shield(self.reconstruct(keyword)?), value).into()
1086            }
1087            "breakpoint" => {
1088                DebugExpr::new(DebugKeyword::Breakpoint(self.reconstruct(keyword)?), value).into()
1089            }
1090            kind => return Err(self.unsupported(kind, keyword)),
1091        })
1092    }
1093
1094    fn reconstruct<T>(&self, node: tree_sitter::Node<'_>) -> Result<T, ParseError>
1095    where
1096        for<'tree> T: Reconstruct<TreeSitterNode<'tree, 'source>>,
1097    {
1098        T::reconstruct(TreeSitterNode::with_span(
1099            node,
1100            self.source,
1101            self.span(node),
1102        ))
1103        .map_err(Into::into)
1104    }
1105
1106    fn delimiter_spans(&self, node: tree_sitter::Node<'_>) -> Result<DoubleSpan, ParseError> {
1107        let kind = match node.kind() {
1108            "parenthesized_expression" | "sequence" => DelimiterKind::Parenthesis,
1109            "array" => DelimiterKind::Bracket,
1110            "list" => DelimiterKind::Brace,
1111            "angle_bar_list" => DelimiterKind::AngleBar,
1112            other => return Err(self.unsupported(other, node)),
1113        };
1114        let opening = self.span(self.required_kind(node, kind.opening())?);
1115        let closing = self.required_kind(node, kind.closing())?;
1116        let closing = if closing.start_byte() >= self.source.len() {
1117            Span::from_offset(self.source.len())
1118        } else {
1119            self.span(closing)
1120        };
1121        Ok(DoubleSpan::new(opening, closing))
1122    }
1123
1124    fn children<'tree>(&self, node: tree_sitter::Node<'tree>) -> Vec<tree_sitter::Node<'tree>> {
1125        (0..node.child_count())
1126            .filter_map(|index| node.child(u32::try_from(index).expect("child count fits u32")))
1127            .collect()
1128    }
1129
1130    fn semantic_children<'tree>(
1131        &self,
1132        node: tree_sitter::Node<'tree>,
1133    ) -> Vec<tree_sitter::Node<'tree>> {
1134        self.children(node)
1135            .into_iter()
1136            .filter(|child| child.is_named() && !child.is_extra())
1137            .collect()
1138    }
1139
1140    fn only_semantic_child<'tree>(
1141        &self,
1142        node: tree_sitter::Node<'tree>,
1143    ) -> Result<tree_sitter::Node<'tree>, ParseError> {
1144        let children = self.semantic_children(node);
1145        match children.as_slice() {
1146            [child] => Ok(*child),
1147            _ => Err(self.unsupported("cell contents", node)),
1148        }
1149    }
1150
1151    fn first_expression_child<'tree>(
1152        &self,
1153        node: tree_sitter::Node<'tree>,
1154    ) -> Option<tree_sitter::Node<'tree>> {
1155        self.semantic_children(node).into_iter().find(|child| {
1156            !matches!(
1157                child.kind(),
1158                "then_clause" | "else_clause" | "except_clause" | "iteration_range" | "loop_body"
1159            )
1160        })
1161    }
1162
1163    fn required_expression_child<'tree>(
1164        &self,
1165        node: tree_sitter::Node<'tree>,
1166    ) -> Result<tree_sitter::Node<'tree>, ParseError> {
1167        self.first_expression_child(node)
1168            .ok_or_else(|| self.unsupported("expression child", node))
1169    }
1170
1171    fn child_by_field<'tree>(
1172        &self,
1173        node: tree_sitter::Node<'tree>,
1174        field: &str,
1175    ) -> Option<tree_sitter::Node<'tree>> {
1176        node.child_by_field_name(field)
1177    }
1178
1179    fn required_field<'tree>(
1180        &self,
1181        node: tree_sitter::Node<'tree>,
1182        field: &str,
1183    ) -> Result<tree_sitter::Node<'tree>, ParseError> {
1184        self.child_by_field(node, field)
1185            .ok_or_else(|| self.unsupported(field, node))
1186    }
1187
1188    fn optional_kind<'tree>(
1189        &self,
1190        node: tree_sitter::Node<'tree>,
1191        kind: &str,
1192    ) -> Option<tree_sitter::Node<'tree>> {
1193        self.children(node)
1194            .into_iter()
1195            .find(|child| !child.is_extra() && child.kind() == kind)
1196    }
1197
1198    fn required_kind<'tree>(
1199        &self,
1200        node: tree_sitter::Node<'tree>,
1201        kind: &str,
1202    ) -> Result<tree_sitter::Node<'tree>, ParseError> {
1203        self.optional_kind(node, kind)
1204            .ok_or_else(|| self.unsupported(kind, node))
1205    }
1206
1207    fn text(&self, node: tree_sitter::Node<'_>) -> Cow<'_, str> {
1208        let range = self
1209            .span(node)
1210            .bounds()
1211            .map_or_else(|| node.byte_range(), |(start, end)| start..end);
1212        String::from_utf8_lossy(&self.source[range])
1213    }
1214
1215    fn span(&self, node: tree_sitter::Node<'_>) -> Span {
1216        let range = node.byte_range();
1217        self.aliases
1218            .iter()
1219            .find(|alias| alias.bare == range)
1220            .map_or_else(
1221                || {
1222                    self.source_span.subspan(
1223                        node.start_byte().min(self.source.len()),
1224                        node.end_byte().min(self.source.len()),
1225                    )
1226                },
1227                |alias| self.source_span.subspan(alias.full.start, alias.full.end),
1228            )
1229    }
1230
1231    fn unsupported(&self, kind: impl Into<String>, node: tree_sitter::Node<'_>) -> ParseError {
1232        self.unsupported_span(kind, self.span(node))
1233    }
1234
1235    fn unsupported_span(&self, kind: impl Into<String>, span: Span) -> ParseError {
1236        ParseError::UnsupportedNode {
1237            kind: kind.into(),
1238            span,
1239        }
1240    }
1241}
1242
1243#[derive(Clone)]
1244struct CoreAlias {
1245    full: Range<usize>,
1246    bare: Range<usize>,
1247}
1248
1249fn renamed_source(source: &str) -> Result<(Cow<'_, str>, Vec<CoreAlias>), LexError> {
1250    let tokens = lex_str(source)?;
1251    let mut aliases = Vec::new();
1252    collect_core_aliases(&tokens, &mut aliases);
1253    if aliases.is_empty() {
1254        return Ok((Cow::Borrowed(source), aliases));
1255    }
1256
1257    let mut renamed = source.as_bytes().to_vec();
1258    for alias in &aliases {
1259        renamed[alias.full.start..alias.bare.start].fill(b' ');
1260    }
1261    Ok((
1262        Cow::Owned(String::from_utf8(renamed).expect("replacing ASCII bytes preserves UTF-8")),
1263        aliases,
1264    ))
1265}
1266
1267type RecoveredSource<'source> = (Cow<'source, str>, Vec<CoreAlias>, Vec<LexError>);
1268
1269fn renamed_source_recovering(source: &str) -> Result<RecoveredSource<'_>, LexError> {
1270    let recovered = lex_str_recovering(source)?;
1271    let (tokens, diagnostics) = recovered.into_parts();
1272    let mut aliases = Vec::new();
1273    collect_core_aliases(&tokens, &mut aliases);
1274    let mut missing = Vec::new();
1275    collect_missing_closers(&tokens, &mut missing);
1276
1277    if aliases.is_empty() && missing.is_empty() {
1278        return Ok((Cow::Borrowed(source), aliases, diagnostics));
1279    }
1280
1281    let mut renamed = source.as_bytes().to_vec();
1282    for alias in &aliases {
1283        renamed[alias.full.start..alias.bare.start].fill(b' ');
1284    }
1285    for kind in missing {
1286        renamed.extend_from_slice(kind.closing().as_bytes());
1287    }
1288    Ok((
1289        Cow::Owned(String::from_utf8(renamed).expect("ASCII recovery preserves UTF-8")),
1290        aliases,
1291        diagnostics,
1292    ))
1293}
1294
1295fn collect_missing_closers(tokens: &TokenStream, missing: &mut Vec<DelimiterKind>) {
1296    for token in tokens.iter() {
1297        let TokenTree::Group(group) = token else {
1298            continue;
1299        };
1300        collect_missing_closers(group.stream(), missing);
1301        if !group.delimiter().is_closed() {
1302            missing.push(group.delim_kind());
1303        }
1304    }
1305}
1306
1307fn collect_core_aliases(tokens: &TokenStream, aliases: &mut Vec<CoreAlias>) {
1308    for token in tokens.iter() {
1309        match token {
1310            TokenTree::Group(group) => collect_core_aliases(group.stream(), aliases),
1311            TokenTree::Ident(identifier) => {
1312                let spelling = identifier.text();
1313                let bare = crate::lexer::canonical_word_spelling(spelling);
1314                if bare == spelling {
1315                    continue;
1316                }
1317                let Some((start, end)) = identifier.span().bounds() else {
1318                    continue;
1319                };
1320                aliases.push(CoreAlias {
1321                    full: start..end,
1322                    bare: end - bare.len()..end,
1323                });
1324            }
1325            TokenTree::Eoc(_)
1326            | TokenTree::Literal(_)
1327            | TokenTree::Punct(_)
1328            | TokenTree::Trivia(_) => {}
1329        }
1330    }
1331}
1332
1333#[derive(Clone)]
1334/// A borrowed Tree-sitter node paired with the source bytes it spans.
1335pub struct TreeSitterNode<'tree, 'source> {
1336    node: tree_sitter::Node<'tree>,
1337    source: &'source [u8],
1338    span: Option<Span>,
1339}
1340
1341impl<'tree, 'source> TreeSitterNode<'tree, 'source> {
1342    /// Creates an external reconstruction node.
1343    pub fn new(node: tree_sitter::Node<'tree>, source: &'source [u8]) -> Self {
1344        Self {
1345            node,
1346            source,
1347            span: None,
1348        }
1349    }
1350
1351    fn with_span(node: tree_sitter::Node<'tree>, source: &'source [u8], span: Span) -> Self {
1352        Self {
1353            node,
1354            source,
1355            span: Some(span),
1356        }
1357    }
1358}
1359
1360impl ExternalCstNode for TreeSitterNode<'_, '_> {
1361    type Children<'syntax>
1362        = IntoIter<ExternalCstChild<Self>>
1363    where
1364        Self: 'syntax;
1365
1366    fn identity(&self) -> CSTNodeClassLabel<'_> {
1367        CSTNodeClassLabel::new(self.node.kind(), self.node.is_named())
1368    }
1369
1370    fn children(&self) -> Self::Children<'_> {
1371        let parent = self.node;
1372        (0..parent.child_count())
1373            .filter_map(|index| {
1374                let index = u32::try_from(index).expect("Tree-sitter child count fits u32");
1375                parent.child(index).map(|node| ExternalCstChild {
1376                    field: parent.field_name_for_child(index),
1377                    node: Self::new(node, self.source),
1378                })
1379            })
1380            .collect::<Vec<_>>()
1381            .into_iter()
1382    }
1383
1384    fn text(&self) -> Cow<'_, str> {
1385        let range = self
1386            .span
1387            .as_ref()
1388            .and_then(Span::bounds)
1389            .map_or_else(|| self.node.byte_range(), |(start, end)| start..end);
1390        String::from_utf8_lossy(&self.source[range])
1391    }
1392
1393    fn is_extra(&self) -> bool {
1394        self.node.is_extra()
1395    }
1396}
1397
1398impl Spanned for TreeSitterNode<'_, '_> {
1399    fn span(&self) -> Span {
1400        self.span
1401            .clone()
1402            .unwrap_or_else(|| Span::new(self.node.start_byte(), self.node.end_byte()))
1403    }
1404}