blob: 9284d029a4d2aaa1aebfeded14e700a1ed8ac55b [file] [log] [blame]
David Tolnay9bfd1122019-04-14 12:43:31 -07001// Not public API.
2#[doc(hidden)]
3#[macro_export(local_inner_macros)]
4macro_rules! punct_len {
5 ($mode:ident, +) => ( 1usize );
6 ($mode:ident, +=) => ( 2usize );
7 ($mode:ident, &) => ( 1usize );
8 ($mode:ident, &&) => ( 2usize );
9 ($mode:ident, &=) => ( 2usize );
10 ($mode:ident, @) => ( 1usize );
11 ($mode:ident, !) => ( 1usize );
12 ($mode:ident, ^) => ( 1usize );
13 ($mode:ident, ^=) => ( 2usize );
14 ($mode:ident, :) => ( 1usize );
15 ($mode:ident, ::) => ( 2usize );
16 ($mode:ident, ,) => ( 1usize );
17 ($mode:ident, /) => ( 1usize );
18 ($mode:ident, /=) => ( 2usize );
19 ($mode:ident, .) => ( 1usize );
20 ($mode:ident, ..) => ( 2usize );
21 ($mode:ident, ...) => ( 3usize );
22 ($mode:ident, ..=) => ( 3usize );
23 ($mode:ident, =) => ( 1usize );
24 ($mode:ident, ==) => ( 2usize );
25 ($mode:ident, >=) => ( 2usize );
26 ($mode:ident, >) => ( 1usize );
27 ($mode:ident, <=) => ( 2usize );
28 ($mode:ident, <) => ( 1usize );
29 ($mode:ident, *=) => ( 2usize );
30 ($mode:ident, !=) => ( 2usize );
31 ($mode:ident, |) => ( 1usize );
32 ($mode:ident, |=) => ( 2usize );
33 ($mode:ident, ||) => ( 2usize );
34 ($mode:ident, #) => ( 1usize );
35 ($mode:ident, ?) => ( 1usize );
36 ($mode:ident, ->) => ( 2usize );
37 ($mode:ident, <-) => ( 2usize );
38 ($mode:ident, %) => ( 1usize );
39 ($mode:ident, %=) => ( 2usize );
40 ($mode:ident, =>) => ( 2usize );
41 ($mode:ident, ;) => ( 1usize );
42 ($mode:ident, <<) => ( 2usize );
43 ($mode:ident, <<=) => ( 3usize );
44 ($mode:ident, >>) => ( 2usize );
45 ($mode:ident, >>=) => ( 3usize );
46 ($mode:ident, *) => ( 1usize );
47 ($mode:ident, -) => ( 1usize );
48 ($mode:ident, -=) => ( 2usize );
49 ($mode:ident, ~) => ( 1usize );
50 (lenient, $tt:tt) => ( 0usize );
51 (strict, $tt:tt) => ({ unexpected!($tt); 0usize });
52 ($mode:ident, $head:tt $($tail:tt)+) => ( punct_len!($mode, $head) $(+ punct_len!($mode, $tail))+ );
53}
54
55// Not public API.
56#[doc(hidden)]
57#[macro_export]
58macro_rules! unexpected {
59 () => {};
60}
61
62// Not public API.
63#[doc(hidden)]
64#[macro_export]
65macro_rules! stringify_punct {
66 ($($tt:tt)+) => ( concat!($(stringify!($tt)),+) );
67}
68
69// Not public API.
70// Without this, local_inner_macros breaks when looking for concat!
71#[doc(hidden)]
72#[macro_export]
73macro_rules! my_concat {
74 ($($tt:tt)*) => ( concat!($($tt)*) );
75}
76
77/// Define a type that supports parsing and printing a multi-character symbol
78/// as if it were a token.
79///
80/// # Usage
81///
82/// As a convention, it is recommended that this macro be invoked within a
83/// module called `punct` or `punctuation` and that the resulting parser be invoked
84/// with a `punct::` or `punctuation::` prefix.
85///
86/// ```edition2018
87/// mod punct {
88/// syn::custom_punctuation!(LeftRightArrow, <=>);
89/// }
90/// ```
91///
92/// The generated syntax tree node supports the following operations just like
93/// any built-in punctuation token.
94///
95/// - [Peeking] — `input.peek(punct::LeftRightArrow)`
96///
97/// - [Parsing] — `input.parse::<punct::LeftRightArrow>()?`
98///
99/// - [Printing] — `quote!( ... #left_right_arrow ... )`
100///
101/// - Construction from a [`Span`] — `let left_right_arrow = punct::LeftRightArrow(sp)`
102///
103/// - Construction from multiple [`Span`] — `let left_right_arrow = punct::LeftRightArrow([sp, sp, sp])`
104///
105/// - Field access to its spans — `let spans = left_right_arrow.spans`
106///
107/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
108/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
109/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
110/// [`Span`]: struct.Span.html
111///
112/// # Example
113///
114/// ```edition2018
115/// use syn::{Expr, ExprParen, parenthesized};
116/// use syn::punctuated::Punctuated;
117/// use syn::parse::{Parse, ParseStream, Result};
118/// use syn::token::Paren;
119///
120/// mod punct {
121/// syn::custom_punctuation!(PathSeparator, </>);
122/// }
123///
124/// // (expr) </> (expr) </> (expr) ...
125/// struct PathSegments {
126/// segments: Punctuated<Expr, punct::PathSeparator>,
127/// }
128///
129/// impl Parse for PathSegments {
130/// fn parse(input: ParseStream) -> Result<Self> {
131/// let mut segments = Punctuated::new();
132///
133/// let la = input.lookahead1();
134/// if la.peek(Paren) {
135/// let content;
136/// let paren_token = parenthesized!(content in input);
137/// let expr = Box::new(content.parse()?);
138/// segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
139/// } else {
140/// return Err(la.error());
141/// }
142///
143/// while input.peek(punct::PathSeparator) {
144/// segments.push_punct(input.parse()?);
145/// let content;
146/// let paren_token = parenthesized!(content in input);
147/// let expr = Box::new(content.parse()?);
148/// segments.push_value(Expr::Paren(ExprParen { attrs: vec![], paren_token, expr }));
149/// }
150///
151/// Ok(PathSegments { segments })
152/// }
153/// }
154///
155/// let _: PathSegments = syn::parse_str(r#"("five") </> ("hundred")"#).unwrap();
156/// ```
157///
158#[macro_export(local_inner_macros)]
159macro_rules! custom_punctuation {
160 ($ident:ident, $($tt:tt)+) => {
161 pub struct $ident {
162 pub spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)],
163 }
164
165 #[doc(hidden)]
166 #[allow(non_snake_case)]
167 pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; punct_len!(lenient, $($tt)+)]>>(
168 spans: __S,
169 ) -> $ident {
170 let _punct_len = punct_len!(strict, $($tt)+);
171 $ident {
172 spans: $crate::export::IntoSpans::into_spans(spans)
173 }
174 }
175
176 impl $crate::export::Default for $ident {
177 fn default() -> Self {
178 $ident($crate::export::Span::call_site())
179 }
180 }
181
182 impl_parse_for_custom_punctuation!($ident, $($tt)+);
183 impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
184 impl_clone_for_custom_punctuation!($ident, $($tt)+);
185 impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
186 };
187}
188
189// Not public API.
190#[cfg(feature = "parsing")]
191#[doc(hidden)]
192#[macro_export(local_inner_macros)]
193macro_rules! impl_parse_for_custom_punctuation {
194 ($ident: ident, $($tt:tt)+) => {
195 impl $crate::token::CustomToken for $ident {
196 fn peek(cursor: $crate::buffer::Cursor) -> bool {
197 $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
198 }
199
200 fn display() -> &'static $crate::export::str {
201 my_concat!("`", stringify_punct!($($tt)+), "`")
202 }
203 }
204
205 impl $crate::parse::Parse for $ident {
206 fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
207 let spans: [$crate::export::Span; punct_len!(lenient, $($tt)+)] =
208 $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
209 Ok($ident(spans))
210 }
211 }
212 };
213}
214
215// Not public API.
216#[cfg(not(feature = "parsing"))]
217#[doc(hidden)]
218#[macro_export]
219macro_rules! impl_parse_for_custom_punctuation {
220 ($ident: ident, $($tt:tt)+) => {};
221}
222
223// Not public API.
224#[cfg(feature = "printing")]
225#[doc(hidden)]
226#[macro_export(local_inner_macros)]
227macro_rules! impl_to_tokens_for_custom_punctuation {
228 ($ident: ident, $($tt:tt)+) => {
229 impl $crate::export::ToTokens for $ident {
230 fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
231 $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
232 }
233 }
234 };
235}
236
237// Not public API.
238#[cfg(not(feature = "printing"))]
239#[doc(hidden)]
240#[macro_export]
241macro_rules! impl_to_tokens_for_custom_punctuation {
242 ($ident: ident, $($tt:tt)+) => {};
243}
244
245// Not public API.
246#[cfg(feature = "clone-impls")]
247#[doc(hidden)]
248#[macro_export]
249macro_rules! impl_clone_for_custom_punctuation {
250 ($ident: ident, $($tt:tt)+) => {
251 impl $crate::export::Copy for $ident {}
252
253 impl $crate::export::Clone for $ident {
254 fn clone(&self) -> Self {
255 *self
256 }
257 }
258 };
259}
260
261// Not public API.
262#[cfg(not(feature = "clone-impls"))]
263#[doc(hidden)]
264#[macro_export]
265macro_rules! impl_clone_for_custom_punctuation {
266 ($ident: ident, $($tt:tt)+) => {};
267}
268
269// Not public API.
270#[cfg(feature = "extra-traits")]
271#[doc(hidden)]
272#[macro_export(local_inner_macros)]
273macro_rules! impl_extra_traits_for_custom_punctuation {
274 ($ident: ident, $($tt:tt)+) => {
275 impl $crate::export::Debug for $ident {
276 fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
277 $crate::export::Formatter::write_str(f, stringify_punct!($($tt)+))
278 }
279 }
280
281 impl $crate::export::Eq for $ident {}
282
283 impl $crate::export::PartialEq for $ident {
284 fn eq(&self, _other: &Self) -> $crate::export::bool {
285 true
286 }
287 }
288
289 impl $crate::export::Hash for $ident {
290 fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
291 }
292 };
293}
294
295// Not public API.
296#[cfg(not(feature = "extra-traits"))]
297#[doc(hidden)]
298#[macro_export]
299macro_rules! impl_extra_traits_for_custom_punctuation {
300 ($ident: ident, $($tt:tt)+) => {};
301}