macro_rules! custom_punctuation { ($ident:ident, $($tt:tt)+) => { ... }; }
Expand description
Define a type that supports parsing and printing a multi-character symbol as if it were a punctuation token.
§Usage
syn::custom_punctuation!(LeftRightArrow, <=>);
The generated syntax tree node supports the following operations just like any built-in punctuation token.
-
Peeking —
input.peek(LeftRightArrow)
-
Parsing —
input.parse::<LeftRightArrow>()?
-
Printing —
quote!( ... #lrarrow ... )
-
Construction from a
Span
—let lrarrow = LeftRightArrow(sp)
-
Construction from multiple
Span
—let lrarrow = LeftRightArrow([sp, sp, sp])
-
Field access to its spans —
let spans = lrarrow.spans
§Example
use proc_macro2::{TokenStream, TokenTree};
use syn::parse::{Parse, ParseStream, Peek, Result};
use syn::punctuated::Punctuated;
use syn::Expr;
syn::custom_punctuation!(PathSeparator, </>);
// expr </> expr </> expr ...
struct PathSegments {
segments: Punctuated<Expr, PathSeparator>,
}
impl Parse for PathSegments {
fn parse(input: ParseStream) -> Result<Self> {
let mut segments = Punctuated::new();
let first = parse_until(input, PathSeparator)?;
segments.push_value(syn::parse2(first)?);
while input.peek(PathSeparator) {
segments.push_punct(input.parse()?);
let next = parse_until(input, PathSeparator)?;
segments.push_value(syn::parse2(next)?);
}
Ok(PathSegments { segments })
}
}
fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> {
let mut tokens = TokenStream::new();
while !input.is_empty() && !input.peek(end) {
let next: TokenTree = input.parse()?;
tokens.extend(Some(next));
}
Ok(tokens)
}
fn main() {
let input = r#" a::b </> c::d::e "#;
let _: PathSegments = syn::parse_str(input).unwrap();
}