1 | use crate::error::Result; |
2 | use crate::parse::ParseBuffer; |
3 | use crate::token; |
4 | use proc_macro2::extra::DelimSpan; |
5 | use proc_macro2::Delimiter; |
6 | |
7 | // Not public API. |
8 | #[doc (hidden)] |
9 | pub struct Parens<'a> { |
10 | #[doc (hidden)] |
11 | pub token: token::Paren, |
12 | #[doc (hidden)] |
13 | pub content: ParseBuffer<'a>, |
14 | } |
15 | |
16 | // Not public API. |
17 | #[doc (hidden)] |
18 | pub struct Braces<'a> { |
19 | #[doc (hidden)] |
20 | pub token: token::Brace, |
21 | #[doc (hidden)] |
22 | pub content: ParseBuffer<'a>, |
23 | } |
24 | |
25 | // Not public API. |
26 | #[doc (hidden)] |
27 | pub struct Brackets<'a> { |
28 | #[doc (hidden)] |
29 | pub token: token::Bracket, |
30 | #[doc (hidden)] |
31 | pub content: ParseBuffer<'a>, |
32 | } |
33 | |
34 | // Not public API. |
35 | #[cfg (any(feature = "full" , feature = "derive" ))] |
36 | #[doc (hidden)] |
37 | pub struct Group<'a> { |
38 | #[doc (hidden)] |
39 | pub token: token::Group, |
40 | #[doc (hidden)] |
41 | pub content: ParseBuffer<'a>, |
42 | } |
43 | |
44 | // Not public API. |
45 | #[doc (hidden)] |
46 | pub fn parse_parens<'a>(input: &ParseBuffer<'a>) -> Result<Parens<'a>> { |
47 | parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens { |
48 | token: token::Paren(span), |
49 | content, |
50 | }) |
51 | } |
52 | |
53 | // Not public API. |
54 | #[doc (hidden)] |
55 | pub fn parse_braces<'a>(input: &ParseBuffer<'a>) -> Result<Braces<'a>> { |
56 | parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces { |
57 | token: token::Brace(span), |
58 | content, |
59 | }) |
60 | } |
61 | |
62 | // Not public API. |
63 | #[doc (hidden)] |
64 | pub fn parse_brackets<'a>(input: &ParseBuffer<'a>) -> Result<Brackets<'a>> { |
65 | parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets { |
66 | token: token::Bracket(span), |
67 | content, |
68 | }) |
69 | } |
70 | |
71 | #[cfg (any(feature = "full" , feature = "derive" ))] |
72 | pub(crate) fn parse_group<'a>(input: &ParseBuffer<'a>) -> Result<Group<'a>> { |
73 | parse_delimited(input, Delimiter::None).map(|(span, content)| Group { |
74 | token: token::Group(span.join()), |
75 | content, |
76 | }) |
77 | } |
78 | |
79 | fn parse_delimited<'a>( |
80 | input: &ParseBuffer<'a>, |
81 | delimiter: Delimiter, |
82 | ) -> Result<(DelimSpan, ParseBuffer<'a>)> { |
83 | input.step(|cursor| { |
84 | if let Some((content, span, rest)) = cursor.group(delimiter) { |
85 | let scope = crate::buffer::close_span_of_group(*cursor); |
86 | let nested = crate::parse::advance_step_cursor(cursor, content); |
87 | let unexpected = crate::parse::get_unexpected(input); |
88 | let content = crate::parse::new_parse_buffer(scope, nested, unexpected); |
89 | Ok(((span, content), rest)) |
90 | } else { |
91 | let message = match delimiter { |
92 | Delimiter::Parenthesis => "expected parentheses" , |
93 | Delimiter::Brace => "expected curly braces" , |
94 | Delimiter::Bracket => "expected square brackets" , |
95 | Delimiter::None => "expected invisible group" , |
96 | }; |
97 | Err(cursor.error(message)) |
98 | } |
99 | }) |
100 | } |
101 | |
102 | /// Parse a set of parentheses and expose their content to subsequent parsers. |
103 | /// |
104 | /// # Example |
105 | /// |
106 | /// ``` |
107 | /// # use quote::quote; |
108 | /// # |
109 | /// use syn::{parenthesized, token, Ident, Result, Token, Type}; |
110 | /// use syn::parse::{Parse, ParseStream}; |
111 | /// use syn::punctuated::Punctuated; |
112 | /// |
113 | /// // Parse a simplified tuple struct syntax like: |
114 | /// // |
115 | /// // struct S(A, B); |
116 | /// struct TupleStruct { |
117 | /// struct_token: Token![struct], |
118 | /// ident: Ident, |
119 | /// paren_token: token::Paren, |
120 | /// fields: Punctuated<Type, Token![,]>, |
121 | /// semi_token: Token![;], |
122 | /// } |
123 | /// |
124 | /// impl Parse for TupleStruct { |
125 | /// fn parse(input: ParseStream) -> Result<Self> { |
126 | /// let content; |
127 | /// Ok(TupleStruct { |
128 | /// struct_token: input.parse()?, |
129 | /// ident: input.parse()?, |
130 | /// paren_token: parenthesized!(content in input), |
131 | /// fields: content.parse_terminated(Type::parse, Token![,])?, |
132 | /// semi_token: input.parse()?, |
133 | /// }) |
134 | /// } |
135 | /// } |
136 | /// # |
137 | /// # fn main() { |
138 | /// # let input = quote! { |
139 | /// # struct S(A, B); |
140 | /// # }; |
141 | /// # syn::parse2::<TupleStruct>(input).unwrap(); |
142 | /// # } |
143 | /// ``` |
144 | #[macro_export ] |
145 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
146 | macro_rules! parenthesized { |
147 | ($content:ident in $cursor:expr) => { |
148 | match $crate::__private::parse_parens(&$cursor) { |
149 | $crate::__private::Ok(parens) => { |
150 | $content = parens.content; |
151 | parens.token |
152 | } |
153 | $crate::__private::Err(error) => { |
154 | return $crate::__private::Err(error); |
155 | } |
156 | } |
157 | }; |
158 | } |
159 | |
160 | /// Parse a set of curly braces and expose their content to subsequent parsers. |
161 | /// |
162 | /// # Example |
163 | /// |
164 | /// ``` |
165 | /// # use quote::quote; |
166 | /// # |
167 | /// use syn::{braced, token, Ident, Result, Token, Type}; |
168 | /// use syn::parse::{Parse, ParseStream}; |
169 | /// use syn::punctuated::Punctuated; |
170 | /// |
171 | /// // Parse a simplified struct syntax like: |
172 | /// // |
173 | /// // struct S { |
174 | /// // a: A, |
175 | /// // b: B, |
176 | /// // } |
177 | /// struct Struct { |
178 | /// struct_token: Token![struct], |
179 | /// ident: Ident, |
180 | /// brace_token: token::Brace, |
181 | /// fields: Punctuated<Field, Token![,]>, |
182 | /// } |
183 | /// |
184 | /// struct Field { |
185 | /// name: Ident, |
186 | /// colon_token: Token![:], |
187 | /// ty: Type, |
188 | /// } |
189 | /// |
190 | /// impl Parse for Struct { |
191 | /// fn parse(input: ParseStream) -> Result<Self> { |
192 | /// let content; |
193 | /// Ok(Struct { |
194 | /// struct_token: input.parse()?, |
195 | /// ident: input.parse()?, |
196 | /// brace_token: braced!(content in input), |
197 | /// fields: content.parse_terminated(Field::parse, Token![,])?, |
198 | /// }) |
199 | /// } |
200 | /// } |
201 | /// |
202 | /// impl Parse for Field { |
203 | /// fn parse(input: ParseStream) -> Result<Self> { |
204 | /// Ok(Field { |
205 | /// name: input.parse()?, |
206 | /// colon_token: input.parse()?, |
207 | /// ty: input.parse()?, |
208 | /// }) |
209 | /// } |
210 | /// } |
211 | /// # |
212 | /// # fn main() { |
213 | /// # let input = quote! { |
214 | /// # struct S { |
215 | /// # a: A, |
216 | /// # b: B, |
217 | /// # } |
218 | /// # }; |
219 | /// # syn::parse2::<Struct>(input).unwrap(); |
220 | /// # } |
221 | /// ``` |
222 | #[macro_export ] |
223 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
224 | macro_rules! braced { |
225 | ($content:ident in $cursor:expr) => { |
226 | match $crate::__private::parse_braces(&$cursor) { |
227 | $crate::__private::Ok(braces) => { |
228 | $content = braces.content; |
229 | braces.token |
230 | } |
231 | $crate::__private::Err(error) => { |
232 | return $crate::__private::Err(error); |
233 | } |
234 | } |
235 | }; |
236 | } |
237 | |
238 | /// Parse a set of square brackets and expose their content to subsequent |
239 | /// parsers. |
240 | /// |
241 | /// # Example |
242 | /// |
243 | /// ``` |
244 | /// # use quote::quote; |
245 | /// # |
246 | /// use proc_macro2::TokenStream; |
247 | /// use syn::{bracketed, token, Result, Token}; |
248 | /// use syn::parse::{Parse, ParseStream}; |
249 | /// |
250 | /// // Parse an outer attribute like: |
251 | /// // |
252 | /// // #[repr(C, packed)] |
253 | /// struct OuterAttribute { |
254 | /// pound_token: Token![#], |
255 | /// bracket_token: token::Bracket, |
256 | /// content: TokenStream, |
257 | /// } |
258 | /// |
259 | /// impl Parse for OuterAttribute { |
260 | /// fn parse(input: ParseStream) -> Result<Self> { |
261 | /// let content; |
262 | /// Ok(OuterAttribute { |
263 | /// pound_token: input.parse()?, |
264 | /// bracket_token: bracketed!(content in input), |
265 | /// content: content.parse()?, |
266 | /// }) |
267 | /// } |
268 | /// } |
269 | /// # |
270 | /// # fn main() { |
271 | /// # let input = quote! { |
272 | /// # #[repr(C, packed)] |
273 | /// # }; |
274 | /// # syn::parse2::<OuterAttribute>(input).unwrap(); |
275 | /// # } |
276 | /// ``` |
277 | #[macro_export ] |
278 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
279 | macro_rules! bracketed { |
280 | ($content:ident in $cursor:expr) => { |
281 | match $crate::__private::parse_brackets(&$cursor) { |
282 | $crate::__private::Ok(brackets) => { |
283 | $content = brackets.content; |
284 | brackets.token |
285 | } |
286 | $crate::__private::Err(error) => { |
287 | return $crate::__private::Err(error); |
288 | } |
289 | } |
290 | }; |
291 | } |
292 | |