stmt.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. use crate::attr::Attribute;
  3. use crate::expr::Expr;
  4. use crate::item::Item;
  5. use crate::mac::Macro;
  6. use crate::pat::Pat;
  7. use crate::token;
  8. ast_struct! {
  9. /// A braced block containing Rust statements.
  10. #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
  11. pub struct Block {
  12. pub brace_token: token::Brace,
  13. /// Statements in a block
  14. pub stmts: Vec<Stmt>,
  15. }
  16. }
  17. ast_enum! {
  18. /// A statement, usually ending in a semicolon.
  19. #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
  20. pub enum Stmt {
  21. /// A local (let) binding.
  22. Local(Local),
  23. /// An item definition.
  24. Item(Item),
  25. /// Expression, with or without trailing semicolon.
  26. Expr(Expr, Option<Token![;]>),
  27. /// A macro invocation in statement position.
  28. ///
  29. /// Syntactically it's ambiguous which other kind of statement this
  30. /// macro would expand to. It can be any of local variable (`let`),
  31. /// item, or expression.
  32. Macro(StmtMacro),
  33. }
  34. }
  35. ast_struct! {
  36. /// A local `let` binding: `let x: u64 = s.parse()?;`.
  37. #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
  38. pub struct Local {
  39. pub attrs: Vec<Attribute>,
  40. pub let_token: Token![let],
  41. pub pat: Pat,
  42. pub init: Option<LocalInit>,
  43. pub semi_token: Token![;],
  44. }
  45. }
  46. ast_struct! {
  47. /// The expression assigned in a local `let` binding, including optional
  48. /// diverging `else` block.
  49. ///
  50. /// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and
  51. /// `= r else { return }` in `let Ok(x) = r else { return }`.
  52. #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
  53. pub struct LocalInit {
  54. pub eq_token: Token![=],
  55. pub expr: Box<Expr>,
  56. pub diverge: Option<(Token![else], Box<Expr>)>,
  57. }
  58. }
  59. ast_struct! {
  60. /// A macro invocation in statement position.
  61. ///
  62. /// Syntactically it's ambiguous which other kind of statement this macro
  63. /// would expand to. It can be any of local variable (`let`), item, or
  64. /// expression.
  65. #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
  66. pub struct StmtMacro {
  67. pub attrs: Vec<Attribute>,
  68. pub mac: Macro,
  69. pub semi_token: Option<Token![;]>,
  70. }
  71. }
  72. #[cfg(feature = "parsing")]
  73. pub(crate) mod parsing {
  74. use crate::attr::Attribute;
  75. use crate::classify;
  76. use crate::error::Result;
  77. use crate::expr::{Expr, ExprBlock, ExprMacro};
  78. use crate::ident::Ident;
  79. use crate::item;
  80. use crate::mac::{self, Macro};
  81. use crate::parse::discouraged::Speculative as _;
  82. use crate::parse::{Parse, ParseStream};
  83. use crate::pat::{Pat, PatType};
  84. use crate::path::Path;
  85. use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
  86. use crate::token;
  87. use crate::ty::Type;
  88. use proc_macro2::TokenStream;
  89. struct AllowNoSemi(bool);
  90. impl Block {
  91. /// Parse the body of a block as zero or more statements, possibly
  92. /// including one trailing expression.
  93. ///
  94. /// # Example
  95. ///
  96. /// ```
  97. /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token};
  98. /// use syn::parse::{Parse, ParseStream};
  99. ///
  100. /// // Parse a function with no generics or parameter list.
  101. /// //
  102. /// // fn playground {
  103. /// // let mut x = 1;
  104. /// // x += 1;
  105. /// // println!("{}", x);
  106. /// // }
  107. /// struct MiniFunction {
  108. /// attrs: Vec<Attribute>,
  109. /// fn_token: Token![fn],
  110. /// name: Ident,
  111. /// brace_token: token::Brace,
  112. /// stmts: Vec<Stmt>,
  113. /// }
  114. ///
  115. /// impl Parse for MiniFunction {
  116. /// fn parse(input: ParseStream) -> Result<Self> {
  117. /// let outer_attrs = input.call(Attribute::parse_outer)?;
  118. /// let fn_token: Token![fn] = input.parse()?;
  119. /// let name: Ident = input.parse()?;
  120. ///
  121. /// let content;
  122. /// let brace_token = braced!(content in input);
  123. /// let inner_attrs = content.call(Attribute::parse_inner)?;
  124. /// let stmts = content.call(Block::parse_within)?;
  125. ///
  126. /// Ok(MiniFunction {
  127. /// attrs: {
  128. /// let mut attrs = outer_attrs;
  129. /// attrs.extend(inner_attrs);
  130. /// attrs
  131. /// },
  132. /// fn_token,
  133. /// name,
  134. /// brace_token,
  135. /// stmts,
  136. /// })
  137. /// }
  138. /// }
  139. /// ```
  140. #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
  141. pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
  142. let mut stmts = Vec::new();
  143. loop {
  144. while let semi @ Some(_) = input.parse()? {
  145. stmts.push(Stmt::Expr(Expr::Verbatim(TokenStream::new()), semi));
  146. }
  147. if input.is_empty() {
  148. break;
  149. }
  150. let stmt = parse_stmt(input, AllowNoSemi(true))?;
  151. let requires_semicolon = match &stmt {
  152. Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt),
  153. Stmt::Macro(stmt) => {
  154. stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace()
  155. }
  156. Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false,
  157. };
  158. stmts.push(stmt);
  159. if input.is_empty() {
  160. break;
  161. } else if requires_semicolon {
  162. return Err(input.error("unexpected token, expected `;`"));
  163. }
  164. }
  165. Ok(stmts)
  166. }
  167. }
  168. #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
  169. impl Parse for Block {
  170. fn parse(input: ParseStream) -> Result<Self> {
  171. let content;
  172. Ok(Block {
  173. brace_token: braced!(content in input),
  174. stmts: content.call(Block::parse_within)?,
  175. })
  176. }
  177. }
  178. #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
  179. impl Parse for Stmt {
  180. fn parse(input: ParseStream) -> Result<Self> {
  181. let allow_nosemi = AllowNoSemi(false);
  182. parse_stmt(input, allow_nosemi)
  183. }
  184. }
  185. fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> {
  186. let begin = input.fork();
  187. let attrs = input.call(Attribute::parse_outer)?;
  188. // brace-style macros; paren and bracket macros get parsed as
  189. // expression statements.
  190. let ahead = input.fork();
  191. let mut is_item_macro = false;
  192. if let Ok(path) = ahead.call(Path::parse_mod_style) {
  193. if ahead.peek(Token![!]) {
  194. if ahead.peek2(Ident) || ahead.peek2(Token![try]) {
  195. is_item_macro = true;
  196. } else if ahead.peek2(token::Brace)
  197. && !(ahead.peek3(Token![.]) && !ahead.peek3(Token![..])
  198. || ahead.peek3(Token![?]))
  199. {
  200. input.advance_to(&ahead);
  201. return stmt_mac(input, attrs, path).map(Stmt::Macro);
  202. }
  203. }
  204. }
  205. if input.peek(Token![let]) && !input.peek(token::Group) {
  206. stmt_local(input, attrs).map(Stmt::Local)
  207. } else if input.peek(Token![pub])
  208. || input.peek(Token![crate]) && !input.peek2(Token![::])
  209. || input.peek(Token![extern])
  210. || input.peek(Token![use])
  211. || input.peek(Token![static])
  212. && (input.peek2(Token![mut])
  213. || input.peek2(Ident)
  214. && !(input.peek2(Token![async])
  215. && (input.peek3(Token![move]) || input.peek3(Token![|]))))
  216. || input.peek(Token![const])
  217. && !(input.peek2(token::Brace)
  218. || input.peek2(Token![static])
  219. || input.peek2(Token![async])
  220. && !(input.peek3(Token![unsafe])
  221. || input.peek3(Token![extern])
  222. || input.peek3(Token![fn]))
  223. || input.peek2(Token![move])
  224. || input.peek2(Token![|]))
  225. || input.peek(Token![unsafe]) && !input.peek2(token::Brace)
  226. || input.peek(Token![async])
  227. && (input.peek2(Token![unsafe])
  228. || input.peek2(Token![extern])
  229. || input.peek2(Token![fn]))
  230. || input.peek(Token![fn])
  231. || input.peek(Token![mod])
  232. || input.peek(Token![type])
  233. || input.peek(Token![struct])
  234. || input.peek(Token![enum])
  235. || input.peek(Token![union]) && input.peek2(Ident)
  236. || input.peek(Token![auto]) && input.peek2(Token![trait])
  237. || input.peek(Token![trait])
  238. || input.peek(Token![default])
  239. && (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
  240. || input.peek(Token![impl])
  241. || input.peek(Token![macro])
  242. || is_item_macro
  243. {
  244. let item = item::parsing::parse_rest_of_item(begin, attrs, input)?;
  245. Ok(Stmt::Item(item))
  246. } else {
  247. stmt_expr(input, allow_nosemi, attrs)
  248. }
  249. }
  250. fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> {
  251. let bang_token: Token![!] = input.parse()?;
  252. let (delimiter, tokens) = mac::parse_delimiter(input)?;
  253. let semi_token: Option<Token![;]> = input.parse()?;
  254. Ok(StmtMacro {
  255. attrs,
  256. mac: Macro {
  257. path,
  258. bang_token,
  259. delimiter,
  260. tokens,
  261. },
  262. semi_token,
  263. })
  264. }
  265. fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
  266. let let_token: Token![let] = input.parse()?;
  267. let mut pat = Pat::parse_single(input)?;
  268. if input.peek(Token![:]) {
  269. let colon_token: Token![:] = input.parse()?;
  270. let ty: Type = input.parse()?;
  271. pat = Pat::Type(PatType {
  272. attrs: Vec::new(),
  273. pat: Box::new(pat),
  274. colon_token,
  275. ty: Box::new(ty),
  276. });
  277. }
  278. let init = if let Some(eq_token) = input.parse()? {
  279. let eq_token: Token![=] = eq_token;
  280. let expr: Expr = input.parse()?;
  281. let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) {
  282. let else_token: Token![else] = input.parse()?;
  283. let diverge = ExprBlock {
  284. attrs: Vec::new(),
  285. label: None,
  286. block: input.parse()?,
  287. };
  288. Some((else_token, Box::new(Expr::Block(diverge))))
  289. } else {
  290. None
  291. };
  292. Some(LocalInit {
  293. eq_token,
  294. expr: Box::new(expr),
  295. diverge,
  296. })
  297. } else {
  298. None
  299. };
  300. let semi_token: Token![;] = input.parse()?;
  301. Ok(Local {
  302. attrs,
  303. let_token,
  304. pat,
  305. init,
  306. semi_token,
  307. })
  308. }
  309. fn stmt_expr(
  310. input: ParseStream,
  311. allow_nosemi: AllowNoSemi,
  312. mut attrs: Vec<Attribute>,
  313. ) -> Result<Stmt> {
  314. let mut e = Expr::parse_with_earlier_boundary_rule(input)?;
  315. let mut attr_target = &mut e;
  316. loop {
  317. attr_target = match attr_target {
  318. Expr::Assign(e) => &mut e.left,
  319. Expr::Binary(e) => &mut e.left,
  320. Expr::Cast(e) => &mut e.expr,
  321. Expr::Array(_)
  322. | Expr::Async(_)
  323. | Expr::Await(_)
  324. | Expr::Block(_)
  325. | Expr::Break(_)
  326. | Expr::Call(_)
  327. | Expr::Closure(_)
  328. | Expr::Const(_)
  329. | Expr::Continue(_)
  330. | Expr::Field(_)
  331. | Expr::ForLoop(_)
  332. | Expr::Group(_)
  333. | Expr::If(_)
  334. | Expr::Index(_)
  335. | Expr::Infer(_)
  336. | Expr::Let(_)
  337. | Expr::Lit(_)
  338. | Expr::Loop(_)
  339. | Expr::Macro(_)
  340. | Expr::Match(_)
  341. | Expr::MethodCall(_)
  342. | Expr::Paren(_)
  343. | Expr::Path(_)
  344. | Expr::Range(_)
  345. | Expr::RawAddr(_)
  346. | Expr::Reference(_)
  347. | Expr::Repeat(_)
  348. | Expr::Return(_)
  349. | Expr::Struct(_)
  350. | Expr::Try(_)
  351. | Expr::TryBlock(_)
  352. | Expr::Tuple(_)
  353. | Expr::Unary(_)
  354. | Expr::Unsafe(_)
  355. | Expr::While(_)
  356. | Expr::Yield(_)
  357. | Expr::Verbatim(_) => break,
  358. };
  359. }
  360. attrs.extend(attr_target.replace_attrs(Vec::new()));
  361. attr_target.replace_attrs(attrs);
  362. let semi_token: Option<Token![;]> = input.parse()?;
  363. match e {
  364. Expr::Macro(ExprMacro { attrs, mac })
  365. if semi_token.is_some() || mac.delimiter.is_brace() =>
  366. {
  367. return Ok(Stmt::Macro(StmtMacro {
  368. attrs,
  369. mac,
  370. semi_token,
  371. }));
  372. }
  373. _ => {}
  374. }
  375. if semi_token.is_some() {
  376. Ok(Stmt::Expr(e, semi_token))
  377. } else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) {
  378. Ok(Stmt::Expr(e, None))
  379. } else {
  380. Err(input.error("expected semicolon"))
  381. }
  382. }
  383. }
  384. #[cfg(feature = "printing")]
  385. pub(crate) mod printing {
  386. use crate::classify;
  387. use crate::expr::{self, Expr};
  388. use crate::fixup::FixupContext;
  389. use crate::stmt::{Block, Local, Stmt, StmtMacro};
  390. use crate::token;
  391. use proc_macro2::TokenStream;
  392. use quote::{ToTokens, TokenStreamExt};
  393. #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
  394. impl ToTokens for Block {
  395. fn to_tokens(&self, tokens: &mut TokenStream) {
  396. self.brace_token.surround(tokens, |tokens| {
  397. tokens.append_all(&self.stmts);
  398. });
  399. }
  400. }
  401. #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
  402. impl ToTokens for Stmt {
  403. fn to_tokens(&self, tokens: &mut TokenStream) {
  404. match self {
  405. Stmt::Local(local) => local.to_tokens(tokens),
  406. Stmt::Item(item) => item.to_tokens(tokens),
  407. Stmt::Expr(expr, semi) => {
  408. expr::printing::print_expr(expr, tokens, FixupContext::new_stmt());
  409. semi.to_tokens(tokens);
  410. }
  411. Stmt::Macro(mac) => mac.to_tokens(tokens),
  412. }
  413. }
  414. }
  415. #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
  416. impl ToTokens for Local {
  417. fn to_tokens(&self, tokens: &mut TokenStream) {
  418. expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
  419. self.let_token.to_tokens(tokens);
  420. self.pat.to_tokens(tokens);
  421. if let Some(init) = &self.init {
  422. init.eq_token.to_tokens(tokens);
  423. expr::printing::print_subexpression(
  424. &init.expr,
  425. init.diverge.is_some() && classify::expr_trailing_brace(&init.expr),
  426. tokens,
  427. FixupContext::NONE,
  428. );
  429. if let Some((else_token, diverge)) = &init.diverge {
  430. else_token.to_tokens(tokens);
  431. match &**diverge {
  432. Expr::Block(diverge) => diverge.to_tokens(tokens),
  433. _ => token::Brace::default().surround(tokens, |tokens| {
  434. expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt());
  435. }),
  436. }
  437. }
  438. }
  439. self.semi_token.to_tokens(tokens);
  440. }
  441. }
  442. #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
  443. impl ToTokens for StmtMacro {
  444. fn to_tokens(&self, tokens: &mut TokenStream) {
  445. expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
  446. self.mac.to_tokens(tokens);
  447. self.semi_token.to_tokens(tokens);
  448. }
  449. }
  450. }