blob: 9eb005e59f4d742d302adb27d92691d8ce484f5a [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 Tolnayd658dab2018-09-01 02:47:42 -07004use parse::{ParseBuffer, ParseStream};
David Tolnay94f06632018-08-31 10:17:17 -07005use private;
David Tolnay776f8e02018-08-24 22:32:10 -04006use token;
David Tolnay18c754c2018-08-21 23:26:58 -04007
David Tolnay734079e2018-09-01 02:03:37 -07008// Not public API.
9#[doc(hidden)]
David Tolnay42342c82018-08-25 08:36:35 -040010pub struct Parens<'a> {
11 pub token: token::Paren,
12 pub content: ParseBuffer<'a>,
13}
14
David Tolnay734079e2018-09-01 02:03:37 -070015// Not public API.
16#[doc(hidden)]
David Tolnay18c754c2018-08-21 23:26:58 -040017pub struct Braces<'a> {
18 pub token: token::Brace,
19 pub content: ParseBuffer<'a>,
20}
21
David Tolnay734079e2018-09-01 02:03:37 -070022// Not public API.
23#[doc(hidden)]
David Tolnay42342c82018-08-25 08:36:35 -040024pub struct Brackets<'a> {
25 pub token: token::Bracket,
26 pub content: ParseBuffer<'a>,
27}
28
David Tolnay734079e2018-09-01 02:03:37 -070029// Not public API.
David Tolnayaa77a852018-08-31 11:15:10 -070030#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay734079e2018-09-01 02:03:37 -070031#[doc(hidden)]
David Tolnaya7d69fc2018-08-26 13:30:24 -040032pub struct Group<'a> {
33 pub token: token::Group,
34 pub content: ParseBuffer<'a>,
35}
36
David Tolnay734079e2018-09-01 02:03:37 -070037// Not public API.
38#[doc(hidden)]
39pub fn parse_parens(input: ParseStream) -> Result<Parens> {
David Tolnay70f30e92018-09-01 02:04:17 -070040 parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens {
41 token: token::Paren(span),
42 content: content,
43 })
David Tolnay734079e2018-09-01 02:03:37 -070044}
David Tolnay42342c82018-08-25 08:36:35 -040045
David Tolnay734079e2018-09-01 02:03:37 -070046// Not public API.
47#[doc(hidden)]
48pub fn parse_braces(input: ParseStream) -> Result<Braces> {
David Tolnay70f30e92018-09-01 02:04:17 -070049 parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces {
50 token: token::Brace(span),
51 content: content,
52 })
David Tolnay734079e2018-09-01 02:03:37 -070053}
David Tolnay42342c82018-08-25 08:36:35 -040054
David Tolnay734079e2018-09-01 02:03:37 -070055// Not public API.
56#[doc(hidden)]
57pub fn parse_brackets(input: ParseStream) -> Result<Brackets> {
David Tolnay70f30e92018-09-01 02:04:17 -070058 parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets {
59 token: token::Bracket(span),
60 content: content,
61 })
David Tolnayf57f76f2018-08-31 10:23:17 -070062}
David Tolnaya7d69fc2018-08-26 13:30:24 -040063
David Tolnayaa77a852018-08-31 11:15:10 -070064#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay10951d52018-08-31 10:27:39 -070065impl private {
David Tolnayf57f76f2018-08-31 10:23:17 -070066 pub fn parse_group(input: ParseStream) -> Result<Group> {
David Tolnay70f30e92018-09-01 02:04:17 -070067 parse_delimited(input, Delimiter::None).map(|(span, content)| Group {
68 token: token::Group(span),
69 content: content,
70 })
David Tolnaya7d69fc2018-08-26 13:30:24 -040071 }
David Tolnay42342c82018-08-25 08:36:35 -040072}
73
David Tolnay734079e2018-09-01 02:03:37 -070074fn parse_delimited(input: ParseStream, delimiter: Delimiter) -> Result<(Span, ParseBuffer)> {
75 input.step(|cursor| {
76 if let Some((content, span, rest)) = cursor.group(delimiter) {
77 let unexpected = private::get_unexpected(input);
David Tolnay70f30e92018-09-01 02:04:17 -070078 let content = private::new_parse_buffer(span, cursor.advance(content), unexpected);
David Tolnay734079e2018-09-01 02:03:37 -070079 Ok(((span, content), rest))
80 } else {
81 let message = match delimiter {
82 Delimiter::Parenthesis => "expected parentheses",
83 Delimiter::Brace => "expected curly braces",
84 Delimiter::Bracket => "expected square brackets",
85 Delimiter::None => "expected invisible group",
86 };
87 Err(cursor.error(message))
88 }
89 })
90}
91
David Tolnay42342c82018-08-25 08:36:35 -040092/// Parse a set of parentheses and expose their content to subsequent parsers.
David Tolnay8bb9cca2018-09-01 01:50:19 -070093///
David Tolnay0e5a4cb2018-09-01 01:58:02 -070094/// # Example
95///
David Tolnay8bb9cca2018-09-01 01:50:19 -070096/// ```rust
David Tolnay8bb9cca2018-09-01 01:50:19 -070097/// # extern crate quote;
David Tolnay9b00f652018-09-01 10:31:02 -070098/// # extern crate syn;
David Tolnay8bb9cca2018-09-01 01:50:19 -070099/// #
David Tolnay9b00f652018-09-01 10:31:02 -0700100/// # use quote::quote;
101/// #
David Tolnay8bb9cca2018-09-01 01:50:19 -0700102/// use syn::{parenthesized, token, Ident, Token, Type};
103/// use syn::parse::{Parse, ParseStream, Result};
104/// use syn::punctuated::Punctuated;
105///
106/// // Parse a simplified tuple struct syntax like:
107/// //
108/// // struct S(A, B);
109/// struct TupleStruct {
110/// struct_token: Token![struct],
111/// ident: Ident,
112/// paren_token: token::Paren,
113/// fields: Punctuated<Type, Token![,]>,
114/// semi_token: Token![;],
115/// }
116///
117/// impl Parse for TupleStruct {
118/// fn parse(input: ParseStream) -> Result<Self> {
119/// let content;
120/// Ok(TupleStruct {
121/// struct_token: input.parse()?,
122/// ident: input.parse()?,
123/// paren_token: parenthesized!(content in input),
124/// fields: content.parse_terminated(Type::parse)?,
125/// semi_token: input.parse()?,
126/// })
127/// }
128/// }
129/// #
130/// # fn main() {
131/// # let input = quote! {
132/// # struct S(A, B);
133/// # };
134/// # syn::parse2::<TupleStruct>(input).unwrap();
135/// # }
136/// ```
David Tolnay42342c82018-08-25 08:36:35 -0400137#[macro_export]
138macro_rules! parenthesized {
139 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700140 match $crate::group::parse_parens(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400141 $crate::export::Ok(parens) => {
142 $content = parens.content;
143 parens.token
144 }
145 $crate::export::Err(error) => {
146 return $crate::export::Err(error);
147 }
148 }
149 };
David Tolnay18c754c2018-08-21 23:26:58 -0400150}
151
152/// Parse a set of curly braces and expose their content to subsequent parsers.
153///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700154/// # Example
155///
David Tolnay18c754c2018-08-21 23:26:58 -0400156/// ```rust
David Tolnay44962212018-09-01 01:41:44 -0700157/// # extern crate quote;
David Tolnay9b00f652018-09-01 10:31:02 -0700158/// # extern crate syn;
159/// #
David Tolnay44962212018-09-01 01:41:44 -0700160/// # use quote::quote;
David Tolnay18c754c2018-08-21 23:26:58 -0400161/// #
David Tolnay44962212018-09-01 01:41:44 -0700162/// use syn::{braced, token, Ident, Token, Type};
David Tolnayb6254182018-08-25 08:44:54 -0400163/// use syn::parse::{Parse, ParseStream, Result};
David Tolnaye7635332018-08-26 08:16:18 -0400164/// use syn::punctuated::Punctuated;
David Tolnay18c754c2018-08-21 23:26:58 -0400165///
166/// // Parse a simplified struct syntax like:
167/// //
168/// // struct S {
169/// // a: A,
170/// // b: B,
171/// // }
172/// struct Struct {
David Tolnay44962212018-09-01 01:41:44 -0700173/// struct_token: Token![struct],
174/// ident: Ident,
175/// brace_token: token::Brace,
176/// fields: Punctuated<Field, Token![,]>,
177/// }
178///
179/// struct Field {
180/// name: Ident,
181/// colon_token: Token![:],
182/// ty: Type,
David Tolnay18c754c2018-08-21 23:26:58 -0400183/// }
184///
185/// impl Parse for Struct {
186/// fn parse(input: ParseStream) -> Result<Self> {
187/// let content;
188/// Ok(Struct {
189/// struct_token: input.parse()?,
190/// ident: input.parse()?,
191/// brace_token: braced!(content in input),
David Tolnaye7635332018-08-26 08:16:18 -0400192/// fields: content.parse_terminated(Field::parse)?,
David Tolnay18c754c2018-08-21 23:26:58 -0400193/// })
194/// }
195/// }
David Tolnay44962212018-09-01 01:41:44 -0700196///
197/// impl Parse for Field {
198/// fn parse(input: ParseStream) -> Result<Self> {
199/// Ok(Field {
200/// name: input.parse()?,
201/// colon_token: input.parse()?,
202/// ty: input.parse()?,
203/// })
204/// }
205/// }
206/// #
207/// # fn main() {
208/// # let input = quote! {
209/// # struct S {
210/// # a: A,
211/// # b: B,
212/// # }
213/// # };
214/// # syn::parse2::<Struct>(input).unwrap();
215/// # }
David Tolnay18c754c2018-08-21 23:26:58 -0400216/// ```
217#[macro_export]
218macro_rules! braced {
219 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700220 match $crate::group::parse_braces(&$cursor) {
David Tolnay456c9822018-08-25 08:09:46 -0400221 $crate::export::Ok(braces) => {
David Tolnay18c754c2018-08-21 23:26:58 -0400222 $content = braces.content;
223 braces.token
224 }
David Tolnay456c9822018-08-25 08:09:46 -0400225 $crate::export::Err(error) => {
226 return $crate::export::Err(error);
David Tolnay18c754c2018-08-21 23:26:58 -0400227 }
228 }
229 };
230}
David Tolnay42342c82018-08-25 08:36:35 -0400231
232/// Parse a set of square brackets and expose their content to subsequent
233/// parsers.
David Tolnay1d2960c2018-09-01 01:57:19 -0700234///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700235/// # Example
236///
David Tolnay1d2960c2018-09-01 01:57:19 -0700237/// ```rust
David Tolnay9b00f652018-09-01 10:31:02 -0700238/// # extern crate proc_macro2;
David Tolnay1d2960c2018-09-01 01:57:19 -0700239/// # extern crate quote;
David Tolnay9b00f652018-09-01 10:31:02 -0700240/// # extern crate syn;
David Tolnay1d2960c2018-09-01 01:57:19 -0700241/// #
David Tolnay9b00f652018-09-01 10:31:02 -0700242/// # use quote::quote;
243/// #
David Tolnay1d2960c2018-09-01 01:57:19 -0700244/// use proc_macro2::TokenStream;
245/// use syn::{bracketed, token, Token};
246/// use syn::parse::{Parse, ParseStream, Result};
247///
248/// // Parse an outer attribute like:
249/// //
250/// // #[repr(C, packed)]
251/// struct OuterAttribute {
252/// pound_token: Token![#],
253/// bracket_token: token::Bracket,
254/// content: TokenStream,
255/// }
256///
257/// impl Parse for OuterAttribute {
258/// fn parse(input: ParseStream) -> Result<Self> {
259/// let content;
260/// Ok(OuterAttribute {
261/// pound_token: input.parse()?,
262/// bracket_token: bracketed!(content in input),
263/// content: content.parse()?,
264/// })
265/// }
266/// }
267/// #
268/// # fn main() {
269/// # let input = quote! {
270/// # #[repr(C, packed)]
271/// # };
272/// # syn::parse2::<OuterAttribute>(input).unwrap();
273/// # }
274/// ```
David Tolnay42342c82018-08-25 08:36:35 -0400275#[macro_export]
276macro_rules! bracketed {
277 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700278 match $crate::group::parse_brackets(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400279 $crate::export::Ok(brackets) => {
280 $content = brackets.content;
281 brackets.token
282 }
283 $crate::export::Err(error) => {
284 return $crate::export::Err(error);
285 }
286 }
287 };
288}