indoc/
expr.rs

1use crate::error::{Error, Result};
2use proc_macro::token_stream::IntoIter as TokenIter;
3use proc_macro::{Spacing, Span, TokenStream, TokenTree};
4use std::iter::{self, Peekable};
5
6pub fn parse(input: &mut Peekable<TokenIter>, require_comma: bool) -> Result<TokenStream> {
7    #[derive(PartialEq)]
8    enum Lookbehind {
9        JointColon,
10        DoubleColon,
11        JointHyphen,
12        Other,
13    }
14
15    let mut expr = TokenStream::new();
16    let mut lookbehind = Lookbehind::Other;
17    let mut angle_bracket_depth = 0;
18
19    loop {
20        if angle_bracket_depth == 0 {
21            match input.peek() {
22                Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
23                    return Ok(expr);
24                }
25                _ => {}
26            }
27        }
28        match input.next() {
29            Some(TokenTree::Punct(punct)) => {
30                let ch = punct.as_char();
31                let spacing = punct.spacing();
32                expr.extend(iter::once(TokenTree::Punct(punct)));
33                lookbehind = match ch {
34                    ':' if lookbehind == Lookbehind::JointColon => Lookbehind::DoubleColon,
35                    ':' if spacing == Spacing::Joint => Lookbehind::JointColon,
36                    '<' if lookbehind == Lookbehind::DoubleColon => {
37                        angle_bracket_depth += 1;
38                        Lookbehind::Other
39                    }
40                    '>' if angle_bracket_depth > 0 && lookbehind != Lookbehind::JointHyphen => {
41                        angle_bracket_depth -= 1;
42                        Lookbehind::Other
43                    }
44                    '-' if spacing == Spacing::Joint => Lookbehind::JointHyphen,
45                    _ => Lookbehind::Other,
46                };
47            }
48            Some(token) => expr.extend(iter::once(token)),
49            None => {
50                return if require_comma {
51                    Err(Error::new(
52                        Span::call_site(),
53                        "unexpected end of macro input",
54                    ))
55                } else {
56                    Ok(expr)
57                };
58            }
59        }
60    }
61}