1 use proc_macro2::Ident;
2 use std::mem;
3 use syn::parse::{Error, ParseStream, Result};
4 use syn::{parenthesized, token, LitStr, Token};
5
6 #[derive(Clone)]
7 pub enum CfgExpr {
8 Unconditional,
9 Eq(Ident, Option<LitStr>),
10 All(Vec<CfgExpr>),
11 Any(Vec<CfgExpr>),
12 Not(Box<CfgExpr>),
13 }
14
15 impl CfgExpr {
merge(&mut self, expr: 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
parse_attribute(input: ParseStream) -> Result<CfgExpr>28 pub fn parse_attribute(input: ParseStream) -> Result<CfgExpr> {
29 let content;
30 parenthesized!(content in input);
31 let cfg_expr = content.call(parse_single)?;
32 content.parse::<Option<Token![,]>>()?;
33 Ok(cfg_expr)
34 }
35
parse_single(input: ParseStream) -> Result<CfgExpr>36 fn 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
parse_multiple(input: ParseStream) -> Result<Vec<CfgExpr>>66 fn 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