@@ -2,8 +2,9 @@ use proc_macro2::TokenStream;
22use quote:: { format_ident, quote, quote_spanned, ToTokens } ;
33use syn:: spanned:: Spanned ;
44use syn:: {
5- parse_macro_input, parse_quote, Attribute , Data , DeriveInput , Fields , GenericParam , Generics ,
6- Ident , Index , Lit , Meta , MetaNameValue , NestedMeta ,
5+ parse:: { Parse , ParseStream } ,
6+ parse_macro_input, parse_quote, Attribute , Data , DeriveInput ,
7+ Fields , GenericParam , Generics , Ident , Index , LitStr , Meta , Token
78} ;
89
910/// Implementation of `[#derive(Visit)]`
@@ -84,38 +85,43 @@ struct Attributes {
8485 with : Option < Ident > ,
8586}
8687
88+ struct WithIdent {
89+ with : Option < Ident > ,
90+ }
91+ impl Parse for WithIdent {
92+ fn parse ( input : ParseStream ) -> Result < Self , syn:: Error > {
93+ let mut result = WithIdent { with : None } ;
94+ let ident = input. parse :: < Ident > ( ) ?;
95+ if ident != "with" {
96+ return Err ( syn:: Error :: new ( ident. span ( ) , "Expected identifier to be `with`" ) ) ;
97+ }
98+ input. parse :: < Token ! ( =) > ( ) ?;
99+ let s = input. parse :: < LitStr > ( ) ?;
100+ result. with = Some ( format_ident ! ( "{}" , s. value( ) , span = s. span( ) ) ) ;
101+ Ok ( result)
102+ }
103+ }
104+
87105impl Attributes {
88106 fn parse ( attrs : & [ Attribute ] ) -> Self {
89107 let mut out = Self :: default ( ) ;
90- for attr in attrs. iter ( ) . filter ( |a| a. path . is_ident ( "visit" ) ) {
91- let meta = attr. parse_meta ( ) . expect ( "visit attribute" ) ;
92- match meta {
93- Meta :: List ( l) => {
94- for nested in & l. nested {
95- match nested {
96- NestedMeta :: Meta ( Meta :: NameValue ( v) ) => out. parse_name_value ( v) ,
97- _ => panic ! ( "Expected #[visit(key = \" value\" )]" ) ,
108+ for attr in attrs {
109+ if let Meta :: List ( ref metalist) = attr. meta {
110+ if metalist. path . is_ident ( "visit" ) {
111+ match syn:: parse2 :: < WithIdent > ( metalist. tokens . clone ( ) ) {
112+ Ok ( with_ident) => {
113+ out. with = with_ident. with ;
114+ }
115+ Err ( e) => {
116+ panic ! ( "{}" , e) ;
98117 }
99118 }
100119 }
101- _ => panic ! ( "Expected #[visit(...)]" ) ,
102120 }
103121 }
104122 out
105123 }
106124
107- /// Updates self with a name value attribute
108- fn parse_name_value ( & mut self , v : & MetaNameValue ) {
109- if v. path . is_ident ( "with" ) {
110- match & v. lit {
111- Lit :: Str ( s) => self . with = Some ( format_ident ! ( "{}" , s. value( ) , span = s. span( ) ) ) ,
112- _ => panic ! ( "Expected a string value, got {}" , v. lit. to_token_stream( ) ) ,
113- }
114- return ;
115- }
116- panic ! ( "Unrecognised kv attribute {}" , v. path. to_token_stream( ) )
117- }
118-
119125 /// Returns the pre and post visit token streams
120126 fn visit ( & self , s : TokenStream ) -> ( Option < TokenStream > , Option < TokenStream > ) {
121127 let pre_visit = self . with . as_ref ( ) . map ( |m| {
0 commit comments