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]) && (input.peek2(Token![mut]) || input.peek2(Ident)) 179 || input.peek(Token![const]) && !input.peek2(token::Brace) 180 || input.peek(Token![unsafe]) && !input.peek2(token::Brace) 181 || input.peek(Token![async]) 182 && (input.peek2(Token![unsafe]) 183 || input.peek2(Token![extern]) 184 || input.peek2(Token![fn])) 185 || input.peek(Token![fn]) 186 || input.peek(Token![mod]) 187 || input.peek(Token![type]) 188 || input.peek(Token![struct]) 189 || input.peek(Token![enum]) 190 || input.peek(Token![union]) && input.peek2(Ident) 191 || input.peek(Token![auto]) && input.peek2(Token![trait]) 192 || input.peek(Token![trait]) 193 || input.peek(Token![default]) 194 && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) 195 || input.peek(Token![impl]) 196 || input.peek(Token![macro]) 197 { 198 let mut item: Item = input.parse()?; 199 attrs.extend(item.replace_attrs(Vec::new())); 200 item.replace_attrs(attrs); 201 Ok(Stmt::Item(item)) 202 } else { 203 stmt_expr(input, allow_nosemi, attrs) 204 } 205 } 206 stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt>207 fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> { 208 let bang_token: Token![!] = input.parse()?; 209 let ident: Option<Ident> = input.parse()?; 210 let (delimiter, tokens) = mac::parse_delimiter(input)?; 211 let semi_token: Option<Token![;]> = input.parse()?; 212 213 Ok(Stmt::Item(Item::Macro(ItemMacro { 214 attrs, 215 ident, 216 mac: Macro { 217 path, 218 bang_token, 219 delimiter, 220 tokens, 221 }, 222 semi_token, 223 }))) 224 } 225 stmt_local(input: ParseStream, attrs: Vec<Attribute>, begin: ParseBuffer) -> Result<Stmt>226 fn stmt_local(input: ParseStream, attrs: Vec<Attribute>, begin: ParseBuffer) -> Result<Stmt> { 227 let let_token: Token![let] = input.parse()?; 228 229 let mut pat: Pat = pat::parsing::multi_pat_with_leading_vert(input)?; 230 if input.peek(Token![:]) { 231 let colon_token: Token![:] = input.parse()?; 232 let ty: Type = input.parse()?; 233 pat = Pat::Type(PatType { 234 attrs: Vec::new(), 235 pat: Box::new(pat), 236 colon_token, 237 ty: Box::new(ty), 238 }); 239 } 240 241 let init = if input.peek(Token![=]) { 242 let eq_token: Token![=] = input.parse()?; 243 let init: Expr = input.parse()?; 244 245 if input.peek(Token![else]) { 246 input.parse::<Token![else]>()?; 247 let content; 248 braced!(content in input); 249 content.call(Block::parse_within)?; 250 let verbatim = Expr::Verbatim(verbatim::between(begin, input)); 251 let semi_token: Token![;] = input.parse()?; 252 return Ok(Stmt::Semi(verbatim, semi_token)); 253 } 254 255 Some((eq_token, Box::new(init))) 256 } else { 257 None 258 }; 259 260 let semi_token: Token![;] = input.parse()?; 261 262 Ok(Stmt::Local(Local { 263 attrs, 264 let_token, 265 pat, 266 init, 267 semi_token, 268 })) 269 } 270 stmt_expr( input: ParseStream, allow_nosemi: bool, mut attrs: Vec<Attribute>, ) -> Result<Stmt>271 fn stmt_expr( 272 input: ParseStream, 273 allow_nosemi: bool, 274 mut attrs: Vec<Attribute>, 275 ) -> Result<Stmt> { 276 let mut e = expr::parsing::expr_early(input)?; 277 278 let mut attr_target = &mut e; 279 loop { 280 attr_target = match attr_target { 281 Expr::Assign(e) => &mut e.left, 282 Expr::AssignOp(e) => &mut e.left, 283 Expr::Binary(e) => &mut e.left, 284 _ => break, 285 }; 286 } 287 attrs.extend(attr_target.replace_attrs(Vec::new())); 288 attr_target.replace_attrs(attrs); 289 290 if input.peek(Token![;]) { 291 return Ok(Stmt::Semi(e, input.parse()?)); 292 } 293 294 if allow_nosemi || !expr::requires_terminator(&e) { 295 Ok(Stmt::Expr(e)) 296 } else { 297 Err(input.error("expected semicolon")) 298 } 299 } 300 } 301 302 #[cfg(feature = "printing")] 303 mod printing { 304 use super::*; 305 use proc_macro2::TokenStream; 306 use quote::{ToTokens, TokenStreamExt}; 307 308 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 309 impl ToTokens for Block { to_tokens(&self, tokens: &mut TokenStream)310 fn to_tokens(&self, tokens: &mut TokenStream) { 311 self.brace_token.surround(tokens, |tokens| { 312 tokens.append_all(&self.stmts); 313 }); 314 } 315 } 316 317 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 318 impl ToTokens for Stmt { to_tokens(&self, tokens: &mut TokenStream)319 fn to_tokens(&self, tokens: &mut TokenStream) { 320 match self { 321 Stmt::Local(local) => local.to_tokens(tokens), 322 Stmt::Item(item) => item.to_tokens(tokens), 323 Stmt::Expr(expr) => expr.to_tokens(tokens), 324 Stmt::Semi(expr, semi) => { 325 expr.to_tokens(tokens); 326 semi.to_tokens(tokens); 327 } 328 } 329 } 330 } 331 332 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 333 impl ToTokens for Local { to_tokens(&self, tokens: &mut TokenStream)334 fn to_tokens(&self, tokens: &mut TokenStream) { 335 expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); 336 self.let_token.to_tokens(tokens); 337 self.pat.to_tokens(tokens); 338 if let Some((eq_token, init)) = &self.init { 339 eq_token.to_tokens(tokens); 340 init.to_tokens(tokens); 341 } 342 self.semi_token.to_tokens(tokens); 343 } 344 } 345 } 346