xref: /third_party/rust/crates/cxx/syntax/cfg.rs (revision 33d722a9)
1use proc_macro2::Ident;
2use std::mem;
3use syn::parse::{Error, ParseStream, Result};
4use syn::{parenthesized, token, Attribute, LitStr, Token};
5
6#[derive(Clone)]
7pub enum CfgExpr {
8    Unconditional,
9    Eq(Ident, Option<LitStr>),
10    All(Vec<CfgExpr>),
11    Any(Vec<CfgExpr>),
12    Not(Box<CfgExpr>),
13}
14
15impl CfgExpr {
16    pub fn merge(&mut self, expr: CfgExpr) {
17        if let CfgExpr::Unconditional = self {
18            *self = expr;
19        } else if let CfgExpr::All(list) = self {
20            list.push(expr);
21        } else {
22            let prev = mem::replace(self, CfgExpr::Unconditional);
23            *self = CfgExpr::All(vec![prev, expr]);
24        }
25    }
26}
27
28pub fn parse_attribute(attr: &Attribute) -> Result<CfgExpr> {
29    attr.parse_args_with(|input: ParseStream| {
30        let cfg_expr = input.call(parse_single)?;
31        input.parse::<Option<Token![,]>>()?;
32        Ok(cfg_expr)
33    })
34}
35
36fn parse_single(input: ParseStream) -> Result<CfgExpr> {
37    let ident: Ident = input.parse()?;
38    let lookahead = input.lookahead1();
39    if input.peek(token::Paren) {
40        let content;
41        parenthesized!(content in input);
42        if ident == "all" {
43            let list = content.call(parse_multiple)?;
44            Ok(CfgExpr::All(list))
45        } else if ident == "any" {
46            let list = content.call(parse_multiple)?;
47            Ok(CfgExpr::Any(list))
48        } else if ident == "not" {
49            let expr = content.call(parse_single)?;
50            content.parse::<Option<Token![,]>>()?;
51            Ok(CfgExpr::Not(Box::new(expr)))
52        } else {
53            Err(Error::new(ident.span(), "unrecognized cfg expression"))
54        }
55    } else if lookahead.peek(Token![=]) {
56        input.parse::<Token![=]>()?;
57        let string: LitStr = input.parse()?;
58        Ok(CfgExpr::Eq(ident, Some(string)))
59    } else if lookahead.peek(Token![,]) || input.is_empty() {
60        Ok(CfgExpr::Eq(ident, None))
61    } else {
62        Err(lookahead.error())
63    }
64}
65
66fn parse_multiple(input: ParseStream) -> Result<Vec<CfgExpr>> {
67    let mut vec = Vec::new();
68    while !input.is_empty() {
69        let expr = input.call(parse_single)?;
70        vec.push(expr);
71        if input.is_empty() {
72            break;
73        }
74        input.parse::<Token![,]>()?;
75    }
76    Ok(vec)
77}
78