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