2
2
//!
3
3
//! See: <https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation>
4
4
5
- use std:: { fmt, slice:: Iter as SliceIter } ;
5
+ use std:: { fmt, iter :: Peekable , slice:: Iter as SliceIter } ;
6
6
7
+ use syntax:: {
8
+ ast:: { self , Meta } ,
9
+ NodeOrToken ,
10
+ } ;
7
11
use tt:: SmolStr ;
8
12
9
13
/// A simple configuration value passed in from the outside.
@@ -47,6 +51,12 @@ impl CfgExpr {
47
51
pub fn parse < S > ( tt : & tt:: Subtree < S > ) -> CfgExpr {
48
52
next_cfg_expr ( & mut tt. token_trees . iter ( ) ) . unwrap_or ( CfgExpr :: Invalid )
49
53
}
54
+ /// Parses a `cfg` attribute from the meta
55
+ pub fn parse_from_attr_meta ( meta : Meta ) -> Option < CfgExpr > {
56
+ let tt = meta. token_tree ( ) ?;
57
+ let mut iter = tt. token_trees_and_tokens ( ) . skip ( 1 ) . peekable ( ) ;
58
+ next_cfg_expr_from_syntax ( & mut iter)
59
+ }
50
60
/// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
51
61
pub fn fold ( & self , query : & dyn Fn ( & CfgAtom ) -> bool ) -> Option < bool > {
52
62
match self {
@@ -62,8 +72,71 @@ impl CfgExpr {
62
72
}
63
73
}
64
74
}
75
+ fn next_cfg_expr_from_syntax < I > ( iter : & mut Peekable < I > ) -> Option < CfgExpr >
76
+ where
77
+ I : Iterator < Item = NodeOrToken < ast:: TokenTree , syntax:: SyntaxToken > > ,
78
+ {
79
+ let name = match iter. next ( ) {
80
+ None => return None ,
81
+ Some ( NodeOrToken :: Token ( element) ) => match element. kind ( ) {
82
+ syntax:: T ![ ident] => SmolStr :: new ( element. text ( ) ) ,
83
+ _ => return Some ( CfgExpr :: Invalid ) ,
84
+ } ,
85
+ Some ( _) => return Some ( CfgExpr :: Invalid ) ,
86
+ } ;
87
+ let result = match name. as_str ( ) {
88
+ "all" | "any" | "not" => {
89
+ let mut preds = Vec :: new ( ) ;
90
+ let Some ( NodeOrToken :: Node ( tree) ) = iter. next ( ) else {
91
+ return Some ( CfgExpr :: Invalid ) ;
92
+ } ;
93
+ let mut tree_iter = tree. token_trees_and_tokens ( ) . skip ( 1 ) . peekable ( ) ;
94
+ while tree_iter
95
+ . peek ( )
96
+ . filter (
97
+ |element| matches ! ( element, NodeOrToken :: Token ( token) if ( token. kind( ) != syntax:: T ![ ')' ] ) ) ,
98
+ )
99
+ . is_some ( )
100
+ {
101
+ let pred = next_cfg_expr_from_syntax ( & mut tree_iter) ;
102
+ if let Some ( pred) = pred {
103
+ preds. push ( pred) ;
104
+ }
105
+ }
106
+ let group = match name. as_str ( ) {
107
+ "all" => CfgExpr :: All ( preds) ,
108
+ "any" => CfgExpr :: Any ( preds) ,
109
+ "not" => CfgExpr :: Not ( Box :: new ( preds. pop ( ) . unwrap_or ( CfgExpr :: Invalid ) ) ) ,
110
+ _ => unreachable ! ( ) ,
111
+ } ;
112
+ Some ( group)
113
+ }
114
+ _ => match iter. peek ( ) {
115
+ Some ( NodeOrToken :: Token ( element) ) if ( element. kind ( ) == syntax:: T ![ =] ) => {
116
+ iter. next ( ) ;
117
+ match iter. next ( ) {
118
+ Some ( NodeOrToken :: Token ( value_token) )
119
+ if ( value_token. kind ( ) == syntax:: SyntaxKind :: STRING ) =>
120
+ {
121
+ let value = value_token. text ( ) ;
122
+ let value = SmolStr :: new ( value. trim_matches ( '"' ) ) ;
123
+ Some ( CfgExpr :: Atom ( CfgAtom :: KeyValue { key : name, value } ) )
124
+ }
125
+ _ => None ,
126
+ }
127
+ }
128
+ _ => Some ( CfgExpr :: Atom ( CfgAtom :: Flag ( name) ) ) ,
129
+ } ,
130
+ } ;
131
+ if let Some ( NodeOrToken :: Token ( element) ) = iter. peek ( ) {
132
+ if element. kind ( ) == syntax:: T ![ , ] {
133
+ iter. next ( ) ;
134
+ }
135
+ }
136
+ result
137
+ }
65
138
66
- pub ( crate ) fn next_cfg_expr < S > ( it : & mut SliceIter < ' _ , tt:: TokenTree < S > > ) -> Option < CfgExpr > {
139
+ fn next_cfg_expr < S > ( it : & mut SliceIter < ' _ , tt:: TokenTree < S > > ) -> Option < CfgExpr > {
67
140
let name = match it. next ( ) {
68
141
None => return None ,
69
142
Some ( tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( ident) ) ) => ident. text . clone ( ) ,
0 commit comments