blob: 17721d56d548ee6cb81b72f11f36e46b50e91b1c [file] [log] [blame]
David Tolnayac51b362018-08-30 23:59:52 -07001//! Extension traits to provide parsing methods on foreign types.
David Tolnay94d304f2018-08-30 23:43:53 -07002//!
3//! *This module is available if Syn is built with the `"parsing"` feature.*
4
5use proc_macro2::Ident;
6
David Tolnaye1da66f2019-04-22 14:41:06 -07007use parse::{ParseStream, Result};
8
9#[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -070010use buffer::Cursor;
David Tolnaye1da66f2019-04-22 14:41:06 -070011#[cfg(syn_can_use_associated_constants)]
12use parse::Peek;
13#[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -070014use sealed::lookahead;
David Tolnaye1da66f2019-04-22 14:41:06 -070015#[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -070016use token::CustomToken;
David Tolnay94d304f2018-08-30 23:43:53 -070017
David Tolnayc15a0002019-04-22 12:33:39 -070018/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
David Tolnay94d304f2018-08-30 23:43:53 -070019///
David Tolnayc15a0002019-04-22 12:33:39 -070020/// This trait is sealed and cannot be implemented for types outside of Syn. It
21/// is implemented only for `proc_macro2::Ident`.
David Tolnay94d304f2018-08-30 23:43:53 -070022///
23/// *This trait is available if Syn is built with the `"parsing"` feature.*
24pub trait IdentExt: Sized + private::Sealed {
25 /// Parses any identifier including keywords.
26 ///
David Tolnayb8a68e42019-04-22 14:01:56 -070027 /// This is useful when parsing macro input which allows Rust keywords as
David Tolnay94d304f2018-08-30 23:43:53 -070028 /// identifiers.
29 ///
David Tolnayc15a0002019-04-22 12:33:39 -070030 /// # Example
31 ///
David Tolnay95989db2019-01-01 15:05:57 -050032 /// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -050033 /// use syn::{Error, Ident, Result, Token};
David Tolnayac51b362018-08-30 23:59:52 -070034 /// use syn::ext::IdentExt;
David Tolnay67fea042018-11-24 14:50:20 -080035 /// use syn::parse::ParseStream;
David Tolnay94d304f2018-08-30 23:43:53 -070036 ///
David Tolnayb8a68e42019-04-22 14:01:56 -070037 /// mod kw {
38 /// syn::custom_keyword!(name);
39 /// }
40 ///
David Tolnay94d304f2018-08-30 23:43:53 -070041 /// // Parses input that looks like `name = NAME` where `NAME` can be
42 /// // any identifier.
43 /// //
44 /// // Examples:
45 /// //
46 /// // name = anything
47 /// // name = impl
David Tolnayac51b362018-08-30 23:59:52 -070048 /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
David Tolnayb8a68e42019-04-22 14:01:56 -070049 /// input.parse::<kw::name>()?;
David Tolnayac51b362018-08-30 23:59:52 -070050 /// input.parse::<Token![=]>()?;
51 /// let name = input.call(Ident::parse_any)?;
52 /// Ok(name)
53 /// }
David Tolnay94d304f2018-08-30 23:43:53 -070054 /// ```
55 fn parse_any(input: ParseStream) -> Result<Self>;
David Tolnayc15a0002019-04-22 12:33:39 -070056
David Tolnayb8a68e42019-04-22 14:01:56 -070057 /// Peeks any identifier including keywords. Usage:
58 /// `input.peek(Ident::peek_any)`
59 ///
60 /// This is different from `input.peek(Ident)` which only returns true in
61 /// the case of an ident which is not a Rust keyword.
David Tolnaye1da66f2019-04-22 14:41:06 -070062 #[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -070063 #[allow(non_upper_case_globals)]
64 const peek_any: private::PeekFn = private::PeekFn;
65
David Tolnayc15a0002019-04-22 12:33:39 -070066 /// Strips the raw marker `r#`, if any, from the beginning of an ident.
67 ///
68 /// - unraw(`x`) = `x`
69 /// - unraw(`move`) = `move`
70 /// - unraw(`r#move`) = `move`
71 ///
72 /// # Example
73 ///
74 /// In the case of interop with other languages like Python that have a
75 /// different set of keywords than Rust, we might come across macro input
76 /// that involves raw identifiers to refer to ordinary variables in the
77 /// other language with a name that happens to be a Rust keyword.
78 ///
79 /// The function below appends an identifier from the caller's input onto a
80 /// fixed prefix. Without using `unraw()`, this would tend to produce
81 /// invalid identifiers like `__pyo3_get_r#move`.
82 ///
83 /// ```edition2018
84 /// use proc_macro2::Span;
85 /// use syn::Ident;
86 /// use syn::ext::IdentExt;
87 ///
88 /// fn ident_for_getter(variable: &Ident) -> Ident {
89 /// let getter = format!("__pyo3_get_{}", variable.unraw());
90 /// Ident::new(&getter, Span::call_site())
91 /// }
92 /// ```
93 fn unraw(&self) -> Ident;
David Tolnay94d304f2018-08-30 23:43:53 -070094}
95
96impl IdentExt for Ident {
97 fn parse_any(input: ParseStream) -> Result<Self> {
98 input.step(|cursor| match cursor.ident() {
99 Some((ident, rest)) => Ok((ident, rest)),
100 None => Err(cursor.error("expected ident")),
101 })
102 }
David Tolnayc15a0002019-04-22 12:33:39 -0700103
104 fn unraw(&self) -> Ident {
105 let string = self.to_string();
106 if string.starts_with("r#") {
107 Ident::new(&string[2..], self.span())
108 } else {
109 self.clone()
110 }
111 }
David Tolnay94d304f2018-08-30 23:43:53 -0700112}
113
David Tolnaye1da66f2019-04-22 14:41:06 -0700114#[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -0700115impl Peek for private::PeekFn {
116 type Token = private::IdentAny;
117}
118
David Tolnaye1da66f2019-04-22 14:41:06 -0700119#[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -0700120impl CustomToken for private::IdentAny {
121 fn peek(cursor: Cursor) -> bool {
122 cursor.ident().is_some()
123 }
124
125 fn display() -> &'static str {
126 "identifier"
127 }
128}
129
David Tolnaye1da66f2019-04-22 14:41:06 -0700130#[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -0700131impl lookahead::Sealed for private::PeekFn {}
132
David Tolnay94d304f2018-08-30 23:43:53 -0700133mod private {
134 use proc_macro2::Ident;
135
136 pub trait Sealed {}
137
138 impl Sealed for Ident {}
David Tolnayb8a68e42019-04-22 14:01:56 -0700139
David Tolnaye1da66f2019-04-22 14:41:06 -0700140 #[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -0700141 #[derive(Copy, Clone)]
142 pub struct PeekFn;
David Tolnaye1da66f2019-04-22 14:41:06 -0700143 #[cfg(syn_can_use_associated_constants)]
David Tolnayb8a68e42019-04-22 14:01:56 -0700144 pub struct IdentAny;
David Tolnay94d304f2018-08-30 23:43:53 -0700145}