2021-07-18 14:53:06 -05:00
|
|
|
// force-host
|
|
|
|
// no-prefer-dynamic
|
|
|
|
|
|
|
|
#![crate_type = "proc-macro"]
|
|
|
|
#![deny(warnings)]
|
|
|
|
#![feature(proc_macro_expand, proc_macro_span)]
|
|
|
|
|
|
|
|
extern crate proc_macro;
|
|
|
|
|
|
|
|
use proc_macro::*;
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn expand_expr_is(input: TokenStream) -> TokenStream {
|
2022-04-29 02:58:41 -05:00
|
|
|
expand_expr_is_inner(input, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn expand_expr_is_trim(input: TokenStream) -> TokenStream {
|
|
|
|
expand_expr_is_inner(input, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream {
|
2021-07-18 14:53:06 -05:00
|
|
|
let mut iter = input.into_iter();
|
|
|
|
let mut expected_tts = Vec::new();
|
|
|
|
loop {
|
|
|
|
match iter.next() {
|
|
|
|
Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break,
|
|
|
|
Some(tt) => expected_tts.push(tt),
|
|
|
|
None => panic!("expected comma"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-29 02:58:41 -05:00
|
|
|
// If requested, trim the "invisible" delimiters at the start and end.
|
|
|
|
let expected = expected_tts.into_iter().collect::<TokenStream>().to_string();
|
|
|
|
let expected = if trim_invisible {
|
|
|
|
let len1 = "/*«*/ ".len();
|
|
|
|
let len2 = " /*»*/".len();
|
|
|
|
&expected[len1..expected.len() - len2]
|
|
|
|
} else {
|
|
|
|
&expected[..]
|
|
|
|
};
|
|
|
|
let expanded = iter.collect::<TokenStream>().expand_expr().unwrap().to_string();
|
|
|
|
|
|
|
|
assert_eq!(expected, expanded);
|
2021-07-18 14:53:06 -05:00
|
|
|
|
|
|
|
TokenStream::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn expand_expr_fail(input: TokenStream) -> TokenStream {
|
|
|
|
match input.expand_expr() {
|
|
|
|
Ok(ts) => panic!("expand_expr unexpectedly succeeded: `{}`", ts),
|
|
|
|
Err(_) => TokenStream::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
|
|
|
|
// Check that the passed in `file!()` invocation and a parsed `file!`
|
|
|
|
// invocation expand to the same literal.
|
|
|
|
let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string();
|
|
|
|
let parse_t = TokenStream::from_str("file!{}")
|
|
|
|
.unwrap()
|
|
|
|
.expand_expr()
|
|
|
|
.expect("expand_expr failed on internal macro")
|
|
|
|
.to_string();
|
|
|
|
assert_eq!(input_t, parse_t);
|
|
|
|
|
|
|
|
// Check that the literal matches `Span::call_site().source_file().path()`
|
|
|
|
let expect_t =
|
|
|
|
Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string();
|
|
|
|
assert_eq!(input_t, expect_t);
|
|
|
|
|
|
|
|
TokenStream::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn recursive_expand(_: TokenStream) -> TokenStream {
|
|
|
|
// Recursively call until we hit the recursion limit and get an error.
|
|
|
|
//
|
|
|
|
// NOTE: This doesn't panic if expansion fails because that'll cause a very
|
|
|
|
// large number of errors to fill the output.
|
|
|
|
TokenStream::from_str("recursive_expand!{}")
|
|
|
|
.unwrap()
|
|
|
|
.expand_expr()
|
|
|
|
.unwrap_or(std::iter::once(TokenTree::Literal(Literal::u32_suffixed(0))).collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn echo_pm(input: TokenStream) -> TokenStream {
|
|
|
|
input
|
|
|
|
}
|