1 | use super::*; |
2 | |
3 | ast_struct! { |
4 | /// A braced block containing Rust statements. |
5 | /// |
6 | /// *This type is available only if Syn is built with the `"full"` feature.* |
7 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
8 | pub struct Block { |
9 | pub brace_token: token::Brace, |
10 | /// Statements in a block |
11 | pub stmts: Vec<Stmt>, |
12 | } |
13 | } |
14 | |
15 | ast_enum! { |
16 | /// A statement, usually ending in a semicolon. |
17 | /// |
18 | /// *This type is available only if Syn is built with the `"full"` feature.* |
19 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
20 | pub enum Stmt { |
21 | /// A local (let) binding. |
22 | Local(Local), |
23 | |
24 | /// An item definition. |
25 | Item(Item), |
26 | |
27 | /// Expr without trailing semicolon. |
28 | Expr(Expr), |
29 | |
30 | /// Expression with trailing semicolon. |
31 | Semi(Expr, Token![;]), |
32 | } |
33 | } |
34 | |
35 | ast_struct! { |
36 | /// A local `let` binding: `let x: u64 = s.parse()?`. |
37 | /// |
38 | /// *This type is available only if Syn is built with the `"full"` feature.* |
39 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
40 | pub struct Local { |
41 | pub attrs: Vec<Attribute>, |
42 | pub let_token: Token![let], |
43 | pub pat: Pat, |
44 | pub init: Option<(Token![=], Box<Expr>)>, |
45 | pub semi_token: Token![;], |
46 | } |
47 | } |
48 | |
49 | #[cfg (feature = "parsing" )] |
50 | pub mod parsing { |
51 | use super::*; |
52 | use crate::parse::discouraged::Speculative; |
53 | use crate::parse::{Parse, ParseBuffer, ParseStream, Result}; |
54 | use proc_macro2::TokenStream; |
55 | |
56 | impl Block { |
57 | /// Parse the body of a block as zero or more statements, possibly |
58 | /// including one trailing expression. |
59 | /// |
60 | /// *This function is available only if Syn is built with the `"parsing"` |
61 | /// feature.* |
62 | /// |
63 | /// # Example |
64 | /// |
65 | /// ``` |
66 | /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token}; |
67 | /// use syn::parse::{Parse, ParseStream}; |
68 | /// |
69 | /// // Parse a function with no generics or parameter list. |
70 | /// // |
71 | /// // fn playground { |
72 | /// // let mut x = 1; |
73 | /// // x += 1; |
74 | /// // println!("{}", x); |
75 | /// // } |
76 | /// struct MiniFunction { |
77 | /// attrs: Vec<Attribute>, |
78 | /// fn_token: Token![fn], |
79 | /// name: Ident, |
80 | /// brace_token: token::Brace, |
81 | /// stmts: Vec<Stmt>, |
82 | /// } |
83 | /// |
84 | /// impl Parse for MiniFunction { |
85 | /// fn parse(input: ParseStream) -> Result<Self> { |
86 | /// let outer_attrs = input.call(Attribute::parse_outer)?; |
87 | /// let fn_token: Token![fn] = input.parse()?; |
88 | /// let name: Ident = input.parse()?; |
89 | /// |
90 | /// let content; |
91 | /// let brace_token = braced!(content in input); |
92 | /// let inner_attrs = content.call(Attribute::parse_inner)?; |
93 | /// let stmts = content.call(Block::parse_within)?; |
94 | /// |
95 | /// Ok(MiniFunction { |
96 | /// attrs: { |
97 | /// let mut attrs = outer_attrs; |
98 | /// attrs.extend(inner_attrs); |
99 | /// attrs |
100 | /// }, |
101 | /// fn_token, |
102 | /// name, |
103 | /// brace_token, |
104 | /// stmts, |
105 | /// }) |
106 | /// } |
107 | /// } |
108 | /// ``` |
109 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
110 | pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> { |
111 | let mut stmts = Vec::new(); |
112 | loop { |
113 | while let Some(semi) = input.parse::<Option<Token![;]>>()? { |
114 | stmts.push(Stmt::Semi(Expr::Verbatim(TokenStream::new()), semi)); |
115 | } |
116 | if input.is_empty() { |
117 | break; |
118 | } |
119 | let s = parse_stmt(input, true)?; |
120 | let requires_semicolon = if let Stmt::Expr(s) = &s { |
121 | expr::requires_terminator(s) |
122 | } else { |
123 | false |
124 | }; |
125 | stmts.push(s); |
126 | if input.is_empty() { |
127 | break; |
128 | } else if requires_semicolon { |
129 | return Err(input.error("unexpected token" )); |
130 | } |
131 | } |
132 | Ok(stmts) |
133 | } |
134 | } |
135 | |
136 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
137 | impl Parse for Block { |
138 | fn parse(input: ParseStream) -> Result<Self> { |
139 | let content; |
140 | Ok(Block { |
141 | brace_token: braced!(content in input), |
142 | stmts: content.call(Block::parse_within)?, |
143 | }) |
144 | } |
145 | } |
146 | |
147 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
148 | impl Parse for Stmt { |
149 | fn parse(input: ParseStream) -> Result<Self> { |
150 | parse_stmt(input, false) |
151 | } |
152 | } |
153 | |
154 | fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> { |
155 | let begin = input.fork(); |
156 | let mut attrs = input.call(Attribute::parse_outer)?; |
157 | |
158 | // brace-style macros; paren and bracket macros get parsed as |
159 | // expression statements. |
160 | let ahead = input.fork(); |
161 | if let Ok(path) = ahead.call(Path::parse_mod_style) { |
162 | if ahead.peek(Token![!]) |
163 | && (ahead.peek2(token::Brace) |
164 | && !(ahead.peek3(Token![.]) || ahead.peek3(Token![?])) |
165 | || ahead.peek2(Ident)) |
166 | { |
167 | input.advance_to(&ahead); |
168 | return stmt_mac(input, attrs, path); |
169 | } |
170 | } |
171 | |
172 | if input.peek(Token![let]) { |
173 | stmt_local(input, attrs, begin) |
174 | } else if input.peek(Token![pub]) |
175 | || input.peek(Token![crate]) && !input.peek2(Token![::]) |
176 | || input.peek(Token![extern]) |
177 | || input.peek(Token![use]) |
178 | || input.peek(Token![static]) |
179 | && (input.peek2(Token![mut]) |
180 | || input.peek2(Ident) |
181 | && !(input.peek2(Token![async]) |
182 | && (input.peek3(Token![move]) || input.peek3(Token![|])))) |
183 | || input.peek(Token![const]) && !input.peek2(token::Brace) |
184 | || input.peek(Token![unsafe]) && !input.peek2(token::Brace) |
185 | || input.peek(Token![async]) |
186 | && (input.peek2(Token![unsafe]) |
187 | || input.peek2(Token![extern]) |
188 | || input.peek2(Token![fn])) |
189 | || input.peek(Token![fn]) |
190 | || input.peek(Token![mod]) |
191 | || input.peek(Token![type]) |
192 | || input.peek(Token![struct]) |
193 | || input.peek(Token![enum]) |
194 | || input.peek(Token![union]) && input.peek2(Ident) |
195 | || input.peek(Token![auto]) && input.peek2(Token![trait]) |
196 | || input.peek(Token![trait]) |
197 | || input.peek(Token![default]) |
198 | && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) |
199 | || input.peek(Token![impl]) |
200 | || input.peek(Token![macro]) |
201 | { |
202 | let mut item: Item = input.parse()?; |
203 | attrs.extend(item.replace_attrs(Vec::new())); |
204 | item.replace_attrs(attrs); |
205 | Ok(Stmt::Item(item)) |
206 | } else { |
207 | stmt_expr(input, allow_nosemi, attrs) |
208 | } |
209 | } |
210 | |
211 | fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> { |
212 | let bang_token: Token![!] = input.parse()?; |
213 | let ident: Option<Ident> = input.parse()?; |
214 | let (delimiter, tokens) = mac::parse_delimiter(input)?; |
215 | let semi_token: Option<Token![;]> = input.parse()?; |
216 | |
217 | Ok(Stmt::Item(Item::Macro(ItemMacro { |
218 | attrs, |
219 | ident, |
220 | mac: Macro { |
221 | path, |
222 | bang_token, |
223 | delimiter, |
224 | tokens, |
225 | }, |
226 | semi_token, |
227 | }))) |
228 | } |
229 | |
230 | fn stmt_local(input: ParseStream, attrs: Vec<Attribute>, begin: ParseBuffer) -> Result<Stmt> { |
231 | let let_token: Token![let] = input.parse()?; |
232 | |
233 | let mut pat: Pat = pat::parsing::multi_pat_with_leading_vert(input)?; |
234 | if input.peek(Token![:]) { |
235 | let colon_token: Token![:] = input.parse()?; |
236 | let ty: Type = input.parse()?; |
237 | pat = Pat::Type(PatType { |
238 | attrs: Vec::new(), |
239 | pat: Box::new(pat), |
240 | colon_token, |
241 | ty: Box::new(ty), |
242 | }); |
243 | } |
244 | |
245 | let init = if input.peek(Token![=]) { |
246 | let eq_token: Token![=] = input.parse()?; |
247 | let init: Expr = input.parse()?; |
248 | |
249 | if input.peek(Token![else]) { |
250 | input.parse::<Token![else]>()?; |
251 | let content; |
252 | braced!(content in input); |
253 | content.call(Block::parse_within)?; |
254 | let verbatim = Expr::Verbatim(verbatim::between(begin, input)); |
255 | let semi_token: Token![;] = input.parse()?; |
256 | return Ok(Stmt::Semi(verbatim, semi_token)); |
257 | } |
258 | |
259 | Some((eq_token, Box::new(init))) |
260 | } else { |
261 | None |
262 | }; |
263 | |
264 | let semi_token: Token![;] = input.parse()?; |
265 | |
266 | Ok(Stmt::Local(Local { |
267 | attrs, |
268 | let_token, |
269 | pat, |
270 | init, |
271 | semi_token, |
272 | })) |
273 | } |
274 | |
275 | fn stmt_expr( |
276 | input: ParseStream, |
277 | allow_nosemi: bool, |
278 | mut attrs: Vec<Attribute>, |
279 | ) -> Result<Stmt> { |
280 | let mut e = expr::parsing::expr_early(input)?; |
281 | |
282 | let mut attr_target = &mut e; |
283 | loop { |
284 | attr_target = match attr_target { |
285 | Expr::Assign(e) => &mut e.left, |
286 | Expr::AssignOp(e) => &mut e.left, |
287 | Expr::Binary(e) => &mut e.left, |
288 | _ => break, |
289 | }; |
290 | } |
291 | attrs.extend(attr_target.replace_attrs(Vec::new())); |
292 | attr_target.replace_attrs(attrs); |
293 | |
294 | if input.peek(Token![;]) { |
295 | return Ok(Stmt::Semi(e, input.parse()?)); |
296 | } |
297 | |
298 | if allow_nosemi || !expr::requires_terminator(&e) { |
299 | Ok(Stmt::Expr(e)) |
300 | } else { |
301 | Err(input.error("expected semicolon" )) |
302 | } |
303 | } |
304 | } |
305 | |
306 | #[cfg (feature = "printing" )] |
307 | mod printing { |
308 | use super::*; |
309 | use proc_macro2::TokenStream; |
310 | use quote::{ToTokens, TokenStreamExt}; |
311 | |
312 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
313 | impl ToTokens for Block { |
314 | fn to_tokens(&self, tokens: &mut TokenStream) { |
315 | self.brace_token.surround(tokens, |tokens| { |
316 | tokens.append_all(&self.stmts); |
317 | }); |
318 | } |
319 | } |
320 | |
321 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
322 | impl ToTokens for Stmt { |
323 | fn to_tokens(&self, tokens: &mut TokenStream) { |
324 | match self { |
325 | Stmt::Local(local) => local.to_tokens(tokens), |
326 | Stmt::Item(item) => item.to_tokens(tokens), |
327 | Stmt::Expr(expr) => expr.to_tokens(tokens), |
328 | Stmt::Semi(expr, semi) => { |
329 | expr.to_tokens(tokens); |
330 | semi.to_tokens(tokens); |
331 | } |
332 | } |
333 | } |
334 | } |
335 | |
336 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
337 | impl ToTokens for Local { |
338 | fn to_tokens(&self, tokens: &mut TokenStream) { |
339 | expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); |
340 | self.let_token.to_tokens(tokens); |
341 | self.pat.to_tokens(tokens); |
342 | if let Some((eq_token, init)) = &self.init { |
343 | eq_token.to_tokens(tokens); |
344 | init.to_tokens(tokens); |
345 | } |
346 | self.semi_token.to_tokens(tokens); |
347 | } |
348 | } |
349 | } |
350 | |