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)*);
18 let subtree = tt::Subtree {
19 delimiter: Some(tt::Delimiter {
20 kind: tt::DelimiterKind::$delim,
21 id: tt::TokenId::unspecified(),
23 token_trees: $crate::quote::IntoTt::to_tokens(children),
29 ( @PUNCT $first:literal ) => {
32 tt::Leaf::Punct(tt::Punct {
34 spacing: tt::Spacing::Alone,
35 id: tt::TokenId::unspecified(),
41 ( @PUNCT $first:literal, $sec:literal ) => {
44 tt::Leaf::Punct(tt::Punct {
46 spacing: tt::Spacing::Joint,
47 id: tt::TokenId::unspecified(),
49 tt::Leaf::Punct(tt::Punct {
51 spacing: tt::Spacing::Alone,
52 id: tt::TokenId::unspecified(),
59 ( # $first:ident $($tail:tt)* ) => {
61 let token = $crate::quote::ToTokenTree::to_token($first);
62 let mut tokens = vec![token.into()];
63 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
64 tokens.append(&mut tail_tokens);
69 ( ## $first:ident $($tail:tt)* ) => {
71 let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
72 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
73 tokens.append(&mut tail_tokens);
79 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
81 ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) };
83 ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) };
86 ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] };
90 tt::Leaf::Ident(tt::Ident {
91 text: stringify!($tt).into(),
92 id: tt::TokenId::unspecified(),
98 // FIXME: Not all puncts are handled
99 ( -> ) => {$crate::__quote!(@PUNCT '-', '>')};
100 ( & ) => {$crate::__quote!(@PUNCT '&')};
101 ( , ) => {$crate::__quote!(@PUNCT ',')};
102 ( : ) => {$crate::__quote!(@PUNCT ':')};
103 ( :: ) => {$crate::__quote!(@PUNCT ':', ':')};
104 ( . ) => {$crate::__quote!(@PUNCT '.')};
106 ( $first:tt $($tail:tt)+ ) => {
108 let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first));
109 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
111 tokens.append(&mut tail_tokens);
118 /// It probably should implement in proc-macro
122 $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*))
126 pub(crate) trait IntoTt {
127 fn to_subtree(self) -> tt::Subtree;
128 fn to_tokens(self) -> Vec<tt::TokenTree>;
131 impl IntoTt for Vec<tt::TokenTree> {
132 fn to_subtree(self) -> tt::Subtree {
133 tt::Subtree { delimiter: None, token_trees: self }
136 fn to_tokens(self) -> Vec<tt::TokenTree> {
141 impl IntoTt for tt::Subtree {
142 fn to_subtree(self) -> tt::Subtree {
146 fn to_tokens(self) -> Vec<tt::TokenTree> {
147 vec![tt::TokenTree::Subtree(self)]
151 pub(crate) trait ToTokenTree {
152 fn to_token(self) -> tt::TokenTree;
155 impl ToTokenTree for tt::TokenTree {
156 fn to_token(self) -> tt::TokenTree {
161 impl ToTokenTree for tt::Subtree {
162 fn to_token(self) -> tt::TokenTree {
167 macro_rules! impl_to_to_tokentrees {
168 ($($ty:ty => $this:ident $im:block);*) => {
170 impl ToTokenTree for $ty {
171 fn to_token($this) -> tt::TokenTree {
172 let leaf: tt::Leaf = $im.into();
177 impl ToTokenTree for &$ty {
178 fn to_token($this) -> tt::TokenTree {
179 let leaf: tt::Leaf = $im.clone().into();
187 impl_to_to_tokentrees! {
188 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
189 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
190 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
191 tt::Leaf => self { self };
192 tt::Literal => self { self };
193 tt::Ident => self { self };
194 tt::Punct => self { self };
195 &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}};
196 String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}
202 fn test_quote_delimiters() {
203 assert_eq!(quote!({}).to_string(), "{}");
204 assert_eq!(quote!(()).to_string(), "()");
205 assert_eq!(quote!([]).to_string(), "[]");
209 fn test_quote_idents() {
210 assert_eq!(quote!(32).to_string(), "32");
211 assert_eq!(quote!(struct).to_string(), "struct");
215 fn test_quote_hash_simple_literal() {
217 assert_eq!(quote!(#a).to_string(), "20");
218 let s: String = "hello".into();
219 assert_eq!(quote!(#s).to_string(), "\"hello\"");
222 fn mk_ident(name: &str) -> tt::Ident {
223 tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
227 fn test_quote_hash_token_tree() {
228 let a = mk_ident("hello");
230 let quoted = quote!(#a);
231 assert_eq!(quoted.to_string(), "hello");
232 let t = format!("{:?}", quoted);
233 assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }");
237 fn test_quote_simple_derive_copy() {
238 let name = mk_ident("Foo");
240 let quoted = quote! {
241 impl Clone for #name {
242 fn clone(&self) -> Self {
248 assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}");
252 fn test_quote_derive_copy_hack() {
253 // Assume the given struct is:
258 let struct_name = mk_ident("Foo");
259 let fields = [mk_ident("name"), mk_ident("id")];
261 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();
263 let list = tt::Subtree {
264 delimiter: Some(tt::Delimiter {
265 kind: tt::DelimiterKind::Brace,
266 id: tt::TokenId::unspecified(),
268 token_trees: fields.collect(),
271 let quoted = quote! {
272 impl Clone for #struct_name {
273 fn clone(&self) -> Self {
279 assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}");