mirror of
https://github.com/servo/servo.git
synced 2025-08-18 03:45:33 +01:00
style: Add collect_values function to SpecifiedValueInfo trait for collecting possible values.
This is the basic structure of the stuff. Following patches will fill the gap between Gecko and Servo on value generating, and finally hook it into InspectorUtils. Bug: 1434130 Reviewed-by: emilio MozReview-Commit-ID: KNLAfFBiY6e
This commit is contained in:
parent
3b9c40dd14
commit
26c3aeda97
5 changed files with 192 additions and 47 deletions
|
@ -4,15 +4,21 @@
|
|||
|
||||
use cg;
|
||||
use quote::Tokens;
|
||||
use syn::{Data, DeriveInput, Fields};
|
||||
use syn::{Data, DeriveInput, Fields, Type};
|
||||
use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs};
|
||||
|
||||
pub fn derive(mut input: DeriveInput) -> Tokens {
|
||||
let attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
|
||||
let mut types_value = quote!(0);
|
||||
// If the whole value is wrapped in a function, value types of its
|
||||
// fields should not be propagated.
|
||||
if attrs.function.is_none() {
|
||||
let mut types = vec![];
|
||||
let mut values = vec![];
|
||||
|
||||
let input_ident = input.ident;
|
||||
let input_name = || cg::to_css_identifier(input_ident.as_ref());
|
||||
if let Some(function) = attrs.function {
|
||||
values.push(function.explicit().unwrap_or_else(input_name));
|
||||
// If the whole value is wrapped in a function, value types of
|
||||
// its fields should not be propagated.
|
||||
} else {
|
||||
let mut where_clause = input.generics.where_clause.take();
|
||||
for param in input.generics.type_params() {
|
||||
cg::add_predicate(
|
||||
|
@ -26,18 +32,55 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
|
|||
Data::Enum(ref e) => {
|
||||
for v in e.variants.iter() {
|
||||
let attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v);
|
||||
if attrs.function.is_none() {
|
||||
derive_struct_fields(&v.fields, &mut types_value);
|
||||
if attrs.skip {
|
||||
continue;
|
||||
}
|
||||
if let Some(aliases) = attrs.aliases {
|
||||
for alias in aliases.split(",") {
|
||||
values.push(alias.to_string());
|
||||
}
|
||||
}
|
||||
if let Some(keyword) = attrs.keyword {
|
||||
values.push(keyword);
|
||||
continue;
|
||||
}
|
||||
let variant_name = || cg::to_css_identifier(v.ident.as_ref());
|
||||
if let Some(function) = attrs.function {
|
||||
values.push(function.explicit().unwrap_or_else(variant_name));
|
||||
} else {
|
||||
if !derive_struct_fields(&v.fields, &mut types, &mut values) {
|
||||
values.push(variant_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Struct(ref s) => {
|
||||
derive_struct_fields(&s.fields, &mut types_value)
|
||||
if !derive_struct_fields(&s.fields, &mut types, &mut values) {
|
||||
values.push(input_name());
|
||||
}
|
||||
}
|
||||
Data::Union(_) => unreachable!("union is not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
let mut types_value = quote!(0);
|
||||
types_value.append_all(types.iter().map(|ty| quote! {
|
||||
| <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES
|
||||
}));
|
||||
|
||||
let mut nested_collects = quote!();
|
||||
nested_collects.append_all(types.iter().map(|ty| quote! {
|
||||
<#ty as ::style_traits::SpecifiedValueInfo>::collect_completion_keywords(_f);
|
||||
}));
|
||||
|
||||
let append_values = if values.is_empty() {
|
||||
quote!()
|
||||
} else {
|
||||
let mut value_list = quote!();
|
||||
value_list.append_separated(values.iter(), quote!(,));
|
||||
quote! { _f(&[#value_list]); }
|
||||
};
|
||||
|
||||
let name = &input.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
quote! {
|
||||
|
@ -45,24 +88,37 @@ pub fn derive(mut input: DeriveInput) -> Tokens {
|
|||
#where_clause
|
||||
{
|
||||
const SUPPORTED_TYPES: u8 = #types_value;
|
||||
|
||||
fn collect_completion_keywords(_f: &mut FnMut(&[&'static str])) {
|
||||
#nested_collects
|
||||
#append_values
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_struct_fields(fields: &Fields, supports_body: &mut Tokens) {
|
||||
/// Derive from the given fields. Return false if the fields is a Unit,
|
||||
/// true otherwise.
|
||||
fn derive_struct_fields<'a>(
|
||||
fields: &'a Fields,
|
||||
types: &mut Vec<&'a Type>,
|
||||
values: &mut Vec<String>,
|
||||
) -> bool {
|
||||
let fields = match *fields {
|
||||
Fields::Unit => return,
|
||||
Fields::Unit => return false,
|
||||
Fields::Named(ref fields) => fields.named.iter(),
|
||||
Fields::Unnamed(ref fields) => fields.unnamed.iter(),
|
||||
};
|
||||
supports_body.append_all(fields.map(|field| {
|
||||
types.extend(fields.filter_map(|field| {
|
||||
let attrs = cg::parse_field_attrs::<CssFieldAttrs>(field);
|
||||
if attrs.skip {
|
||||
return quote!();
|
||||
if let Some(if_empty) = attrs.if_empty {
|
||||
values.push(if_empty);
|
||||
}
|
||||
let ty = &field.ty;
|
||||
quote! {
|
||||
| <#ty as ::style_traits::SpecifiedValueInfo>::SUPPORTED_TYPES
|
||||
if !attrs.skip {
|
||||
Some(&field.ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
true
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue