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}