Skip to content

Commit

Permalink
Auto merge of #21371 - retep007:generic-servo, r=<try>
Browse files Browse the repository at this point in the history
[WIP] Generic script crate

Separation is based on adding types to TypeHolderTrait which contains
associated types with traits that script crate actually needs. This allows
using static methods and Sized types.

Affects servo in two ways:
- generic structs do not compile in script crate but are left for later monomorphization
- dom_structs itself are moved to separate crate

TODO:
- [ ] tests
- [ ] performance
- [ ] polyshing

Fixes #1799

r? @jdm

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #1799 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21371)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Aug 9, 2018
2 parents 2fc0633 + e668042 commit 32f598e
Show file tree
Hide file tree
Showing 368 changed files with 11,282 additions and 9,641 deletions.
55 changes: 47 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion components/dom_struct/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish = false
version = "0.0.1"

[dependencies]
quote = "0.6.3"
quote = "0.6.4"
syn = { version = "0.14.2", features = ["full"] }

[lib]
Expand Down
26 changes: 16 additions & 10 deletions components/dom_struct/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,29 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate proc_macro;

#[macro_use]
extern crate quote;
extern crate syn;
#[macro_use] extern crate quote;

use proc_macro::TokenStream;
use proc_macro::{TokenStream};
use quote::__rt::Span;
use syn::*;

#[proc_macro_attribute]
pub fn dom_struct(args: TokenStream, input: TokenStream) -> TokenStream {
let mut base = None;
let mut crater = None;
if !args.is_empty() {
panic!("#[dom_struct] takes no arguments");
use quote::ToTokens;

let args = args.to_string();
let crate_name = args.trim_matches(&['(', ')', ' '][..]);
crater = Some(syn::Ident::new(crate_name, Span::call_site()));
base = Some(quote! {#[base = #crate_name]});
println!("{}", base.clone().unwrap());
}
let attributes = quote! {
#[derive(DenyPublicFields, DomObject, JSTraceable, MallocSizeOf)]
#[derive(DomObject, DenyPublicFields, JSTraceable, MallocSizeOf)]
#base
#[must_root]
#[repr(C)]
};
Expand All @@ -32,19 +40,17 @@ pub fn dom_struct(args: TokenStream, input: TokenStream) -> TokenStream {

if let Item::Struct(s) = item {
let s2 = s.clone();
if s.generics.params.len() > 0 {
return quote!(#s2).into();
}
if let Fields::Named(ref f) = s.fields {
let f = f.named.first().expect("Must have at least one field").into_value();
let ident = f.ident.as_ref().expect("Must have named fields");
let name = &s.ident;
let (impl_generics, ty_generics, _) = &s.generics.split_for_impl();
let ty = &f.ty;

quote! (
#s2

impl ::dom::bindings::inheritance::HasParent for #name {
impl#impl_generics #crater::dom::bindings::inheritance::HasParent for #name#ty_generics {
type Parent = #ty;
/// This is used in a type assertion to ensure that
/// the source and webidls agree as to what the parent type is
Expand Down
82 changes: 65 additions & 17 deletions components/domobject_derive/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,36 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![recursion_limit = "128"]
#![feature(log_syntax)]

extern crate proc_macro;
#[macro_use] extern crate quote;
#[macro_use] extern crate syn;

#[proc_macro_derive(DomObject)]
use quote::ToTokens;

#[proc_macro_derive(DomObject, attributes(base))]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse(input).unwrap();
expand_dom_object(input).into()
}

fn expand_dom_object(input: syn::DeriveInput) -> quote::Tokens {
let attrs = input.attrs.iter().filter(|attr| match attr.interpret_meta().unwrap() {
syn::Meta::NameValue(syn::MetaNameValue { ref ident, .. }) if ident == "base" => {
true
}
_ => false,
}).collect::<Vec<_>>();
let mut base = quote::Tokens::new();
let mut th = quote!{TH};
if attrs.len() > 0 {
if let syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(st), .. }) = attrs[0].interpret_meta().unwrap() {
syn::Ident::from(&st.value()[..]).to_tokens(&mut base);
th = quote!{TypeHolder};
}
}

let fields = if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = input.data {
fields.iter().collect::<Vec<&syn::Field>>()
} else {
Expand All @@ -41,53 +59,83 @@ fn expand_dom_object(input: syn::DeriveInput) -> quote::Tokens {
unsafe fn to_jsval(&self,
cx: *mut ::js::jsapi::JSContext,
rval: ::js::rust::MutableHandleValue) {
let object = ::dom::bindings::reflector::DomObject::reflector(self).get_jsobject();
let object = #base::dom::bindings::reflector::DomObject::reflector(self).get_jsobject();
object.to_jsval(cx, rval)
}
}

impl #impl_generics ::dom::bindings::reflector::DomObject for #name #ty_generics #where_clause {
impl #impl_generics #base::dom::bindings::reflector::DomObject for #name #ty_generics #where_clause {
type TypeHolder = #th;

#[inline]
fn reflector(&self) -> &::dom::bindings::reflector::Reflector {
fn reflector(&self) -> &#base::dom::bindings::reflector::Reflector<Self::TypeHolder> {
self.#first_field_name.reflector()
}
}

impl #impl_generics ::dom::bindings::reflector::MutDomObject for #name #ty_generics #where_clause {
impl #impl_generics #base::dom::bindings::reflector::MutDomObject for #name #ty_generics #where_clause {
fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
self.#first_field_name.init_reflector(obj);
}
}
};
if name == "IterableIterator" {
items = quote! {
impl #impl_generics ::js::conversions::ToJSValConvertible for #name #ty_generics #where_clause {
#[allow(unsafe_code)]
unsafe fn to_jsval(&self,
cx: *mut ::js::jsapi::JSContext,
rval: ::js::rust::MutableHandleValue) {
let object = #base::dom::bindings::reflector::DomObject::reflector(self).get_jsobject();
object.to_jsval(cx, rval)
}
}

impl #impl_generics #base::dom::bindings::reflector::DomObject for #name #ty_generics #where_clause {
type TypeHolder = T::TypeHolder;

#[inline]
fn reflector(&self) -> &#base::dom::bindings::reflector::Reflector<Self::TypeHolder> {
self.#first_field_name.reflector()
}
}

impl #impl_generics #base::dom::bindings::reflector::MutDomObject for #name #ty_generics #where_clause {
fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
self.#first_field_name.init_reflector(obj);
}
}
};
}

let mut params = quote::Tokens::new();
params.append_separated(input.generics.type_params().map(|param| param.ident), ", ");
params.append_separated(input.generics.type_params().map(|param| param.ident), quote!(,));


// 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.
// This allows us to support parameterized DOM objects
// such as IteratorIterable<T>.
items.append_all(field_types.iter().map(|ty| {
quote! {
impl #impl_generics ShouldNotImplDomObject for ((#params), #ty) #where_clause {}
}
}));
// items.append_all(field_types.iter().map(|ty| {
// quote! {
// impl #impl_generics ShouldNotImplDomObject for ((#params), #ty) #where_clause {}
// }
// }));

let mut generics = input.generics.clone();
generics.params.push(parse_quote!(__T: ::dom::bindings::reflector::DomObject));
generics.params.push(parse_quote!(__T: #base::dom::bindings::reflector::DomObject));

let (impl_generics, _, where_clause) = generics.split_for_impl();

items.append_all(quote! {
trait ShouldNotImplDomObject {}
impl #impl_generics ShouldNotImplDomObject for ((#params), __T) #where_clause {}
});
// items.append_all(quote! {
// trait ShouldNotImplDomObject {}
// impl #impl_generics ShouldNotImplDomObject for ((#params), __T) #where_clause {}
// });

let dummy_const = syn::Ident::from(format!("_IMPL_DOMOBJECT_FOR_{}", name));
let tokens = quote! {
#[allow(non_upper_case_globals)]
const #dummy_const: () = { #items };
};

tokens
}
Loading

0 comments on commit 32f598e

Please sign in to comment.