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