| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| use crate::error::Result; | |
| use crate::parse::ParseBuffer; | |
| use crate::token; | |
| use proc_macro2::extra::DelimSpan; | |
| use proc_macro2::Delimiter; | |
| // Not public API. | |
| #[doc(hidden)] | |
| pub struct Parens<'a> { | |
| #[doc(hidden)] | |
| pub token: token::Paren, | |
| #[doc(hidden)] | |
| pub content: ParseBuffer<'a>, | |
| } | |
| // Not public API. | |
| #[doc(hidden)] | |
| pub struct Braces<'a> { | |
| #[doc(hidden)] | |
| pub token: token::Brace, | |
| #[doc(hidden)] | |
| pub content: ParseBuffer<'a>, | |
| } | |
| // Not public API. | |
| #[doc(hidden)] | |
| pub struct Brackets<'a> { | |
| #[doc(hidden)] | |
| pub token: token::Bracket, | |
| #[doc(hidden)] | |
| pub content: ParseBuffer<'a>, | |
| } | |
| // Not public API. | |
| #[cfg(any(feature = "full", feature = "derive"))] | |
| #[doc(hidden)] | |
| pub struct Group<'a> { | |
| #[doc(hidden)] | |
| pub token: token::Group, | |
| #[doc(hidden)] | |
| pub content: ParseBuffer<'a>, | |
| } | |
| // Not public API. | |
| #[doc(hidden)] | |
| pub fn parse_parens<'a>(input: &ParseBuffer<'a>) -> Result<Parens<'a>> { | |
| parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens { | |
| token: token::Paren(span), | |
| content, | |
| }) | |
| } | |
| // Not public API. | |
| #[doc(hidden)] | |
| pub fn parse_braces<'a>(input: &ParseBuffer<'a>) -> Result<Braces<'a>> { | |
| parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces { | |
| token: token::Brace(span), | |
| content, | |
| }) | |
| } | |
| // Not public API. | |
| #[doc(hidden)] | |
| pub fn parse_brackets<'a>(input: &ParseBuffer<'a>) -> Result<Brackets<'a>> { | |
| parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets { | |
| token: token::Bracket(span), | |
| content, | |
| }) | |
| } | |
| #[cfg(any(feature = "full", feature = "derive"))] | |
| pub(crate) fn parse_group<'a>(input: &ParseBuffer<'a>) -> Result<Group<'a>> { | |
| parse_delimited(input, Delimiter::None).map(|(span, content)| Group { | |
| token: token::Group(span.join()), | |
| content, | |
| }) | |
| } | |
| fn parse_delimited<'a>( | |
| input: &ParseBuffer<'a>, | |
| delimiter: Delimiter, | |
| ) -> Result<(DelimSpan, ParseBuffer<'a>)> { | |
| input.step(|cursor| { | |
| if let Some((content, span, rest)) = cursor.group(delimiter) { | |
| let scope = span.close(); | |
| let nested = crate::parse::advance_step_cursor(cursor, content); | |
| let unexpected = crate::parse::get_unexpected(input); | |
| let content = crate::parse::new_parse_buffer(scope, nested, unexpected); | |
| Ok(((span, content), rest)) | |
| } else { | |
| let message = match delimiter { | |
| Delimiter::Parenthesis => "expected parentheses", | |
| Delimiter::Brace => "expected curly braces", | |
| Delimiter::Bracket => "expected square brackets", | |
| Delimiter::None => "expected invisible group", | |
| }; | |
| Err(cursor.error(message)) | |
| } | |
| }) | |
| } | |
| /// Parse a set of parentheses and expose their content to subsequent parsers. | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # use quote::quote; | |
| /// # | |
| /// use syn::{parenthesized, token, Ident, Result, Token, Type}; | |
| /// use syn::parse::{Parse, ParseStream}; | |
| /// use syn::punctuated::Punctuated; | |
| /// | |
| /// // Parse a simplified tuple struct syntax like: | |
| /// // | |
| /// // struct S(A, B); | |
| /// struct TupleStruct { | |
| /// struct_token: Token![struct], | |
| /// ident: Ident, | |
| /// paren_token: token::Paren, | |
| /// fields: Punctuated<Type, Token![,]>, | |
| /// semi_token: Token![;], | |
| /// } | |
| /// | |
| /// impl Parse for TupleStruct { | |
| /// fn parse(input: ParseStream) -> Result<Self> { | |
| /// let content; | |
| /// Ok(TupleStruct { | |
| /// struct_token: input.parse()?, | |
| /// ident: input.parse()?, | |
| /// paren_token: parenthesized!(content in input), | |
| /// fields: content.parse_terminated(Type::parse, Token![,])?, | |
| /// semi_token: input.parse()?, | |
| /// }) | |
| /// } | |
| /// } | |
| /// # | |
| /// # fn main() { | |
| /// # let input = quote! { | |
| /// # struct S(A, B); | |
| /// # }; | |
| /// # syn::parse2::<TupleStruct>(input).unwrap(); | |
| /// # } | |
| /// ``` | |
| #[macro_export] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] | |
| macro_rules! parenthesized { | |
| ($content:ident in $cursor:expr) => { | |
| match $crate::__private::parse_parens(&$cursor) { | |
| $crate::__private::Ok(parens) => { | |
| $content = parens.content; | |
| parens.token | |
| } | |
| $crate::__private::Err(error) => { | |
| return $crate::__private::Err(error); | |
| } | |
| } | |
| }; | |
| } | |
| /// Parse a set of curly braces and expose their content to subsequent parsers. | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # use quote::quote; | |
| /// # | |
| /// use syn::{braced, token, Ident, Result, Token, Type}; | |
| /// use syn::parse::{Parse, ParseStream}; | |
| /// use syn::punctuated::Punctuated; | |
| /// | |
| /// // Parse a simplified struct syntax like: | |
| /// // | |
| /// // struct S { | |
| /// // a: A, | |
| /// // b: B, | |
| /// // } | |
| /// struct Struct { | |
| /// struct_token: Token![struct], | |
| /// ident: Ident, | |
| /// brace_token: token::Brace, | |
| /// fields: Punctuated<Field, Token![,]>, | |
| /// } | |
| /// | |
| /// struct Field { | |
| /// name: Ident, | |
| /// colon_token: Token![:], | |
| /// ty: Type, | |
| /// } | |
| /// | |
| /// impl Parse for Struct { | |
| /// fn parse(input: ParseStream) -> Result<Self> { | |
| /// let content; | |
| /// Ok(Struct { | |
| /// struct_token: input.parse()?, | |
| /// ident: input.parse()?, | |
| /// brace_token: braced!(content in input), | |
| /// fields: content.parse_terminated(Field::parse, Token![,])?, | |
| /// }) | |
| /// } | |
| /// } | |
| /// | |
| /// impl Parse for Field { | |
| /// fn parse(input: ParseStream) -> Result<Self> { | |
| /// Ok(Field { | |
| /// name: input.parse()?, | |
| /// colon_token: input.parse()?, | |
| /// ty: input.parse()?, | |
| /// }) | |
| /// } | |
| /// } | |
| /// # | |
| /// # fn main() { | |
| /// # let input = quote! { | |
| /// # struct S { | |
| /// # a: A, | |
| /// # b: B, | |
| /// # } | |
| /// # }; | |
| /// # syn::parse2::<Struct>(input).unwrap(); | |
| /// # } | |
| /// ``` | |
| #[macro_export] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] | |
| macro_rules! braced { | |
| ($content:ident in $cursor:expr) => { | |
| match $crate::__private::parse_braces(&$cursor) { | |
| $crate::__private::Ok(braces) => { | |
| $content = braces.content; | |
| braces.token | |
| } | |
| $crate::__private::Err(error) => { | |
| return $crate::__private::Err(error); | |
| } | |
| } | |
| }; | |
| } | |
| /// Parse a set of square brackets and expose their content to subsequent | |
| /// parsers. | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # use quote::quote; | |
| /// # | |
| /// use proc_macro2::TokenStream; | |
| /// use syn::{bracketed, token, Result, Token}; | |
| /// use syn::parse::{Parse, ParseStream}; | |
| /// | |
| /// // Parse an outer attribute like: | |
| /// // | |
| /// // #[repr(C, packed)] | |
| /// struct OuterAttribute { | |
| /// pound_token: Token![#], | |
| /// bracket_token: token::Bracket, | |
| /// content: TokenStream, | |
| /// } | |
| /// | |
| /// impl Parse for OuterAttribute { | |
| /// fn parse(input: ParseStream) -> Result<Self> { | |
| /// let content; | |
| /// Ok(OuterAttribute { | |
| /// pound_token: input.parse()?, | |
| /// bracket_token: bracketed!(content in input), | |
| /// content: content.parse()?, | |
| /// }) | |
| /// } | |
| /// } | |
| /// # | |
| /// # fn main() { | |
| /// # let input = quote! { | |
| /// # #[repr(C, packed)] | |
| /// # }; | |
| /// # syn::parse2::<OuterAttribute>(input).unwrap(); | |
| /// # } | |
| /// ``` | |
| #[macro_export] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] | |
| macro_rules! bracketed { | |
| ($content:ident in $cursor:expr) => { | |
| match $crate::__private::parse_brackets(&$cursor) { | |
| $crate::__private::Ok(brackets) => { | |
| $content = brackets.content; | |
| brackets.token | |
| } | |
| $crate::__private::Err(error) => { | |
| return $crate::__private::Err(error); | |
| } | |
| } | |
| }; | |
| } |