22//!
33//! See: <https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation>
44
5- use std:: { fmt, slice:: Iter as SliceIter } ;
5+ use std:: { fmt, iter :: Peekable , slice:: Iter as SliceIter } ;
66
7+ use syntax:: {
8+ ast:: { self , Meta } ,
9+ NodeOrToken ,
10+ } ;
711use tt:: SmolStr ;
812
913/// A simple configuration value passed in from the outside.
@@ -47,6 +51,12 @@ impl CfgExpr {
4751 pub fn parse < S > ( tt : & tt:: Subtree < S > ) -> CfgExpr {
4852 next_cfg_expr ( & mut tt. token_trees . iter ( ) ) . unwrap_or ( CfgExpr :: Invalid )
4953 }
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+ }
5060 /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
5161 pub fn fold ( & self , query : & dyn Fn ( & CfgAtom ) -> bool ) -> Option < bool > {
5262 match self {
@@ -62,8 +72,71 @@ impl CfgExpr {
6272 }
6373 }
6474}
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+ }
65138
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 > {
67140 let name = match it. next ( ) {
68141 None => return None ,
69142 Some ( tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( ident) ) ) => ident. text . clone ( ) ,
0 commit comments