1 //! A simplified version of quote-crate like quasi quote macro
3 // A helper macro quote macro
5 // 1. Not all puncts are handled
6 // 2. #()* pattern repetition not supported now
7 // * But we can do it manually, see `test_quote_derive_copy_hack`
10 macro_rules! __quote {
12 Vec::<tt::TokenTree>::new()
15 ( @SUBTREE $delim:ident $($tt:tt)* ) => {
17 let children = $crate::__quote!($($tt)*);
19 delimiter: Some(tt::Delimiter {
20 kind: tt::DelimiterKind::$delim,
21 id: tt::TokenId::unspecified(),
23 token_trees: $crate::quote::IntoTt::to_tokens(children),
28 ( @PUNCT $first:literal ) => {
31 tt::Leaf::Punct(tt::Punct {
33 spacing: tt::Spacing::Alone,
34 id: tt::TokenId::unspecified(),
40 ( @PUNCT $first:literal, $sec:literal ) => {
43 tt::Leaf::Punct(tt::Punct {
45 spacing: tt::Spacing::Joint,
46 id: tt::TokenId::unspecified(),
48 tt::Leaf::Punct(tt::Punct {
50 spacing: tt::Spacing::Alone,
51 id: tt::TokenId::unspecified(),
58 ( # $first:ident $($tail:tt)* ) => {
60 let token = $crate::quote::ToTokenTree::to_token($first);
61 let mut tokens = vec![token.into()];
62 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
63 tokens.append(&mut tail_tokens);
68 ( ## $first:ident $($tail:tt)* ) => {
70 let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
71 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
72 tokens.append(&mut tail_tokens);
78 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
80 ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) };
82 ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) };
85 ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] };
89 tt::Leaf::Ident(tt::Ident {
90 text: stringify!($tt).into(),
91 id: tt::TokenId::unspecified(),
97 // FIXME: Not all puncts are handled
98 ( -> ) => {$crate::__quote!(@PUNCT '-', '>')};
99 ( & ) => {$crate::__quote!(@PUNCT '&')};
100 ( , ) => {$crate::__quote!(@PUNCT ',')};
101 ( : ) => {$crate::__quote!(@PUNCT ':')};
102 ( ; ) => {$crate::__quote!(@PUNCT ';')};
103 ( :: ) => {$crate::__quote!(@PUNCT ':', ':')};
104 ( . ) => {$crate::__quote!(@PUNCT '.')};
105 ( < ) => {$crate::__quote!(@PUNCT '<')};
106 ( > ) => {$crate::__quote!(@PUNCT '>')};
107 ( ! ) => {$crate::__quote!(@PUNCT '!')};
109 ( $first:tt $($tail:tt)+ ) => {
111 let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first));
112 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
114 tokens.append(&mut tail_tokens);
121 /// It probably should implement in proc-macro
125 $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*))
129 pub(crate) trait IntoTt {
130 fn to_subtree(self) -> tt::Subtree;
131 fn to_tokens(self) -> Vec<tt::TokenTree>;
134 impl IntoTt for Vec<tt::TokenTree> {
135 fn to_subtree(self) -> tt::Subtree {
136 tt::Subtree { delimiter: None, token_trees: self }
139 fn to_tokens(self) -> Vec<tt::TokenTree> {
144 impl IntoTt for tt::Subtree {
145 fn to_subtree(self) -> tt::Subtree {
149 fn to_tokens(self) -> Vec<tt::TokenTree> {
150 vec![tt::TokenTree::Subtree(self)]
154 pub(crate) trait ToTokenTree {
155 fn to_token(self) -> tt::TokenTree;
158 impl ToTokenTree for tt::TokenTree {
159 fn to_token(self) -> tt::TokenTree {
164 impl ToTokenTree for tt::Subtree {
165 fn to_token(self) -> tt::TokenTree {
170 macro_rules! impl_to_to_tokentrees {
171 ($($ty:ty => $this:ident $im:block);*) => {
173 impl ToTokenTree for $ty {
174 fn to_token($this) -> tt::TokenTree {
175 let leaf: tt::Leaf = $im.into();
180 impl ToTokenTree for &$ty {
181 fn to_token($this) -> tt::TokenTree {
182 let leaf: tt::Leaf = $im.clone().into();
190 impl_to_to_tokentrees! {
191 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
192 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
193 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
194 bool => self { tt::Ident{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
195 tt::Leaf => self { self };
196 tt::Literal => self { self };
197 tt::Ident => self { self };
198 tt::Punct => self { self };
199 &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}};
200 String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}
206 fn test_quote_delimiters() {
207 assert_eq!(quote!({}).to_string(), "{}");
208 assert_eq!(quote!(()).to_string(), "()");
209 assert_eq!(quote!([]).to_string(), "[]");
213 fn test_quote_idents() {
214 assert_eq!(quote!(32).to_string(), "32");
215 assert_eq!(quote!(struct).to_string(), "struct");
219 fn test_quote_hash_simple_literal() {
221 assert_eq!(quote!(#a).to_string(), "20");
222 let s: String = "hello".into();
223 assert_eq!(quote!(#s).to_string(), "\"hello\"");
226 fn mk_ident(name: &str) -> tt::Ident {
227 tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
231 fn test_quote_hash_token_tree() {
232 let a = mk_ident("hello");
234 let quoted = quote!(#a);
235 assert_eq!(quoted.to_string(), "hello");
236 let t = format!("{:?}", quoted);
237 assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295");
241 fn test_quote_simple_derive_copy() {
242 let name = mk_ident("Foo");
244 let quoted = quote! {
245 impl Clone for #name {
246 fn clone(&self) -> Self {
252 assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}");
256 fn test_quote_derive_copy_hack() {
257 // Assume the given struct is:
262 let struct_name = mk_ident("Foo");
263 let fields = [mk_ident("name"), mk_ident("id")];
264 let fields = fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees).flatten();
266 let list = tt::Subtree {
267 delimiter: Some(tt::Delimiter {
268 kind: tt::DelimiterKind::Brace,
269 id: tt::TokenId::unspecified(),
271 token_trees: fields.collect(),
274 let quoted = quote! {
275 impl Clone for #struct_name {
276 fn clone(&self) -> Self {
282 assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}");