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, 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 mut attrs = input.call(Attribute::parse_outer)?; 156 157 // brace-style macros; paren and bracket macros get parsed as 158 // expression statements. 159 let ahead = input.fork(); 160 if let Ok(path) = ahead.call(Path::parse_mod_style) { 161 if ahead.peek(Token![!]) && (ahead.peek2(token::Brace) || ahead.peek2(Ident)) { 162 input.advance_to(&ahead); 163 return stmt_mac(input, attrs, path); 164 } 165 } 166 167 if input.peek(Token![let]) { 168 stmt_local(input, attrs).map(Stmt::Local) 169 } else if input.peek(Token![pub]) 170 || input.peek(Token![crate]) && !input.peek2(Token![::]) 171 || input.peek(Token![extern]) 172 || input.peek(Token![use]) 173 || input.peek(Token![static]) && (input.peek2(Token![mut]) || input.peek2(Ident)) 174 || input.peek(Token![const]) && !input.peek2(token::Brace) 175 || input.peek(Token![unsafe]) && !input.peek2(token::Brace) 176 || input.peek(Token![async]) 177 && (input.peek2(Token![unsafe]) 178 || input.peek2(Token![extern]) 179 || input.peek2(Token![fn])) 180 || input.peek(Token![fn]) 181 || input.peek(Token![mod]) 182 || input.peek(Token![type]) 183 || input.peek(item::parsing::existential) && input.peek2(Token![type]) 184 || input.peek(Token![struct]) 185 || input.peek(Token![enum]) 186 || input.peek(Token![union]) && input.peek2(Ident) 187 || input.peek(Token![auto]) && input.peek2(Token![trait]) 188 || input.peek(Token![trait]) 189 || input.peek(Token![default]) 190 && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) 191 || input.peek(Token![impl]) 192 || input.peek(Token![macro]) 193 { 194 let mut item: Item = input.parse()?; 195 attrs.extend(item.replace_attrs(Vec::new())); 196 item.replace_attrs(attrs); 197 Ok(Stmt::Item(item)) 198 } else { 199 stmt_expr(input, allow_nosemi, attrs) 200 } 201 } 202 stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt>203 fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> { 204 let bang_token: Token![!] = input.parse()?; 205 let ident: Option<Ident> = input.parse()?; 206 let (delimiter, tokens) = mac::parse_delimiter(input)?; 207 let semi_token: Option<Token![;]> = input.parse()?; 208 209 Ok(Stmt::Item(Item::Macro(ItemMacro { 210 attrs, 211 ident, 212 mac: Macro { 213 path, 214 bang_token, 215 delimiter, 216 tokens, 217 }, 218 semi_token, 219 }))) 220 } 221 stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local>222 fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> { 223 Ok(Local { 224 attrs, 225 let_token: input.parse()?, 226 pat: { 227 let mut pat: Pat = pat::parsing::multi_pat_with_leading_vert(input)?; 228 if input.peek(Token![:]) { 229 let colon_token: Token![:] = input.parse()?; 230 let ty: Type = input.parse()?; 231 pat = Pat::Type(PatType { 232 attrs: Vec::new(), 233 pat: Box::new(pat), 234 colon_token, 235 ty: Box::new(ty), 236 }); 237 } 238 pat 239 }, 240 init: { 241 if input.peek(Token![=]) { 242 let eq_token: Token![=] = input.parse()?; 243 let init: Expr = input.parse()?; 244 Some((eq_token, Box::new(init))) 245 } else { 246 None 247 } 248 }, 249 semi_token: input.parse()?, 250 }) 251 } 252 stmt_expr( input: ParseStream, allow_nosemi: bool, mut attrs: Vec<Attribute>, ) -> Result<Stmt>253 fn stmt_expr( 254 input: ParseStream, 255 allow_nosemi: bool, 256 mut attrs: Vec<Attribute>, 257 ) -> Result<Stmt> { 258 let mut e = expr::parsing::expr_early(input)?; 259 260 let mut attr_target = &mut e; 261 while let Expr::Binary(e) = attr_target { 262 attr_target = &mut e.left; 263 } 264 attrs.extend(attr_target.replace_attrs(Vec::new())); 265 attr_target.replace_attrs(attrs); 266 267 if input.peek(Token![;]) { 268 return Ok(Stmt::Semi(e, input.parse()?)); 269 } 270 271 if allow_nosemi || !expr::requires_terminator(&e) { 272 Ok(Stmt::Expr(e)) 273 } else { 274 Err(input.error("expected semicolon")) 275 } 276 } 277 } 278 279 #[cfg(feature = "printing")] 280 mod printing { 281 use super::*; 282 use proc_macro2::TokenStream; 283 use quote::{ToTokens, TokenStreamExt}; 284 285 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 286 impl ToTokens for Block { to_tokens(&self, tokens: &mut TokenStream)287 fn to_tokens(&self, tokens: &mut TokenStream) { 288 self.brace_token.surround(tokens, |tokens| { 289 tokens.append_all(&self.stmts); 290 }); 291 } 292 } 293 294 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 295 impl ToTokens for Stmt { to_tokens(&self, tokens: &mut TokenStream)296 fn to_tokens(&self, tokens: &mut TokenStream) { 297 match self { 298 Stmt::Local(local) => local.to_tokens(tokens), 299 Stmt::Item(item) => item.to_tokens(tokens), 300 Stmt::Expr(expr) => expr.to_tokens(tokens), 301 Stmt::Semi(expr, semi) => { 302 expr.to_tokens(tokens); 303 semi.to_tokens(tokens); 304 } 305 } 306 } 307 } 308 309 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 310 impl ToTokens for Local { to_tokens(&self, tokens: &mut TokenStream)311 fn to_tokens(&self, tokens: &mut TokenStream) { 312 expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); 313 self.let_token.to_tokens(tokens); 314 self.pat.to_tokens(tokens); 315 if let Some((eq_token, init)) = &self.init { 316 eq_token.to_tokens(tokens); 317 init.to_tokens(tokens); 318 } 319 self.semi_token.to_tokens(tokens); 320 } 321 } 322 } 323