custom_keyword.rs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. /// Define a type that supports parsing and printing a given identifier as if it
  3. /// were a keyword.
  4. ///
  5. /// # Usage
  6. ///
  7. /// As a convention, it is recommended that this macro be invoked within a
  8. /// module called `kw` or `keyword` and that the resulting parser be invoked
  9. /// with a `kw::` or `keyword::` prefix.
  10. ///
  11. /// ```
  12. /// mod kw {
  13. /// syn::custom_keyword!(whatever);
  14. /// }
  15. /// ```
  16. ///
  17. /// The generated syntax tree node supports the following operations just like
  18. /// any built-in keyword token.
  19. ///
  20. /// - [Peeking] — `input.peek(kw::whatever)`
  21. ///
  22. /// - [Parsing] — `input.parse::<kw::whatever>()?`
  23. ///
  24. /// - [Printing] — `quote!( ... #whatever_token ... )`
  25. ///
  26. /// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)`
  27. ///
  28. /// - Field access to its span — `let sp = whatever_token.span`
  29. ///
  30. /// [Peeking]: crate::parse::ParseBuffer::peek
  31. /// [Parsing]: crate::parse::ParseBuffer::parse
  32. /// [Printing]: quote::ToTokens
  33. /// [`Span`]: proc_macro2::Span
  34. ///
  35. /// # Example
  36. ///
  37. /// This example parses input that looks like `bool = true` or `str = "value"`.
  38. /// The key must be either the identifier `bool` or the identifier `str`. If
  39. /// `bool`, the value may be either `true` or `false`. If `str`, the value may
  40. /// be any string literal.
  41. ///
  42. /// The symbols `bool` and `str` are not reserved keywords in Rust so these are
  43. /// not considered keywords in the `syn::token` module. Like any other
  44. /// identifier that is not a keyword, these can be declared as custom keywords
  45. /// by crates that need to use them as such.
  46. ///
  47. /// ```
  48. /// use syn::{LitBool, LitStr, Result, Token};
  49. /// use syn::parse::{Parse, ParseStream};
  50. ///
  51. /// mod kw {
  52. /// syn::custom_keyword!(bool);
  53. /// syn::custom_keyword!(str);
  54. /// }
  55. ///
  56. /// enum Argument {
  57. /// Bool {
  58. /// bool_token: kw::bool,
  59. /// eq_token: Token![=],
  60. /// value: LitBool,
  61. /// },
  62. /// Str {
  63. /// str_token: kw::str,
  64. /// eq_token: Token![=],
  65. /// value: LitStr,
  66. /// },
  67. /// }
  68. ///
  69. /// impl Parse for Argument {
  70. /// fn parse(input: ParseStream) -> Result<Self> {
  71. /// let lookahead = input.lookahead1();
  72. /// if lookahead.peek(kw::bool) {
  73. /// Ok(Argument::Bool {
  74. /// bool_token: input.parse::<kw::bool>()?,
  75. /// eq_token: input.parse()?,
  76. /// value: input.parse()?,
  77. /// })
  78. /// } else if lookahead.peek(kw::str) {
  79. /// Ok(Argument::Str {
  80. /// str_token: input.parse::<kw::str>()?,
  81. /// eq_token: input.parse()?,
  82. /// value: input.parse()?,
  83. /// })
  84. /// } else {
  85. /// Err(lookahead.error())
  86. /// }
  87. /// }
  88. /// }
  89. /// ```
  90. #[macro_export]
  91. macro_rules! custom_keyword {
  92. ($ident:ident) => {
  93. #[allow(non_camel_case_types)]
  94. pub struct $ident {
  95. #[allow(dead_code)]
  96. pub span: $crate::__private::Span,
  97. }
  98. #[doc(hidden)]
  99. #[allow(dead_code, non_snake_case)]
  100. pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>(
  101. span: __S,
  102. ) -> $ident {
  103. $ident {
  104. span: $crate::__private::IntoSpans::into_spans(span),
  105. }
  106. }
  107. const _: () = {
  108. impl $crate::__private::Default for $ident {
  109. fn default() -> Self {
  110. $ident {
  111. span: $crate::__private::Span::call_site(),
  112. }
  113. }
  114. }
  115. $crate::impl_parse_for_custom_keyword!($ident);
  116. $crate::impl_to_tokens_for_custom_keyword!($ident);
  117. $crate::impl_clone_for_custom_keyword!($ident);
  118. $crate::impl_extra_traits_for_custom_keyword!($ident);
  119. };
  120. };
  121. }
  122. // Not public API.
  123. #[cfg(feature = "parsing")]
  124. #[doc(hidden)]
  125. #[macro_export]
  126. macro_rules! impl_parse_for_custom_keyword {
  127. ($ident:ident) => {
  128. // For peek.
  129. impl $crate::__private::CustomToken for $ident {
  130. fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool {
  131. if let $crate::__private::Some((ident, _rest)) = cursor.ident() {
  132. ident == $crate::__private::stringify!($ident)
  133. } else {
  134. false
  135. }
  136. }
  137. fn display() -> &'static $crate::__private::str {
  138. $crate::__private::concat!("`", $crate::__private::stringify!($ident), "`")
  139. }
  140. }
  141. impl $crate::parse::Parse for $ident {
  142. fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
  143. input.step(|cursor| {
  144. if let $crate::__private::Some((ident, rest)) = cursor.ident() {
  145. if ident == $crate::__private::stringify!($ident) {
  146. return $crate::__private::Ok(($ident { span: ident.span() }, rest));
  147. }
  148. }
  149. $crate::__private::Err(cursor.error($crate::__private::concat!(
  150. "expected `",
  151. $crate::__private::stringify!($ident),
  152. "`",
  153. )))
  154. })
  155. }
  156. }
  157. };
  158. }
  159. // Not public API.
  160. #[cfg(not(feature = "parsing"))]
  161. #[doc(hidden)]
  162. #[macro_export]
  163. macro_rules! impl_parse_for_custom_keyword {
  164. ($ident:ident) => {};
  165. }
  166. // Not public API.
  167. #[cfg(feature = "printing")]
  168. #[doc(hidden)]
  169. #[macro_export]
  170. macro_rules! impl_to_tokens_for_custom_keyword {
  171. ($ident:ident) => {
  172. impl $crate::__private::ToTokens for $ident {
  173. fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) {
  174. let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span);
  175. $crate::__private::TokenStreamExt::append(tokens, ident);
  176. }
  177. }
  178. };
  179. }
  180. // Not public API.
  181. #[cfg(not(feature = "printing"))]
  182. #[doc(hidden)]
  183. #[macro_export]
  184. macro_rules! impl_to_tokens_for_custom_keyword {
  185. ($ident:ident) => {};
  186. }
  187. // Not public API.
  188. #[cfg(feature = "clone-impls")]
  189. #[doc(hidden)]
  190. #[macro_export]
  191. macro_rules! impl_clone_for_custom_keyword {
  192. ($ident:ident) => {
  193. impl $crate::__private::Copy for $ident {}
  194. #[allow(clippy::expl_impl_clone_on_copy)]
  195. impl $crate::__private::Clone for $ident {
  196. fn clone(&self) -> Self {
  197. *self
  198. }
  199. }
  200. };
  201. }
  202. // Not public API.
  203. #[cfg(not(feature = "clone-impls"))]
  204. #[doc(hidden)]
  205. #[macro_export]
  206. macro_rules! impl_clone_for_custom_keyword {
  207. ($ident:ident) => {};
  208. }
  209. // Not public API.
  210. #[cfg(feature = "extra-traits")]
  211. #[doc(hidden)]
  212. #[macro_export]
  213. macro_rules! impl_extra_traits_for_custom_keyword {
  214. ($ident:ident) => {
  215. impl $crate::__private::Debug for $ident {
  216. fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult {
  217. $crate::__private::Formatter::write_str(
  218. f,
  219. $crate::__private::concat!(
  220. "Keyword [",
  221. $crate::__private::stringify!($ident),
  222. "]",
  223. ),
  224. )
  225. }
  226. }
  227. impl $crate::__private::Eq for $ident {}
  228. impl $crate::__private::PartialEq for $ident {
  229. fn eq(&self, _other: &Self) -> $crate::__private::bool {
  230. true
  231. }
  232. }
  233. impl $crate::__private::Hash for $ident {
  234. fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {}
  235. }
  236. };
  237. }
  238. // Not public API.
  239. #[cfg(not(feature = "extra-traits"))]
  240. #[doc(hidden)]
  241. #[macro_export]
  242. macro_rules! impl_extra_traits_for_custom_keyword {
  243. ($ident:ident) => {};
  244. }