quote.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. use proc_macro::{TokenStream, TokenTree};
  3. pub(crate) trait ToTokens {
  4. fn to_tokens(&self, tokens: &mut TokenStream);
  5. }
  6. impl<T: ToTokens> ToTokens for Option<T> {
  7. fn to_tokens(&self, tokens: &mut TokenStream) {
  8. if let Some(v) = self {
  9. v.to_tokens(tokens);
  10. }
  11. }
  12. }
  13. impl ToTokens for proc_macro::Group {
  14. fn to_tokens(&self, tokens: &mut TokenStream) {
  15. tokens.extend([TokenTree::from(self.clone())]);
  16. }
  17. }
  18. impl ToTokens for TokenTree {
  19. fn to_tokens(&self, tokens: &mut TokenStream) {
  20. tokens.extend([self.clone()]);
  21. }
  22. }
  23. impl ToTokens for TokenStream {
  24. fn to_tokens(&self, tokens: &mut TokenStream) {
  25. tokens.extend(self.clone());
  26. }
  27. }
  28. /// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with
  29. /// the given span.
  30. ///
  31. /// This is a similar to the
  32. /// [`quote_spanned!`](https://docs.rs/quote/latest/quote/macro.quote_spanned.html) macro from the
  33. /// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
  34. macro_rules! quote_spanned {
  35. ($span:expr => $($tt:tt)*) => {{
  36. let mut tokens;
  37. #[allow(clippy::vec_init_then_push)]
  38. {
  39. tokens = ::std::vec::Vec::new();
  40. let span = $span;
  41. quote_spanned!(@proc tokens span $($tt)*);
  42. }
  43. ::proc_macro::TokenStream::from_iter(tokens)
  44. }};
  45. (@proc $v:ident $span:ident) => {};
  46. (@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => {
  47. let mut ts = ::proc_macro::TokenStream::new();
  48. $crate::quote::ToTokens::to_tokens(&$id, &mut ts);
  49. $v.extend(ts);
  50. quote_spanned!(@proc $v $span $($tt)*);
  51. };
  52. (@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => {
  53. for token in $id {
  54. let mut ts = ::proc_macro::TokenStream::new();
  55. $crate::quote::ToTokens::to_tokens(&token, &mut ts);
  56. $v.extend(ts);
  57. }
  58. quote_spanned!(@proc $v $span $($tt)*);
  59. };
  60. (@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
  61. let mut tokens = ::std::vec::Vec::new();
  62. quote_spanned!(@proc tokens $span $($inner)*);
  63. $v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
  64. ::proc_macro::Delimiter::Parenthesis,
  65. ::proc_macro::TokenStream::from_iter(tokens)
  66. )));
  67. quote_spanned!(@proc $v $span $($tt)*);
  68. };
  69. (@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => {
  70. let mut tokens = ::std::vec::Vec::new();
  71. quote_spanned!(@proc tokens $span $($inner)*);
  72. $v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
  73. ::proc_macro::Delimiter::Bracket,
  74. ::proc_macro::TokenStream::from_iter(tokens)
  75. )));
  76. quote_spanned!(@proc $v $span $($tt)*);
  77. };
  78. (@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => {
  79. let mut tokens = ::std::vec::Vec::new();
  80. quote_spanned!(@proc tokens $span $($inner)*);
  81. $v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
  82. ::proc_macro::Delimiter::Brace,
  83. ::proc_macro::TokenStream::from_iter(tokens)
  84. )));
  85. quote_spanned!(@proc $v $span $($tt)*);
  86. };
  87. (@proc $v:ident $span:ident :: $($tt:tt)*) => {
  88. $v.push(::proc_macro::TokenTree::Punct(
  89. ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Joint)
  90. ));
  91. $v.push(::proc_macro::TokenTree::Punct(
  92. ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
  93. ));
  94. quote_spanned!(@proc $v $span $($tt)*);
  95. };
  96. (@proc $v:ident $span:ident : $($tt:tt)*) => {
  97. $v.push(::proc_macro::TokenTree::Punct(
  98. ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
  99. ));
  100. quote_spanned!(@proc $v $span $($tt)*);
  101. };
  102. (@proc $v:ident $span:ident , $($tt:tt)*) => {
  103. $v.push(::proc_macro::TokenTree::Punct(
  104. ::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone)
  105. ));
  106. quote_spanned!(@proc $v $span $($tt)*);
  107. };
  108. (@proc $v:ident $span:ident @ $($tt:tt)*) => {
  109. $v.push(::proc_macro::TokenTree::Punct(
  110. ::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone)
  111. ));
  112. quote_spanned!(@proc $v $span $($tt)*);
  113. };
  114. (@proc $v:ident $span:ident ! $($tt:tt)*) => {
  115. $v.push(::proc_macro::TokenTree::Punct(
  116. ::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone)
  117. ));
  118. quote_spanned!(@proc $v $span $($tt)*);
  119. };
  120. (@proc $v:ident $span:ident ; $($tt:tt)*) => {
  121. $v.push(::proc_macro::TokenTree::Punct(
  122. ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone)
  123. ));
  124. quote_spanned!(@proc $v $span $($tt)*);
  125. };
  126. (@proc $v:ident $span:ident + $($tt:tt)*) => {
  127. $v.push(::proc_macro::TokenTree::Punct(
  128. ::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone)
  129. ));
  130. quote_spanned!(@proc $v $span $($tt)*);
  131. };
  132. (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
  133. $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
  134. quote_spanned!(@proc $v $span $($tt)*);
  135. };
  136. }
  137. /// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with
  138. /// mixed site span ([`Span::mixed_site()`]).
  139. ///
  140. /// This is a similar to the [`quote!`](https://docs.rs/quote/latest/quote/macro.quote.html) macro
  141. /// from the `quote` crate but provides only just enough functionality needed by the current
  142. /// `macros` crate.
  143. ///
  144. /// [`Span::mixed_site()`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.mixed_site
  145. macro_rules! quote {
  146. ($($tt:tt)*) => {
  147. quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*)
  148. }
  149. }