Skip to main content

loess_rust_opaque/
lib.rs

1//! Additional grammar tokens representing the stable Rust programming language,
2//! closely following [The Rust Reference](https://doc.rust-lang.org/stable/reference/).
3//!
4//! Corrections in that regard are not automatically considered breaking changes,
5//! unless they became necessary due to a change in Rust **and** reduce what is considered valid.
6//!
7//! Breaking changes to the API are considered breaking as normal.
8//!
9//! *Note that unstable grammar **is** accidentally accepted in some cases.*  
10//! ***Ceasing to accept unstable grammar is not by itself considered a breaking change for Loess.***
11
12use loess::{Error, ErrorPriority, Errors, Input, IntoTokens, PopFrom};
13use proc_macro2::{TokenStream, TokenTree};
14use quote::ToTokens;
15use syn::{
16	Expr, Pat, Path, Stmt,
17	parse::{Parse, ParseStream, Parser},
18};
19
20fn error_reporter(errors: &mut Errors) -> impl '_ + FnOnce(syn::Error) {
21	move |error| {
22		errors.push(Error::new(
23			ErrorPriority::GRAMMAR,
24			error.to_string(),
25			[error.span()],
26		))
27	}
28}
29
30macro_rules! wrappers {
31	($(
32		$(#[$($attr:tt)*])*
33		$name:ident($wrapped:ty)$(: $(
34			// $(PeekFrom $(@ $PeekFrom:tt)?)?
35			$(PopFrom $(@ $PopFrom:tt)?)?
36			$(IntoTokens $(@ $IntoTokens:tt)?)?
37		),*$(,)?)?;
38	)*) => {$(
39		$(#[$($attr)*])*
40		#[derive(Clone)]
41		pub struct $name($wrapped);
42
43		$($(
44			// $(
45			// 	$(@ $PeekFrom)?
46			// 	impl PeekFrom for $name {
47			// 		fn peek_from(input: &Input) -> bool {
48			// 			fn peek(input: ParseStream) -> syn::Result<bool> {
49			// 				let result = input.peek(<$wrapped>::default());
50			// 				let _ = TokenStream::parse(input).expect("infallible"); // Discard cloned input.
51			// 				Ok(result)
52			// 			}
53
54			// 			let input = input.tokens.iter().cloned().collect::<TokenStream>();
55			// 			peek.parse2(input).expect("infallible")
56			// 		}
57			// 	}
58			// )?
59
60			$(
61				$(@ $PopFrom)?
62				impl PopFrom for $name {
63					fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
64						fn parse(input: ParseStream) -> syn::Result<($wrapped, TokenStream)> {
65							Ok((<$wrapped>::parse(input)?, TokenStream::parse(input)?))
66						}
67
68						let tokens: TokenStream = input.tokens.drain(..).collect();
69						let (parsed, rest) = parse.parse2(tokens).map_err(error_reporter(errors))?;
70						input.prepend(rest.into_iter().collect::<Vec<_>>());
71						Ok(Self(parsed))
72					}
73				}
74			)?
75
76			$(
77				$(@ $IntoTokens)?
78				impl IntoTokens for $name {
79					fn into_tokens(self, root: &TokenStream, tokens: &mut impl Extend<TokenTree>) {
80						self.0.into_token_stream().into_tokens(root, tokens);
81					}
82				}
83			)?
84		)*)?
85	)*};
86}
87
88wrappers! {
89	/// [*Expression*](https://doc.rust-lang.org/stable/reference/expressions.html#r-expr.syntax)
90	Expression(Expr): PopFrom, IntoTokens;
91
92	/// [*Expression*](https://doc.rust-lang.org/stable/reference/expressions.html#r-expr.syntax)
93	/// <sub>except [*StructExpression*](https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#r-expr.struct.syntax)</sub>
94	ExpressionExceptStructExpression(Expr): IntoTokens;
95
96	/// [*Pattern*](https://doc.rust-lang.org/stable/reference/patterns.html#r-patterns.syntax)
97	Pattern(Pat): IntoTokens;
98
99	/// [*SimplePath*](https://doc.rust-lang.org/stable/reference/paths.html#r-paths.simple.syntax)
100	SimplePath(Path): IntoTokens;
101
102	/// [*Statement*](https://doc.rust-lang.org/stable/reference/statements.html#r-statement.syntax)
103	Statement(Stmt): PopFrom, IntoTokens;
104}
105
106impl PopFrom for ExpressionExceptStructExpression {
107	fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
108		fn parse(
109			input: ParseStream,
110		) -> syn::Result<(ExpressionExceptStructExpression, TokenStream)> {
111			Ok((
112				ExpressionExceptStructExpression(Expr::parse_without_eager_brace(input)?),
113				TokenStream::parse(input)?,
114			))
115		}
116
117		let tokens = input.tokens.drain(..).collect::<TokenStream>().into();
118		let (this, rest) = parse.parse2(tokens).map_err(error_reporter(errors))?;
119
120		input.prepend(rest.into_iter().collect::<Vec<_>>());
121		Ok(this)
122	}
123}
124
125impl PopFrom for Pattern {
126	fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
127		fn parse(input: ParseStream) -> syn::Result<(Pattern, TokenStream)> {
128			Ok((
129				Pattern(Pat::parse_multi_with_leading_vert(input)?),
130				TokenStream::parse(input)?,
131			))
132		}
133
134		let tokens = input.tokens.drain(..).collect::<TokenStream>().into();
135		let (this, rest) = parse.parse2(tokens).map_err(error_reporter(errors))?;
136
137		input.prepend(rest.into_iter().collect::<Vec<_>>());
138		Ok(this)
139	}
140}
141
142impl PopFrom for SimplePath {
143	fn pop_from(input: &mut Input, errors: &mut Errors) -> Result<Self, ()> {
144		fn parse(input: ParseStream) -> syn::Result<(SimplePath, TokenStream)> {
145			Ok((
146				SimplePath(Path::parse_mod_style(input)?),
147				TokenStream::parse(input)?,
148			))
149		}
150
151		let tokens = input.tokens.drain(..).collect::<TokenStream>().into();
152		let (this, rest) = parse.parse2(tokens).map_err(error_reporter(errors))?;
153
154		input.prepend(rest.into_iter().collect::<Vec<_>>());
155		Ok(this)
156	}
157}