mirror of https://github.com/torvalds/linux.git
139 lines
3.9 KiB
Rust
139 lines
3.9 KiB
Rust
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
//! Extension traits to provide parsing methods on foreign types.
|
|
|
|
use crate::buffer::Cursor;
|
|
use crate::error::Result;
|
|
use crate::parse::ParseStream;
|
|
use crate::parse::Peek;
|
|
use crate::sealed::lookahead;
|
|
use crate::token::CustomToken;
|
|
use proc_macro2::Ident;
|
|
|
|
/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
|
|
///
|
|
/// This trait is sealed and cannot be implemented for types outside of Syn. It
|
|
/// is implemented only for `proc_macro2::Ident`.
|
|
pub trait IdentExt: Sized + private::Sealed {
|
|
/// Parses any identifier including keywords.
|
|
///
|
|
/// This is useful when parsing macro input which allows Rust keywords as
|
|
/// identifiers.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// use syn::{Error, Ident, Result, Token};
|
|
/// use syn::ext::IdentExt;
|
|
/// use syn::parse::ParseStream;
|
|
///
|
|
/// mod kw {
|
|
/// syn::custom_keyword!(name);
|
|
/// }
|
|
///
|
|
/// // Parses input that looks like `name = NAME` where `NAME` can be
|
|
/// // any identifier.
|
|
/// //
|
|
/// // Examples:
|
|
/// //
|
|
/// // name = anything
|
|
/// // name = impl
|
|
/// fn parse_dsl(input: ParseStream) -> Result<Ident> {
|
|
/// input.parse::<kw::name>()?;
|
|
/// input.parse::<Token![=]>()?;
|
|
/// let name = input.call(Ident::parse_any)?;
|
|
/// Ok(name)
|
|
/// }
|
|
/// ```
|
|
fn parse_any(input: ParseStream) -> Result<Self>;
|
|
|
|
/// Peeks any identifier including keywords. Usage:
|
|
/// `input.peek(Ident::peek_any)`
|
|
///
|
|
/// This is different from `input.peek(Ident)` which only returns true in
|
|
/// the case of an ident which is not a Rust keyword.
|
|
#[allow(non_upper_case_globals)]
|
|
const peek_any: private::PeekFn = private::PeekFn;
|
|
|
|
/// Strips the raw marker `r#`, if any, from the beginning of an ident.
|
|
///
|
|
/// - unraw(`x`) = `x`
|
|
/// - unraw(`move`) = `move`
|
|
/// - unraw(`r#move`) = `move`
|
|
///
|
|
/// # Example
|
|
///
|
|
/// In the case of interop with other languages like Python that have a
|
|
/// different set of keywords than Rust, we might come across macro input
|
|
/// that involves raw identifiers to refer to ordinary variables in the
|
|
/// other language with a name that happens to be a Rust keyword.
|
|
///
|
|
/// The function below appends an identifier from the caller's input onto a
|
|
/// fixed prefix. Without using `unraw()`, this would tend to produce
|
|
/// invalid identifiers like `__pyo3_get_r#move`.
|
|
///
|
|
/// ```
|
|
/// use proc_macro2::Span;
|
|
/// use syn::Ident;
|
|
/// use syn::ext::IdentExt;
|
|
///
|
|
/// fn ident_for_getter(variable: &Ident) -> Ident {
|
|
/// let getter = format!("__pyo3_get_{}", variable.unraw());
|
|
/// Ident::new(&getter, Span::call_site())
|
|
/// }
|
|
/// ```
|
|
fn unraw(&self) -> Ident;
|
|
}
|
|
|
|
impl IdentExt for Ident {
|
|
fn parse_any(input: ParseStream) -> Result<Self> {
|
|
input.step(|cursor| match cursor.ident() {
|
|
Some((ident, rest)) => Ok((ident, rest)),
|
|
None => Err(cursor.error("expected ident")),
|
|
})
|
|
}
|
|
|
|
fn unraw(&self) -> Ident {
|
|
let string = self.to_string();
|
|
if let Some(string) = string.strip_prefix("r#") {
|
|
Ident::new(string, self.span())
|
|
} else {
|
|
self.clone()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Peek for private::PeekFn {
|
|
type Token = private::IdentAny;
|
|
}
|
|
|
|
impl CustomToken for private::IdentAny {
|
|
fn peek(cursor: Cursor) -> bool {
|
|
cursor.ident().is_some()
|
|
}
|
|
|
|
fn display() -> &'static str {
|
|
"identifier"
|
|
}
|
|
}
|
|
|
|
impl lookahead::Sealed for private::PeekFn {}
|
|
|
|
mod private {
|
|
use proc_macro2::Ident;
|
|
|
|
pub trait Sealed {}
|
|
|
|
impl Sealed for Ident {}
|
|
|
|
pub struct PeekFn;
|
|
pub struct IdentAny;
|
|
|
|
impl Copy for PeekFn {}
|
|
impl Clone for PeekFn {
|
|
fn clone(&self) -> Self {
|
|
*self
|
|
}
|
|
}
|
|
}
|