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