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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// Proc macros commonly used by tests.
// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros.
extern crate proc_macro;
use proc_macro::{TokenStream, TokenTree};
// Macro that return empty token stream.
#[proc_macro]
pub fn empty(_: TokenStream) -> TokenStream {
TokenStream::new()
}
#[proc_macro_attribute]
pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream {
TokenStream::new()
}
#[proc_macro_derive(Empty, attributes(empty_helper))]
pub fn empty_derive(_: TokenStream) -> TokenStream {
TokenStream::new()
}
// Macro that panics.
#[proc_macro]
pub fn panic_bang(_: TokenStream) -> TokenStream {
panic!("panic-bang");
}
#[proc_macro_attribute]
pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream {
panic!("panic-attr");
}
#[proc_macro_derive(Panic, attributes(panic_helper))]
pub fn panic_derive(_: TokenStream) -> TokenStream {
panic!("panic-derive");
}
// Macros that return the input stream.
#[proc_macro]
pub fn identity(input: TokenStream) -> TokenStream {
input
}
#[proc_macro_attribute]
pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream {
input
}
#[proc_macro_derive(Identity, attributes(identity_helper))]
pub fn identity_derive(input: TokenStream) -> TokenStream {
input
}
// Macros that iterate and re-collect the input stream.
#[proc_macro]
pub fn recollect(input: TokenStream) -> TokenStream {
input.into_iter().collect()
}
#[proc_macro_attribute]
pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream {
input.into_iter().collect()
}
#[proc_macro_derive(Recollect, attributes(recollect_helper))]
pub fn recollect_derive(input: TokenStream) -> TokenStream {
input.into_iter().collect()
}
// Macros that print their input in the original and re-collected forms (if they differ).
fn print_helper(input: TokenStream, kind: &str) -> TokenStream {
print_helper_ext(input, kind, true)
}
fn deep_recollect(input: TokenStream) -> TokenStream {
input.into_iter().map(|tree| {
match tree {
TokenTree::Group(group) => {
let inner = deep_recollect(group.stream());
let mut new_group = TokenTree::Group(
proc_macro::Group::new(group.delimiter(), inner)
);
new_group.set_span(group.span());
new_group
}
_ => tree,
}
}).collect()
}
fn print_helper_ext(input: TokenStream, kind: &str, debug: bool) -> TokenStream {
let input_display = format!("{}", input);
let input_debug = format!("{:#?}", input);
let recollected = input.clone().into_iter().collect();
let recollected_display = format!("{}", recollected);
let recollected_debug = format!("{:#?}", recollected);
let deep_recollected = deep_recollect(input);
let deep_recollected_display = format!("{}", deep_recollected);
let deep_recollected_debug = format!("{:#?}", deep_recollected);
println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display);
if recollected_display != input_display {
println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display);
}
if deep_recollected_display != recollected_display {
println!("PRINT-{} DEEP-RE-COLLECTED (DISPLAY): {}", kind, deep_recollected_display);
}
if debug {
println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug);
if recollected_debug != input_debug {
println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug);
}
if deep_recollected_debug != recollected_debug {
println!("PRINT-{} DEEP-RE-COLLETED (DEBUG): {}", kind, deep_recollected_debug);
}
}
recollected
}
#[proc_macro]
pub fn print_bang(input: TokenStream) -> TokenStream {
print_helper(input, "BANG")
}
#[proc_macro]
pub fn print_bang_consume(input: TokenStream) -> TokenStream {
print_helper(input, "BANG");
TokenStream::new()
}
#[proc_macro_attribute]
pub fn print_attr(args: TokenStream, input: TokenStream) -> TokenStream {
let debug = match &args.into_iter().collect::<Vec<_>>()[..] {
[TokenTree::Ident(ident)] if ident.to_string() == "nodebug" => false,
_ => true,
};
print_helper_ext(input, "ATTR", debug)
}
#[proc_macro_attribute]
pub fn print_attr_args(args: TokenStream, input: TokenStream) -> TokenStream {
print_helper(args, "ATTR_ARGS");
input
}
#[proc_macro_attribute]
pub fn print_target_and_args(args: TokenStream, input: TokenStream) -> TokenStream {
print_helper(args, "ATTR_ARGS");
print_helper(input.clone(), "ATTR");
input
}
#[proc_macro_attribute]
pub fn print_target_and_args_consume(args: TokenStream, input: TokenStream) -> TokenStream {
print_helper(args, "ATTR_ARGS");
print_helper(input.clone(), "ATTR");
TokenStream::new()
}
#[proc_macro_derive(Print, attributes(print_helper))]
pub fn print_derive(input: TokenStream) -> TokenStream {
print_helper(input, "DERIVE");
TokenStream::new()
}
|