55#![ feature( box_patterns) ]
66
77use itertools:: Itertools ;
8- use proc_macro_error:: ResultExt ;
9- use proc_macro_error:: abort;
10- use proc_macro_error:: proc_macro_error;
118use proc_macro2:: Literal ;
129use proc_macro2:: TokenStream ;
1310use quote:: quote;
1411use syn:: Attribute ;
1512use syn:: DeriveInput ;
13+ use syn:: Error ;
1614use syn:: Ident ;
1715use syn:: Result ;
1816use syn:: Token ;
@@ -45,11 +43,15 @@ use syn::token;
4543/// }
4644///
4745/// It also implements the Display trait for the enum.
48- #[ proc_macro_error]
4946#[ proc_macro_derive( TextualDecl , attributes( decl, function) ) ]
5047pub fn textual_decl_derive ( input : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
5148 let input = parse_macro_input ! ( input as DeriveInput ) ;
49+ do_textual_decl_derive ( input)
50+ . unwrap_or_else ( Error :: into_compile_error)
51+ . into ( )
52+ }
5253
54+ fn do_textual_decl_derive ( input : DeriveInput ) -> Result < TokenStream > {
5355 let name = & input. ident ;
5456 let vis = & input. vis ;
5557 let ( impl_generics, ty_generics, where_clause) = input. generics . split_for_impl ( ) ;
@@ -62,19 +64,19 @@ pub fn textual_decl_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS
6264 syn:: Data :: Enum ( e) => {
6365 for variant in e. variants {
6466 let variant_name = & variant. ident ;
65- let attr = extract_exactly_one_attr ( & variant. ident , variant. attrs , "decl" ) ;
66- let decl: Decl = syn:: parse2 ( attr. tokens ) . unwrap_or_abort ( ) ;
67+ let attr = extract_exactly_one_attr ( & variant. ident , variant. attrs , "decl" ) ? ;
68+ let decl: Decl = syn:: parse2 ( attr. tokens ) ? ;
6769
6870 // Enforce sorted variant order.
6971 let variant_name_str = format ! ( "{variant_name}" ) ;
7072 if let Some ( last_str) = last {
7173 if last_str > variant_name_str {
72- abort ! (
73- variant_name,
74+ return Err ( Error :: new (
75+ variant_name. span ( ) ,
7476 format ! (
7577 "Variants are out of order - '{last_str}' must be after '{variant_name_str}'"
76- )
77- ) ;
78+ ) ,
79+ ) ) ;
7880 }
7981 }
8082 last = Some ( variant_name_str) ;
@@ -127,11 +129,21 @@ pub fn textual_decl_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS
127129 }
128130 }
129131 }
130- syn:: Data :: Struct ( s) => abort ! ( s. struct_token, "TextualDecl does not support 'struct'" ) ,
131- syn:: Data :: Union ( u) => abort ! ( u. union_token, "TextualDecl does not support 'union'" ) ,
132+ syn:: Data :: Struct ( s) => {
133+ return Err ( Error :: new (
134+ s. struct_token . span ,
135+ "TextualDecl does not support 'struct'" ,
136+ ) ) ;
137+ }
138+ syn:: Data :: Union ( u) => {
139+ return Err ( Error :: new (
140+ u. union_token . span ,
141+ "TextualDecl does not support 'union'" ,
142+ ) ) ;
143+ }
132144 }
133145
134- let output = quote ! {
146+ Ok ( quote ! {
135147 impl #impl_generics #name #ty_generics #where_clause {
136148 #vis fn write_decls( txf: & mut TextualFile <' _>, subset: & HashSet <#name #ty_generics>) -> Result <( ) > {
137149 #( #decls) *
@@ -150,28 +162,29 @@ pub fn textual_decl_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS
150162 }
151163 }
152164 }
153- } ;
154-
155- output. into ( )
165+ } )
156166}
157167
158- fn extract_exactly_one_attr ( ident : & Ident , attrs : Vec < Attribute > , name : & str ) -> Attribute {
168+ fn extract_exactly_one_attr ( ident : & Ident , attrs : Vec < Attribute > , name : & str ) -> Result < Attribute > {
159169 let mut attrs = attrs. into_iter ( ) . filter ( |attr| attr. path . is_ident ( name) ) ;
160170
161171 let attr = if let Some ( attr) = attrs. next ( ) {
162172 attr
163173 } else {
164- abort ! ( ident, "variant is missing 'decl' attribute" ) ;
174+ return Err ( Error :: new (
175+ ident. span ( ) ,
176+ "variant is missing 'decl' attribute" ,
177+ ) ) ;
165178 } ;
166179
167180 if let Some ( next) = attrs. next ( ) {
168- abort ! (
181+ return Err ( Error :: new_spanned (
169182 next. path ,
170- "'decl' attribute may not be specified multiple times"
171- ) ;
183+ "'decl' attribute may not be specified multiple times" ,
184+ ) ) ;
172185 }
173186
174- attr
187+ Ok ( attr)
175188}
176189
177190enum Decl {
@@ -202,7 +215,7 @@ impl Parse for Decl {
202215 }
203216 return Ok ( Decl :: Skip ) ;
204217 } else {
205- abort ! ( tag, "Unknown 'decl' type" ) ;
218+ return Err ( Error :: new ( tag. span ( ) , "Unknown 'decl' type" ) ) ;
206219 }
207220 } ;
208221
@@ -308,7 +321,7 @@ impl Parse for DeclTy {
308321 } else {
309322 use syn:: ext:: IdentExt ;
310323 let id = Ident :: parse_any ( input) ?;
311- abort ! ( id , "Unexpected token" ) ;
324+ return Err ( Error :: new ( id . span ( ) , "Unexpected token" ) ) ;
312325 }
313326 }
314327}
0 commit comments