blob: 272e435f242cb0d0b688dc957a6e20d884fcfa06 [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) {
David Tolnayfe89fcc2018-09-08 17:56:31 -070077 #[cfg(procmacro2_semver_exempt)]
78 let scope = private::close_span_of_group(*cursor);
79 #[cfg(not(procmacro2_semver_exempt))]
80 let scope = span;
David Tolnay6ea3fdc2018-09-01 13:30:53 -070081 let nested = private::advance_step_cursor(cursor, content);
David Tolnayfe89fcc2018-09-08 17:56:31 -070082 let unexpected = private::get_unexpected(input);
83 let content = private::new_parse_buffer(scope, nested, unexpected);
David Tolnay734079e2018-09-01 02:03:37 -070084 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
David Tolnay42342c82018-08-25 08:36:35 -040097/// Parse a set of parentheses and expose their content to subsequent parsers.
David Tolnay8bb9cca2018-09-01 01:50:19 -070098///
David Tolnay0e5a4cb2018-09-01 01:58:02 -070099/// # Example
100///
David Tolnay95989db2019-01-01 15:05:57 -0500101/// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -0500102/// # use quote::quote;
David Tolnay8bb9cca2018-09-01 01:50:19 -0700103/// #
David Tolnayfd5b1172018-12-31 17:54:36 -0500104/// use syn::{parenthesized, token, Ident, Result, Token, Type};
David Tolnay67fea042018-11-24 14:50:20 -0800105/// use syn::parse::{Parse, ParseStream};
David Tolnay8bb9cca2018-09-01 01:50:19 -0700106/// 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/// ```
David Tolnay42342c82018-08-25 08:36:35 -0400139#[macro_export]
140macro_rules! parenthesized {
141 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700142 match $crate::group::parse_parens(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400143 $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 };
David Tolnay18c754c2018-08-21 23:26:58 -0400152}
153
154/// Parse a set of curly braces and expose their content to subsequent parsers.
155///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700156/// # Example
157///
David Tolnay95989db2019-01-01 15:05:57 -0500158/// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -0500159/// # use quote::quote;
David Tolnay9b00f652018-09-01 10:31:02 -0700160/// #
David Tolnayfd5b1172018-12-31 17:54:36 -0500161/// use syn::{braced, token, Ident, Result, Token, Type};
David Tolnay67fea042018-11-24 14:50:20 -0800162/// use syn::parse::{Parse, ParseStream};
David Tolnaye7635332018-08-26 08:16:18 -0400163/// use syn::punctuated::Punctuated;
David Tolnay18c754c2018-08-21 23:26:58 -0400164///
165/// // Parse a simplified struct syntax like:
166/// //
167/// // struct S {
168/// // a: A,
169/// // b: B,
170/// // }
171/// struct Struct {
David Tolnay44962212018-09-01 01:41:44 -0700172/// 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,
David Tolnay18c754c2018-08-21 23:26:58 -0400182/// }
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),
David Tolnaye7635332018-08-26 08:16:18 -0400191/// fields: content.parse_terminated(Field::parse)?,
David Tolnay18c754c2018-08-21 23:26:58 -0400192/// })
193/// }
194/// }
David Tolnay44962212018-09-01 01:41:44 -0700195///
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/// # }
David Tolnay18c754c2018-08-21 23:26:58 -0400215/// ```
216#[macro_export]
217macro_rules! braced {
218 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700219 match $crate::group::parse_braces(&$cursor) {
David Tolnay456c9822018-08-25 08:09:46 -0400220 $crate::export::Ok(braces) => {
David Tolnay18c754c2018-08-21 23:26:58 -0400221 $content = braces.content;
222 braces.token
223 }
David Tolnay456c9822018-08-25 08:09:46 -0400224 $crate::export::Err(error) => {
225 return $crate::export::Err(error);
David Tolnay18c754c2018-08-21 23:26:58 -0400226 }
227 }
228 };
229}
David Tolnay42342c82018-08-25 08:36:35 -0400230
231/// Parse a set of square brackets and expose their content to subsequent
232/// parsers.
David Tolnay1d2960c2018-09-01 01:57:19 -0700233///
David Tolnay0e5a4cb2018-09-01 01:58:02 -0700234/// # Example
235///
David Tolnay95989db2019-01-01 15:05:57 -0500236/// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -0500237/// # use quote::quote;
238/// #
David Tolnay1d2960c2018-09-01 01:57:19 -0700239/// use proc_macro2::TokenStream;
David Tolnayfd5b1172018-12-31 17:54:36 -0500240/// use syn::{bracketed, token, Result, Token};
David Tolnay67fea042018-11-24 14:50:20 -0800241/// use syn::parse::{Parse, ParseStream};
David Tolnay1d2960c2018-09-01 01:57:19 -0700242///
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/// ```
David Tolnay42342c82018-08-25 08:36:35 -0400270#[macro_export]
271macro_rules! bracketed {
272 ($content:ident in $cursor:expr) => {
David Tolnay734079e2018-09-01 02:03:37 -0700273 match $crate::group::parse_brackets(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400274 $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}