Skip to main content

rustfmt_nightly/parse/macros/
cfg_match.rs

1use std::panic::{AssertUnwindSafe, catch_unwind};
2
3use rustc_ast::ast;
4use rustc_ast::token::TokenKind;
5use rustc_parse::exp;
6use rustc_parse::parser::{AllowConstBlockItems, ForceCollect};
7
8use crate::parse::macros::build_stream_parser;
9use crate::parse::session::ParseSess;
10
11pub(crate) fn parse_cfg_match<'a>(
12    psess: &'a ParseSess,
13    mac: &'a ast::MacCall,
14) -> Result<Vec<ast::Item>, &'static str> {
15    match catch_unwind(AssertUnwindSafe(|| parse_cfg_match_inner(psess, mac))) {
16        Ok(Ok(items)) => Ok(items),
17        Ok(err @ Err(_)) => err,
18        Err(..) => Err("failed to parse cfg_match!"),
19    }
20}
21
22fn parse_cfg_match_inner<'a>(
23    psess: &'a ParseSess,
24    mac: &'a ast::MacCall,
25) -> Result<Vec<ast::Item>, &'static str> {
26    let ts = mac.args.tokens.clone();
27    let mut parser = build_stream_parser(psess.inner(), ts);
28
29    if parser.token == TokenKind::OpenBrace {
30        return Err("Expression position cfg_match! not yet supported");
31    }
32
33    let mut items = vec![];
34
35    while parser.token.kind != TokenKind::Eof {
36        if !parser.eat_keyword(exp!(Underscore)) {
37            parser.parse_attr_item(ForceCollect::No).map_err(|e| {
38                e.cancel();
39                "Failed to parse attr item"
40            })?;
41        }
42
43        if !parser.eat(exp!(FatArrow)) {
44            return Err("Expected a fat arrow");
45        }
46
47        if !parser.eat(exp!(OpenBrace)) {
48            return Err("Expected an opening brace");
49        }
50
51        while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof {
52            let item = match parser
53                .parse_item(ForceCollect::No, AllowConstBlockItems::DoesNotMatter)
54            {
55                Ok(Some(item_ptr)) => *item_ptr,
56                Ok(None) => continue,
57                Err(err) => {
58                    err.cancel();
59                    parser.psess.dcx().reset_err_count();
60                    return Err(
61                        "Expected item inside cfg_match block, but failed to parse it as an item",
62                    );
63                }
64            };
65            if let ast::ItemKind::Mod(..) = item.kind {
66                items.push(item);
67            }
68        }
69
70        if !parser.eat(exp!(CloseBrace)) {
71            return Err("Expected a closing brace");
72        }
73
74        if parser.eat(exp!(Eof)) {
75            break;
76        }
77    }
78
79    Ok(items)
80}