syn/
group.rs

1use crate::error::Result;
2use crate::parse::ParseBuffer;
3use crate::token;
4use proc_macro2::extra::DelimSpan;
5use proc_macro2::Delimiter;
6
7// Not public API.
8#[doc(hidden)]
9pub 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)]
18pub 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)]
27pub 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)]
37pub 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)]
46pub 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)]
55pub 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)]
64pub 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"))]
72pub(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
79fn 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 = span.close();
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(docsrs, doc(cfg(feature = "parsing")))]
146macro_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                _ = $content;
152                parens.token
153            }
154            $crate::__private::Err(error) => {
155                return $crate::__private::Err(error);
156            }
157        }
158    };
159}
160
161/// Parse a set of curly braces and expose their content to subsequent parsers.
162///
163/// # Example
164///
165/// ```
166/// # use quote::quote;
167/// #
168/// use syn::{braced, token, Ident, Result, Token, Type};
169/// use syn::parse::{Parse, ParseStream};
170/// use syn::punctuated::Punctuated;
171///
172/// // Parse a simplified struct syntax like:
173/// //
174/// //     struct S {
175/// //         a: A,
176/// //         b: B,
177/// //     }
178/// struct Struct {
179///     struct_token: Token![struct],
180///     ident: Ident,
181///     brace_token: token::Brace,
182///     fields: Punctuated<Field, Token![,]>,
183/// }
184///
185/// struct Field {
186///     name: Ident,
187///     colon_token: Token![:],
188///     ty: Type,
189/// }
190///
191/// impl Parse for Struct {
192///     fn parse(input: ParseStream) -> Result<Self> {
193///         let content;
194///         Ok(Struct {
195///             struct_token: input.parse()?,
196///             ident: input.parse()?,
197///             brace_token: braced!(content in input),
198///             fields: content.parse_terminated(Field::parse, Token![,])?,
199///         })
200///     }
201/// }
202///
203/// impl Parse for Field {
204///     fn parse(input: ParseStream) -> Result<Self> {
205///         Ok(Field {
206///             name: input.parse()?,
207///             colon_token: input.parse()?,
208///             ty: input.parse()?,
209///         })
210///     }
211/// }
212/// #
213/// # fn main() {
214/// #     let input = quote! {
215/// #         struct S {
216/// #             a: A,
217/// #             b: B,
218/// #         }
219/// #     };
220/// #     syn::parse2::<Struct>(input).unwrap();
221/// # }
222/// ```
223#[macro_export]
224#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
225macro_rules! braced {
226    ($content:ident in $cursor:expr) => {
227        match $crate::__private::parse_braces(&$cursor) {
228            $crate::__private::Ok(braces) => {
229                $content = braces.content;
230                _ = $content;
231                braces.token
232            }
233            $crate::__private::Err(error) => {
234                return $crate::__private::Err(error);
235            }
236        }
237    };
238}
239
240/// Parse a set of square brackets and expose their content to subsequent
241/// parsers.
242///
243/// # Example
244///
245/// ```
246/// # use quote::quote;
247/// #
248/// use proc_macro2::TokenStream;
249/// use syn::{bracketed, token, Result, Token};
250/// use syn::parse::{Parse, ParseStream};
251///
252/// // Parse an outer attribute like:
253/// //
254/// //     #[repr(C, packed)]
255/// struct OuterAttribute {
256///     pound_token: Token![#],
257///     bracket_token: token::Bracket,
258///     content: TokenStream,
259/// }
260///
261/// impl Parse for OuterAttribute {
262///     fn parse(input: ParseStream) -> Result<Self> {
263///         let content;
264///         Ok(OuterAttribute {
265///             pound_token: input.parse()?,
266///             bracket_token: bracketed!(content in input),
267///             content: content.parse()?,
268///         })
269///     }
270/// }
271/// #
272/// # fn main() {
273/// #     let input = quote! {
274/// #         #[repr(C, packed)]
275/// #     };
276/// #     syn::parse2::<OuterAttribute>(input).unwrap();
277/// # }
278/// ```
279#[macro_export]
280#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
281macro_rules! bracketed {
282    ($content:ident in $cursor:expr) => {
283        match $crate::__private::parse_brackets(&$cursor) {
284            $crate::__private::Ok(brackets) => {
285                $content = brackets.content;
286                _ = $content;
287                brackets.token
288            }
289            $crate::__private::Err(error) => {
290                return $crate::__private::Err(error);
291            }
292        }
293    };
294}