1use std::vec;
4
5use proc_macro2::TokenStream;
6use proc_macro2_diagnostics::Diagnostic;
7use syn::{parse::ParseStream, spanned::Spanned, Result};
8
9pub mod recoverable;
10
11#[cfg(feature = "rawtext-stable-hack")]
12use {proc_macro2::Span, std::str::FromStr};
13
14use self::recoverable::{ParseRecoverable, ParsingResult, RecoverableContext};
15#[cfg(feature = "rawtext-stable-hack")]
16use crate::rawtext_stable_hack;
17use crate::{node::*, ParserConfig};
18pub struct Parser<C> {
25 config: ParserConfig<C>,
26}
27
28impl Default for Parser<Infallible> {
29 fn default() -> Self {
30 Self {
31 config: ParserConfig::default(),
32 }
33 }
34}
35
36impl<C: CustomNode + std::fmt::Debug> Parser<C> {
37 pub fn new(config: ParserConfig<C>) -> Self {
39 Parser { config }
40 }
41
42 pub fn parse_simple(&self, v: impl Into<TokenStream>) -> Result<Vec<Node<C>>> {
49 self.parse_recoverable(v).into_result()
50 }
51
52 pub fn parse_recoverable(&self, v: impl Into<TokenStream>) -> ParsingResult<Vec<Node<C>>> {
55 use syn::parse::Parser as _;
56
57 let parser = move |input: ParseStream| Ok(self.parse_syn_stream(input));
58 let source = parser.parse2(v.into()).expect("No errors from parser");
59
60 #[cfg(feature = "rawtext-stable-hack")]
61 let source = Self::reparse_raw_text(&self, parser, source);
63 source
64 }
65 #[cfg(feature = "rawtext-stable-hack")]
66 fn reparse_raw_text<Parser>(
67 &self,
68 parser: Parser,
69 mut source: ParsingResult<Vec<Node<C>>>,
70 ) -> ParsingResult<Vec<Node<C>>>
71 where
72 Parser: FnOnce(ParseStream) -> syn::Result<ParsingResult<Vec<Node<C>>>>,
73 {
74 use syn::parse::Parser as _;
75 if rawtext_stable_hack::is_join_span_available() {
77 return source;
78 }
79 if !source.is_ok() {
81 let (mut source, errors) = source.split_vec();
82 rawtext_stable_hack::inject_raw_text_default(&mut source);
83 return ParsingResult::from_parts_vec(source, errors);
84 }
85 if !rawtext_stable_hack::is_macro_args_recoverable() {
87 source.push_diagnostic(Diagnostic::new(
88 proc_macro2_diagnostics::Level::Warning,
89 "Failed to retrive source text of macro call, maybe macro was called from other macro?",
90 ));
91 return source;
92 }
93 if self.config.macro_pattern.is_empty() {
96 return source;
97 }
98 let text = Span::call_site()
99 .source_text()
100 .expect("Source text should be available");
101
102 proc_macro2::fallback::force();
103 let stream = TokenStream::from_str(&text).unwrap();
104 let stream = self
105 .config
106 .macro_pattern
107 .match_content(stream)
108 .expect("Cannot find macro pattern inside Span::call_site");
109 let hacked = parser.parse2(stream).expect("No errors from parser");
110
111 let mut source = source.into_result().expect("was checked");
112 let hacked = hacked.into_result().expect("was checked");
113 proc_macro2::fallback::unforce();
114 rawtext_stable_hack::inject_raw_text(&mut source, &hacked);
115
116 return ParsingResult::Ok(source);
117 }
118
119 pub fn parse_syn_stream(&self, input: ParseStream) -> ParsingResult<Vec<Node<C>>> {
121 let mut nodes = vec![];
122 let mut top_level_nodes = 0;
123
124 let mut parser = RecoverableContext::new(self.config.clone().into());
125 while !input.is_empty() {
126 let Some(parsed_node) = Node::parse_recoverable(&mut parser, input) else {
127 parser.push_diagnostic(input.error("Node parse failed".to_string()));
128 break;
129 };
130
131 if let Some(type_of_top_level_nodes) = &self.config.type_of_top_level_nodes {
132 if &parsed_node.r#type() != type_of_top_level_nodes {
133 parser.push_diagnostic(input.error(format!(
134 "top level nodes need to be of type {}",
135 type_of_top_level_nodes
136 )));
137 break;
138 }
139 }
140
141 top_level_nodes += 1;
142 nodes.push(parsed_node)
143 }
144
145 if !input.is_empty() {
147 let tts = input
148 .parse::<TokenStream>()
149 .expect("No error in parsing token stream");
150 parser.push_diagnostic(Diagnostic::spanned(
151 tts.span(),
152 proc_macro2_diagnostics::Level::Error,
153 "Tokens was skipped after incorrect parsing",
154 ));
155 }
156
157 if let Some(number_of_top_level_nodes) = &self.config.number_of_top_level_nodes {
158 if &top_level_nodes != number_of_top_level_nodes {
159 parser.push_diagnostic(input.error(format!(
160 "saw {} top level nodes but exactly {} are required",
161 top_level_nodes, number_of_top_level_nodes
162 )))
163 }
164 }
165
166 let nodes = if self.config.flat_tree {
167 nodes.into_iter().flat_map(Node::flatten).collect()
168 } else {
169 nodes
170 };
171
172 let errors = parser.diagnostics;
173
174 let nodes = if nodes.is_empty() {
175 Some(vec![])
176 } else {
177 Some(nodes)
178 };
179 ParsingResult::from_parts(nodes, errors)
180 }
181}