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