syn_pub_items/
group.rs

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