blob: ca37545687c2e5e8a0ffb8b0681248f9252d16f4 [file] [log] [blame]
David Tolnay42342c82018-08-25 08:36:35 -04001use proc_macro2::{Delimiter, Span};
David Tolnay18c754c2018-08-21 23:26:58 -04002
David Tolnayad4b2472018-08-25 08:25:24 -04003use error::Result;
David Tolnayaa77a852018-08-31 11:15:10 -07004use parse::ParseBuffer;
5#[cfg(any(feature = "full", feature = "derive"))]
6use parse::ParseStream;
David Tolnay94f06632018-08-31 10:17:17 -07007use private;
David Tolnay776f8e02018-08-24 22:32:10 -04008use token;
David Tolnay18c754c2018-08-21 23:26:58 -04009
David Tolnay734079e2018-09-01 02:03:37 -070010// Not public API.
11#[doc(hidden)]
David Tolnay42342c82018-08-25 08:36:35 -040012pub struct Parens<'a> {
13 pub token: token::Paren,
14 pub content: ParseBuffer<'a>,
15}
16
David Tolnay734079e2018-09-01 02:03:37 -070017// Not public API.
18#[doc(hidden)]
David Tolnay18c754c2018-08-21 23:26:58 -040019pub struct Braces<'a> {
20 pub token: token::Brace,
21 pub content: ParseBuffer<'a>,
22}
23
David Tolnay734079e2018-09-01 02:03:37 -070024// Not public API.
25#[doc(hidden)]
David Tolnay42342c82018-08-25 08:36:35 -040026pub struct Brackets<'a> {
27 pub token: token::Bracket,
28 pub content: ParseBuffer<'a>,
29}
30
David Tolnay734079e2018-09-01 02:03:37 -070031// Not public API.
David Tolnayaa77a852018-08-31 11:15:10 -070032#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay734079e2018-09-01 02:03:37 -070033#[doc(hidden)]
David Tolnaya7d69fc2018-08-26 13:30:24 -040034pub struct Group<'a> {
35 pub token: token::Group,
36 pub content: ParseBuffer<'a>,
37}
38
David Tolnay734079e2018-09-01 02:03:37 -070039// Not public API.
40#[doc(hidden)]
41pub fn parse_parens(input: ParseStream) -> Result<Parens> {
42 parse_delimited(input, Delimiter::Parenthesis)
43 .map(|(span, content)| Parens {
44 token: token::Paren(span),
45 content: content,
David Tolnay18c754c2018-08-21 23:26:58 -040046 })
David Tolnay734079e2018-09-01 02:03:37 -070047}
David Tolnay42342c82018-08-25 08:36:35 -040048
David Tolnay734079e2018-09-01 02:03:37 -070049// Not public API.
50#[doc(hidden)]
51pub fn parse_braces(input: ParseStream) -> Result<Braces> {
52 parse_delimited(input, Delimiter::Brace)
53 .map(|(span, content)| Braces {
54 token: token::Brace(span),
55 content: content,
56 })
57}
David Tolnay42342c82018-08-25 08:36:35 -040058
David Tolnay734079e2018-09-01 02:03:37 -070059// Not public API.
60#[doc(hidden)]
61pub fn parse_brackets(input: ParseStream) -> Result<Brackets> {
62 parse_delimited(input, Delimiter::Bracket)
63 .map(|(span, content)| Brackets {
64 token: token::Bracket(span),
65 content: content,
66 })
David Tolnayf57f76f2018-08-31 10:23:17 -070067}
David Tolnaya7d69fc2018-08-26 13:30:24 -040068
David Tolnayaa77a852018-08-31 11:15:10 -070069#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay10951d52018-08-31 10:27:39 -070070impl private {
David Tolnayf57f76f2018-08-31 10:23:17 -070071 pub fn parse_group(input: ParseStream) -> Result<Group> {
David Tolnay734079e2018-09-01 02:03:37 -070072 parse_delimited(input, Delimiter::None)
David Tolnaya7d69fc2018-08-26 13:30:24 -040073 .map(|(span, content)| Group {
74 token: token::Group(span),
75 content: content,
76 })
77 }
David Tolnay42342c82018-08-25 08:36:35 -040078}
79
David Tolnay734079e2018-09-01 02:03:37 -070080fn parse_delimited(input: ParseStream, delimiter: Delimiter) -> Result<(Span, ParseBuffer)> {
81 input.step(|cursor| {
82 if let Some((content, span, rest)) = cursor.group(delimiter) {
83 let unexpected = private::get_unexpected(input);
84 let content =
85 private::new_parse_buffer(span, cursor.advance(content), unexpected);
86 Ok(((span, content), rest))
87 } else {
88 let message = match delimiter {
89 Delimiter::Parenthesis => "expected parentheses",
90 Delimiter::Brace => "expected curly braces",
91 Delimiter::Bracket => "expected square brackets",
92 Delimiter::None => "expected invisible group",
93 };
94 Err(cursor.error(message))
95 }
96 })
97}
98
David Tolnay42342c82018-08-25 08:36:35 -040099/// Parse a set of parentheses and expose their content to subsequent parsers.
David Tolnay8bb9cca2018-09-01 01:50:19 -0700100///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700101/// # Example
102///
David Tolnay8bb9cca2018-09-01 01:50:19 -0700103/// ```rust
104/// # #[macro_use]
105/// # extern crate quote;
106/// #
107/// extern crate syn;
108///
109/// use syn::{parenthesized, token, Ident, Token, Type};
110/// use syn::parse::{Parse, ParseStream, Result};
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)?,
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/// ```
David Tolnay42342c82018-08-25 08:36:35 -0400144#[macro_export]
145macro_rules! parenthesized {
146 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700147 match $crate::group::parse_parens(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400148 $crate::export::Ok(parens) => {
149 $content = parens.content;
150 parens.token
151 }
152 $crate::export::Err(error) => {
153 return $crate::export::Err(error);
154 }
155 }
156 };
David Tolnay18c754c2018-08-21 23:26:58 -0400157}
158
159/// Parse a set of curly braces and expose their content to subsequent parsers.
160///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700161/// # Example
162///
David Tolnay18c754c2018-08-21 23:26:58 -0400163/// ```rust
David Tolnay44962212018-09-01 01:41:44 -0700164/// # extern crate quote;
165/// # use quote::quote;
David Tolnay18c754c2018-08-21 23:26:58 -0400166/// #
David Tolnay44962212018-09-01 01:41:44 -0700167/// extern crate syn;
168///
169/// use syn::{braced, token, Ident, Token, Type};
David Tolnayb6254182018-08-25 08:44:54 -0400170/// use syn::parse::{Parse, ParseStream, Result};
David Tolnaye7635332018-08-26 08:16:18 -0400171/// use syn::punctuated::Punctuated;
David Tolnay18c754c2018-08-21 23:26:58 -0400172///
173/// // Parse a simplified struct syntax like:
174/// //
175/// // struct S {
176/// // a: A,
177/// // b: B,
178/// // }
179/// struct Struct {
David Tolnay44962212018-09-01 01:41:44 -0700180/// struct_token: Token![struct],
181/// ident: Ident,
182/// brace_token: token::Brace,
183/// fields: Punctuated<Field, Token![,]>,
184/// }
185///
186/// struct Field {
187/// name: Ident,
188/// colon_token: Token![:],
189/// ty: Type,
David Tolnay18c754c2018-08-21 23:26:58 -0400190/// }
191///
192/// impl Parse for Struct {
193/// fn parse(input: ParseStream) -> Result<Self> {
194/// let content;
195/// Ok(Struct {
196/// struct_token: input.parse()?,
197/// ident: input.parse()?,
198/// brace_token: braced!(content in input),
David Tolnaye7635332018-08-26 08:16:18 -0400199/// fields: content.parse_terminated(Field::parse)?,
David Tolnay18c754c2018-08-21 23:26:58 -0400200/// })
201/// }
202/// }
David Tolnay44962212018-09-01 01:41:44 -0700203///
204/// impl Parse for Field {
205/// fn parse(input: ParseStream) -> Result<Self> {
206/// Ok(Field {
207/// name: input.parse()?,
208/// colon_token: input.parse()?,
209/// ty: input.parse()?,
210/// })
211/// }
212/// }
213/// #
214/// # fn main() {
215/// # let input = quote! {
216/// # struct S {
217/// # a: A,
218/// # b: B,
219/// # }
220/// # };
221/// # syn::parse2::<Struct>(input).unwrap();
222/// # }
David Tolnay18c754c2018-08-21 23:26:58 -0400223/// ```
224#[macro_export]
225macro_rules! braced {
226 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700227 match $crate::group::parse_braces(&$cursor) {
David Tolnay456c9822018-08-25 08:09:46 -0400228 $crate::export::Ok(braces) => {
David Tolnay18c754c2018-08-21 23:26:58 -0400229 $content = braces.content;
230 braces.token
231 }
David Tolnay456c9822018-08-25 08:09:46 -0400232 $crate::export::Err(error) => {
233 return $crate::export::Err(error);
David Tolnay18c754c2018-08-21 23:26:58 -0400234 }
235 }
236 };
237}
David Tolnay42342c82018-08-25 08:36:35 -0400238
239/// Parse a set of square brackets and expose their content to subsequent
240/// parsers.
David Tolnay1d2960c2018-09-01 01:57:19 -0700241///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700242/// # Example
243///
David Tolnay1d2960c2018-09-01 01:57:19 -0700244/// ```rust
245/// # #[macro_use]
246/// # extern crate quote;
247/// #
248/// extern crate proc_macro2;
249/// extern crate syn;
250///
251/// use proc_macro2::TokenStream;
252/// use syn::{bracketed, token, Token};
253/// use syn::parse::{Parse, ParseStream, Result};
254///
255/// // Parse an outer attribute like:
256/// //
257/// // #[repr(C, packed)]
258/// struct OuterAttribute {
259/// pound_token: Token![#],
260/// bracket_token: token::Bracket,
261/// content: TokenStream,
262/// }
263///
264/// impl Parse for OuterAttribute {
265/// fn parse(input: ParseStream) -> Result<Self> {
266/// let content;
267/// Ok(OuterAttribute {
268/// pound_token: input.parse()?,
269/// bracket_token: bracketed!(content in input),
270/// content: content.parse()?,
271/// })
272/// }
273/// }
274/// #
275/// # fn main() {
276/// # let input = quote! {
277/// # #[repr(C, packed)]
278/// # };
279/// # syn::parse2::<OuterAttribute>(input).unwrap();
280/// # }
281/// ```
David Tolnay42342c82018-08-25 08:36:35 -0400282#[macro_export]
283macro_rules! bracketed {
284 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700285 match $crate::group::parse_brackets(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400286 $crate::export::Ok(brackets) => {
287 $content = brackets.content;
288 brackets.token
289 }
290 $crate::export::Err(error) => {
291 return $crate::export::Err(error);
292 }
293 }
294 };
295}