diff --git a/Cargo.lock b/Cargo.lock index 7e41ec7fbf7..4508675ddb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -708,8 +708,8 @@ version = "0.0.1" name = "domobject_derive" version = "0.0.1" 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)", + "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]] diff --git a/components/domobject_derive/Cargo.toml b/components/domobject_derive/Cargo.toml index 5b9f8f4aab5..ca05937294e 100644 --- a/components/domobject_derive/Cargo.toml +++ b/components/domobject_derive/Cargo.toml @@ -10,5 +10,5 @@ path = "lib.rs" proc-macro = true [dependencies] -syn = "0.11" -quote = "0.3.15" +syn = "0.12.12" +quote = "0.4.2" diff --git a/components/domobject_derive/lib.rs b/components/domobject_derive/lib.rs index c718b514fc5..6b7a9ccb6a7 100644 --- a/components/domobject_derive/lib.rs +++ b/components/domobject_derive/lib.rs @@ -2,20 +2,21 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![recursion_limit = "128"] + extern crate proc_macro; #[macro_use] extern crate quote; -extern crate syn; +#[macro_use] extern crate syn; #[proc_macro_derive(DomObject)] pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - expand_string(&input.to_string()).parse().unwrap() + let input = syn::parse(input).unwrap(); + expand_dom_object(input).into() } -fn expand_string(input: &str) -> String { - let type_ = syn::parse_macro_input(input).unwrap(); - - let fields = if let syn::Body::Struct(syn::VariantData::Struct(ref fields)) = type_.body { - fields +fn expand_dom_object(input: syn::DeriveInput) -> quote::Tokens { + let fields = if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = input.data { + fields.iter().collect::>() } else { panic!("#[derive(DomObject)] should only be applied on proper structs") }; @@ -23,6 +24,7 @@ fn expand_string(input: &str) -> String { let (first_field, fields) = fields .split_first() .expect("#[derive(DomObject)] should not be applied on empty structs"); + let first_field_name = first_field.ident.as_ref().unwrap(); let mut field_types = vec![]; for field in fields { @@ -31,9 +33,8 @@ fn expand_string(input: &str) -> String { } } - let name = &type_.ident; - let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl(); - + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let mut items = quote! { impl #impl_generics ::js::conversions::ToJSValConvertible for #name #ty_generics #where_clause { #[allow(unsafe_code)] @@ -60,7 +61,7 @@ fn expand_string(input: &str) -> String { }; let mut params = quote::Tokens::new(); - params.append_separated(type_.generics.ty_params.iter().map(|param| ¶m.ident), ", "); + params.append_separated(input.generics.type_params().map(|param| param.ident), ", "); // For each field in the struct, we implement ShouldNotImplDomObject for a // pair of all the type parameters of the DomObject and and the field type. @@ -72,33 +73,21 @@ fn expand_string(input: &str) -> String { } })); - let bound = syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: syn::parse_path("::dom::bindings::reflector::DomObject").unwrap(), - }, - syn::TraitBoundModifier::None - ); + let mut generics = input.generics.clone(); + generics.params.push(parse_quote!(__T: ::dom::bindings::reflector::DomObject)); - let mut generics = type_.generics.clone(); - generics.ty_params.push(syn::TyParam { - attrs: vec![], - ident: "__T".into(), - bounds: vec![bound], - default: None, - }); let (impl_generics, _, where_clause) = generics.split_for_impl(); - items.append(quote! { + items.append_all(quote! { trait ShouldNotImplDomObject {} impl #impl_generics ShouldNotImplDomObject for ((#params), __T) #where_clause {} - }.as_str()); + }); - let dummy_const = syn::Ident::new(format!("_IMPL_DOMOBJECT_FOR_{}", name)); + let dummy_const = syn::Ident::from(format!("_IMPL_DOMOBJECT_FOR_{}", name)); let tokens = quote! { #[allow(non_upper_case_globals)] const #dummy_const: () = { #items }; }; - tokens.to_string() + tokens }