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