1 /// Define a type that supports parsing and printing a given identifier as if it
6 /// As a convention, it is recommended that this macro be invoked within a
7 /// module called `kw` or `keyword` and that the resulting parser be invoked
8 /// with a `kw::` or `keyword::` prefix.
12 /// syn::custom_keyword!(whatever);
16 /// The generated syntax tree node supports the following operations just like
17 /// any built-in keyword token.
19 /// - [Peeking] — `input.peek(kw::whatever)`
21 /// - [Parsing] — `input.parse::<kw::whatever>()?`
23 /// - [Printing] — `quote!( ... #whatever_token ... )`
25 /// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)`
27 /// - Field access to its span — `let sp = whatever_token.span`
29 /// [Peeking]: crate::parse::ParseBuffer::peek
30 /// [Parsing]: crate::parse::ParseBuffer::parse
31 /// [Printing]: quote::ToTokens
32 /// [`Span`]: proc_macro2::Span
36 /// This example parses input that looks like `bool = true` or `str = "value"`.
37 /// The key must be either the identifier `bool` or the identifier `str`. If
38 /// `bool`, the value may be either `true` or `false`. If `str`, the value may
39 /// be any string literal.
41 /// The symbols `bool` and `str` are not reserved keywords in Rust so these are
42 /// not considered keywords in the `syn::token` module. Like any other
43 /// identifier that is not a keyword, these can be declared as custom keywords
44 /// by crates that need to use them as such.
47 /// use syn::{LitBool, LitStr, Result, Token};
48 /// use syn::parse::{Parse, ParseStream};
51 /// syn::custom_keyword!(bool);
52 /// syn::custom_keyword!(str);
57 /// bool_token: kw::bool,
58 /// eq_token: Token![=],
62 /// str_token: kw::str,
63 /// eq_token: Token![=],
68 /// impl Parse for Argument {
69 /// fn parse(input: ParseStream) -> Result<Self> {
70 /// let lookahead = input.lookahead1();
71 /// if lookahead.peek(kw::bool) {
72 /// Ok(Argument::Bool {
73 /// bool_token: input.parse::<kw::bool>()?,
74 /// eq_token: input.parse()?,
75 /// value: input.parse()?,
77 /// } else if lookahead.peek(kw::str) {
78 /// Ok(Argument::Str {
79 /// str_token: input.parse::<kw::str>()?,
80 /// eq_token: input.parse()?,
81 /// value: input.parse()?,
84 /// Err(lookahead.error())
90 macro_rules
! custom_keyword
{
92 #[allow(non_camel_case_types)]
94 pub span
: $
crate::__private
::Span
,
98 #[allow(dead_code, non_snake_case)]
99 pub fn $ident
<__S
: $
crate::__private
::IntoSpans
<[$
crate::__private
::Span
; 1]>>(
103 span
: $
crate::__private
::IntoSpans
::into_spans(span
)[0],
107 impl $
crate::__private
::Default
for $ident
{
108 fn default() -> Self {
110 span
: $
crate::__private
::Span
::call_site(),
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
);
123 #[cfg(feature = "parsing")]
126 macro_rules
! impl_parse_for_custom_keyword
{
129 impl $
crate::token
::CustomToken
for $ident
{
130 fn peek(cursor
: $
crate::buffer
::Cursor
) -> $
crate::__private
::bool
{
131 if let Some((ident
, _rest
)) = cursor
.ident() {
132 ident
== stringify
!($ident
)
138 fn display() -> &'
static $
crate::__private
::str {
139 concat
!("`", stringify
!($ident
), "`")
143 impl $
crate::parse
::Parse
for $ident
{
144 fn parse(input
: $
crate::parse
::ParseStream
) -> $
crate::parse
::Result
<$ident
> {
145 input
.step(|cursor
| {
146 if let $
crate::__private
::Some((ident
, rest
)) = cursor
.ident() {
147 if ident
== stringify
!($ident
) {
148 return $
crate::__private
::Ok(($ident { span: ident.span() }
, rest
));
151 $
crate::__private
::Err(cursor
.error(concat
!(
163 #[cfg(not(feature = "parsing"))]
166 macro_rules
! impl_parse_for_custom_keyword
{
167 ($ident
:ident
) => {}
;
171 #[cfg(feature = "printing")]
174 macro_rules
! impl_to_tokens_for_custom_keyword
{
176 impl $
crate::__private
::ToTokens
for $ident
{
177 fn to_tokens(&self, tokens
: &mut $
crate::__private
::TokenStream2
) {
178 let ident
= $
crate::Ident
::new(stringify
!($ident
), self.span
);
179 $
crate::__private
::TokenStreamExt
::append(tokens
, ident
);
186 #[cfg(not(feature = "printing"))]
189 macro_rules
! impl_to_tokens_for_custom_keyword
{
190 ($ident
:ident
) => {}
;
194 #[cfg(feature = "clone-impls")]
197 macro_rules
! impl_clone_for_custom_keyword
{
199 impl $
crate::__private
::Copy
for $ident {}
201 #[allow(clippy::expl_impl_clone_on_copy)]
202 impl $
crate::__private
::Clone
for $ident
{
203 fn clone(&self) -> Self {
211 #[cfg(not(feature = "clone-impls"))]
214 macro_rules
! impl_clone_for_custom_keyword
{
215 ($ident
:ident
) => {}
;
219 #[cfg(feature = "extra-traits")]
222 macro_rules
! impl_extra_traits_for_custom_keyword
{
224 impl $
crate::__private
::Debug
for $ident
{
225 fn fmt(&self, f
: &mut $
crate::__private
::Formatter
) -> $
crate::__private
::fmt
::Result
{
226 $
crate::__private
::Formatter
::write_str(
228 concat
!("Keyword [", stringify
!($ident
), "]"),
233 impl $
crate::__private
::Eq
for $ident {}
235 impl $
crate::__private
::PartialEq
for $ident
{
236 fn eq(&self, _other
: &Self) -> $
crate::__private
::bool
{
241 impl $
crate::__private
::Hash
for $ident
{
242 fn hash
<__H
: $
crate::__private
::Hasher
>(&self, _state
: &mut __H
) {}
248 #[cfg(not(feature = "extra-traits"))]
251 macro_rules
! impl_extra_traits_for_custom_keyword
{
252 ($ident
:ident
) => {}
;