5
5
extern crate proc_macro;
6
6
use self :: proc_macro:: TokenStream ;
7
7
use quote:: quote;
8
+ use std:: collections:: HashSet ;
8
9
use syn:: parse_macro_input;
9
10
10
11
/// `input` contains a single identifier, corresponding to a user-defined macro.
@@ -13,22 +14,26 @@ use syn::parse_macro_input;
13
14
/// See tests/analyze or below for the API.
14
15
#[ proc_macro]
15
16
pub fn for_each_api ( input : TokenStream ) -> TokenStream {
17
+ let input = parse_macro_input ! ( input as Input ) ;
16
18
let files = get_libm_files ( ) ;
17
- let functions = get_functions ( & files) ;
18
- let input = parse_macro_input ! ( input as syn:: Ident ) ;
19
+ let functions = get_functions ( & files, & input. ignored ) ;
19
20
let mut tokens = proc_macro2:: TokenStream :: new ( ) ;
21
+ let input_macro = input. macro_id ;
20
22
for function in functions {
21
23
let id = function. ident ;
24
+ let api_kind = function. api_kind ;
22
25
let ret_ty = function. ret_ty ;
23
26
let arg_tys = function. arg_tys ;
24
27
let arg_ids = get_arg_ids ( arg_tys. len ( ) ) ;
25
28
let t = quote ! {
26
- #input ! {
29
+ #input_macro ! {
27
30
id: #id;
31
+ api_kind: #api_kind;
28
32
arg_tys: #( #arg_tys) , * ;
29
33
arg_ids: #( #arg_ids) , * ;
30
34
ret_ty: #ret_ty;
31
35
}
36
+
32
37
} ;
33
38
tokens. extend ( t) ;
34
39
}
@@ -78,6 +83,7 @@ fn get_libm_files() -> Vec<syn::File> {
78
83
/// Function signature that will be expanded for the user macro.
79
84
struct FnSig {
80
85
ident : syn:: Ident ,
86
+ api_kind : syn:: Ident ,
81
87
c_abi : bool ,
82
88
ret_ty : Option < syn:: Type > ,
83
89
arg_tys : Vec < syn:: Type > ,
@@ -101,7 +107,7 @@ macro_rules! syn_to_str {
101
107
102
108
/// Extracts all public functions from the libm files while
103
109
/// doing some sanity checks on the function signatures.
104
- fn get_functions ( files : & [ syn:: File ] ) -> Vec < FnSig > {
110
+ fn get_functions ( files : & [ syn:: File ] , ignored : & Option < HashSet < String > > ) -> Vec < FnSig > {
105
111
let mut error = false ;
106
112
let mut functions = Vec :: new ( ) ;
107
113
// Traverse all files matching function items
@@ -122,10 +128,17 @@ fn get_functions(files: &[syn::File]) -> Vec<FnSig> {
122
128
// Build a function signature while doing some sanity checks
123
129
let mut fn_sig = FnSig {
124
130
ident : ident. clone ( ) ,
131
+ api_kind : to_api_kind ( ident. clone ( ) ) ,
125
132
c_abi : false ,
126
133
arg_tys : Vec :: new ( ) ,
127
134
ret_ty : None ,
128
135
} ;
136
+ // Skip ignored functions:
137
+ if let Some ( ignored) = ignored {
138
+ if ignored. contains ( & fn_sig. name ( ) ) {
139
+ continue ;
140
+ }
141
+ }
129
142
macro_rules! err {
130
143
( $msg: expr) => { {
131
144
#[ cfg( feature = "analyze" ) ]
@@ -300,3 +313,48 @@ fn get_arg_ids(len: usize) -> Vec<syn::Ident> {
300
313
}
301
314
ids
302
315
}
316
+
317
+ /// Returns the ApiKind enum variant for this function
318
+ fn to_api_kind ( id : syn:: Ident ) -> syn:: Ident {
319
+ let name = syn_to_str ! ( id) ;
320
+ let first = name. chars ( ) . nth ( 0 ) . unwrap ( ) ;
321
+ let first_upper = first. to_uppercase ( ) . nth ( 0 ) . unwrap ( ) ;
322
+ let name = name. replacen ( first, & first_upper. to_string ( ) , 1 ) ;
323
+ syn:: Ident :: new ( & name, proc_macro2:: Span :: call_site ( ) )
324
+ }
325
+
326
+ #[ derive( Debug ) ]
327
+ struct Input {
328
+ macro_id : syn:: Ident ,
329
+ ignored : Option < HashSet < String > > ,
330
+ }
331
+
332
+ impl syn:: parse:: Parse for Input {
333
+ fn parse ( input : syn:: parse:: ParseStream ) -> syn:: Result < Self > {
334
+ let content;
335
+ let macro_id: syn:: Ident = input. parse ( ) ?;
336
+ let lookahead = input. lookahead1 ( ) ;
337
+ if lookahead. peek ( syn:: token:: Paren ) {
338
+ let _paren_token = syn:: parenthesized!( content in input) ;
339
+ let ignored: syn:: Lit = content. parse :: < syn:: Lit > ( ) ?;
340
+ if let syn:: Lit :: Str ( c) = ignored {
341
+ let s = c. value ( ) ;
342
+ let mut hash_set = HashSet :: < String > :: new ( ) ;
343
+ for i in s. split ( "," ) {
344
+ hash_set. insert ( i. to_string ( ) ) ;
345
+ }
346
+ Ok ( Input {
347
+ macro_id : macro_id,
348
+ ignored : Some ( hash_set) ,
349
+ } )
350
+ } else {
351
+ Err ( lookahead. error ( ) )
352
+ }
353
+ } else {
354
+ Ok ( Input {
355
+ macro_id : macro_id,
356
+ ignored : None ,
357
+ } )
358
+ }
359
+ }
360
+ }
0 commit comments