@@ -2,8 +2,9 @@ use proc_macro2::TokenStream;
2
2
use quote:: { format_ident, quote, quote_spanned, ToTokens } ;
3
3
use syn:: spanned:: Spanned ;
4
4
use syn:: {
5
- parse_macro_input, parse_quote, Attribute , Data , DeriveInput , Expr , ExprLit , ExprPath ,
6
- Fields , GenericParam , Generics , Ident , Index , Lit , Meta , MetaNameValue ,
5
+ parse:: { Parse , ParseStream } ,
6
+ parse_macro_input, parse_quote, Attribute , Data , DeriveInput ,
7
+ Fields , GenericParam , Generics , Ident , Index , LitStr , Meta , Token
7
8
} ;
8
9
9
10
@@ -78,36 +79,41 @@ struct Attributes {
78
79
with : Option < Ident > ,
79
80
}
80
81
82
+ struct WithIdent {
83
+ with : Option < Ident > ,
84
+ }
85
+ impl Parse for WithIdent {
86
+ fn parse ( input : ParseStream ) -> Result < Self , syn:: Error > {
87
+ let mut result = WithIdent { with : None } ;
88
+ let ident = input. parse :: < Ident > ( ) ?;
89
+ if ident != "with" {
90
+ return Err ( syn:: Error :: new ( ident. span ( ) , "Expected identifier to be `with`" ) ) ;
91
+ }
92
+ input. parse :: < Token ! ( =) > ( ) ?;
93
+ let s = input. parse :: < LitStr > ( ) ?;
94
+ result. with = Some ( format_ident ! ( "{}" , s. value( ) , span = s. span( ) ) ) ;
95
+ Ok ( result)
96
+ }
97
+ }
98
+
81
99
impl Attributes {
82
100
fn parse ( attrs : & [ Attribute ] ) -> Self {
83
101
let mut out = Self :: default ( ) ;
84
102
for attr in attrs {
85
- if let Meta :: NameValue ( ref namevalue) = attr. meta {
86
- if namevalue. path . is_ident ( "visit" ) {
87
- out. parse_name_value ( namevalue) ;
88
- }
89
- }
90
- }
91
- if out. with . is_none ( ) {
92
- panic ! ( "Expected #[visit(...)]" ) ;
93
- }
94
- out
95
- }
96
-
97
- /// Updates self with a name value attribute
98
- fn parse_name_value ( & mut self , v : & MetaNameValue ) {
99
- if let Expr :: Assign ( ref assign) = v. value {
100
- if let Expr :: Path ( ExprPath { ref path, .. } ) = * assign. left {
101
- if path. is_ident ( "with" ) {
102
- match * assign. right {
103
- Expr :: Lit ( ExprLit { lit : Lit :: Str ( ref s) , .. } ) => self . with = Some ( format_ident ! ( "{}" , s. value( ) , span = s. span( ) ) ) ,
104
- _ => panic ! ( "Expected a string value, got {}" , v. value. to_token_stream( ) ) ,
103
+ if let Meta :: List ( ref metalist) = attr. meta {
104
+ if metalist. path . is_ident ( "visit" ) {
105
+ match syn:: parse2 :: < WithIdent > ( metalist. tokens . clone ( ) ) {
106
+ Ok ( with_ident) => {
107
+ out. with = with_ident. with ;
108
+ }
109
+ Err ( e) => {
110
+ panic ! ( "{}" , e) ;
111
+ }
105
112
}
106
- return ;
107
113
}
108
114
}
109
115
}
110
- panic ! ( "Unrecognised kv attribute {}" , v . to_token_stream ( ) )
116
+ out
111
117
}
112
118
113
119
/// Returns the pre and post visit token streams
0 commit comments