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
|
#[macro_use]
extern crate proc_macro_error;
#[macro_use]
extern crate syn;
extern crate proc_macro;
use proc_macro2::Span;
use proc_macro_error::{set_dummy, Level, OptionExt, ResultExt};
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
Ident,
};
struct IdentOrUnderscore {
span: Span,
part: String,
}
impl IdentOrUnderscore {
fn new(span: Span, part: String) -> Self {
IdentOrUnderscore { span, part }
}
}
impl Parse for IdentOrUnderscore {
fn parse(input: ParseStream) -> syn::Result<Self> {
let la = input.lookahead1();
if la.peek(Ident) {
let t = input.parse::<Ident>().unwrap();
Ok(IdentOrUnderscore::new(t.span(), t.to_string()))
} else if la.peek(Token![_]) {
let t = input.parse::<Token![_]>().unwrap();
Ok(IdentOrUnderscore::new(t.span(), "_".to_string()))
} else {
Err(la.error())
}
}
}
struct Args(Vec<IdentOrUnderscore>);
impl Parse for Args {
fn parse(input: ParseStream) -> syn::Result<Self> {
let args = Punctuated::<_, Token![,]>::parse_terminated(input)?;
Ok(Args(args.into_iter().collect()))
}
}
#[proc_macro]
#[proc_macro_error]
pub fn make_fn(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut name = String::new();
let input = parse_macro_input!(input as Args);
for arg in input.0 {
match &*arg.part {
"abort" => abort!(
arg.span,
"abort! 3{} args {}", "+", "test";
hint = "help {} test", "message"
),
"abort_call_site" => abort_call_site!(
"abort_call_site! 2{} args {}", "+", "test";
help = "help {} test", "message"
),
"direct_abort" => {
diagnostic!(arg.span, Level::Error, "direct MacroError::abort() test").abort()
}
"result_expect" => {
let e = syn::Error::new(arg.span, "error");
Err(e).expect_or_abort("Result::expect_or_abort() test")
}
"result_unwrap" => {
let e = syn::Error::new(arg.span, "Result::unwrap_or_abort() test");
Err(e).unwrap_or_abort()
}
"option_expect" => None.expect_or_abort("Option::expect_or_abort() test"),
"need_default" => {
set_dummy(quote! {
impl Default for NeedDefault {
fn default() -> Self {
NeedDefault::A
}
}
});
abort!(arg.span, "set_dummy test")
}
part if part.starts_with("multi") => {
let no_help: Option<String> = Option::None;
let help = Some("Option help test");
emit_error!(
arg.span,
"multiple error part: {}", part;
note = "help {} test", "message";
hint =? help;
wow = "I see what you did here...";
help =? no_help
)
}
_ => name.push_str(&arg.part),
}
}
// test that unrelated panics are not affected
if name.is_empty() {
panic!("unrelated panic test")
}
let name = Ident::new(&name, Span::call_site());
quote!( fn #name() {} ).into()
}
|