Skip to content

Commit 3b605bd

Browse files
committed
support customization
1 parent 20ed035 commit 3b605bd

File tree

4 files changed

+105
-4
lines changed

4 files changed

+105
-4
lines changed

crates/formality-macros/src/attrs.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Functions to manipulate the custom attributes that guide our macros in various ways.
22
3-
use syn::{Attribute, DeriveInput};
3+
use syn::{spanned::Spanned, Attribute, DeriveInput};
4+
5+
use crate::custom::Customize;
46

57
/// Checks for any kind of attribute that indicates an "is-a" relationship,
68
/// e.g. `#[cast]` and `#[variable]`.
@@ -37,6 +39,33 @@ pub(crate) fn has_variable_attr(attrs: &[Attribute]) -> bool {
3739
attrs.iter().any(|a| a.path().is_ident("variable"))
3840
}
3941

42+
/// Extracts any customization attribute from a list of attributes.
43+
pub(crate) fn customize(attrs: &[Attribute]) -> syn::Result<Customize> {
44+
let mut v: Vec<Customize> = attrs
45+
.iter()
46+
.filter(|a| a.path().is_ident("customize"))
47+
.map(|a| a.parse_args())
48+
.collect::<syn::Result<_>>()?;
49+
50+
if v.len() > 1 {
51+
Err(syn::Error::new(
52+
attrs
53+
.iter()
54+
.filter(|a| a.path().is_ident("customize"))
55+
.skip(1)
56+
.next()
57+
.unwrap()
58+
.path()
59+
.span(),
60+
"multiple customize attributes",
61+
))
62+
} else if v.len() == 1 {
63+
Ok(v.pop().unwrap())
64+
} else {
65+
Ok(Customize::default())
66+
}
67+
}
68+
4069
/// Removes all attributes from the input that are specific to formality.
4170
pub(crate) fn remove_formality_attributes(input: &mut DeriveInput) {
4271
remove_formality_attributes_from_vec(&mut input.attrs);

crates/formality-macros/src/custom.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use proc_macro2::TokenStream;
2+
3+
#[derive(Default, Debug)]
4+
pub(crate) struct Customize {
5+
pub parse: bool,
6+
pub debug: bool,
7+
}
8+
9+
impl syn::parse::Parse for Customize {
10+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
11+
let mut result = Customize::default();
12+
13+
let token_stream: TokenStream = input.parse()?;
14+
let mut tokens = token_stream.into_iter();
15+
while let Some(token) = tokens.next() {
16+
match token {
17+
proc_macro2::TokenTree::Ident(ident) if ident == "parse" => {
18+
if result.parse {
19+
return Err(syn::Error::new(ident.span(), "already customizing parse"));
20+
}
21+
result.parse = true;
22+
}
23+
24+
proc_macro2::TokenTree::Ident(ident) if ident == "debug" => {
25+
if result.debug {
26+
return Err(syn::Error::new(ident.span(), "already customizing debug"));
27+
}
28+
result.debug = true;
29+
}
30+
31+
_ => {
32+
return Err(syn::Error::new(
33+
token.span(),
34+
"unexpected token in customization",
35+
));
36+
}
37+
}
38+
39+
if let Some(token) = tokens.next() {
40+
match token {
41+
proc_macro2::TokenTree::Punct(p) if p.as_char() == ',' => (),
42+
_ => {
43+
return Err(syn::Error::new(
44+
token.span(),
45+
"unexpected token in customization",
46+
));
47+
}
48+
}
49+
} else {
50+
break;
51+
}
52+
}
53+
54+
Ok(result)
55+
}
56+
}

crates/formality-macros/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ extern crate proc_macro;
77

88
mod attrs;
99
mod cast;
10+
mod custom;
1011
mod debug;
1112
mod fixed_point;
1213
mod fold;

crates/formality-macros/src/term.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use quote::quote;
33
use syn::DeriveInput;
44

55
use crate::{
6-
attrs::remove_formality_attributes,
6+
attrs::{self, remove_formality_attributes},
77
cast::{downcast_impls, upcast_impls},
88
debug::derive_debug_with_spec,
99
fold::derive_fold,
@@ -13,10 +13,25 @@ use crate::{
1313
};
1414

1515
pub fn term(spec: Option<FormalitySpec>, mut input: DeriveInput) -> syn::Result<TokenStream> {
16+
let customize = attrs::customize(&input.attrs)?;
1617
let fold_impl = derive_fold(synstructure::Structure::new(&input));
1718
let visit_impl = derive_visit(synstructure::Structure::new(&input));
18-
let parse_impl = derive_parse_with_spec(synstructure::Structure::new(&input), spec.as_ref())?;
19-
let debug_impl = derive_debug_with_spec(synstructure::Structure::new(&input), spec.as_ref());
19+
let parse_impl = if customize.parse {
20+
None
21+
} else {
22+
Some(derive_parse_with_spec(
23+
synstructure::Structure::new(&input),
24+
spec.as_ref(),
25+
)?)
26+
};
27+
let debug_impl = if customize.debug {
28+
None
29+
} else {
30+
Some(derive_debug_with_spec(
31+
synstructure::Structure::new(&input),
32+
spec.as_ref(),
33+
))
34+
};
2035
let term_impl = derive_term(synstructure::Structure::new(&input));
2136
let downcast_impls = downcast_impls(synstructure::Structure::new(&input));
2237
let upcast_impls = upcast_impls(synstructure::Structure::new(&input));

0 commit comments

Comments
 (0)