1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
extern crate glob;
extern crate proc_macro;
use proc_macro::TokenStream;
use self::glob::{glob, Paths};
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, Lit, Ident, Token};
struct GlobExpand {
glob_pattern: Lit,
lambda: Ident,
}
impl Parse for GlobExpand {
fn parse(input: ParseStream) -> Result<Self> {
let glob_pattern: Lit = input.parse()?;
input.parse::<Token![;]>()?;
let lambda: Ident = input.parse()?;
Ok(GlobExpand {
glob_pattern,
lambda,
})
}
}
const PREFIX: &str = "gen_";
#[proc_macro]
pub fn glob_expand(item: TokenStream) -> TokenStream {
println!("item: \"{}\"", item.to_string());
let GlobExpand {
glob_pattern,
lambda,
} = parse_macro_input!(item as GlobExpand);
let pattern = if let Lit::Str(s) = glob_pattern {
s.value()
} else {
panic!();
};
let empty_ts: proc_macro2::TokenStream = "".parse().unwrap();
let paths: Paths = glob(&pattern).expect("Failed to read testdata dir.");
fn concat(accu: proc_macro2::TokenStream, ts: proc_macro2::TokenStream)
-> proc_macro2::TokenStream {
quote! { #accu #ts }
}
let result = paths.map(|path| {
let path_as_str = path.expect("No such file or directory")
.into_os_string().into_string().expect("bad encoding");
let canonical_name = path_as_str
.replace("\"", " ")
.replace(" ", "_")
.replace("-", "_")
.replace("*", "_")
.replace("/", "_");
let mut func_name = PREFIX.to_string();
func_name.push_str(&canonical_name);
let func_ident = proc_macro2::Ident::new(&func_name,
proc_macro2::Span::call_site());
let item = quote! {
#[test]
fn #func_ident () {
println!("path: {}", #path_as_str);
let f = #lambda ;
f( #path_as_str );
}
};
item
}).fold(empty_ts, concat);
result.into()
}