1use super::*;
2
3ast_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
15ast_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
35ast_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")]
50pub 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")]
307mod 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