function_name_proc_macro/
lib.rs1#[allow(unused_imports)]
2use {
3 ::core::{
4 ops::Not as _,
5 },
6 ::proc_macro::{*,
7 TokenStream,
8 },
9};
10
11#[proc_macro_attribute] pub
12fn named (
13 params: TokenStream,
14 input: TokenStream,
15) -> TokenStream
16{
17 named_impl(params.into(), input.into())
18 .unwrap_or_else(|err| {
19 let err = Some(TokenTree::from(Literal::string(err)));
20 quote!(
21 ::core::compile_error! { #err }
22 )
23 })
24 .into()
25}
26
27fn named_impl (
28 params: TokenStream,
29 input: TokenStream,
30) -> Result<TokenStream, &'static str>
31{
32 if let Some(_) = params.into_iter().next() {
34 return Err("unexpected attribute arguments".into());
35 }
36
37 let ref mut tts = input.into_iter().peekable();
38
39 let mut input = Vec::<TokenTree>::new();
40
41 while matches!(tts.peek(), Some(TokenTree::Punct(p)) if p.as_char() == '#') {
43 input.extend(tts.take(2));
44 }
45
46 let fname = loop {
48 let tt = tts.next().unwrap();
49 if matches!(tt, TokenTree::Ident(ref ident) if ident.to_string() == "fn") {
50 input.push(tt);
51 let fname = tts.peek().unwrap().to_string();
52 input.extend(tts);
53 break Some(TokenTree::from(Literal::string(&fname)));
54 }
55 input.push(tt);
56 };
57
58 let g = match input.last_mut() {
59 | Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => g,
60 | _ => return Err("expected a `fn`"),
61 };
62 let g_span = g.span();
63 *g = Group::new(g.delimiter(), {
64 let mut body = quote!(
65 macro_rules! function_name {() => (
66 #fname
67 )}
68 );
69 body.extend(g.stream());
70 body
71 });
72 g.set_span(g_span);
73 Ok(input.into_iter().collect())
74}
75
76macro_rules! quote_ {
79 (
80 @$q:tt
81 { $($code:tt)* } $($rest:tt)*
82 ) => (
83 $q.push(
84 TokenTree::Group(Group::new(
85 Delimiter::Brace,
86 quote!($($code)*)
87 ))
88 );
89 quote!(@$q $($rest)*);
90 );
91
92 (
93 @$q:tt
94 [ $($code:tt)* ]
95 $($rest:tt)*
96 ) => (
97 $q.push(
98 TokenTree::Group(Group::new(
99 Delimiter::Bracket,
100 quote!($($code)*)
101 ))
102 );
103 quote!(@$q $($rest)*);
104 );
105
106 (
107 @$q:tt
108 ( $($code:tt)* )
109 $($rest:tt)*
110 ) => (
111 $q.push(
112 TokenTree::Group(Group::new(
113 Delimiter::Parenthesis,
114 quote!($($code)*)
115 ))
116 );
117 quote!(@$q $($rest)*);
118 );
119
120 (
121 @$q:tt
122 #$var:ident
123 $($rest:tt)*
124 ) => (
125 $q.extend($var);
126 quote!(@$q $($rest)*);
127 );
128
129 (
130 @$q:tt
131 $tt:tt $($rest:tt)*
132 ) => (
133 $q.extend(
134 stringify!($tt)
135 .parse::<TokenStream>()
136 .unwrap()
137 );
138 quote!(@$q $($rest)*);
139 );
140
141 (
142 @$q:tt
143 ) => ();
145
146 (
147 $($code:tt)*
148 ) => ({
149 let mut _q = Vec::<TokenTree>::new();
150 quote!(@_q $($code)*);
151 _q.into_iter().collect::<TokenStream>()
152 });
153} use quote_ as quote;