diff --git a/Cargo.lock b/Cargo.lock index 8cdcb8f5ae2..9c15ca03ca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,32 +572,31 @@ dependencies = [ [[package]] name = "darling" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "darling_core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "darling_macro" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2951,10 +2950,10 @@ dependencies = [ name = "style_derive" version = "0.0.1" dependencies = [ - "darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "darling 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3049,15 +3048,6 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synstructure" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "synstructure" version = "0.7.0" @@ -3605,9 +3595,9 @@ dependencies = [ "checksum core-text 9.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd581c37283d0c23311d179aefbb891f2324ee0405da58a26e8594ab76e5748" "checksum cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a807ac3ab7a217829c2a3b65732b926b2befe6a35f33b4bf8b503692430f223" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" -"checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac" -"checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821" -"checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9" +"checksum darling 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3effd06d4057f275cb7858889f4952920bab78dd8ff0f6e7dfe0c8d2e67ed89" +"checksum darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "167dd3e235c2f1da16a635c282630452cdf49191eb05711de1bcd1d3d5068c00" +"checksum darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c53edaba455f6073a10c27c72440860eb3f60444f8c8660a391032eeae744d82" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum dbus 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4aee01fb76ada3e5e7ca642ea6664ebf7308a810739ca2aca44909a1191ac254" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" @@ -3788,7 +3778,6 @@ dependencies = [ "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1c669ed757c0ebd04337f6a5bb972d05e0c08fe2540dd3ee3dd9e4daf1604c" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf318c34a2f8381a4f3d4db2c91b45bca2b1cd8cbe56caced900647be164800c" "checksum synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "010366096045d8250555904c58da03377289e7f4b2ce7a5b1027e2b532f41000" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" diff --git a/components/style_derive/Cargo.toml b/components/style_derive/Cargo.toml index 69a62535aaa..c3435d3a92a 100644 --- a/components/style_derive/Cargo.toml +++ b/components/style_derive/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" proc-macro = true [dependencies] -darling = "0.2" -quote = "0.3.15" -syn = { version = "0.11", features = ["visit"] } -synstructure = "0.5.2" +darling = "0.3" +quote = "0.4.2" +syn = { version = "0.12.12", features = ["visit"] } +synstructure = "0.7" diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index d4fe5c94a53..ddf3cf1ec91 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -5,41 +5,41 @@ use cg; use quote::Tokens; use syn::{DeriveInput, Path}; +use synstructure; pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; - let trait_path = &["values", "animated", "Animate"]; + let trait_path = parse_quote!(values::animated::Animate); let (impl_generics, ty_generics, mut where_clause) = - cg::trait_parts(&input, trait_path); + cg::trait_parts(&input, &trait_path); let input_attrs = cg::parse_input_attrs::(&input); - let variants = cg::variants(&input); - let mut match_body = quote!(); - let mut append_error_clause = variants.len() > 1; - match_body.append_all(variants.iter().flat_map(|variant| { - let variant_attrs = cg::parse_variant_attrs::(variant); + let s = synstructure::Structure::new(&input); + let mut append_error_clause = s.variants().len() > 1; + + let mut match_body = s.variants().iter().fold(quote!(), |body, variant| { + let variant_attrs = cg::parse_variant_attrs::(&variant.ast()); if variant_attrs.error { append_error_clause = true; - return None; + return body; } - let name = cg::variant_ctor(&input, variant); - let (this_pattern, this_info) = cg::ref_pattern(&name, variant, "this"); - let (other_pattern, other_info) = cg::ref_pattern(&name, variant, "other"); - let (result_value, result_info) = cg::value(&name, variant, "result"); + let (this_pattern, this_info) = cg::ref_pattern(&variant, "this"); + let (other_pattern, other_info) = cg::ref_pattern(&variant, "other"); + let (result_value, result_info) = cg::value(&variant, "result"); let mut computations = quote!(); let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { - let field_attrs = cg::parse_field_attrs::(&result.field); + let field_attrs = cg::parse_field_attrs::(&result.ast()); if field_attrs.constant { - if cg::is_parameterized(&result.field.ty, where_clause.params, None) { - where_clause.inner.predicates.push(cg::where_predicate( - result.field.ty.clone(), - &["std", "cmp", "PartialEq"], + if cg::is_parameterized(&result.ast().ty, &where_clause.params, None) { + where_clause.add_predicate(cg::where_predicate( + result.ast().ty.clone(), + &parse_quote!(std::cmp::PartialEq), None, )); - where_clause.inner.predicates.push(cg::where_predicate( - result.field.ty.clone(), - &["std", "clone", "Clone"], + where_clause.add_predicate(cg::where_predicate( + result.ast().ty.clone(), + &parse_quote!(std::clone::Clone), None, )); } @@ -50,28 +50,29 @@ pub fn derive(input: DeriveInput) -> Tokens { let #result = ::std::clone::Clone::clone(#this); } } else { - where_clause.add_trait_bound(&result.field.ty); + where_clause.add_trait_bound(&result.ast().ty); quote! { let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; } } })); - Some(quote! { + quote! { + #body (&#this_pattern, &#other_pattern) => { #computations Ok(#result_value) } - }) - })); + } + }); if append_error_clause { if let Some(fallback) = input_attrs.fallback { - match_body.append(quote! { + match_body.append_all(quote! { (this, other) => #fallback(this, other, procedure) }); } else { - match_body.append(quote! { _ => Err(()) }); + match_body.append_all(quote! { _ => Err(()) }); } } diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index aa18fc45d10..3ed23226588 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -4,22 +4,21 @@ use darling::{FromDeriveInput, FromField, FromVariant}; use quote::{ToTokens, Tokens}; -use std::borrow::Cow; use std::collections::HashSet; -use std::iter; -use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Field, Ident}; -use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef}; -use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; -use syn::{TypeBinding, Variant, WhereBoundPredicate, WherePredicate}; -use syn::visit::{self, Visitor}; -use synstructure::{self, BindOpts, BindStyle, BindingInfo}; +use syn::{self, DeriveInput, Field, Ident}; +use syn::{ImplGenerics, Path, PathArguments, PathSegment, AngleBracketedGenericArguments, GenericParam}; +use syn::{QSelf, Type, TypeGenerics, TypeParam}; +use syn::{TypeSlice, TypeArray, TypeTuple, TypePath, TypeParen}; +use syn::{Variant, WherePredicate, GenericArgument, Binding}; +use syn::visit::{self, Visit}; +use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo}; pub struct WhereClause<'input, 'path> { - pub inner: syn::WhereClause, - pub params: &'input [TyParam], - trait_path: &'path [&'path str], - trait_output: Option<&'path str>, - bounded_types: HashSet, + pub inner: Option, + pub params: Vec<&'input TypeParam>, + trait_path: &'path Path, + trait_output: Option, + bounded_types: HashSet, } impl<'input, 'path> ToTokens for WhereClause<'input, 'path> { @@ -29,14 +28,13 @@ impl<'input, 'path> ToTokens for WhereClause<'input, 'path> { } impl<'input, 'path> WhereClause<'input, 'path> { - pub fn add_trait_bound(&mut self, ty: &Ty) { + pub fn add_trait_bound(&mut self, ty: &Type) { let trait_path = self.trait_path; - let params = self.params; let mut found = self.trait_output.map(|_| HashSet::new()); if self.bounded_types.contains(&ty) { return; } - if !is_parameterized(&ty, params, found.as_mut()) { + if !is_parameterized(&ty, &self.params, found.as_mut()) { return; } self.bounded_types.insert(ty.clone()); @@ -44,19 +42,19 @@ impl<'input, 'path> WhereClause<'input, 'path> { let output = if let Some(output) = self.trait_output { output } else { - self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None)); + self.add_predicate(where_predicate(ty.clone(), trait_path, None)); return; }; - if let Ty::Path(None, ref path) = *ty { + if let Type::Path(syn::TypePath { ref path, .. }) = *ty { if path_to_ident(path).is_some() { - self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None)); + self.add_predicate(where_predicate(ty.clone(), trait_path, None)); return; } } - let output_type = map_type_params(ty, params, &mut |ident| { - let ty = Ty::Path(None, ident.clone().into()); + let output_type = map_type_params(ty, &self.params, &mut |ident| { + let ty = Type::Path(syn::TypePath { qself: None, path: ident.clone().into() }); fmap_output_type(ty, trait_path, output) }); @@ -66,20 +64,29 @@ impl<'input, 'path> WhereClause<'input, 'path> { Some((output, output_type)), ); - self.inner.predicates.push(pred); + self.add_predicate(pred); if let Some(found) = found { for ident in found { - let ty = Ty::Path(None, ident.into()); + let ty = Type::Path(syn::TypePath { qself: None, path: ident.into() }); if !self.bounded_types.contains(&ty) { self.bounded_types.insert(ty.clone()); - self.inner.predicates.push( + self.add_predicate( where_predicate(ty, trait_path, None), ); }; } } } + + pub fn add_predicate(&mut self, pred: WherePredicate) { + if let Some(ref mut inner) = self.inner { + inner.predicates.push(pred); + } else { + self.inner = Some(parse_quote!(where)); + self.add_predicate(pred); + } + } } pub fn fmap_match( @@ -90,71 +97,77 @@ pub fn fmap_match( where F: FnMut(BindingInfo) -> Tokens, { - synstructure::each_variant(input, &bind_style.into(), |fields, variant| { - let name = variant_ctor(input, variant); - let (mapped, mapped_fields) = value(&name, variant, "mapped"); - let fields_pairs = fields.into_iter().zip(mapped_fields); + let mut s = synstructure::Structure::new(input); + s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); }); + s.each_variant(|variant| { + let (mapped, mapped_fields) = value(variant, "mapped"); + let fields_pairs = variant.bindings().into_iter().zip(mapped_fields); let mut computations = quote!(); computations.append_all(fields_pairs.map(|(field, mapped_field)| { - let expr = f(field); + let expr = f(field.clone()); quote! { let #mapped_field = #expr; } })); - computations.append(mapped); + computations.append_all(mapped); Some(computations) }) } fn fmap_output_type( - ty: Ty, - trait_path: &[&str], - trait_output: &str, -) -> Ty { - Ty::Path( - Some(QSelf { - ty: Box::new(ty), - position: trait_path.len(), - }), - path(trait_path.iter().chain(iter::once(&trait_output))), - ) + ty: Type, + trait_path: &Path, + trait_output: Ident, +) -> Type { + parse_quote!(<#ty as ::#trait_path>::#trait_output) } pub fn fmap_trait_parts<'input, 'path>( input: &'input DeriveInput, - trait_path: &'path [&'path str], - trait_output: &'path str, -) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>, Path) { + trait_path: &'path Path, + trait_output: Ident, +) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>, Path) { let (impl_generics, ty_generics, mut where_clause) = trait_parts(input, trait_path); where_clause.trait_output = Some(trait_output); let output_ty = PathSegment { ident: input.ident.clone(), - parameters: PathParameters::AngleBracketed(AngleBracketedParameterData { - lifetimes: input.generics.lifetimes.iter().map(|l| l.lifetime.clone()).collect(), - types: input.generics.ty_params.iter().map(|ty| { - fmap_output_type( - Ty::Path(None, ty.ident.clone().into()), - trait_path, - trait_output, - ) + arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args: input.generics.params.iter().map(|arg| { + match arg { + &GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()), + &GenericParam::Type(ref data) => { + let ident = data.ident; + GenericArgument::Type( + fmap_output_type( + parse_quote!(#ident), + trait_path, + trait_output + ) + ) + }, + ref arg => panic!("arguments {:?} cannot be mapped yet", arg) + } }).collect(), - .. Default::default() - }), - }.into(); - (impl_generics, ty_generics, where_clause, output_ty) + colon2_token: Default::default(), + gt_token: Default::default(), + lt_token: Default::default(), + + }) + }; + (impl_generics, ty_generics, where_clause, output_ty.into()) } pub fn is_parameterized( - ty: &Ty, - params: &[TyParam], + ty: &Type, + params: &[&TypeParam], found: Option<&mut HashSet>, ) -> bool { struct IsParameterized<'a, 'b> { - params: &'a [TyParam], + params: &'a [&'a TypeParam], has_free: bool, found: Option<&'b mut HashSet>, } - impl<'a, 'b> Visitor for IsParameterized<'a, 'b> { - fn visit_path(&mut self, path: &Path) { + impl<'a, 'b, 'ast> Visit<'ast> for IsParameterized<'a, 'b> { + fn visit_path(&mut self, path: &'ast Path) { if let Some(ident) = path_to_ident(path) { if self.params.iter().any(|param| param.ident == ident) { self.has_free = true; @@ -163,100 +176,104 @@ pub fn is_parameterized( } } } - visit::walk_path(self, path); + visit::visit_path(self, path); } } let mut visitor = IsParameterized { params, has_free: false, found }; - visitor.visit_ty(ty); + visitor.visit_type(ty); visitor.has_free } -pub fn map_type_params(ty: &Ty, params: &[TyParam], f: &mut F) -> Ty +pub fn map_type_params(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type where - F: FnMut(&Ident) -> Ty, + F: FnMut(&Ident) -> Type, { match *ty { - Ty::Slice(ref ty) => Ty::Slice(Box::new(map_type_params(ty, params, f))), - Ty::Array(ref ty, ref expr) => { - Ty::Array(Box::new(map_type_params(ty, params, f)), expr.clone()) + Type::Slice(ref inner) => { + Type::from(TypeSlice { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) }, - Ty::Never => Ty::Never, - Ty::Tup(ref items) => { - Ty::Tup(items.iter().map(|ty| map_type_params(ty, params, f)).collect()) + Type::Array(ref inner) => { //ref ty, ref expr) => { + Type::from(TypeArray { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() }) }, - Ty::Path(None, ref path) => { + ref ty @ Type::Never(_) => ty.clone(), + Type::Tuple(ref inner) => { + Type::from( + TypeTuple { + elems: inner.elems.iter().map(|ty| map_type_params(&ty, params, f)).collect(), + ..inner.clone() + } + ) + }, + Type::Path(TypePath { qself: None, ref path }) => { if let Some(ident) = path_to_ident(path) { if params.iter().any(|param| param.ident == ident) { return f(ident); } } - Ty::Path(None, map_type_params_in_path(path, params, f)) + Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) }) } - Ty::Path(ref qself, ref path) => { - Ty::Path( - qself.as_ref().map(|qself| { + Type::Path(TypePath { 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() } }), - map_type_params_in_path(path, params, f), - ) + 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() }) }, - Ty::Paren(ref ty) => Ty::Paren(Box::new(map_type_params(ty, params, f))), ref ty => panic!("type {:?} cannot be mapped yet", ty), } } -fn map_type_params_in_path(path: &Path, params: &[TyParam], f: &mut F) -> Path +fn map_type_params_in_path(path: &Path, params: &[&TypeParam], f: &mut F) -> Path where - F: FnMut(&Ident) -> Ty, + F: FnMut(&Ident) -> Type, { Path { - global: path.global, + leading_colon: path.leading_colon, segments: path.segments.iter().map(|segment| { PathSegment { ident: segment.ident.clone(), - parameters: match segment.parameters { - PathParameters::AngleBracketed(ref data) => { - PathParameters::AngleBracketed(AngleBracketedParameterData { - lifetimes: data.lifetimes.clone(), - types: data.types.iter().map(|ty| { - map_type_params(ty, params, f) - }).collect(), - bindings: data.bindings.iter().map(|binding| { - TypeBinding { - ident: binding.ident.clone(), - ty: map_type_params(&binding.ty, params, f), + arguments: match segment.arguments { + PathArguments::AngleBracketed(ref data) => { + PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args: data.args.iter().map(|arg| { + match arg { + ty @ &GenericArgument::Lifetime(_) => ty.clone(), + &GenericArgument::Type(ref data) => { + GenericArgument::Type(map_type_params(data, params, f)) + }, + &GenericArgument::Binding(ref data) => GenericArgument::Binding(Binding { + ty: map_type_params(&data.ty, params, f), + ..data.clone() + }), + ref arg => panic!("arguments {:?} cannot be mapped yet", arg) } }).collect(), + ..data.clone() }) }, + ref arg @ PathArguments::None => arg.clone(), ref parameters => { panic!("parameters {:?} cannot be mapped yet", parameters) - }, + } }, } }).collect(), } } -pub fn path(segments: S) -> Path -where - S: IntoIterator, - ::Item: AsRef, -{ - Path { - global: true, - segments: segments.into_iter().map(|s| s.as_ref().into()).collect(), - } -} - fn path_to_ident(path: &Path) -> Option<&Ident> { match *path { - Path { global: false, ref segments } if segments.len() == 1 => { - if segments[0].parameters.is_empty() { + Path { leading_colon: None, ref segments } if segments.len() == 1 => { + if segments[0].arguments.is_empty() { Some(&segments[0].ident) } else { None @@ -286,36 +303,41 @@ where } } -pub fn parse_variant_attrs(variant: &Variant) -> A +pub fn parse_variant_attrs(variant: &VariantAst) -> A where A: FromVariant, { - match A::from_variant(variant) { + let v = Variant { + ident: *variant.ident, + attrs: variant.attrs.to_vec(), + fields: variant.fields.clone(), + discriminant: variant.discriminant.clone(), + }; + match A::from_variant(&v) { Ok(attrs) => attrs, Err(e) => panic!("failed to parse variant attributes: {}", e), } } + pub fn ref_pattern<'a>( - name: &Ident, - variant: &'a Variant, + variant: &'a VariantInfo, prefix: &str, ) -> (Tokens, Vec>) { - synstructure::match_pattern( - &name, - &variant.data, - &BindOpts::with_prefix(BindStyle::Ref, prefix.to_owned()), - ) + let mut v = variant.clone(); + v.bind_with(|_| BindStyle::Ref); + v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); + (v.pat(), v.bindings().iter().cloned().collect()) } pub fn trait_parts<'input, 'path>( input: &'input DeriveInput, - trait_path: &'path [&'path str], -) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>) { + trait_path: &'path Path, +) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>) { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let where_clause = WhereClause { - inner: where_clause.clone(), - params: &input.generics.ty_params, + inner: where_clause.cloned(), + params: input.generics.type_params().into_iter().collect::>(), trait_path, trait_output: None, bounded_types: HashSet::new() @@ -323,88 +345,35 @@ pub fn trait_parts<'input, 'path>( (impl_generics, ty_generics, where_clause) } -fn trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path { - let (name, parent) = path.split_last().unwrap(); - let last_segment = PathSegment { - ident: (*name).into(), - parameters: PathParameters::AngleBracketed( - AngleBracketedParameterData { - bindings: output.into_iter().map(|(param, ty)| { - TypeBinding { ident: param.into(), ty } - }).collect(), - .. Default::default() - } - ) +fn trait_ref(path: &Path, output: Option<(Ident, Type)>) -> Path { + let segments = path.segments.iter().collect::>(); + let (name, parent) = segments.split_last().unwrap(); + + let last_segment: PathSegment = if let Some((param, ty)) = output { + parse_quote!(#name<#param = #ty>) + } else { + parse_quote!(#name) }; - Path { - global: true, - segments: { - parent - .iter() - .cloned() - .map(Into::into) - .chain(iter::once(last_segment)) - .collect() - }, - } + parse_quote!(::#(#parent::)*#last_segment) } pub fn value<'a>( - name: &Ident, - variant: &'a Variant, + variant: &'a VariantInfo, prefix: &str, ) -> (Tokens, Vec>) { - synstructure::match_pattern( - &name, - &variant.data, - &BindOpts::with_prefix(BindStyle::Move, prefix.to_owned()), - ) -} - -pub fn variant_ctor<'a>( - input: &'a DeriveInput, - variant: &Variant, -) -> Cow<'a, Ident> { - match input.body { - Body::Struct(_) => Cow::Borrowed(&input.ident), - Body::Enum(_) => { - Cow::Owned(Ident::from( - format!("{}::{}", input.ident, variant.ident), - )) - }, - } -} - -pub fn variants(input: &DeriveInput) -> Cow<[Variant]> { - match input.body { - Body::Enum(ref variants) => (&**variants).into(), - Body::Struct(ref data) => { - vec![Variant { - ident: input.ident.clone(), - attrs: input.attrs.clone(), - data: data.clone(), - discriminant: None, - }].into() - }, - } + let mut v = variant.clone(); + v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); + v.bind_with(|_| BindStyle::Move); + (v.pat(), v.bindings().iter().cloned().collect()) } pub fn where_predicate( - bounded_ty: Ty, - trait_path: &[&str], - trait_output: Option<(&str, Ty)>, + bounded_ty: Type, + trait_path: &Path, + trait_output: Option<(Ident, Type)>, ) -> WherePredicate { - WherePredicate::BoundPredicate(WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty, - bounds: vec![TyParamBound::Trait( - PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: trait_ref(trait_path, trait_output), - }, - TraitBoundModifier::None - )], - }) + let trait_ref = trait_ref(trait_path, trait_output); + parse_quote!(#bounded_ty: #trait_ref) } /// Transforms "FooBar" to "foo-bar". diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index cbdd9c62acc..509d1b5be95 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -6,52 +6,54 @@ use animate::AnimationVariantAttrs; use cg; use quote::Tokens; use syn::{DeriveInput, Path}; +use synstructure; pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; - let trait_path = &["values", "distance", "ComputeSquaredDistance"]; + let trait_path = parse_quote!(values::distance::ComputeSquaredDistance); let (impl_generics, ty_generics, mut where_clause) = - cg::trait_parts(&input, trait_path); + cg::trait_parts(&input, &trait_path); let input_attrs = cg::parse_input_attrs::(&input); - let variants = cg::variants(&input); - let mut match_body = quote!(); - let mut append_error_clause = variants.len() > 1; - match_body.append_all(variants.iter().map(|variant| { - let attrs = cg::parse_variant_attrs::(variant); + let s = synstructure::Structure::new(&input); + let mut append_error_clause = s.variants().len() > 1; + + let mut match_body = s.variants().iter().fold(quote!(), |body, variant| { + let attrs = cg::parse_variant_attrs::(&variant.ast()); if attrs.error { append_error_clause = true; - return None; + return body; } - let name = cg::variant_ctor(&input, variant); - let (this_pattern, this_info) = cg::ref_pattern(&name, &variant, "this"); - let (other_pattern, other_info) = cg::ref_pattern(&name, &variant, "other"); + + let (this_pattern, this_info) = cg::ref_pattern(&variant, "this"); + let (other_pattern, other_info) = cg::ref_pattern(&variant, "other"); let sum = if this_info.is_empty() { quote! { ::values::distance::SquaredDistance::Value(0.) } } else { let mut sum = quote!(); sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| { - where_clause.add_trait_bound(&this.field.ty); + where_clause.add_trait_bound(&this.ast().ty); quote! { ::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)? } - }), "+"); + }), quote!(+)); sum }; - Some(quote! { + quote! { + #body (&#this_pattern, &#other_pattern) => { Ok(#sum) } - }) - })); + } + }); if append_error_clause { if let Some(fallback) = input_attrs.fallback { - match_body.append(quote! { + match_body.append_all(quote! { (this, other) => #fallback(this, other) }); } else { - match_body.append(quote! { _ => Err(()) }); + match_body.append_all(quote! { _ => Err(()) }); } } diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index 7778b7ea39c..e414a3bd3f2 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -7,7 +7,7 @@ #[macro_use] extern crate darling; extern crate proc_macro; #[macro_use] extern crate quote; -extern crate syn; +#[macro_use] extern crate syn; extern crate synstructure; use proc_macro::TokenStream; @@ -23,42 +23,42 @@ mod to_css; #[proc_macro_derive(Animate, attributes(animate, animation))] pub fn derive_animate(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - animate::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + animate::derive(input).into() } #[proc_macro_derive(ComputeSquaredDistance, attributes(animation, distance))] pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - compute_squared_distance::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + compute_squared_distance::derive(input).into() } #[proc_macro_derive(ToAnimatedValue)] pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - to_animated_value::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + to_animated_value::derive(input).into() } #[proc_macro_derive(Parse, attributes(css))] pub fn derive_parse(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - parse::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + parse::derive(input).into() } #[proc_macro_derive(ToAnimatedZero, attributes(animation))] pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - to_animated_zero::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + to_animated_zero::derive(input).into() } #[proc_macro_derive(ToComputedValue, attributes(compute))] pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - to_computed_value::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + to_computed_value::derive(input).into() } #[proc_macro_derive(ToCss, attributes(css))] pub fn derive_to_css(stream: TokenStream) -> TokenStream { - let input = syn::parse_derive_input(&stream.to_string()).unwrap(); - to_css::derive(input).to_string().parse().unwrap() + let input = syn::parse(stream).unwrap(); + to_css::derive(input).into() } diff --git a/components/style_derive/parse.rs b/components/style_derive/parse.rs index 79ada00878f..fb429a05599 100644 --- a/components/style_derive/parse.rs +++ b/components/style_derive/parse.rs @@ -10,38 +10,40 @@ use to_css::CssVariantAttrs; pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; + let s = synstructure::Structure::new(&input); - let mut match_body = quote! {}; - - let style = synstructure::BindStyle::Ref.into(); - synstructure::each_variant(&input, &style, |bindings, variant| { + let match_body = s.variants().iter().fold(quote!(), |match_body, variant| { + let bindings = variant.bindings(); assert!( bindings.is_empty(), "Parse is only supported for single-variant enums for now" ); - let variant_attrs = cg::parse_variant_attrs::(variant); + let variant_attrs = cg::parse_variant_attrs::(&variant.ast()); let identifier = cg::to_css_identifier( - &variant_attrs.keyword.as_ref().unwrap_or(&variant.ident).as_ref(), + &variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()), ); - let ident = &variant.ident; + let ident = &variant.ast().ident; - match_body = quote! { + let mut body = quote! { #match_body #identifier => Ok(#name::#ident), }; + let aliases = match variant_attrs.aliases { Some(aliases) => aliases, - None => return, + None => return body, }; for alias in aliases.split(",") { - match_body = quote! { - #match_body + body = quote! { + #body #alias => Ok(#name::#ident), }; } + + body }); let parse_trait_impl = quote! { diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index 7865ba597e9..5d9cdbc0138 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -4,17 +4,17 @@ use cg; use quote; -use syn; +use syn::{self, Ident}; use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let trait_path = &["values", "animated", "ToAnimatedValue"]; + let trait_path = parse_quote!(values::animated::ToAnimatedValue); let (impl_generics, ty_generics, mut where_clause, animated_value_type) = - cg::fmap_trait_parts(&input, trait_path, "AnimatedValue"); + cg::fmap_trait_parts(&input, &trait_path, Ident::from("AnimatedValue")); let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| { - where_clause.add_trait_bound(&binding.field.ty); + where_clause.add_trait_bound(&binding.ast().ty); quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)) }); let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| { diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index be1210faa7a..674a0201fcc 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -6,31 +6,30 @@ use animate::{AnimationVariantAttrs, AnimationFieldAttrs}; use cg; use quote; use syn; -use synstructure::{self, BindStyle}; +use synstructure; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let trait_path = &["values", "animated", "ToAnimatedZero"]; + let trait_path = parse_quote!(values::animated::ToAnimatedZero); let (impl_generics, ty_generics, mut where_clause) = - cg::trait_parts(&input, trait_path); + cg::trait_parts(&input, &trait_path); - let bind_opts = BindStyle::Ref.into(); - let to_body = synstructure::each_variant(&input, &bind_opts, |bindings, variant| { - let attrs = cg::parse_variant_attrs::(variant); + let s = synstructure::Structure::new(&input); + let to_body = s.each_variant(|variant| { + let attrs = cg::parse_variant_attrs::(&variant.ast()); if attrs.error { return Some(quote! { Err(()) }); } - let name = cg::variant_ctor(&input, variant); - let (mapped, mapped_bindings) = cg::value(&name, variant, "mapped"); - let bindings_pairs = bindings.into_iter().zip(mapped_bindings); + let (mapped, mapped_bindings) = cg::value(variant, "mapped"); + let bindings_pairs = variant.bindings().into_iter().zip(mapped_bindings); let mut computations = quote!(); computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| { - let field_attrs = cg::parse_field_attrs::(&binding.field); + let field_attrs = cg::parse_field_attrs::(&binding.ast()); if field_attrs.constant { - if cg::is_parameterized(&binding.field.ty, where_clause.params, None) { - where_clause.inner.predicates.push(cg::where_predicate( - binding.field.ty.clone(), - &["std", "clone", "Clone"], + if cg::is_parameterized(&binding.ast().ty, &where_clause.params, None) { + where_clause.add_predicate(cg::where_predicate( + binding.ast().ty.clone(), + &parse_quote!(std::clone::Clone), None, )); } @@ -38,14 +37,14 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let #mapped_binding = ::std::clone::Clone::clone(#binding); } } else { - where_clause.add_trait_bound(&binding.field.ty); + where_clause.add_trait_bound(&binding.ast().ty); quote! { let #mapped_binding = ::values::animated::ToAnimatedZero::to_animated_zero(#binding)?; } } })); - computations.append(quote! { Ok(#mapped) }); + computations.append_all(quote! { Ok(#mapped) }); Some(computations) }); diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index c53b25408e9..198d5cfe17c 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -4,29 +4,29 @@ use cg; use quote::Tokens; -use syn::DeriveInput; +use syn::{Ident, DeriveInput}; use synstructure::BindStyle; pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; - let trait_path = &["values", "computed", "ToComputedValue"]; + let trait_path = parse_quote!(values::computed::ToComputedValue); let (impl_generics, ty_generics, mut where_clause, computed_value_type) = - cg::fmap_trait_parts(&input, trait_path, "ComputedValue"); + cg::fmap_trait_parts(&input, &trait_path, Ident::from("ComputedValue")); let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - let attrs = cg::parse_field_attrs::(&binding.field); + let attrs = cg::parse_field_attrs::(&binding.ast()); if attrs.clone { - if cg::is_parameterized(&binding.field.ty, where_clause.params, None) { - where_clause.inner.predicates.push(cg::where_predicate( - binding.field.ty.clone(), - &["std", "clone", "Clone"], + if cg::is_parameterized(&binding.ast().ty, &where_clause.params, None) { + where_clause.add_predicate(cg::where_predicate( + binding.ast().ty.clone(), + &parse_quote!(std::clone::Clone), None, )); } quote! { ::std::clone::Clone::clone(#binding) } } else { if !attrs.ignore_bound { - where_clause.add_trait_bound(&binding.field.ty); + where_clause.add_trait_bound(&binding.ast().ty); } quote! { ::values::computed::ToComputedValue::to_computed_value(#binding, context) @@ -34,7 +34,7 @@ pub fn derive(input: DeriveInput) -> Tokens { } }); let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - let attrs = cg::parse_field_attrs::(&binding.field); + let attrs = cg::parse_field_attrs::(&binding.ast()); if attrs.clone { quote! { ::std::clone::Clone::clone(#binding) } } else { diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 93e36753abf..f86418b2361 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -5,20 +5,23 @@ use cg; use darling::{Error, FromMetaItem}; use quote::Tokens; -use syn::{self, DeriveInput, Ident}; +use syn::{self, Ident}; use synstructure; -pub fn derive(input: DeriveInput) -> Tokens { +pub fn derive(input: syn::DeriveInput) -> Tokens { let name = &input.ident; - let trait_path = &["style_traits", "ToCss"]; + let trait_path = parse_quote!(style_traits::ToCss); let (impl_generics, ty_generics, mut where_clause) = - cg::trait_parts(&input, trait_path); + cg::trait_parts(&input, &trait_path); let input_attrs = cg::parse_input_attrs::(&input); - let style = synstructure::BindStyle::Ref.into(); - let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { - let identifier = cg::to_css_identifier(variant.ident.as_ref()); - let variant_attrs = cg::parse_variant_attrs::(variant); + let s = synstructure::Structure::new(&input); + + let match_body = s.each_variant(|variant| { + let bindings = variant.bindings(); + let identifier = cg::to_css_identifier(variant.ast().ident.as_ref()); + let ast = variant.ast(); + let variant_attrs = cg::parse_variant_attrs::(&ast); let separator = if variant_attrs.comma { ", " } else { " " }; if variant_attrs.dimension { @@ -49,9 +52,9 @@ pub fn derive(input: DeriveInput) -> Tokens { }; } else { for binding in bindings { - let attrs = cg::parse_field_attrs::(&binding.field); + let attrs = cg::parse_field_attrs::(&binding.ast()); if !attrs.ignore_bound { - where_clause.add_trait_bound(&binding.field.ty); + where_clause.add_trait_bound(&binding.ast().ty); } expr = quote! { #expr @@ -107,7 +110,7 @@ pub fn derive(input: DeriveInput) -> Tokens { }; if input_attrs.derive_debug { - impls.append(quote! { + impls.append_all(quote! { impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { ::style_traits::ToCss::to_css( @@ -137,7 +140,7 @@ pub struct CssVariantAttrs { pub iterable: bool, pub comma: bool, pub dimension: bool, - pub keyword: Option, + pub keyword: Option, pub aliases: Option, } @@ -157,7 +160,7 @@ impl FromMetaItem for Function { } fn from_string(name: &str) -> Result { - let name = syn::parse_ident(name).map_err(Error::custom)?; + let name = Ident::from(name); Ok(Self { name: Some(name) }) } } diff --git a/servo-tidy.toml b/servo-tidy.toml index dda9bc9d790..8ddfe46baa3 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -42,7 +42,6 @@ packages = [ "syn", "quote", "unicode-xid", - "synstructure", ] # Files that are ignored for all tidy and lint checks. files = [