Bug 1489667 - Format component of style_derive. r=emilio

This cherry-picks servo/servo#21635
This commit is contained in:
chansuke 2018-09-07 22:18:51 +09:00 committed by Emilio Cobos Álvarez
parent f1afe5ceec
commit 0f1a2fb4bc
8 changed files with 156 additions and 127 deletions

View File

@ -31,7 +31,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
Err(()) => { Err(()) => {
append_error_clause = true; append_error_clause = true;
return body; return body;
} },
}; };
quote! { #body #arm } quote! { #body #arm }
}); });

View File

@ -11,23 +11,21 @@ use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
use syn::{Variant, WherePredicate}; use syn::{Variant, WherePredicate};
use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo}; use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo};
pub fn add_predicate( pub fn add_predicate(where_clause: &mut Option<syn::WhereClause>, pred: WherePredicate) {
where_clause: &mut Option<syn::WhereClause>, where_clause
pred: WherePredicate, .get_or_insert(parse_quote!(where))
) { .predicates
where_clause.get_or_insert(parse_quote!(where)).predicates.push(pred); .push(pred);
} }
pub fn fmap_match<F>( pub fn fmap_match<F>(input: &DeriveInput, bind_style: BindStyle, mut f: F) -> Tokens
input: &DeriveInput,
bind_style: BindStyle,
mut f: F,
) -> Tokens
where where
F: FnMut(BindingInfo) -> Tokens, F: FnMut(BindingInfo) -> Tokens,
{ {
let mut s = synstructure::Structure::new(input); let mut s = synstructure::Structure::new(input);
s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); }); s.variants_mut().iter_mut().for_each(|v| {
v.bind_with(|_| bind_style);
});
s.each_variant(|variant| { s.each_variant(|variant| {
let (mapped, mapped_fields) = value(variant, "mapped"); let (mapped, mapped_fields) = value(variant, "mapped");
let fields_pairs = variant.bindings().into_iter().zip(mapped_fields); let fields_pairs = variant.bindings().into_iter().zip(mapped_fields);
@ -41,31 +39,30 @@ where
}) })
} }
pub fn fmap_trait_output( pub fn fmap_trait_output(input: &DeriveInput, trait_path: &Path, trait_output: Ident) -> Path {
input: &DeriveInput,
trait_path: &Path,
trait_output: Ident,
) -> Path {
let segment = PathSegment { let segment = PathSegment {
ident: input.ident.clone(), ident: input.ident.clone(),
arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
args: input.generics.params.iter().map(|arg| { args: input
match arg { .generics
&GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()), .params
.iter()
.map(|arg| match arg {
&GenericParam::Lifetime(ref data) => {
GenericArgument::Lifetime(data.lifetime.clone())
},
&GenericParam::Type(ref data) => { &GenericParam::Type(ref data) => {
let ident = data.ident; let ident = data.ident;
GenericArgument::Type( GenericArgument::Type(
parse_quote!(<#ident as ::#trait_path>::#trait_output), parse_quote!(<#ident as ::#trait_path>::#trait_output),
) )
}, },
ref arg => panic!("arguments {:?} cannot be mapped yet", arg) ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
} }).collect(),
}).collect(),
colon2_token: Default::default(), colon2_token: Default::default(),
gt_token: Default::default(), gt_token: Default::default(),
lt_token: Default::default(), lt_token: Default::default(),
}),
})
}; };
segment.into() segment.into()
} }
@ -75,44 +72,55 @@ where
F: FnMut(&Ident) -> Type, F: FnMut(&Ident) -> Type,
{ {
match *ty { match *ty {
Type::Slice(ref inner) => { Type::Slice(ref inner) => Type::from(TypeSlice {
Type::from(TypeSlice { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) elem: Box::new(map_type_params(&inner.elem, params, f)),
}, ..inner.clone()
Type::Array(ref inner) => { //ref ty, ref expr) => { }),
Type::from(TypeArray { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) Type::Array(ref inner) => {
//ref ty, ref expr) => {
Type::from(TypeArray {
elem: Box::new(map_type_params(&inner.elem, params, f)),
..inner.clone()
})
}, },
ref ty @ Type::Never(_) => ty.clone(), ref ty @ Type::Never(_) => ty.clone(),
Type::Tuple(ref inner) => { Type::Tuple(ref inner) => Type::from(TypeTuple {
Type::from( elems: inner
TypeTuple { .elems
elems: inner.elems.iter().map(|ty| map_type_params(&ty, params, f)).collect(), .iter()
..inner.clone() .map(|ty| map_type_params(&ty, params, f))
} .collect(),
) ..inner.clone()
}, }),
Type::Path(TypePath { qself: None, ref path }) => { Type::Path(TypePath {
qself: None,
ref path,
}) => {
if let Some(ident) = path_to_ident(path) { if let Some(ident) = path_to_ident(path) {
if params.iter().any(|param| param.ident == ident) { if params.iter().any(|param| param.ident == ident) {
return f(ident); return f(ident);
} }
} }
Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) })
}
Type::Path(TypePath { ref qself, ref path }) => {
Type::from(TypePath { Type::from(TypePath {
qself: qself.as_ref().map(|qself| { qself: None,
QSelf {
ty: Box::new(map_type_params(&qself.ty, params, f)),
position: qself.position,
..qself.clone()
}
}),
path: map_type_params_in_path(path, params, f), path: map_type_params_in_path(path, params, f),
}) })
}, },
Type::Paren(ref inner) => { Type::Path(TypePath {
Type::from(TypeParen { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) ref qself,
}, ref path,
}) => Type::from(TypePath {
qself: qself.as_ref().map(|qself| QSelf {
ty: Box::new(map_type_params(&qself.ty, params, f)),
position: qself.position,
..qself.clone()
}),
path: map_type_params_in_path(path, params, f),
}),
Type::Paren(ref inner) => Type::from(TypeParen {
elem: Box::new(map_type_params(&inner.elem, params, f)),
..inner.clone()
}),
ref ty => panic!("type {:?} cannot be mapped yet", ty), ref ty => panic!("type {:?} cannot be mapped yet", ty),
} }
} }
@ -123,41 +131,48 @@ where
{ {
Path { Path {
leading_colon: path.leading_colon, leading_colon: path.leading_colon,
segments: path.segments.iter().map(|segment| { segments: path
PathSegment { .segments
.iter()
.map(|segment| PathSegment {
ident: segment.ident.clone(), ident: segment.ident.clone(),
arguments: match segment.arguments { arguments: match segment.arguments {
PathArguments::AngleBracketed(ref data) => { PathArguments::AngleBracketed(ref data) => {
PathArguments::AngleBracketed(AngleBracketedGenericArguments { PathArguments::AngleBracketed(AngleBracketedGenericArguments {
args: data.args.iter().map(|arg| { args: data
match arg { .args
.iter()
.map(|arg| match arg {
ty @ &GenericArgument::Lifetime(_) => ty.clone(), ty @ &GenericArgument::Lifetime(_) => ty.clone(),
&GenericArgument::Type(ref data) => { &GenericArgument::Type(ref data) => {
GenericArgument::Type(map_type_params(data, params, f)) GenericArgument::Type(map_type_params(data, params, f))
}, },
&GenericArgument::Binding(ref data) => GenericArgument::Binding(Binding { &GenericArgument::Binding(ref data) => {
ty: map_type_params(&data.ty, params, f), GenericArgument::Binding(Binding {
..data.clone() ty: map_type_params(&data.ty, params, f),
}), ..data.clone()
ref arg => panic!("arguments {:?} cannot be mapped yet", arg) })
} },
}).collect(), ref arg => panic!("arguments {:?} cannot be mapped yet", arg),
}).collect(),
..data.clone() ..data.clone()
}) })
}, },
ref arg @ PathArguments::None => arg.clone(), ref arg @ PathArguments::None => arg.clone(),
ref parameters => { ref parameters => panic!("parameters {:?} cannot be mapped yet", parameters),
panic!("parameters {:?} cannot be mapped yet", parameters)
}
}, },
} }).collect(),
}).collect(),
} }
} }
fn path_to_ident(path: &Path) -> Option<&Ident> { fn path_to_ident(path: &Path) -> Option<&Ident> {
match *path { match *path {
Path { leading_colon: None, ref segments } if segments.len() == 1 => { Path {
leading_colon: None,
ref segments,
}
if segments.len() == 1 =>
{
if segments[0].arguments.is_empty() { if segments[0].arguments.is_empty() {
Some(&segments[0].ident) Some(&segments[0].ident)
} else { } else {
@ -203,7 +218,7 @@ where
pub fn parse_variant_attrs<A>(variant: &Variant) -> A pub fn parse_variant_attrs<A>(variant: &Variant) -> A
where where
A: FromVariant A: FromVariant,
{ {
match A::from_variant(variant) { match A::from_variant(variant) {
Ok(attrs) => attrs, Ok(attrs) => attrs,
@ -211,23 +226,20 @@ where
} }
} }
pub fn ref_pattern<'a>(variant: &'a VariantInfo, prefix: &str) -> (Tokens, Vec<BindingInfo<'a>>) {
pub fn ref_pattern<'a>(
variant: &'a VariantInfo,
prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
let mut v = variant.clone(); let mut v = variant.clone();
v.bind_with(|_| BindStyle::Ref); v.bind_with(|_| BindStyle::Ref);
v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); v.bindings_mut()
.iter_mut()
.for_each(|b| b.binding = Ident::from(format!("{}_{}", b.binding, prefix)));
(v.pat(), v.bindings().iter().cloned().collect()) (v.pat(), v.bindings().iter().cloned().collect())
} }
pub fn value<'a>( pub fn value<'a>(variant: &'a VariantInfo, prefix: &str) -> (Tokens, Vec<BindingInfo<'a>>) {
variant: &'a VariantInfo,
prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
let mut v = variant.clone(); let mut v = variant.clone();
v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); v.bindings_mut()
.iter_mut()
.for_each(|b| b.binding = Ident::from(format!("{}_{}", b.binding, prefix)));
v.bind_with(|_| BindStyle::Move); v.bind_with(|_| BindStyle::Move);
(v.pat(), v.bindings().iter().cloned().collect()) (v.pat(), v.bindings().iter().cloned().collect())
} }

View File

@ -4,10 +4,13 @@
#![recursion_limit = "128"] #![recursion_limit = "128"]
#[macro_use] extern crate darling; #[macro_use]
extern crate darling;
extern crate proc_macro; extern crate proc_macro;
#[macro_use] extern crate quote; #[macro_use]
#[macro_use] extern crate syn; extern crate quote;
#[macro_use]
extern crate syn;
extern crate synstructure; extern crate synstructure;
use proc_macro::TokenStream; use proc_macro::TokenStream;

View File

@ -27,23 +27,23 @@ pub fn derive(input: DeriveInput) -> Tokens {
"Parse is only supported for single-variant enums for now" "Parse is only supported for single-variant enums for now"
); );
let css_variant_attrs = let css_variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast()); let parse_attrs = cg::parse_variant_attrs_from_ast::<ParseVariantAttrs>(&variant.ast());
let parse_attrs =
cg::parse_variant_attrs_from_ast::<ParseVariantAttrs>(&variant.ast());
if css_variant_attrs.skip { if css_variant_attrs.skip {
return match_body; return match_body;
} }
let identifier = cg::to_css_identifier( let identifier = cg::to_css_identifier(
&css_variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()), &css_variant_attrs
.keyword
.unwrap_or(variant.ast().ident.as_ref().into()),
); );
let ident = &variant.ast().ident; let ident = &variant.ast().ident;
saw_condition |= parse_attrs.condition.is_some(); saw_condition |= parse_attrs.condition.is_some();
let condition = match parse_attrs.condition { let condition = match parse_attrs.condition {
Some(ref p) => quote! { if #p(context) }, Some(ref p) => quote! { if #p(context) },
None => quote! { }, None => quote!{},
}; };
let mut body = quote! { let mut body = quote! {
@ -87,7 +87,6 @@ pub fn derive(input: DeriveInput) -> Tokens {
quote! { Self::parse(input) } quote! { Self::parse(input) }
}; };
let parse_trait_impl = quote! { let parse_trait_impl = quote! {
impl ::parser::Parse for #name { impl ::parser::Parse for #name {
#[inline] #[inline]

View File

@ -17,8 +17,8 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
let input_name = || cg::to_css_identifier(input_ident.as_ref()); let input_name = || cg::to_css_identifier(input_ident.as_ref());
if let Some(function) = css_attrs.function { if let Some(function) = css_attrs.function {
values.push(function.explicit().unwrap_or_else(input_name)); values.push(function.explicit().unwrap_or_else(input_name));
// If the whole value is wrapped in a function, value types of // If the whole value is wrapped in a function, value types of
// its fields should not be propagated. // its fields should not be propagated.
} else { } else {
let mut where_clause = input.generics.where_clause.take(); let mut where_clause = input.generics.where_clause.take();
for param in input.generics.type_params() { for param in input.generics.type_params() {
@ -66,12 +66,12 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
} }
} }
} }
} },
Data::Struct(ref s) => { Data::Struct(ref s) => {
if !derive_struct_fields(&s.fields, &mut types, &mut values) { if !derive_struct_fields(&s.fields, &mut types, &mut values) {
values.push(input_name()); values.push(input_name());
} }
} },
Data::Union(_) => unreachable!("union is not supported"), Data::Union(_) => unreachable!("union is not supported"),
} }
} }
@ -84,13 +84,17 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
} }
let mut types_value = quote!(0); let mut types_value = quote!(0);
types_value.append_all(types.iter().map(|ty| quote! { types_value.append_all(types.iter().map(|ty| {
| <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES quote! {
| <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES
}
})); }));
let mut nested_collects = quote!(); let mut nested_collects = quote!();
nested_collects.append_all(types.iter().map(|ty| quote! { nested_collects.append_all(types.iter().map(|ty| {
<#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f); quote! {
<#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f);
}
})); }));
if let Some(ty) = info_attrs.ty { if let Some(ty) = info_attrs.ty {
@ -144,7 +148,9 @@ fn derive_struct_fields<'a>(
} }
let css_attrs = cg::parse_field_attrs::<CssFieldAttrs>(field); let css_attrs = cg::parse_field_attrs::<CssFieldAttrs>(field);
if css_attrs.represents_keyword { if css_attrs.represents_keyword {
let ident = field.ident.as_ref() let ident = field
.ident
.as_ref()
.expect("only named field should use represents_keyword"); .expect("only named field should use represents_keyword");
values.push(cg::to_css_identifier(ident.as_ref())); values.push(cg::to_css_identifier(ident.as_ref()));
return None; return None;

View File

@ -16,12 +16,16 @@ pub fn derive(mut input: DeriveInput) -> quote::Tokens {
); );
} }
let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| { let to_body = cg::fmap_match(
quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)) &input,
}); BindStyle::Move,
let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| { |binding| quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)),
quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)) );
}); let from_body = cg::fmap_match(
&input,
BindStyle::Move,
|binding| quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)),
);
input.generics.where_clause = where_clause; input.generics.where_clause = where_clause;
let name = &input.ident; let name = &input.ident;

View File

@ -23,9 +23,11 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
if attrs.field_bound { if attrs.field_bound {
let ty = &binding.ast().ty; let ty = &binding.ast().ty;
let output_type = cg::map_type_params(ty, &params, &mut |ident| { let output_type = cg::map_type_params(
parse_quote!(<#ident as ::values::computed::ToComputedValue>::ComputedValue) ty,
}); &params,
&mut |ident| parse_quote!(<#ident as ::values::computed::ToComputedValue>::ComputedValue),
);
cg::add_predicate( cg::add_predicate(
&mut where_clause, &mut where_clause,
@ -71,7 +73,7 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
::std::clone::Clone::clone(computed) ::std::clone::Clone::clone(computed)
} }
} }
} };
} }
let computed_value_type = cg::fmap_trait_output( let computed_value_type = cg::fmap_trait_output(

View File

@ -19,15 +19,16 @@ pub fn derive(mut input: syn::DeriveInput) -> Tokens {
let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input); let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
if let Data::Enum(_) = input.data { if let Data::Enum(_) = input.data {
assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums"); assert!(
input_attrs.function.is_none(),
"#[css(function)] is not allowed on enums"
);
assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums"); assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums");
} }
let match_body = { let match_body = {
let s = Structure::new(&input); let s = Structure::new(&input);
s.each_variant(|variant| { s.each_variant(|variant| derive_variant_arm(variant, &mut where_clause))
derive_variant_arm(variant, &mut where_clause)
})
}; };
input.generics.where_clause = where_clause; input.generics.where_clause = where_clause;
@ -68,10 +69,7 @@ pub fn derive(mut input: syn::DeriveInput) -> Tokens {
impls impls
} }
fn derive_variant_arm( fn derive_variant_arm(variant: &VariantInfo, generics: &mut Option<WhereClause>) -> Tokens {
variant: &VariantInfo,
generics: &mut Option<WhereClause>,
) -> Tokens {
let bindings = variant.bindings(); let bindings = variant.bindings();
let identifier = cg::to_css_identifier(variant.ast().ident.as_ref()); let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
let ast = variant.ast(); let ast = variant.ast();
@ -124,13 +122,15 @@ fn derive_variant_fields_expr(
where_clause: &mut Option<WhereClause>, where_clause: &mut Option<WhereClause>,
separator: &str, separator: &str,
) -> Tokens { ) -> Tokens {
let mut iter = bindings.iter().filter_map(|binding| { let mut iter = bindings
let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast()); .iter()
if attrs.skip { .filter_map(|binding| {
return None; let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
} if attrs.skip {
Some((binding, attrs)) return None;
}).peekable(); }
Some((binding, attrs))
}).peekable();
let (first, attrs) = match iter.next() { let (first, attrs) = match iter.next() {
Some(pair) => pair, Some(pair) => pair,
@ -190,8 +190,11 @@ fn derive_single_field_expr(
} }
} }
} else if attrs.represents_keyword { } else if attrs.represents_keyword {
let ident = let ident = field
field.ast().ident.as_ref().expect("Unnamed field with represents_keyword?"); .ast()
.ident
.as_ref()
.expect("Unnamed field with represents_keyword?");
let ident = cg::to_css_identifier(ident.as_ref()); let ident = cg::to_css_identifier(ident.as_ref());
quote! { quote! {
if *#field { if *#field {