const_format_proc_macros/
respan_to_macro.rs

1use crate::parse_utils::TokenTreeExt;
2
3use proc_macro2::{Delimiter, Span, TokenStream as TokenStream2, TokenTree as TokenTree2};
4
5const MSG: &str = "Expected the macro to be called as `respan_to!((tokens) more tokens)`";
6
7fn parse_paren(tt: TokenTree2) -> TokenStream2 {
8    match tt {
9        TokenTree2::Group(group) if group.delimiter() == Delimiter::Parenthesis => group.stream(),
10        _ => panic!("{}", MSG),
11    }
12}
13
14fn get_span(ts: TokenStream2) -> Span {
15    let mut iter = ts.into_iter();
16
17    match iter.next() {
18        Some(TokenTree2::Group(group)) if group.delimiter() == Delimiter::None => {
19            get_span(group.stream())
20        }
21        Some(first_tt) => {
22            let mut span = first_tt.span();
23
24            for tt in iter {
25                span = span.join(tt.span()).unwrap_or(span);
26            }
27            span
28        }
29        None => Span::mixed_site(),
30    }
31}
32
33pub(crate) fn implementation(ts: TokenStream2) -> TokenStream2 {
34    let mut iter = ts.into_iter();
35
36    let span_to = get_span(parse_paren(iter.next().expect(MSG)));
37
38    iter.map(|tt| tt.set_span_recursive(span_to)).collect()
39}