• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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")))]
parse_within(input: ParseStream) -> Result<Vec<Stmt>>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 {
parse(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>149         fn parse(input: ParseStream) -> Result<Self> {
150             parse_stmt(input, false)
151         }
152     }
153 
parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt>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 
stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt>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 
stmt_local(input: ParseStream, attrs: Vec<Attribute>, begin: ParseBuffer) -> Result<Stmt>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 
stmt_expr( input: ParseStream, allow_nosemi: bool, mut attrs: Vec<Attribute>, ) -> Result<Stmt>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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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