Skip to main content

m2_syn/
parsed_file.rs

1//! Convenient ownership and projection of one parsed Macaulay2 source file.
2//!
3//! [`ParsedFile`] is the high-level entry point for applications that do not
4//! need to assemble the lexer and parser pipeline themselves. It owns the
5//! generated typed [`SourceFile`] and exposes fresh projections of that tree as
6//! tokens, cells, normalized source, or indented debug output. The typed CST is
7//! the sole mutable representation, so changing it cannot leave a cached token
8//! stream out of sync.
9
10use std::fmt::{Display, Formatter};
11use std::io;
12
13use crate::{
14    Lex, NativeParseError, ParseError, SourceFile, Span, Spanned, TokenStream, parse_file,
15    parse_native,
16    pretty::{PrettyOptions, PrettyReport, PrettyTree, format_tokens, format_tree, print_report},
17};
18
19/// An owned typed CST together with the original input.
20///
21/// [`ParsedFile::from_source`] selects the Tree-sitter adapter, while
22/// [`ParsedFile::from_source_native`] selects the direct precedence parser. After
23/// parsing, callers may mutate [`Self::cst_mut`] or use [`Self::edit`], then
24/// project the resulting tree through [`Self::token_stream`] or
25/// [`Self::to_source`].
26///
27/// The original string is retained as an immutable snapshot for diagnostics.
28/// Current emission is normalized by [`Lex`]; it will become lossless as
29/// trivia ownership is completed in the typed graph.
30#[derive(Debug)]
31pub struct ParsedFile {
32    original_source: String,
33    cst: SourceFile,
34}
35
36impl ParsedFile {
37    /// Parses source with the Tree-sitter adapter.
38    ///
39    /// # Errors
40    ///
41    /// Returns [`ParseError`] when Tree-sitter rejects the source or typed
42    /// reconstruction fails.
43    pub fn from_source(source: impl Into<String>) -> Result<Self, ParseError> {
44        let original_source = source.into();
45        let cst = parse_file(&original_source)?;
46        Ok(Self {
47            original_source,
48            cst,
49        })
50    }
51
52    /// Parses source with the native precedence parser.
53    ///
54    /// # Errors
55    ///
56    /// Returns [`NativeParseError`] when lexing or native parsing fails.
57    pub fn from_source_native(source: impl Into<String>) -> Result<Self, NativeParseError> {
58        let original_source = source.into();
59        let cst = parse_native(&original_source)?;
60        Ok(Self {
61            original_source,
62            cst,
63        })
64    }
65
66    /// Returns the input snapshot exactly as supplied to the parser.
67    pub fn original_source(&self) -> &str {
68        &self.original_source
69    }
70
71    /// Borrows the generated typed CST root.
72    pub fn cst(&self) -> &SourceFile {
73        &self.cst
74    }
75
76    /// Mutably borrows the generated typed CST root.
77    pub fn cst_mut(&mut self) -> &mut SourceFile {
78        &mut self.cst
79    }
80
81    /// Applies an edit and returns the file for further method chaining.
82    pub fn edit(mut self, edit: impl FnOnce(&mut SourceFile)) -> Self {
83        edit(&mut self.cst);
84        self
85    }
86
87    /// Consumes the facade and returns its generated typed CST.
88    pub fn into_cst(self) -> SourceFile {
89        self.cst
90    }
91
92    /// Flattens the current CST into one token stream.
93    pub fn token_stream(&self) -> TokenStream {
94        self.cst.to_token_stream()
95    }
96
97    /// Emits the current CST as normalized Macaulay2 source.
98    pub fn to_source(&self) -> String {
99        self.token_stream().to_string()
100    }
101
102    /// Formats the current raw token representation as a recursively flattened
103    /// table with explicit group boundaries.
104    pub fn pretty_tokens(&self) -> String {
105        format_tokens(&self.token_stream(), PrettyOptions::PLAIN)
106    }
107
108    /// Formats the complete generated typed CST as a Unicode tree.
109    pub fn pretty_cst(&self) -> String {
110        format_tree(&self.cst.pretty_tree(), PrettyOptions::PLAIN)
111    }
112
113    /// Builds a combined source, flat-token, and typed-CST inspection report.
114    pub fn pretty_report(&self) -> PrettyReport<'_> {
115        PrettyReport::new(
116            &self.original_source,
117            self.token_stream(),
118            self.cst.pretty_tree(),
119        )
120    }
121
122    /// Prints the combined report to standard output, enabling ANSI styling
123    /// only when standard output is an interactive terminal.
124    ///
125    /// # Errors
126    ///
127    /// Returns an I/O error when standard output cannot be written.
128    pub fn print_pretty(&self) -> io::Result<()> {
129        print_report(self.pretty_report())
130    }
131}
132
133impl AsRef<SourceFile> for ParsedFile {
134    fn as_ref(&self) -> &SourceFile {
135        self.cst()
136    }
137}
138
139impl AsMut<SourceFile> for ParsedFile {
140    fn as_mut(&mut self) -> &mut SourceFile {
141        self.cst_mut()
142    }
143}
144
145impl Display for ParsedFile {
146    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
147        self.token_stream().fmt(formatter)
148    }
149}
150
151impl Spanned for ParsedFile {
152    fn span(&self) -> Span {
153        self.cst.span()
154    }
155}
156
157impl Lex for ParsedFile {
158    fn to_tokens(&self, output: &mut TokenStream) {
159        self.cst.to_tokens(output);
160    }
161}