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 '.')};
105 ( < ) => {$crate::__quote!(@PUNCT '<')};
106 ( > ) => {$crate::__quote!(@PUNCT '>')};
108 ( $first:tt $($tail:tt)+ ) => {
110 let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first));
111 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
113 tokens.append(&mut tail_tokens);
120 /// It probably should implement in proc-macro
124 $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*))
128 pub(crate) trait IntoTt {
129 fn to_subtree(self) -> tt::Subtree;
130 fn to_tokens(self) -> Vec<tt::TokenTree>;
133 impl IntoTt for Vec<tt::TokenTree> {
134 fn to_subtree(self) -> tt::Subtree {
135 tt::Subtree { delimiter: None, token_trees: self }
138 fn to_tokens(self) -> Vec<tt::TokenTree> {
143 impl IntoTt for tt::Subtree {
144 fn to_subtree(self) -> tt::Subtree {
148 fn to_tokens(self) -> Vec<tt::TokenTree> {
149 vec![tt::TokenTree::Subtree(self)]
153 pub(crate) trait ToTokenTree {
154 fn to_token(self) -> tt::TokenTree;
157 impl ToTokenTree for tt::TokenTree {
158 fn to_token(self) -> tt::TokenTree {
163 impl ToTokenTree for tt::Subtree {
164 fn to_token(self) -> tt::TokenTree {
169 macro_rules! impl_to_to_tokentrees {
170 ($($ty:ty => $this:ident $im:block);*) => {
172 impl ToTokenTree for $ty {
173 fn to_token($this) -> tt::TokenTree {
174 let leaf: tt::Leaf = $im.into();
179 impl ToTokenTree for &$ty {
180 fn to_token($this) -> tt::TokenTree {
181 let leaf: tt::Leaf = $im.clone().into();
189 impl_to_to_tokentrees! {
190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
193 tt::Leaf => self { self };
194 tt::Literal => self { self };
195 tt::Ident => self { self };
196 tt::Punct => self { self };
197 &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}};
198 String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}
204 fn test_quote_delimiters() {
205 assert_eq!(quote!({}).to_string(), "{}");
206 assert_eq!(quote!(()).to_string(), "()");
207 assert_eq!(quote!([]).to_string(), "[]");
211 fn test_quote_idents() {
212 assert_eq!(quote!(32).to_string(), "32");
213 assert_eq!(quote!(struct).to_string(), "struct");
217 fn test_quote_hash_simple_literal() {
219 assert_eq!(quote!(#a).to_string(), "20");
220 let s: String = "hello".into();
221 assert_eq!(quote!(#s).to_string(), "\"hello\"");
224 fn mk_ident(name: &str) -> tt::Ident {
225 tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
229 fn test_quote_hash_token_tree() {
230 let a = mk_ident("hello");
232 let quoted = quote!(#a);
233 assert_eq!(quoted.to_string(), "hello");
234 let t = format!("{:?}", quoted);
235 assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }");
239 fn test_quote_simple_derive_copy() {
240 let name = mk_ident("Foo");
242 let quoted = quote! {
243 impl Clone for #name {
244 fn clone(&self) -> Self {
250 assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}");
254 fn test_quote_derive_copy_hack() {
255 // Assume the given struct is:
260 let struct_name = mk_ident("Foo");
261 let fields = [mk_ident("name"), mk_ident("id")];
263 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();
265 let list = tt::Subtree {
266 delimiter: Some(tt::Delimiter {
267 kind: tt::DelimiterKind::Brace,
268 id: tt::TokenId::unspecified(),
270 token_trees: fields.collect(),
273 let quoted = quote! {
274 impl Clone for #struct_name {
275 fn clone(&self) -> Self {
281 assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}");