Skip to content

Commit

Permalink
[WIP] Generic script crate
Browse files Browse the repository at this point in the history
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 does not compile in script crate, but are left for later monomorphization
- dom_structs itself are moved to separate crate

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

Fixes servo#1799

r? @jdm
  • Loading branch information
hrvolapeter committed Aug 17, 2018
1 parent 2fc0633 commit d8d4e1a
Show file tree
Hide file tree
Showing 371 changed files with 11,390 additions and 9,629 deletions.
56 changes: 48 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
17 changes: 12 additions & 5 deletions components/dom_struct/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@ extern crate quote;
extern crate syn;

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] });
}
let attributes = quote! {
#[derive(DenyPublicFields, DomObject, JSTraceable, MallocSizeOf)]
#base
#[must_root]
#[repr(C)]
};
Expand All @@ -32,19 +41,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, where_clause) = &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 #where_clause {
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
55 changes: 39 additions & 16 deletions components/domobject_derive/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,31 @@ extern crate proc_macro;
#[macro_use] extern crate quote;
#[macro_use] extern crate syn;

#[proc_macro_derive(DomObject)]
use quote::ToTokens;
use syn::{Meta, Ident, Lit, MetaNameValue};

#[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 Meta::NameValue(MetaNameValue { lit: Lit::Str(st), .. }) = attrs[0].interpret_meta().unwrap() {
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 @@ -34,54 +52,59 @@ fn expand_dom_object(input: syn::DeriveInput) -> quote::Tokens {
}

let name = &input.ident;
if name == "IterableIterator" {
th = quote!{ T::TypeHolder }
}
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)]
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);
}
}
};

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! {
Expand Down
23 changes: 18 additions & 5 deletions components/jstraceable_derive/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,49 @@
extern crate quote;
#[macro_use] extern crate syn;
#[macro_use] extern crate synstructure;
use quote::ToTokens;
use syn::{Meta, Lit, Ident};

decl_derive!([JSTraceable] => js_traceable_derive);
decl_derive!([JSTraceable, attributes(base)] => js_traceable_derive);

fn js_traceable_derive(s: synstructure::Structure) -> quote::Tokens {
let match_body = s.each(|binding| {
Some(quote!(#binding.trace(tracer);))
});

let ast = s.ast();
let attrs = ast.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();
if attrs.len() > 0 {
if let Meta::NameValue(syn::MetaNameValue { lit: Lit::Str(st), .. }) = attrs[0].interpret_meta().unwrap() {
Ident::from(&st.value()[..]).to_tokens(&mut base);
}
}
let name = ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let mut where_clause = where_clause.unwrap_or(&parse_quote!(where)).clone();
for param in ast.generics.type_params() {
let ident = param.ident;
where_clause.predicates.push(parse_quote!(#ident: ::dom::bindings::trace::JSTraceable))
where_clause.predicates.push(parse_quote!(#ident: #base::dom::bindings::trace::JSTraceable))
}

let tokens = quote! {
#[allow(unsafe_code)]
unsafe impl #impl_generics ::dom::bindings::trace::JSTraceable for #name #ty_generics #where_clause {
unsafe impl #impl_generics #base::dom::bindings::trace::JSTraceable for #name #ty_generics #where_clause {
#[inline]
#[allow(unused_variables, unused_imports)]
unsafe fn trace(&self, tracer: *mut ::js::jsapi::JSTracer) {
use ::dom::bindings::trace::JSTraceable;
use #base::dom::bindings::trace::JSTraceable;
match *self {
#match_body
}
}
}
};

tokens
}
4 changes: 4 additions & 0 deletions components/layout_thread/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ gfx_traits = {path = "../gfx_traits"}
histogram = "0.6.8"
html5ever = "0.22"
ipc-channel = "0.10"
jstraceable_derive = {path = "../jstraceable_derive"}
layout = {path = "../layout"}
layout_traits = {path = "../layout_traits"}
lazy_static = "1"
libc = "0.2"
log = "0.4"
time = "0.1.17"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
metrics = {path = "../metrics"}
mozjs = { version = "0.7", features = ["promises"]}
msg = {path = "../msg"}
net_traits = {path = "../net_traits"}
parking_lot = "0.6"
Expand All @@ -41,6 +44,7 @@ rayon = "1"
script = {path = "../script"}
script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
script_servoparser = {path = "../script_servoparser"}
selectors = { path = "../selectors" }
serde_json = "1.0"
servo_allocator = {path = "../allocator"}
Expand Down
Loading

0 comments on commit d8d4e1a

Please sign in to comment.