rustfmt_nightly/parse/macros/
cfg_if.rs
1use std::panic::{AssertUnwindSafe, catch_unwind};
2
3use rustc_ast::ast;
4use rustc_ast::token::{Delimiter, TokenKind};
5use rustc_parse::exp;
6use rustc_parse::parser::ForceCollect;
7use rustc_span::symbol::kw;
8
9use crate::parse::macros::build_stream_parser;
10use crate::parse::session::ParseSess;
11
12pub(crate) fn parse_cfg_if<'a>(
13 psess: &'a ParseSess,
14 mac: &'a ast::MacCall,
15) -> Result<Vec<ast::Item>, &'static str> {
16 match catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(psess, mac))) {
17 Ok(Ok(items)) => Ok(items),
18 Ok(err @ Err(_)) => err,
19 Err(..) => Err("failed to parse cfg_if!"),
20 }
21}
22
23fn parse_cfg_if_inner<'a>(
24 psess: &'a ParseSess,
25 mac: &'a ast::MacCall,
26) -> Result<Vec<ast::Item>, &'static str> {
27 let ts = mac.args.tokens.clone();
28 let mut parser = build_stream_parser(psess.inner(), ts);
29
30 let mut items = vec![];
31 let mut process_if_cfg = true;
32
33 while parser.token.kind != TokenKind::Eof {
34 if process_if_cfg {
35 if !parser.eat_keyword(exp!(If)) {
36 return Err("Expected `if`");
37 }
38
39 if !matches!(parser.token.kind, TokenKind::Pound) {
40 return Err("Failed to parse attributes");
41 }
42
43 parser
52 .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
53 .map_err(|e| {
54 e.cancel();
55 "Failed to parse attributes"
56 })?;
57 }
58
59 if !parser.eat(exp!(OpenBrace)) {
60 return Err("Expected an opening brace");
61 }
62
63 while parser.token != TokenKind::CloseDelim(Delimiter::Brace)
64 && parser.token.kind != TokenKind::Eof
65 {
66 let item = match parser.parse_item(ForceCollect::No) {
67 Ok(Some(item_ptr)) => item_ptr.into_inner(),
68 Ok(None) => continue,
69 Err(err) => {
70 err.cancel();
71 parser.psess.dcx().reset_err_count();
72 return Err(
73 "Expected item inside cfg_if block, but failed to parse it as an item",
74 );
75 }
76 };
77 if let ast::ItemKind::Mod(..) = item.kind {
78 items.push(item);
79 }
80 }
81
82 if !parser.eat(exp!(CloseBrace)) {
83 return Err("Expected a closing brace");
84 }
85
86 if parser.eat(exp!(Eof)) {
87 break;
88 }
89
90 if !parser.eat_keyword(exp!(Else)) {
91 return Err("Expected `else`");
92 }
93
94 process_if_cfg = parser.token.is_keyword(kw::If);
95 }
96
97 Ok(items)
98}