logos_codegen/parser/
nested.rs1use proc_macro2::token_stream::IntoIter as TokenIter;
2use proc_macro2::{Ident, Literal, TokenStream, TokenTree};
3use quote::quote;
4
5use crate::util::{expect_punct, is_punct};
6
7pub enum NestedValue {
8 Assign(TokenStream),
10 Literal(Literal),
12 Group(TokenStream),
14 KeywordAssign(Ident, TokenStream),
16}
17
18pub enum Nested {
19 Unnamed(TokenStream),
24 Named(Ident, NestedValue),
26 Unexpected(TokenStream),
28}
29
30pub struct AttributeParser {
31 inner: TokenIter,
32}
33
34pub struct Empty;
35
36impl From<Empty> for TokenStream {
37 fn from(_: Empty) -> TokenStream {
38 TokenStream::new()
39 }
40}
41
42impl AttributeParser {
43 pub fn new(stream: TokenStream) -> Self {
44 AttributeParser {
45 inner: stream.into_iter(),
46 }
47 }
48
49 pub fn parsed<T>(&mut self) -> Option<syn::Result<T>>
50 where
51 T: syn::parse::Parse,
52 {
53 let tokens = self.collect_tail(TokenStream::new());
54
55 if tokens.is_empty() {
56 return None;
57 }
58
59 Some(syn::parse2(tokens))
60 }
61
62 fn next_tt(&mut self) -> Option<TokenTree> {
63 expect_punct(self.inner.next(), ',')
64 }
65
66 fn collect_tail<T>(&mut self, first: T) -> TokenStream
67 where
68 T: Into<TokenStream>,
69 {
70 let mut out = first.into();
71
72 while let Some(tt) = self.next_tt() {
73 out.extend(Some(tt));
74 }
75
76 out
77 }
78
79 fn parse_unnamed(&mut self, first: Ident, next: TokenTree) -> Nested {
80 let mut out = TokenStream::from(TokenTree::Ident(first));
81
82 out.extend(self.collect_tail(next));
83
84 Nested::Unnamed(out.into_iter().collect())
85 }
86
87 fn parse_assign(&mut self, name: Ident) -> Nested {
88 let value = self.collect_tail(Empty);
89
90 Nested::Named(name, NestedValue::Assign(value))
91 }
92
93 fn parse_literal(&mut self, name: Ident, lit: Literal) -> Nested {
94 let _ = self.collect_tail(Empty);
96
97 Nested::Named(name, NestedValue::Literal(lit))
98 }
99
100 fn parse_group(&mut self, name: Ident, group: TokenStream) -> Nested {
101 Nested::Named(name, NestedValue::Group(group))
102 }
103
104 fn parse_keyword(&mut self, keyword: Ident, name: Ident) -> Nested {
105 let error = expect_punct(self.next_tt(), '=');
106
107 match error {
108 Some(error) => {
109 let error = self.collect_tail(error);
110
111 Nested::Unexpected(error)
112 }
113 None => {
114 let value = self.collect_tail(Empty);
115
116 Nested::Named(keyword, NestedValue::KeywordAssign(name, value))
117 }
118 }
119 }
120}
121
122impl Iterator for AttributeParser {
123 type Item = Nested;
124
125 fn next(&mut self) -> Option<Nested> {
126 let first = self.inner.next()?;
127
128 let name = match first {
129 TokenTree::Ident(ident) => ident,
130 tt => {
131 let stream = self.collect_tail(tt);
132
133 return Some(Nested::Unnamed(stream.into_iter().collect()));
134 }
135 };
136
137 match self.next_tt() {
138 Some(tt) if is_punct(&tt, '=') => Some(self.parse_assign(name)),
139 Some(TokenTree::Literal(lit)) => Some(self.parse_literal(name, lit)),
140 Some(TokenTree::Group(group)) => Some(self.parse_group(name, group.stream())),
141 Some(TokenTree::Ident(next)) => Some(self.parse_keyword(name, next)),
142 Some(next) => Some(self.parse_unnamed(name, next)),
143 None => Some(Nested::Unnamed(quote!(#name))),
144 }
145 }
146}