1use crate::syntax::cfg::{CfgExpr, ComputedCfg};
2use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream};
3use quote::{ToTokens, TokenStreamExt as _};
4use syn::{token, AttrStyle, Attribute, MacroDelimiter, Meta, MetaList, Path, Token};
5
6impl<'a> ComputedCfg<'a> {
7 pub(crate) fn into_attr(&self) -> Option<Attribute> {
8 if let ComputedCfg::Leaf(CfgExpr::Unconditional) = self {
9 None
10 } else {
11 let span = Span::call_site();
12 Some(Attribute {
13 pound_token: Token,
14 style: AttrStyle::Outer,
15 bracket_token: token::Bracket(span),
16 meta: Meta::List(MetaList {
17 path: Path::from(Ident::new("cfg", span)),
18 delimiter: MacroDelimiter::Paren(token::Paren(span)),
19 tokens: self.as_meta().into_token_stream(),
20 }),
21 })
22 }
23 }
24
25 pub(crate) fn as_meta(&self) -> impl ToTokens + '_ {
26 Print {
27 cfg: self,
28 span: Span::call_site(),
29 }
30 }
31}
32
33struct Print<'a, Cfg> {
34 cfg: &'a Cfg,
35 span: Span,
36}
37
38impl<'a> ToTokens for Print<'a, CfgExpr> {
39 fn to_tokens(&self, tokens: &mut TokenStream) {
40 let span = self.span;
41 let print = |cfg| Print { cfg, span };
42 match self.cfg {
43 CfgExpr::Unconditional => unreachable!(),
44 CfgExpr::Eq(ident, value) => {
45 ident.to_tokens(tokens);
46 if let Some(value) = value {
47 Token.to_tokens(tokens);
48 value.to_tokens(tokens);
49 }
50 }
51 CfgExpr::All(inner) => {
52 tokens.append(Ident::new("all", span));
53 let mut group = TokenStream::new();
54 group.append_separated(inner.iter().map(print), Token);
55 tokens.append(Group::new(Delimiter::Parenthesis, group));
56 }
57 CfgExpr::Any(inner) => {
58 tokens.append(Ident::new("any", span));
59 let mut group = TokenStream::new();
60 group.append_separated(inner.iter().map(print), Token);
61 tokens.append(Group::new(Delimiter::Parenthesis, group));
62 }
63 CfgExpr::Not(inner) => {
64 tokens.append(Ident::new("not", span));
65 let group = print(inner).into_token_stream();
66 tokens.append(Group::new(Delimiter::Parenthesis, group));
67 }
68 }
69 }
70}
71
72impl<'a> ToTokens for Print<'a, ComputedCfg<'a>> {
73 fn to_tokens(&self, tokens: &mut TokenStream) {
74 let span = self.span;
75 match *self.cfg {
76 ComputedCfg::Leaf(cfg) => Print { cfg, span }.to_tokens(tokens),
77 ComputedCfg::All(ref inner) => {
78 tokens.append(Ident::new("all", span));
79 let mut group = TokenStream::new();
80 group.append_separated(
81 inner.iter().map(|&cfg| Print { cfg, span }),
82 Token,
83 );
84 tokens.append(Group::new(Delimiter::Parenthesis, group));
85 }
86 ComputedCfg::Any(ref inner) => {
87 tokens.append(Ident::new("any", span));
88 let mut group = TokenStream::new();
89 group
90 .append_separated(inner.iter().map(|cfg| Print { cfg, span }), Token);
91 tokens.append(Group::new(Delimiter::Parenthesis, group));
92 }
93 }
94 }
95}