| //@ force-host |
| //@ no-prefer-dynamic |
| |
| // Proc macros commonly used by tests. |
| // `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros. |
| |
| #![crate_type = "proc-macro"] |
| |
| 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() |
| } |