1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT 2*69942c0aSMiguel Ojeda 3808c999fSMiguel Ojeda use crate::attr::Attribute; 4808c999fSMiguel Ojeda use crate::expr::Expr; 5808c999fSMiguel Ojeda use crate::item::Item; 6808c999fSMiguel Ojeda use crate::mac::Macro; 7808c999fSMiguel Ojeda use crate::pat::Pat; 8808c999fSMiguel Ojeda use crate::token; 9808c999fSMiguel Ojeda 10808c999fSMiguel Ojeda ast_struct! { 11808c999fSMiguel Ojeda /// A braced block containing Rust statements. 12808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 13808c999fSMiguel Ojeda pub struct Block { 14808c999fSMiguel Ojeda pub brace_token: token::Brace, 15808c999fSMiguel Ojeda /// Statements in a block 16808c999fSMiguel Ojeda pub stmts: Vec<Stmt>, 17808c999fSMiguel Ojeda } 18808c999fSMiguel Ojeda } 19808c999fSMiguel Ojeda 20808c999fSMiguel Ojeda ast_enum! { 21808c999fSMiguel Ojeda /// A statement, usually ending in a semicolon. 22808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 23808c999fSMiguel Ojeda pub enum Stmt { 24808c999fSMiguel Ojeda /// A local (let) binding. 25808c999fSMiguel Ojeda Local(Local), 26808c999fSMiguel Ojeda 27808c999fSMiguel Ojeda /// An item definition. 28808c999fSMiguel Ojeda Item(Item), 29808c999fSMiguel Ojeda 30808c999fSMiguel Ojeda /// Expression, with or without trailing semicolon. 31808c999fSMiguel Ojeda Expr(Expr, Option<Token![;]>), 32808c999fSMiguel Ojeda 33808c999fSMiguel Ojeda /// A macro invocation in statement position. 34808c999fSMiguel Ojeda /// 35808c999fSMiguel Ojeda /// Syntactically it's ambiguous which other kind of statement this 36808c999fSMiguel Ojeda /// macro would expand to. It can be any of local variable (`let`), 37808c999fSMiguel Ojeda /// item, or expression. 38808c999fSMiguel Ojeda Macro(StmtMacro), 39808c999fSMiguel Ojeda } 40808c999fSMiguel Ojeda } 41808c999fSMiguel Ojeda 42808c999fSMiguel Ojeda ast_struct! { 43808c999fSMiguel Ojeda /// A local `let` binding: `let x: u64 = s.parse()?;`. 44808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 45808c999fSMiguel Ojeda pub struct Local { 46808c999fSMiguel Ojeda pub attrs: Vec<Attribute>, 47808c999fSMiguel Ojeda pub let_token: Token![let], 48808c999fSMiguel Ojeda pub pat: Pat, 49808c999fSMiguel Ojeda pub init: Option<LocalInit>, 50808c999fSMiguel Ojeda pub semi_token: Token![;], 51808c999fSMiguel Ojeda } 52808c999fSMiguel Ojeda } 53808c999fSMiguel Ojeda 54808c999fSMiguel Ojeda ast_struct! { 55808c999fSMiguel Ojeda /// The expression assigned in a local `let` binding, including optional 56808c999fSMiguel Ojeda /// diverging `else` block. 57808c999fSMiguel Ojeda /// 58808c999fSMiguel Ojeda /// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and 59808c999fSMiguel Ojeda /// `= r else { return }` in `let Ok(x) = r else { return }`. 60808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 61808c999fSMiguel Ojeda pub struct LocalInit { 62808c999fSMiguel Ojeda pub eq_token: Token![=], 63808c999fSMiguel Ojeda pub expr: Box<Expr>, 64808c999fSMiguel Ojeda pub diverge: Option<(Token![else], Box<Expr>)>, 65808c999fSMiguel Ojeda } 66808c999fSMiguel Ojeda } 67808c999fSMiguel Ojeda 68808c999fSMiguel Ojeda ast_struct! { 69808c999fSMiguel Ojeda /// A macro invocation in statement position. 70808c999fSMiguel Ojeda /// 71808c999fSMiguel Ojeda /// Syntactically it's ambiguous which other kind of statement this macro 72808c999fSMiguel Ojeda /// would expand to. It can be any of local variable (`let`), item, or 73808c999fSMiguel Ojeda /// expression. 74808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))] 75808c999fSMiguel Ojeda pub struct StmtMacro { 76808c999fSMiguel Ojeda pub attrs: Vec<Attribute>, 77808c999fSMiguel Ojeda pub mac: Macro, 78808c999fSMiguel Ojeda pub semi_token: Option<Token![;]>, 79808c999fSMiguel Ojeda } 80808c999fSMiguel Ojeda } 81808c999fSMiguel Ojeda 82808c999fSMiguel Ojeda #[cfg(feature = "parsing")] 83808c999fSMiguel Ojeda pub(crate) mod parsing { 84808c999fSMiguel Ojeda use crate::attr::Attribute; 85808c999fSMiguel Ojeda use crate::classify; 86808c999fSMiguel Ojeda use crate::error::Result; 87808c999fSMiguel Ojeda use crate::expr::{Expr, ExprBlock, ExprMacro}; 88808c999fSMiguel Ojeda use crate::ident::Ident; 89808c999fSMiguel Ojeda use crate::item; 90808c999fSMiguel Ojeda use crate::mac::{self, Macro}; 91808c999fSMiguel Ojeda use crate::parse::discouraged::Speculative as _; 92808c999fSMiguel Ojeda use crate::parse::{Parse, ParseStream}; 93808c999fSMiguel Ojeda use crate::pat::{Pat, PatType}; 94808c999fSMiguel Ojeda use crate::path::Path; 95808c999fSMiguel Ojeda use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro}; 96808c999fSMiguel Ojeda use crate::token; 97808c999fSMiguel Ojeda use crate::ty::Type; 98808c999fSMiguel Ojeda use proc_macro2::TokenStream; 99808c999fSMiguel Ojeda 100808c999fSMiguel Ojeda struct AllowNoSemi(bool); 101808c999fSMiguel Ojeda 102808c999fSMiguel Ojeda impl Block { 103808c999fSMiguel Ojeda /// Parse the body of a block as zero or more statements, possibly 104808c999fSMiguel Ojeda /// including one trailing expression. 105808c999fSMiguel Ojeda /// 106808c999fSMiguel Ojeda /// # Example 107808c999fSMiguel Ojeda /// 108808c999fSMiguel Ojeda /// ``` 109808c999fSMiguel Ojeda /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token}; 110808c999fSMiguel Ojeda /// use syn::parse::{Parse, ParseStream}; 111808c999fSMiguel Ojeda /// 112808c999fSMiguel Ojeda /// // Parse a function with no generics or parameter list. 113808c999fSMiguel Ojeda /// // 114808c999fSMiguel Ojeda /// // fn playground { 115808c999fSMiguel Ojeda /// // let mut x = 1; 116808c999fSMiguel Ojeda /// // x += 1; 117808c999fSMiguel Ojeda /// // println!("{}", x); 118808c999fSMiguel Ojeda /// // } 119808c999fSMiguel Ojeda /// struct MiniFunction { 120808c999fSMiguel Ojeda /// attrs: Vec<Attribute>, 121808c999fSMiguel Ojeda /// fn_token: Token![fn], 122808c999fSMiguel Ojeda /// name: Ident, 123808c999fSMiguel Ojeda /// brace_token: token::Brace, 124808c999fSMiguel Ojeda /// stmts: Vec<Stmt>, 125808c999fSMiguel Ojeda /// } 126808c999fSMiguel Ojeda /// 127808c999fSMiguel Ojeda /// impl Parse for MiniFunction { 128808c999fSMiguel Ojeda /// fn parse(input: ParseStream) -> Result<Self> { 129808c999fSMiguel Ojeda /// let outer_attrs = input.call(Attribute::parse_outer)?; 130808c999fSMiguel Ojeda /// let fn_token: Token![fn] = input.parse()?; 131808c999fSMiguel Ojeda /// let name: Ident = input.parse()?; 132808c999fSMiguel Ojeda /// 133808c999fSMiguel Ojeda /// let content; 134808c999fSMiguel Ojeda /// let brace_token = braced!(content in input); 135808c999fSMiguel Ojeda /// let inner_attrs = content.call(Attribute::parse_inner)?; 136808c999fSMiguel Ojeda /// let stmts = content.call(Block::parse_within)?; 137808c999fSMiguel Ojeda /// 138808c999fSMiguel Ojeda /// Ok(MiniFunction { 139808c999fSMiguel Ojeda /// attrs: { 140808c999fSMiguel Ojeda /// let mut attrs = outer_attrs; 141808c999fSMiguel Ojeda /// attrs.extend(inner_attrs); 142808c999fSMiguel Ojeda /// attrs 143808c999fSMiguel Ojeda /// }, 144808c999fSMiguel Ojeda /// fn_token, 145808c999fSMiguel Ojeda /// name, 146808c999fSMiguel Ojeda /// brace_token, 147808c999fSMiguel Ojeda /// stmts, 148808c999fSMiguel Ojeda /// }) 149808c999fSMiguel Ojeda /// } 150808c999fSMiguel Ojeda /// } 151808c999fSMiguel Ojeda /// ``` 152808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] parse_within(input: ParseStream) -> Result<Vec<Stmt>>153808c999fSMiguel Ojeda pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> { 154808c999fSMiguel Ojeda let mut stmts = Vec::new(); 155808c999fSMiguel Ojeda loop { 156808c999fSMiguel Ojeda while let semi @ Some(_) = input.parse()? { 157808c999fSMiguel Ojeda stmts.push(Stmt::Expr(Expr::Verbatim(TokenStream::new()), semi)); 158808c999fSMiguel Ojeda } 159808c999fSMiguel Ojeda if input.is_empty() { 160808c999fSMiguel Ojeda break; 161808c999fSMiguel Ojeda } 162808c999fSMiguel Ojeda let stmt = parse_stmt(input, AllowNoSemi(true))?; 163808c999fSMiguel Ojeda let requires_semicolon = match &stmt { 164808c999fSMiguel Ojeda Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt), 165808c999fSMiguel Ojeda Stmt::Macro(stmt) => { 166808c999fSMiguel Ojeda stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace() 167808c999fSMiguel Ojeda } 168808c999fSMiguel Ojeda Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false, 169808c999fSMiguel Ojeda }; 170808c999fSMiguel Ojeda stmts.push(stmt); 171808c999fSMiguel Ojeda if input.is_empty() { 172808c999fSMiguel Ojeda break; 173808c999fSMiguel Ojeda } else if requires_semicolon { 174808c999fSMiguel Ojeda return Err(input.error("unexpected token, expected `;`")); 175808c999fSMiguel Ojeda } 176808c999fSMiguel Ojeda } 177808c999fSMiguel Ojeda Ok(stmts) 178808c999fSMiguel Ojeda } 179808c999fSMiguel Ojeda } 180808c999fSMiguel Ojeda 181808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 182808c999fSMiguel Ojeda impl Parse for Block { parse(input: ParseStream) -> Result<Self>183808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> { 184808c999fSMiguel Ojeda let content; 185808c999fSMiguel Ojeda Ok(Block { 186808c999fSMiguel Ojeda brace_token: braced!(content in input), 187808c999fSMiguel Ojeda stmts: content.call(Block::parse_within)?, 188808c999fSMiguel Ojeda }) 189808c999fSMiguel Ojeda } 190808c999fSMiguel Ojeda } 191808c999fSMiguel Ojeda 192808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] 193808c999fSMiguel Ojeda impl Parse for Stmt { parse(input: ParseStream) -> Result<Self>194808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> { 195808c999fSMiguel Ojeda let allow_nosemi = AllowNoSemi(false); 196808c999fSMiguel Ojeda parse_stmt(input, allow_nosemi) 197808c999fSMiguel Ojeda } 198808c999fSMiguel Ojeda } 199808c999fSMiguel Ojeda parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt>200808c999fSMiguel Ojeda fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> { 201808c999fSMiguel Ojeda let begin = input.fork(); 202808c999fSMiguel Ojeda let attrs = input.call(Attribute::parse_outer)?; 203808c999fSMiguel Ojeda 204808c999fSMiguel Ojeda // brace-style macros; paren and bracket macros get parsed as 205808c999fSMiguel Ojeda // expression statements. 206808c999fSMiguel Ojeda let ahead = input.fork(); 207808c999fSMiguel Ojeda let mut is_item_macro = false; 208808c999fSMiguel Ojeda if let Ok(path) = ahead.call(Path::parse_mod_style) { 209808c999fSMiguel Ojeda if ahead.peek(Token![!]) { 210808c999fSMiguel Ojeda if ahead.peek2(Ident) || ahead.peek2(Token![try]) { 211808c999fSMiguel Ojeda is_item_macro = true; 212808c999fSMiguel Ojeda } else if ahead.peek2(token::Brace) 213808c999fSMiguel Ojeda && !(ahead.peek3(Token![.]) && !ahead.peek3(Token![..]) 214808c999fSMiguel Ojeda || ahead.peek3(Token![?])) 215808c999fSMiguel Ojeda { 216808c999fSMiguel Ojeda input.advance_to(&ahead); 217808c999fSMiguel Ojeda return stmt_mac(input, attrs, path).map(Stmt::Macro); 218808c999fSMiguel Ojeda } 219808c999fSMiguel Ojeda } 220808c999fSMiguel Ojeda } 221808c999fSMiguel Ojeda 222808c999fSMiguel Ojeda if input.peek(Token![let]) && !input.peek(token::Group) { 223808c999fSMiguel Ojeda stmt_local(input, attrs).map(Stmt::Local) 224808c999fSMiguel Ojeda } else if input.peek(Token![pub]) 225808c999fSMiguel Ojeda || input.peek(Token![crate]) && !input.peek2(Token![::]) 226808c999fSMiguel Ojeda || input.peek(Token![extern]) 227808c999fSMiguel Ojeda || input.peek(Token![use]) 228808c999fSMiguel Ojeda || input.peek(Token![static]) 229808c999fSMiguel Ojeda && (input.peek2(Token![mut]) 230808c999fSMiguel Ojeda || input.peek2(Ident) 231808c999fSMiguel Ojeda && !(input.peek2(Token![async]) 232808c999fSMiguel Ojeda && (input.peek3(Token![move]) || input.peek3(Token![|])))) 233808c999fSMiguel Ojeda || input.peek(Token![const]) 234808c999fSMiguel Ojeda && !(input.peek2(token::Brace) 235808c999fSMiguel Ojeda || input.peek2(Token![static]) 236808c999fSMiguel Ojeda || input.peek2(Token![async]) 237808c999fSMiguel Ojeda && !(input.peek3(Token![unsafe]) 238808c999fSMiguel Ojeda || input.peek3(Token![extern]) 239808c999fSMiguel Ojeda || input.peek3(Token![fn])) 240808c999fSMiguel Ojeda || input.peek2(Token![move]) 241808c999fSMiguel Ojeda || input.peek2(Token![|])) 242808c999fSMiguel Ojeda || input.peek(Token![unsafe]) && !input.peek2(token::Brace) 243808c999fSMiguel Ojeda || input.peek(Token![async]) 244808c999fSMiguel Ojeda && (input.peek2(Token![unsafe]) 245808c999fSMiguel Ojeda || input.peek2(Token![extern]) 246808c999fSMiguel Ojeda || input.peek2(Token![fn])) 247808c999fSMiguel Ojeda || input.peek(Token![fn]) 248808c999fSMiguel Ojeda || input.peek(Token![mod]) 249808c999fSMiguel Ojeda || input.peek(Token![type]) 250808c999fSMiguel Ojeda || input.peek(Token![struct]) 251808c999fSMiguel Ojeda || input.peek(Token![enum]) 252808c999fSMiguel Ojeda || input.peek(Token![union]) && input.peek2(Ident) 253808c999fSMiguel Ojeda || input.peek(Token![auto]) && input.peek2(Token![trait]) 254808c999fSMiguel Ojeda || input.peek(Token![trait]) 255808c999fSMiguel Ojeda || input.peek(Token![default]) 256808c999fSMiguel Ojeda && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) 257808c999fSMiguel Ojeda || input.peek(Token![impl]) 258808c999fSMiguel Ojeda || input.peek(Token![macro]) 259808c999fSMiguel Ojeda || is_item_macro 260808c999fSMiguel Ojeda { 261808c999fSMiguel Ojeda let item = item::parsing::parse_rest_of_item(begin, attrs, input)?; 262808c999fSMiguel Ojeda Ok(Stmt::Item(item)) 263808c999fSMiguel Ojeda } else { 264808c999fSMiguel Ojeda stmt_expr(input, allow_nosemi, attrs) 265808c999fSMiguel Ojeda } 266808c999fSMiguel Ojeda } 267808c999fSMiguel Ojeda stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro>268808c999fSMiguel Ojeda fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> { 269808c999fSMiguel Ojeda let bang_token: Token![!] = input.parse()?; 270808c999fSMiguel Ojeda let (delimiter, tokens) = mac::parse_delimiter(input)?; 271808c999fSMiguel Ojeda let semi_token: Option<Token![;]> = input.parse()?; 272808c999fSMiguel Ojeda 273808c999fSMiguel Ojeda Ok(StmtMacro { 274808c999fSMiguel Ojeda attrs, 275808c999fSMiguel Ojeda mac: Macro { 276808c999fSMiguel Ojeda path, 277808c999fSMiguel Ojeda bang_token, 278808c999fSMiguel Ojeda delimiter, 279808c999fSMiguel Ojeda tokens, 280808c999fSMiguel Ojeda }, 281808c999fSMiguel Ojeda semi_token, 282808c999fSMiguel Ojeda }) 283808c999fSMiguel Ojeda } 284808c999fSMiguel Ojeda stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local>285808c999fSMiguel Ojeda fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> { 286808c999fSMiguel Ojeda let let_token: Token![let] = input.parse()?; 287808c999fSMiguel Ojeda 288808c999fSMiguel Ojeda let mut pat = Pat::parse_single(input)?; 289808c999fSMiguel Ojeda if input.peek(Token![:]) { 290808c999fSMiguel Ojeda let colon_token: Token![:] = input.parse()?; 291808c999fSMiguel Ojeda let ty: Type = input.parse()?; 292808c999fSMiguel Ojeda pat = Pat::Type(PatType { 293808c999fSMiguel Ojeda attrs: Vec::new(), 294808c999fSMiguel Ojeda pat: Box::new(pat), 295808c999fSMiguel Ojeda colon_token, 296808c999fSMiguel Ojeda ty: Box::new(ty), 297808c999fSMiguel Ojeda }); 298808c999fSMiguel Ojeda } 299808c999fSMiguel Ojeda 300808c999fSMiguel Ojeda let init = if let Some(eq_token) = input.parse()? { 301808c999fSMiguel Ojeda let eq_token: Token![=] = eq_token; 302808c999fSMiguel Ojeda let expr: Expr = input.parse()?; 303808c999fSMiguel Ojeda 304808c999fSMiguel Ojeda let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) { 305808c999fSMiguel Ojeda let else_token: Token![else] = input.parse()?; 306808c999fSMiguel Ojeda let diverge = ExprBlock { 307808c999fSMiguel Ojeda attrs: Vec::new(), 308808c999fSMiguel Ojeda label: None, 309808c999fSMiguel Ojeda block: input.parse()?, 310808c999fSMiguel Ojeda }; 311808c999fSMiguel Ojeda Some((else_token, Box::new(Expr::Block(diverge)))) 312808c999fSMiguel Ojeda } else { 313808c999fSMiguel Ojeda None 314808c999fSMiguel Ojeda }; 315808c999fSMiguel Ojeda 316808c999fSMiguel Ojeda Some(LocalInit { 317808c999fSMiguel Ojeda eq_token, 318808c999fSMiguel Ojeda expr: Box::new(expr), 319808c999fSMiguel Ojeda diverge, 320808c999fSMiguel Ojeda }) 321808c999fSMiguel Ojeda } else { 322808c999fSMiguel Ojeda None 323808c999fSMiguel Ojeda }; 324808c999fSMiguel Ojeda 325808c999fSMiguel Ojeda let semi_token: Token![;] = input.parse()?; 326808c999fSMiguel Ojeda 327808c999fSMiguel Ojeda Ok(Local { 328808c999fSMiguel Ojeda attrs, 329808c999fSMiguel Ojeda let_token, 330808c999fSMiguel Ojeda pat, 331808c999fSMiguel Ojeda init, 332808c999fSMiguel Ojeda semi_token, 333808c999fSMiguel Ojeda }) 334808c999fSMiguel Ojeda } 335808c999fSMiguel Ojeda stmt_expr( input: ParseStream, allow_nosemi: AllowNoSemi, mut attrs: Vec<Attribute>, ) -> Result<Stmt>336808c999fSMiguel Ojeda fn stmt_expr( 337808c999fSMiguel Ojeda input: ParseStream, 338808c999fSMiguel Ojeda allow_nosemi: AllowNoSemi, 339808c999fSMiguel Ojeda mut attrs: Vec<Attribute>, 340808c999fSMiguel Ojeda ) -> Result<Stmt> { 341808c999fSMiguel Ojeda let mut e = Expr::parse_with_earlier_boundary_rule(input)?; 342808c999fSMiguel Ojeda 343808c999fSMiguel Ojeda let mut attr_target = &mut e; 344808c999fSMiguel Ojeda loop { 345808c999fSMiguel Ojeda attr_target = match attr_target { 346808c999fSMiguel Ojeda Expr::Assign(e) => &mut e.left, 347808c999fSMiguel Ojeda Expr::Binary(e) => &mut e.left, 348808c999fSMiguel Ojeda Expr::Cast(e) => &mut e.expr, 349808c999fSMiguel Ojeda Expr::Array(_) 350808c999fSMiguel Ojeda | Expr::Async(_) 351808c999fSMiguel Ojeda | Expr::Await(_) 352808c999fSMiguel Ojeda | Expr::Block(_) 353808c999fSMiguel Ojeda | Expr::Break(_) 354808c999fSMiguel Ojeda | Expr::Call(_) 355808c999fSMiguel Ojeda | Expr::Closure(_) 356808c999fSMiguel Ojeda | Expr::Const(_) 357808c999fSMiguel Ojeda | Expr::Continue(_) 358808c999fSMiguel Ojeda | Expr::Field(_) 359808c999fSMiguel Ojeda | Expr::ForLoop(_) 360808c999fSMiguel Ojeda | Expr::Group(_) 361808c999fSMiguel Ojeda | Expr::If(_) 362808c999fSMiguel Ojeda | Expr::Index(_) 363808c999fSMiguel Ojeda | Expr::Infer(_) 364808c999fSMiguel Ojeda | Expr::Let(_) 365808c999fSMiguel Ojeda | Expr::Lit(_) 366808c999fSMiguel Ojeda | Expr::Loop(_) 367808c999fSMiguel Ojeda | Expr::Macro(_) 368808c999fSMiguel Ojeda | Expr::Match(_) 369808c999fSMiguel Ojeda | Expr::MethodCall(_) 370808c999fSMiguel Ojeda | Expr::Paren(_) 371808c999fSMiguel Ojeda | Expr::Path(_) 372808c999fSMiguel Ojeda | Expr::Range(_) 373808c999fSMiguel Ojeda | Expr::RawAddr(_) 374808c999fSMiguel Ojeda | Expr::Reference(_) 375808c999fSMiguel Ojeda | Expr::Repeat(_) 376808c999fSMiguel Ojeda | Expr::Return(_) 377808c999fSMiguel Ojeda | Expr::Struct(_) 378808c999fSMiguel Ojeda | Expr::Try(_) 379808c999fSMiguel Ojeda | Expr::TryBlock(_) 380808c999fSMiguel Ojeda | Expr::Tuple(_) 381808c999fSMiguel Ojeda | Expr::Unary(_) 382808c999fSMiguel Ojeda | Expr::Unsafe(_) 383808c999fSMiguel Ojeda | Expr::While(_) 384808c999fSMiguel Ojeda | Expr::Yield(_) 385808c999fSMiguel Ojeda | Expr::Verbatim(_) => break, 386808c999fSMiguel Ojeda }; 387808c999fSMiguel Ojeda } 388808c999fSMiguel Ojeda attrs.extend(attr_target.replace_attrs(Vec::new())); 389808c999fSMiguel Ojeda attr_target.replace_attrs(attrs); 390808c999fSMiguel Ojeda 391808c999fSMiguel Ojeda let semi_token: Option<Token![;]> = input.parse()?; 392808c999fSMiguel Ojeda 393808c999fSMiguel Ojeda match e { 394808c999fSMiguel Ojeda Expr::Macro(ExprMacro { attrs, mac }) 395808c999fSMiguel Ojeda if semi_token.is_some() || mac.delimiter.is_brace() => 396808c999fSMiguel Ojeda { 397808c999fSMiguel Ojeda return Ok(Stmt::Macro(StmtMacro { 398808c999fSMiguel Ojeda attrs, 399808c999fSMiguel Ojeda mac, 400808c999fSMiguel Ojeda semi_token, 401808c999fSMiguel Ojeda })); 402808c999fSMiguel Ojeda } 403808c999fSMiguel Ojeda _ => {} 404808c999fSMiguel Ojeda } 405808c999fSMiguel Ojeda 406808c999fSMiguel Ojeda if semi_token.is_some() { 407808c999fSMiguel Ojeda Ok(Stmt::Expr(e, semi_token)) 408808c999fSMiguel Ojeda } else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) { 409808c999fSMiguel Ojeda Ok(Stmt::Expr(e, None)) 410808c999fSMiguel Ojeda } else { 411808c999fSMiguel Ojeda Err(input.error("expected semicolon")) 412808c999fSMiguel Ojeda } 413808c999fSMiguel Ojeda } 414808c999fSMiguel Ojeda } 415808c999fSMiguel Ojeda 416808c999fSMiguel Ojeda #[cfg(feature = "printing")] 417808c999fSMiguel Ojeda pub(crate) mod printing { 418808c999fSMiguel Ojeda use crate::classify; 419808c999fSMiguel Ojeda use crate::expr::{self, Expr}; 420808c999fSMiguel Ojeda use crate::fixup::FixupContext; 421808c999fSMiguel Ojeda use crate::stmt::{Block, Local, Stmt, StmtMacro}; 422808c999fSMiguel Ojeda use crate::token; 423808c999fSMiguel Ojeda use proc_macro2::TokenStream; 424808c999fSMiguel Ojeda use quote::{ToTokens, TokenStreamExt}; 425808c999fSMiguel Ojeda 426808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 427808c999fSMiguel Ojeda impl ToTokens for Block { to_tokens(&self, tokens: &mut TokenStream)428808c999fSMiguel Ojeda fn to_tokens(&self, tokens: &mut TokenStream) { 429808c999fSMiguel Ojeda self.brace_token.surround(tokens, |tokens| { 430808c999fSMiguel Ojeda tokens.append_all(&self.stmts); 431808c999fSMiguel Ojeda }); 432808c999fSMiguel Ojeda } 433808c999fSMiguel Ojeda } 434808c999fSMiguel Ojeda 435808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 436808c999fSMiguel Ojeda impl ToTokens for Stmt { to_tokens(&self, tokens: &mut TokenStream)437808c999fSMiguel Ojeda fn to_tokens(&self, tokens: &mut TokenStream) { 438808c999fSMiguel Ojeda match self { 439808c999fSMiguel Ojeda Stmt::Local(local) => local.to_tokens(tokens), 440808c999fSMiguel Ojeda Stmt::Item(item) => item.to_tokens(tokens), 441808c999fSMiguel Ojeda Stmt::Expr(expr, semi) => { 442808c999fSMiguel Ojeda expr::printing::print_expr(expr, tokens, FixupContext::new_stmt()); 443808c999fSMiguel Ojeda semi.to_tokens(tokens); 444808c999fSMiguel Ojeda } 445808c999fSMiguel Ojeda Stmt::Macro(mac) => mac.to_tokens(tokens), 446808c999fSMiguel Ojeda } 447808c999fSMiguel Ojeda } 448808c999fSMiguel Ojeda } 449808c999fSMiguel Ojeda 450808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 451808c999fSMiguel Ojeda impl ToTokens for Local { to_tokens(&self, tokens: &mut TokenStream)452808c999fSMiguel Ojeda fn to_tokens(&self, tokens: &mut TokenStream) { 453808c999fSMiguel Ojeda expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); 454808c999fSMiguel Ojeda self.let_token.to_tokens(tokens); 455808c999fSMiguel Ojeda self.pat.to_tokens(tokens); 456808c999fSMiguel Ojeda if let Some(init) = &self.init { 457808c999fSMiguel Ojeda init.eq_token.to_tokens(tokens); 458808c999fSMiguel Ojeda expr::printing::print_subexpression( 459808c999fSMiguel Ojeda &init.expr, 460808c999fSMiguel Ojeda init.diverge.is_some() && classify::expr_trailing_brace(&init.expr), 461808c999fSMiguel Ojeda tokens, 462808c999fSMiguel Ojeda FixupContext::NONE, 463808c999fSMiguel Ojeda ); 464808c999fSMiguel Ojeda if let Some((else_token, diverge)) = &init.diverge { 465808c999fSMiguel Ojeda else_token.to_tokens(tokens); 466808c999fSMiguel Ojeda match &**diverge { 467808c999fSMiguel Ojeda Expr::Block(diverge) => diverge.to_tokens(tokens), 468808c999fSMiguel Ojeda _ => token::Brace::default().surround(tokens, |tokens| { 469808c999fSMiguel Ojeda expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt()); 470808c999fSMiguel Ojeda }), 471808c999fSMiguel Ojeda } 472808c999fSMiguel Ojeda } 473808c999fSMiguel Ojeda } 474808c999fSMiguel Ojeda self.semi_token.to_tokens(tokens); 475808c999fSMiguel Ojeda } 476808c999fSMiguel Ojeda } 477808c999fSMiguel Ojeda 478808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] 479808c999fSMiguel Ojeda impl ToTokens for StmtMacro { to_tokens(&self, tokens: &mut TokenStream)480808c999fSMiguel Ojeda fn to_tokens(&self, tokens: &mut TokenStream) { 481808c999fSMiguel Ojeda expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); 482808c999fSMiguel Ojeda self.mac.to_tokens(tokens); 483808c999fSMiguel Ojeda self.semi_token.to_tokens(tokens); 484808c999fSMiguel Ojeda } 485808c999fSMiguel Ojeda } 486808c999fSMiguel Ojeda } 487