Skip to main content

rustidy_parse/
recursive.rs

1//! Recursively parsable types
2
3// Exports
4pub use rustidy_macros::ParseRecursive;
5
6// Imports
7use {
8	crate::{self as rustidy_parse, PeekState},
9	super::{ParsableFrom, Parse, ParseError, Parser, ParserError, ParserTag},
10	core::{marker::PhantomData, mem},
11	either::Either,
12};
13
14/// Recursive type
15pub trait ParsableRecursive<R> {
16	/// The prefix for this type
17	type Prefix: Parse;
18
19	/// Base type
20	type Base: Parse;
21
22	/// The suffix for this type
23	type Suffix: Parse;
24
25	/// The infix of this type
26	type Infix: Parse;
27
28	/// Creates this type from it's parts
29	fn join_prefix(prefix: Self::Prefix, root: R, parser: &mut Parser) -> Self;
30
31	/// Converts the base to this type
32	fn from_base(base: Self::Base, parser: &mut Parser) -> Self;
33
34	/// Creates this type from it's parts
35	fn join_suffix(root: R, suffix: Self::Suffix, parser: &mut Parser) -> Self;
36
37	/// Creates this type from it's parts
38	fn join_infix(lhs: R, infix: Self::Infix, rhs: R, parser: &mut Parser) -> Self;
39}
40
41pub trait FromRecursiveRoot<R> {
42	fn from_recursive_root(root: R, parser: &mut Parser) -> Self;
43}
44
45impl<R, T> FromRecursiveRoot<R> for T
46where
47	T: From<R>, {
48	fn from_recursive_root(root: R, _parser: &mut Parser) -> T {
49		T::from(root)
50	}
51}
52
53pub trait TryFromRecursiveRoot<R>: Sized {
54	fn try_from_recursive_root(root: R, parser: &mut Parser) -> Option<Self>;
55}
56
57impl<R> TryFromRecursiveRoot<R> for R {
58	fn try_from_recursive_root(root: R, _parser: &mut Parser) -> Option<Self> {
59		Some(root)
60	}
61}
62
63pub trait IntoRecursiveRoot<R> {
64	fn into_recursive_root(self, parser: &mut Parser) -> R;
65}
66
67
68impl<R> IntoRecursiveRoot<R> for R {
69	fn into_recursive_root(self, _parser: &mut Parser) -> Self {
70		self
71	}
72}
73
74
75impl<R> ParsableRecursive<R> for ! {
76	type Base = !;
77	type Infix = !;
78	type Prefix = !;
79	type Suffix = !;
80
81	fn join_prefix(prefix: Self::Prefix, _: R, _parser: &mut Parser) -> Self {
82		prefix
83	}
84
85	fn from_base(base: Self::Base, _parser: &mut Parser) -> Self {
86		base
87	}
88
89	fn join_suffix(_: R, suffix: Self::Suffix, _parser: &mut Parser) -> Self {
90		suffix
91	}
92
93	fn join_infix(_: R, infix: Self::Infix, _: R, _parser: &mut Parser) -> Self {
94		infix
95	}
96}
97
98/// Recursive type parser
99#[derive(derive_more::Debug)]
100pub struct RecursiveWrapper<T, R>(pub T, pub PhantomData<R>);
101
102impl<T, R> ParsableFrom<RecursiveWrapper<T, R>> for T {
103	fn from_parsable(wrapper: RecursiveWrapper<T, R>) -> Self {
104		wrapper.0
105	}
106}
107
108// TODO: Instead of parsing with `R` and then converting to `T`, can we
109//       somehow parse the "top-level" with `T` and the bottom with `R`?
110impl<T, R> crate::Parse for RecursiveWrapper<T, R>
111where
112	T: TryFromRecursiveRoot<R>,
113	R: ParsableRecursive<R>, {
114	type Error = RecursiveWrapperError<R>;
115
116	// TODO: Account for precedence
117	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
118		let convert_inner = |parser: &mut Parser, inner: RecursiveWrapperInnerPart<R>| {
119			let mut base = R::from_base(inner.base, parser);
120			for prefix in inner.prefixes.into_iter().rev() {
121				base = R::join_prefix(prefix, base, parser);
122			}
123			for suffix in inner.suffixes {
124				base = R::join_suffix(base, suffix, parser);
125			}
126
127			base
128		};
129
130		let inner = self::parse(parser)?;
131
132		let mut base = convert_inner(parser, inner.first);
133		for (infix, rhs) in inner.rest {
134			base = R::join_infix(base, infix, convert_inner(parser, rhs), parser);
135		}
136
137		let base = T::try_from_recursive_root(base, parser)
138			.ok_or(Self::Error::FromRoot)?;
139
140		Ok(Self(base, PhantomData))
141	}
142}
143
144#[derive(derive_more::Debug, ParseError)]
145pub enum RecursiveWrapperError<R: ParsableRecursive<R>> {
146	#[parse_error(transparent)]
147	Prefix(ParserError<R::Prefix>),
148
149	#[parse_error(transparent)]
150	Suffix(ParserError<R::Suffix>),
151
152	#[parse_error(transparent)]
153	Infix(ParserError<R::Infix>),
154
155	#[parse_error(transparent)]
156	Base(ParserError<R::Base>),
157
158	#[parse_error(transparent)]
159	#[doc(hidden)]
160	BracesOpen(ParserError<ParseBracesOpen>),
161
162	#[parse_error(fmt = "Expected a prefix or base")]
163	#[parse_error(multiple)]
164	PrefixOrBase {
165		prefix: ParserError<R::Prefix>,
166		base:   ParserError<R::Base>,
167	},
168
169	#[parse_error(fmt = "Expected a suffix or infix")]
170	#[parse_error(multiple)]
171	SuffixOrInfix {
172		suffix: ParserError<R::Suffix>,
173		infix:  ParserError<R::Infix>,
174	},
175
176	#[parse_error(fmt = "None matched")]
177	#[parse_error(multiple)]
178	None {
179		prefix: ParserError<R::Prefix>,
180		suffix: ParserError<R::Suffix>,
181		infix:  ParserError<R::Infix>,
182		base:   ParserError<R::Base>,
183	},
184
185	#[parse_error(fmt = "Unable to convert from root")]
186	FromRoot,
187}
188
189#[derive(derive_more::Debug)]
190struct RecursiveWrapperInner<R: ParsableRecursive<R>> {
191	first: RecursiveWrapperInnerPart<R>,
192	rest:  Vec<(R::Infix, RecursiveWrapperInnerPart<R>)>,
193}
194
195#[derive(derive_more::Debug)]
196struct RecursiveWrapperInnerPart<R: ParsableRecursive<R>> {
197	prefixes: Vec<R::Prefix>,
198	base:     R::Base,
199	suffixes: Vec<R::Suffix>,
200}
201
202fn parse<R: ParsableRecursive<R>>(parser: &mut Parser) -> Result<RecursiveWrapperInner<R>, RecursiveWrapperError<R>> {
203	// Note: We want to ensure that any tags that are active at the beginning
204	//       stay active throughout the whole parsing, so we manually set them
205	//       on each parse.
206	// TODO: This is not a very good solution.
207	#[expect(clippy::type_complexity, reason = "TODO")]
208	fn peek<T: Parse>(parser: &mut Parser, tags: &[ParserTag],) -> Result<Result<(T, PeekState), ParserError<T>>, ParserError<T>> {
209		parser
210			.with_tags(tags.iter().copied(), Parser::peek::<T>)
211	}
212	let tags = parser.tags().collect::<Vec<_>>();
213
214	let mut inners = vec![];
215
216	let mut cur_prefixes = vec![];
217	let last_inner = loop {
218		let prefix = peek::<R::Prefix>(parser, &tags)
219			.map_err(RecursiveWrapperError::Prefix)?;
220		let base = peek::<R::Base>(parser, &tags)
221			.map_err(RecursiveWrapperError::Base)?;
222
223		let parsed = match (prefix, base) {
224			(Ok((prefix, prefix_state)), Ok((base, base_state))) => {
225				parser.set_peeked(base_state);
226				match peek::<R::Base>(parser, &tags)
227					.map_err(RecursiveWrapperError::Base)?
228					.is_ok() {
229					true => Either::Left((prefix, prefix_state)),
230					// TODO: We should undo the peek here
231					false => Either::Right((base, None)),
232				}
233			},
234			(Ok((prefix, prefix_state)), Err(_)) => Either::Left((prefix, prefix_state)),
235			(Err(_), Ok((base, base_state))) => Either::Right((base, Some(base_state))),
236			(Err(prefix), Err(base)) => return Err(
237				RecursiveWrapperError::PrefixOrBase { prefix, base }
238			),
239		};
240
241		match parsed {
242			Either::Left((prefix, prefix_state)) => {
243				parser.set_peeked(prefix_state);
244				cur_prefixes.push(prefix);
245			},
246			Either::Right((base, base_state)) => {
247				if let Some(state) = base_state {
248					parser.set_peeked(state);
249				}
250
251				let mut cur_suffixes = vec![];
252				let infix = loop {
253					let suffix = peek::<R::Suffix>(parser, &tags)
254						.map_err(RecursiveWrapperError::Suffix)?;
255					let infix = peek::<R::Infix>(parser, &tags)
256						.map_err(RecursiveWrapperError::Infix)?;
257
258					let parsed = match (suffix, infix) {
259						(Ok((suffix, suffix_state)), Ok((infix, infix_state))) => 'parsed: {
260							parser.set_peeked(infix_state);
261							// TODO: This is a semi-hack to ensure that we parse `for _ in 0.. {}` correctly.
262							//       Technically this should be always correct, since the only suffix that can
263							//       be equal to an infix is `..`, and it can't be chained, so the only time
264							//       we'd ever find a block expression after `..` would be when it shouldn't
265							//       be parsed.
266							//       Despite that, this is a very inelegant way to perform this check, and we
267							//       should instead just make optional suffixes / base expressions aware of the
268							//       `SkipOptionalTrailingBlockExpression` tag and skip themselves or something
269							//       similar that doesn't involve us doing anything.
270							if tags
271								.contains(&ParserTag::SkipOptionalTrailingBlockExpression) && peek::<ParseBracesOpen>(parser, &tags)
272								.map_err(RecursiveWrapperError::BracesOpen)?
273								.is_ok() {
274								// TODO: We should undo the peek here
275								break 'parsed Either::Left((suffix, suffix_state));
276							}
277
278							match peek::<R::Prefix>(parser, &tags)
279								.map_err(RecursiveWrapperError::Prefix)?
280								.is_ok() || peek::<R::Base>(parser, &tags)
281								.map_err(RecursiveWrapperError::Base)?
282								.is_ok() {
283								// TODO: We should undo the peek here
284								true => Either::Right((infix, None)),
285								false => Either::Left((suffix, suffix_state)),
286							}
287						},
288						(Ok((suffix, suffix_state)), Err(_)) => Either::Left((suffix, suffix_state)),
289						(Err(_), Ok((infix, infix_state))) => Either::Right((infix, Some(infix_state))),
290						(Err(_), Err(_)) => break None,
291					};
292
293					match parsed {
294						Either::Left((suffix, suffix_state)) => {
295							parser.set_peeked(suffix_state);
296							cur_suffixes.push(suffix);
297						},
298						Either::Right((infix, infix_state)) => {
299							if let Some(state) = infix_state {
300								parser.set_peeked(state);
301							}
302							break Some(infix);
303						},
304					}
305				};
306
307				let inner = RecursiveWrapperInnerPart {
308					prefixes: mem::take(&mut cur_prefixes),
309					base,
310					suffixes: cur_suffixes,
311				};
312
313				match infix {
314					Some(infix) => inners.push((inner, infix)),
315					None => break inner,
316				}
317			},
318		}
319	};
320
321	let mut inners = inners.into_iter();
322	let (first, rest) = match inners.next() {
323		Some((first_inner, mut infix)) => {
324			let mut rest = vec![];
325			for (inner, next_infix) in inners {
326				rest.push((infix, inner));
327				infix = next_infix;
328			}
329			rest.push((infix, last_inner));
330
331			(first_inner, rest)
332		},
333		None => (last_inner, vec![]),
334	};
335
336	Ok(RecursiveWrapperInner { first, rest })
337}
338
339/// Hack to ensure we don't parse optional trailing block expressions
340/// on range expressions.
341#[doc(hidden)]
342pub struct ParseBracesOpen;
343
344impl Parse for ParseBracesOpen {
345	type Error = ();
346
347	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
348		if parser.has_tag(ParserTag::SkipDelimiters) {
349			return Err(());
350		}
351
352		parser.try_update_with(|s| {
353			// TODO: Parse proper whitespace here
354			*s = s.trim_start();
355			match s.strip_prefix('{') {
356				Some(rest) => {
357					*s = rest;
358					Ok(())
359				},
360				None => Err(()),
361			}
362		}).map(|_| Self)
363	}
364}