1862 lines · 54.5 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")]use crate::lookahead;#[cfg(feature = "parsing")]use crate::parse::{Parse, Parser};use crate::{Error, Result};use proc_macro2::{Ident, Literal, Span};#[cfg(feature = "parsing")]use proc_macro2::{TokenStream, TokenTree};use std::ffi::{CStr, CString};use std::fmt::{self, Display};#[cfg(feature = "extra-traits")]use std::hash::{Hash, Hasher};use std::str::{self, FromStr}; ast_enum_of_structs! {    /// A Rust literal such as a string or integer or boolean.    ///    /// # Syntax tree enum    ///    /// This type is a [syntax tree enum].    ///    /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums    #[non_exhaustive]    pub enum Lit {        /// A UTF-8 string literal: `"foo"`.        Str(LitStr),         /// A byte string literal: `b"foo"`.        ByteStr(LitByteStr),         /// A nul-terminated C-string literal: `c"foo"`.        CStr(LitCStr),         /// A byte literal: `b'f'`.        Byte(LitByte),         /// A character literal: `'a'`.        Char(LitChar),         /// An integer literal: `1` or `1u16`.        Int(LitInt),         /// A floating point literal: `1f64` or `1.0e10f64`.        ///        /// Must be finite. May not be infinite or NaN.        Float(LitFloat),         /// A boolean literal: `true` or `false`.        Bool(LitBool),         /// A raw token literal not interpreted by Syn.        Verbatim(Literal),    }} ast_struct! {    /// A UTF-8 string literal: `"foo"`.    pub struct LitStr {        repr: Box<LitRepr>,    }} ast_struct! {    /// A byte string literal: `b"foo"`.    pub struct LitByteStr {        repr: Box<LitRepr>,    }} ast_struct! {    /// A nul-terminated C-string literal: `c"foo"`.    pub struct LitCStr {        repr: Box<LitRepr>,    }} ast_struct! {    /// A byte literal: `b'f'`.    pub struct LitByte {        repr: Box<LitRepr>,    }} ast_struct! {    /// A character literal: `'a'`.    pub struct LitChar {        repr: Box<LitRepr>,    }} struct LitRepr {    token: Literal,    suffix: Box<str>,} ast_struct! {    /// An integer literal: `1` or `1u16`.    pub struct LitInt {        repr: Box<LitIntRepr>,    }} struct LitIntRepr {    token: Literal,    digits: Box<str>,    suffix: Box<str>,} ast_struct! {    /// A floating point literal: `1f64` or `1.0e10f64`.    ///    /// Must be finite. May not be infinite or NaN.    pub struct LitFloat {        repr: Box<LitFloatRepr>,    }} struct LitFloatRepr {    token: Literal,    digits: Box<str>,    suffix: Box<str>,} ast_struct! {    /// A boolean literal: `true` or `false`.    pub struct LitBool {        pub value: bool,        pub span: Span,    }} impl LitStr {    pub fn new(value: &str, span: Span) -> Self {        let mut token = Literal::string(value);        token.set_span(span);        LitStr {            repr: Box::new(LitRepr {                token,                suffix: Box::<str>::default(),            }),        }    }     pub fn value(&self) -> String {        let repr = self.repr.token.to_string();        let (value, _suffix) = value::parse_lit_str(&repr);        String::from(value)    }     /// Parse a syntax tree node from the content of this string literal.    ///    /// All spans in the syntax tree will point to the span of this `LitStr`.    ///    /// # Example    ///    /// ```    /// use syn::{Attribute, Error, Expr, Lit, Meta, Path, Result};    ///    /// // Parses the path from an attribute that looks like:    /// //    /// //     #[path = "a::b::c"]    /// //    /// // or returns `None` if the input is some other attribute.    /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {    ///     if !attr.path().is_ident("path") {    ///         return Ok(None);    ///     }    ///    ///     if let Meta::NameValue(meta) = &attr.meta {    ///         if let Expr::Lit(expr) = &meta.value {    ///             if let Lit::Str(lit_str) = &expr.lit {    ///                 return lit_str.parse().map(Some);    ///             }    ///         }    ///     }    ///    ///     let message = "expected #[path = \"...\"]";    ///     Err(Error::new_spanned(attr, message))    /// }    /// ```    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse<T: Parse>(&self) -> Result<T> {        self.parse_with(T::parse)    }     /// Invoke parser on the content of this string literal.    ///    /// All spans in the syntax tree will point to the span of this `LitStr`.    ///    /// # Example    ///    /// ```    /// # use proc_macro2::Span;    /// # use syn::{LitStr, Result};    /// #    /// # fn main() -> Result<()> {    /// #     let lit_str = LitStr::new("a::b::c", Span::call_site());    /// #    /// #     const IGNORE: &str = stringify! {    /// let lit_str: LitStr = /* ... */;    /// #     };    ///    /// // Parse a string literal like "a::b::c" into a Path, not allowing    /// // generic arguments on any of the path segments.    /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;    /// #    /// #     Ok(())    /// # }    /// ```    #[cfg(feature = "parsing")]    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]    pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {        use proc_macro2::Group;         // Token stream with every span replaced by the given one.        fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {            stream                .into_iter()                .map(|token| respan_token_tree(token, span))                .collect()        }         // Token tree with every span replaced by the given one.        fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {            match &mut token {                TokenTree::Group(g) => {                    let stream = respan_token_stream(g.stream(), span);                    *g = Group::new(g.delimiter(), stream);                    g.set_span(span);                }                other => other.set_span(span),            }            token        }         // Parse string literal into a token stream with every span equal to the        // original literal's span.        let span = self.span();        let mut tokens = TokenStream::from_str(&self.value())?;        tokens = respan_token_stream(tokens, span);         let result = crate::parse::parse_scoped(parser, span, tokens)?;         let suffix = self.suffix();        if !suffix.is_empty() {            return Err(Error::new(                self.span(),                format!("unexpected suffix `{}` on string literal", suffix),            ));        }         Ok(result)    }     pub fn span(&self) -> Span {        self.repr.token.span()    }     pub fn set_span(&mut self, span: Span) {        self.repr.token.set_span(span);    }     pub fn suffix(&self) -> &str {        &self.repr.suffix    }     pub fn token(&self) -> Literal {        self.repr.token.clone()    }} impl LitByteStr {    pub fn new(value: &[u8], span: Span) -> Self {        let mut token = Literal::byte_string(value);        token.set_span(span);        LitByteStr {            repr: Box::new(LitRepr {                token,                suffix: Box::<str>::default(),            }),        }    }     pub fn value(&self) -> Vec<u8> {        let repr = self.repr.token.to_string();        let (value, _suffix) = value::parse_lit_byte_str(&repr);        value    }     pub fn span(&self) -> Span {        self.repr.token.span()    }     pub fn set_span(&mut self, span: Span) {        self.repr.token.set_span(span);    }     pub fn suffix(&self) -> &str {        &self.repr.suffix    }     pub fn token(&self) -> Literal {        self.repr.token.clone()    }} impl LitCStr {    pub fn new(value: &CStr, span: Span) -> Self {        let mut token = Literal::c_string(value);        token.set_span(span);        LitCStr {            repr: Box::new(LitRepr {                token,                suffix: Box::<str>::default(),            }),        }    }     pub fn value(&self) -> CString {        let repr = self.repr.token.to_string();        let (value, _suffix) = value::parse_lit_c_str(&repr);        value    }     pub fn span(&self) -> Span {        self.repr.token.span()    }     pub fn set_span(&mut self, span: Span) {        self.repr.token.set_span(span);    }     pub fn suffix(&self) -> &str {        &self.repr.suffix    }     pub fn token(&self) -> Literal {        self.repr.token.clone()    }} impl LitByte {    pub fn new(value: u8, span: Span) -> Self {        let mut token = Literal::u8_suffixed(value);        token.set_span(span);        LitByte {            repr: Box::new(LitRepr {                token,                suffix: Box::<str>::default(),            }),        }    }     pub fn value(&self) -> u8 {        let repr = self.repr.token.to_string();        let (value, _suffix) = value::parse_lit_byte(&repr);        value    }     pub fn span(&self) -> Span {        self.repr.token.span()    }     pub fn set_span(&mut self, span: Span) {        self.repr.token.set_span(span);    }     pub fn suffix(&self) -> &str {        &self.repr.suffix    }     pub fn token(&self) -> Literal {        self.repr.token.clone()    }} impl LitChar {    pub fn new(value: char, span: Span) -> Self {        let mut token = Literal::character(value);        token.set_span(span);        LitChar {            repr: Box::new(LitRepr {                token,                suffix: Box::<str>::default(),            }),        }    }     pub fn value(&self) -> char {        let repr = self.repr.token.to_string();        let (value, _suffix) = value::parse_lit_char(&repr);        value    }     pub fn span(&self) -> Span {        self.repr.token.span()    }     pub fn set_span(&mut self, span: Span) {        self.repr.token.set_span(span);    }     pub fn suffix(&self) -> &str {        &self.repr.suffix    }     pub fn token(&self) -> Literal {        self.repr.token.clone()    }} impl LitInt {    pub fn new(repr: &str, span: Span) -> Self {        let (digits, suffix) = match value::parse_lit_int(repr) {            Some(parse) => parse,            None => panic!("not an integer literal: `{}`", repr),        };         let mut token: Literal = repr.parse().unwrap();        token.set_span(span);        LitInt {            repr: Box::new(LitIntRepr {                token,                digits,                suffix,            }),        }    }     pub fn base10_digits(&self) -> &str {        &self.repr.digits    }     /// Parses the literal into a selected number type.    ///    /// This is equivalent to `lit.base10_digits().parse()` except that the    /// resulting errors will be correctly spanned to point to the literal token    /// in the macro input.    ///    /// ```    /// use syn::LitInt;    /// use syn::parse::{Parse, ParseStream, Result};    ///    /// struct Port {    ///     value: u16,    /// }    ///    /// impl Parse for Port {    ///     fn parse(input: ParseStream) -> Result<Self> {    ///         let lit: LitInt = input.parse()?;    ///         let value = lit.base10_parse::<u16>()?;    ///         Ok(Port { value })    ///     }    /// }    /// ```    pub fn base10_parse<N>(&self) -> Result<N>    where        N: FromStr,        N::Err: Display,    {        self.base10_digits()            .parse()            .map_err(|err| Error::new(self.span(), err))    }     pub fn suffix(&self) -> &str {        &self.repr.suffix    }     pub fn span(&self) -> Span {        self.repr.token.span()    }     pub fn set_span(&mut self, span: Span) {        self.repr.token.set_span(span);    }     pub fn token(&self) -> Literal {        self.repr.token.clone()    }} impl From<Literal> for LitInt {    fn from(token: Literal) -> Self {        let repr = token.to_string();        if let Some((digits, suffix)) = value::parse_lit_int(&repr) {            LitInt {                repr: Box::new(LitIntRepr {                    token,                    digits,                    suffix,                }),            }        } else {            panic!("not an integer literal: `{}`", repr);        }    }

Lines 1–500 of 1862.