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}