Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487// SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::attr::Attribute;use crate::expr::Expr;use crate::item::Item;use crate::mac::Macro;use crate::pat::Pat;use crate::token;
ast_struct! { /// A braced block containing Rust statements. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pub struct Block { pub brace_token: token::Brace, /// Statements in a block pub stmts: Vec<Stmt>, }}
ast_enum! { /// A statement, usually ending in a semicolon. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pub enum Stmt { /// A local (let) binding. Local(Local),
/// An item definition. Item(Item),
/// Expression, with or without trailing semicolon. Expr(Expr, Option<Token![;]>),
/// A macro invocation in statement position. /// /// Syntactically it's ambiguous which other kind of statement this /// macro would expand to. It can be any of local variable (`let`), /// item, or expression. Macro(StmtMacro), }}
ast_struct! { /// A local `let` binding: `let x: u64 = s.parse()?;`. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pub struct Local { pub attrs: Vec<Attribute>, pub let_token: Token![let], pub pat: Pat, pub init: Option<LocalInit>, pub semi_token: Token![;], }}
ast_struct! { /// The expression assigned in a local `let` binding, including optional /// diverging `else` block. /// /// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and /// `= r else { return }` in `let Ok(x) = r else { return }`. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pub struct LocalInit { pub eq_token: Token![=], pub expr: Box<Expr>, pub diverge: Option<(Token![else], Box<Expr>)>, }}
ast_struct! { /// A macro invocation in statement position. /// /// Syntactically it's ambiguous which other kind of statement this macro /// would expand to. It can be any of local variable (`let`), item, or /// expression. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pub struct StmtMacro { pub attrs: Vec<Attribute>, pub mac: Macro, pub semi_token: Option<Token![;]>, }}
#[cfg(feature = "parsing")]pub(crate) mod parsing { use crate::attr::Attribute; use crate::classify; use crate::error::Result; use crate::expr::{Expr, ExprBlock, ExprMacro}; use crate::ident::Ident; use crate::item; use crate::mac::{self, Macro}; use crate::parse::discouraged::Speculative as _; use crate::parse::{Parse, ParseStream}; use crate::pat::{Pat, PatType}; use crate::path::Path; use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro}; use crate::token; use crate::ty::Type; use proc_macro2::TokenStream;
struct AllowNoSemi(bool);
impl Block { /// Parse the body of a block as zero or more statements, possibly /// including one trailing expression. /// /// # Example /// /// ``` /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token}; /// use syn::parse::{Parse, ParseStream}; /// /// // Parse a function with no generics or parameter list. /// // /// // fn playground { /// // let mut x = 1; /// // x += 1; /// // println!("{}", x); /// // } /// struct MiniFunction { /// attrs: Vec<Attribute>, /// fn_token: Token![fn], /// name: Ident, /// brace_token: token::Brace, /// stmts: Vec<Stmt>, /// } /// /// impl Parse for MiniFunction { /// fn parse(input: ParseStream) -> Result<Self> { /// let outer_attrs = input.call(Attribute::parse_outer)?; /// let fn_token: Token![fn] = input.parse()?; /// let name: Ident = input.parse()?; /// /// let content; /// let brace_token = braced!(content in input); /// let inner_attrs = content.call(Attribute::parse_inner)?; /// let stmts = content.call(Block::parse_within)?; /// /// Ok(MiniFunction { /// attrs: { /// let mut attrs = outer_attrs; /// attrs.extend(inner_attrs); /// attrs /// }, /// fn_token, /// name, /// brace_token, /// stmts, /// }) /// } /// } /// ``` #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> { let mut stmts = Vec::new(); loop { while let semi @ Some(_) = input.parse()? { stmts.push(Stmt::Expr(Expr::Verbatim(TokenStream::new()), semi)); } if input.is_empty() { break; } let stmt = parse_stmt(input, AllowNoSemi(true))?; let requires_semicolon = match &stmt { Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt), Stmt::Macro(stmt) => { stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace() } Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false, }; stmts.push(stmt); if input.is_empty() { break; } else if requires_semicolon { return Err(input.error("unexpected token, expected `;`")); } } Ok(stmts) } }
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Block { fn parse(input: ParseStream) -> Result<Self> { let content; Ok(Block { brace_token: braced!(content in input), stmts: content.call(Block::parse_within)?, }) } }
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Stmt { fn parse(input: ParseStream) -> Result<Self> { let allow_nosemi = AllowNoSemi(false); parse_stmt(input, allow_nosemi) } }
fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> { let begin = input.fork(); let attrs = input.call(Attribute::parse_outer)?;
// brace-style macros; paren and bracket macros get parsed as // expression statements. let ahead = input.fork(); let mut is_item_macro = false; if let Ok(path) = ahead.call(Path::parse_mod_style) { if ahead.peek(Token![!]) { if ahead.peek2(Ident) || ahead.peek2(Token![try]) { is_item_macro = true; } else if ahead.peek2(token::Brace) && !(ahead.peek3(Token![.]) && !ahead.peek3(Token![..]) || ahead.peek3(Token![?])) { input.advance_to(&ahead); return stmt_mac(input, attrs, path).map(Stmt::Macro); } } }
if input.peek(Token![let]) && !input.peek(token::Group) { stmt_local(input, attrs).map(Stmt::Local) } else if input.peek(Token![pub]) || input.peek(Token![crate]) && !input.peek2(Token![::]) || input.peek(Token![extern]) || input.peek(Token![use]) || input.peek(Token![static]) && (input.peek2(Token![mut]) || input.peek2(Ident) && !(input.peek2(Token![async]) && (input.peek3(Token![move]) || input.peek3(Token![|])))) || input.peek(Token![const]) && !(input.peek2(token::Brace) || input.peek2(Token![static]) || input.peek2(Token![async]) && !(input.peek3(Token![unsafe]) || input.peek3(Token![extern]) || input.peek3(Token![fn])) || input.peek2(Token![move]) || input.peek2(Token![|])) || input.peek(Token![unsafe]) && !input.peek2(token::Brace) || input.peek(Token![async]) && (input.peek2(Token![unsafe]) || input.peek2(Token![extern]) || input.peek2(Token![fn])) || input.peek(Token![fn]) || input.peek(Token![mod]) || input.peek(Token![type]) || input.peek(Token![struct]) || input.peek(Token![enum]) || input.peek(Token![union]) && input.peek2(Ident) || input.peek(Token![auto]) && input.peek2(Token![trait]) || input.peek(Token![trait]) || input.peek(Token![default]) && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) || input.peek(Token![impl]) || input.peek(Token![macro]) || is_item_macro { let item = item::parsing::parse_rest_of_item(begin, attrs, input)?; Ok(Stmt::Item(item)) } else { stmt_expr(input, allow_nosemi, attrs) } }
fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> { let bang_token: Token![!] = input.parse()?; let (delimiter, tokens) = mac::parse_delimiter(input)?; let semi_token: Option<Token![;]> = input.parse()?;
Ok(StmtMacro { attrs, mac: Macro { path, bang_token, delimiter, tokens, }, semi_token, }) }
fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> { let let_token: Token![let] = input.parse()?;
let mut pat = Pat::parse_single(input)?; if input.peek(Token![:]) { let colon_token: Token![:] = input.parse()?; let ty: Type = input.parse()?; pat = Pat::Type(PatType { attrs: Vec::new(), pat: Box::new(pat), colon_token, ty: Box::new(ty), }); }
let init = if let Some(eq_token) = input.parse()? { let eq_token: Token![=] = eq_token; let expr: Expr = input.parse()?;
let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) { let else_token: Token![else] = input.parse()?; let diverge = ExprBlock { attrs: Vec::new(), label: None, block: input.parse()?, }; Some((else_token, Box::new(Expr::Block(diverge)))) } else { None };
Some(LocalInit { eq_token, expr: Box::new(expr), diverge, }) } else { None };
let semi_token: Token![;] = input.parse()?;
Ok(Local { attrs, let_token, pat, init, semi_token, }) }
fn stmt_expr( input: ParseStream, allow_nosemi: AllowNoSemi, mut attrs: Vec<Attribute>, ) -> Result<Stmt> { let mut e = Expr::parse_with_earlier_boundary_rule(input)?;
let mut attr_target = &mut e; loop { attr_target = match attr_target { Expr::Assign(e) => &mut e.left, Expr::Binary(e) => &mut e.left, Expr::Cast(e) => &mut e.expr, Expr::Array(_) | Expr::Async(_) | Expr::Await(_) | Expr::Block(_) | Expr::Break(_) | Expr::Call(_) | Expr::Closure(_) | Expr::Const(_) | Expr::Continue(_) | Expr::Field(_) | Expr::ForLoop(_) | Expr::Group(_) | Expr::If(_) | Expr::Index(_) | Expr::Infer(_) | Expr::Let(_) | Expr::Lit(_) | Expr::Loop(_) | Expr::Macro(_) | Expr::Match(_) | Expr::MethodCall(_) | Expr::Paren(_) | Expr::Path(_) | Expr::Range(_) | Expr::RawAddr(_) | Expr::Reference(_) | Expr::Repeat(_) | Expr::Return(_) | Expr::Struct(_) | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) | Expr::Unary(_) | Expr::Unsafe(_) | Expr::While(_) | Expr::Yield(_) | Expr::Verbatim(_) => break, }; } attrs.extend(attr_target.replace_attrs(Vec::new())); attr_target.replace_attrs(attrs);
let semi_token: Option<Token![;]> = input.parse()?;
match e { Expr::Macro(ExprMacro { attrs, mac }) if semi_token.is_some() || mac.delimiter.is_brace() => { return Ok(Stmt::Macro(StmtMacro { attrs, mac, semi_token, })); } _ => {} }
if semi_token.is_some() { Ok(Stmt::Expr(e, semi_token)) } else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) { Ok(Stmt::Expr(e, None)) } else { Err(input.error("expected semicolon")) } }}
#[cfg(feature = "printing")]pub(crate) mod printing { use crate::classify; use crate::expr::{self, Expr}; use crate::fixup::FixupContext; use crate::stmt::{Block, Local, Stmt, StmtMacro}; use crate::token; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt};
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for Block { fn to_tokens(&self, tokens: &mut TokenStream) { self.brace_token.surround(tokens, |tokens| { tokens.append_all(&self.stmts); }); } }
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for Stmt { fn to_tokens(&self, tokens: &mut TokenStream) { match self { Stmt::Local(local) => local.to_tokens(tokens), Stmt::Item(item) => item.to_tokens(tokens), Stmt::Expr(expr, semi) => { expr::printing::print_expr(expr, tokens, FixupContext::new_stmt()); semi.to_tokens(tokens); } Stmt::Macro(mac) => mac.to_tokens(tokens), } } }
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for Local { fn to_tokens(&self, tokens: &mut TokenStream) { expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); self.let_token.to_tokens(tokens); self.pat.to_tokens(tokens); if let Some(init) = &self.init { init.eq_token.to_tokens(tokens); expr::printing::print_subexpression( &init.expr, init.diverge.is_some() && classify::expr_trailing_brace(&init.expr), tokens, FixupContext::NONE, ); if let Some((else_token, diverge)) = &init.diverge { else_token.to_tokens(tokens); match &**diverge { Expr::Block(diverge) => diverge.to_tokens(tokens), _ => token::Brace::default().surround(tokens, |tokens| { expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt()); }), } } } self.semi_token.to_tokens(tokens); } }
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for StmtMacro { fn to_tokens(&self, tokens: &mut TokenStream) { expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); self.mac.to_tokens(tokens); self.semi_token.to_tokens(tokens); } }}