• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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