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    CellStream, NativeParseError, ParseError, SourceFile, SourceId, Span, Spanned, ToCells,
15    ToTokens, TokenStream, parse_file, parse_native,
16    pretty::{PrettyOptions, PrettyReport, PrettyTree, format_cells, format_tree, print_report},
17};
18
19/// An owned typed CST together with the source identity and 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`],
25/// [`Self::cell_stream`], or [`Self::to_source`].
26///
27/// The original string is retained as an immutable snapshot for diagnostics.
28/// Current emission is normalized by `ToTokens`; 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    source_id: SourceId,
34    cst: SourceFile,
35}
36
37impl ParsedFile {
38    /// Parses source with the Tree-sitter adapter and a fresh source identity.
39    pub fn from_source(source: impl Into<String>) -> Result<Self, ParseError> {
40        Self::from_source_with_id(source, SourceId::fresh())
41    }
42
43    /// Parses source with the Tree-sitter adapter and an explicit source id.
44    pub fn from_source_with_id(
45        source: impl Into<String>,
46        source_id: SourceId,
47    ) -> Result<Self, ParseError> {
48        let original_source = source.into();
49        let cst = parse_file(&original_source, source_id)?;
50        Ok(Self {
51            original_source,
52            source_id,
53            cst,
54        })
55    }
56
57    /// Parses source with the native precedence parser and a fresh source identity.
58    pub fn from_source_native(source: impl Into<String>) -> Result<Self, NativeParseError> {
59        Self::from_source_native_with_id(source, SourceId::fresh())
60    }
61
62    /// Parses source with the native precedence parser and an explicit source id.
63    pub fn from_source_native_with_id(
64        source: impl Into<String>,
65        source_id: SourceId,
66    ) -> Result<Self, NativeParseError> {
67        let original_source = source.into();
68        let cst = parse_native(&original_source, source_id)?;
69        Ok(Self {
70            original_source,
71            source_id,
72            cst,
73        })
74    }
75
76    /// Returns the input snapshot exactly as supplied to the parser.
77    pub fn original_source(&self) -> &str {
78        &self.original_source
79    }
80
81    /// Returns the source identity attached to parsed spans.
82    pub fn source_id(&self) -> SourceId {
83        self.source_id
84    }
85
86    /// Borrows the generated typed CST root.
87    pub fn cst(&self) -> &SourceFile {
88        &self.cst
89    }
90
91    /// Mutably borrows the generated typed CST root.
92    pub fn cst_mut(&mut self) -> &mut SourceFile {
93        &mut self.cst
94    }
95
96    /// Applies an edit and returns the file for further method chaining.
97    pub fn edit(mut self, edit: impl FnOnce(&mut SourceFile)) -> Self {
98        edit(&mut self.cst);
99        self
100    }
101
102    /// Consumes the facade and returns its generated typed CST.
103    pub fn into_cst(self) -> SourceFile {
104        self.cst
105    }
106
107    /// Flattens the current CST into one token stream.
108    pub fn token_stream(&self) -> TokenStream {
109        self.cst.to_token_stream()
110    }
111
112    /// Flattens the current CST into its linearly ordered cells.
113    pub fn cell_stream(&self) -> CellStream {
114        self.cst.to_cell_stream(self.source_id)
115    }
116
117    /// Emits the current CST as normalized Macaulay2 source.
118    pub fn to_source(&self) -> String {
119        self.token_stream().to_string()
120    }
121
122    /// Formats the current raw token representation as a recursively flattened
123    /// table with explicit group boundaries.
124    pub fn pretty_tokens(&self) -> String {
125        format_cells(&self.cell_stream(), PrettyOptions::PLAIN)
126    }
127
128    /// Formats the complete generated typed CST as a Unicode tree.
129    pub fn pretty_cst(&self) -> String {
130        format_tree(&self.cst.pretty_tree(), PrettyOptions::PLAIN)
131    }
132
133    /// Builds a combined source, flat-token, and typed-CST inspection report.
134    pub fn pretty_report(&self) -> PrettyReport<'_> {
135        PrettyReport::new(
136            &self.original_source,
137            self.cell_stream(),
138            self.cst.pretty_tree(),
139        )
140    }
141
142    /// Prints the combined report to standard output, enabling ANSI styling
143    /// only when standard output is an interactive terminal.
144    pub fn print_pretty(&self) -> io::Result<()> {
145        print_report(self.pretty_report())
146    }
147}
148
149impl AsRef<SourceFile> for ParsedFile {
150    fn as_ref(&self) -> &SourceFile {
151        self.cst()
152    }
153}
154
155impl AsMut<SourceFile> for ParsedFile {
156    fn as_mut(&mut self) -> &mut SourceFile {
157        self.cst_mut()
158    }
159}
160
161impl Display for ParsedFile {
162    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
163        self.token_stream().fmt(formatter)
164    }
165}
166
167impl Spanned for ParsedFile {
168    fn span(&self) -> Span {
169        self.cst.span()
170    }
171}
172
173impl ToTokens for ParsedFile {
174    fn to_tokens(&self, output: &mut TokenStream) {
175        self.cst.to_tokens(output);
176    }
177}
178
179impl ToCells for ParsedFile {
180    fn to_cells(&self, output: &mut CellStream) {
181        self.cst.to_cells(output);
182    }
183}