aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2017-02-14 14:13:43 +0100
committerAnthony Ramine <n.oxyde@gmail.com>2017-02-14 14:13:43 +0100
commitc84cea995bd5d1596eaffe041b479ba1081a50fe (patch)
tree99b71bdc33af9fe83250374e7072bb0506232d10
parent1dfdd0bab82b2356c6fb15d0d0e898a972983ba1 (diff)
downloadservo-c84cea995bd5d1596eaffe041b479ba1081a50fe.tar.gz
servo-c84cea995bd5d1596eaffe041b479ba1081a50fe.zip
Derive DomObject with a proc macro
-rw-r--r--Cargo.lock9
-rw-r--r--components/domobject_derive/Cargo.toml14
-rw-r--r--components/domobject_derive/lib.rs53
-rw-r--r--components/plugins/jstraceable.rs4
-rw-r--r--components/plugins/lib.rs6
-rw-r--r--components/plugins/reflector.rs82
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/bindings/reflector.rs12
-rw-r--r--components/script/lib.rs2
9 files changed, 92 insertions, 91 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d4bd99511e9..35473330695 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -651,6 +651,14 @@ dependencies = [
]
[[package]]
+name = "domobject_derive"
+version = "0.0.1"
+dependencies = [
+ "quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.10.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "dtoa"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2255,6 +2263,7 @@ dependencies = [
"cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"devtools_traits 0.0.1",
+ "domobject_derive 0.0.1",
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/components/domobject_derive/Cargo.toml b/components/domobject_derive/Cargo.toml
new file mode 100644
index 00000000000..0fc9b7f2124
--- /dev/null
+++ b/components/domobject_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "domobject_derive"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+publish = false
+
+[lib]
+path = "lib.rs"
+proc-macro = true
+
+[dependencies]
+syn = "0.10"
+quote = "0.3"
diff --git a/components/domobject_derive/lib.rs b/components/domobject_derive/lib.rs
new file mode 100644
index 00000000000..037ae597e8b
--- /dev/null
+++ b/components/domobject_derive/lib.rs
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+extern crate proc_macro;
+#[macro_use] extern crate quote;
+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()
+}
+
+fn expand_string(input: &str) -> String {
+ let type_ = syn::parse_macro_input(input).unwrap();
+
+ let first_field_name = if let syn::Body::Struct(syn::VariantData::Struct(ref fields)) = type_.body {
+ let first_field = fields.first().expect("#[derive(DomObject)] should not be applied on empty structs");
+ first_field.ident.as_ref().unwrap()
+ } else {
+ panic!("#[derive(DomObject)] should only be applied on proper structs")
+ };
+
+ let name = &type_.ident;
+ let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
+
+ let tokens = 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::jsapi::MutableHandleValue) {
+ let object = ::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 {
+ #[inline]
+ fn reflector(&self) -> &::dom::bindings::reflector::Reflector {
+ self.#first_field_name.reflector()
+ }
+ }
+
+ impl #impl_generics ::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);
+ }
+ }
+ };
+
+ tokens.to_string()
+}
diff --git a/components/plugins/jstraceable.rs b/components/plugins/jstraceable.rs
index 233f90b3bb7..498f4006010 100644
--- a/components/plugins/jstraceable.rs
+++ b/components/plugins/jstraceable.rs
@@ -15,9 +15,7 @@ pub fn expand_dom_struct(cx: &mut ExtCtxt, sp: Span, _: &MetaItem, anno: Annotat
item2.attrs.push(quote_attr!(cx, #[repr(C)]));
item2.attrs.push(quote_attr!(cx, #[derive(JSTraceable)]));
item2.attrs.push(quote_attr!(cx, #[derive(HeapSizeOf)]));
-
- // The following attributes are only for internal usage
- item2.attrs.push(quote_attr!(cx, #[_generate_reflector]));
+ item2.attrs.push(quote_attr!(cx, #[derive(DomObject)]));
// #[dom_struct] gets consumed, so this lets us keep around a residue
// Do NOT register a modifier/decorator on this attribute
item2.attrs.push(quote_attr!(cx, #[_dom_struct_marker]));
diff --git a/components/plugins/lib.rs b/components/plugins/lib.rs
index a8efe9ab1fb..eca3feef5f1 100644
--- a/components/plugins/lib.rs
+++ b/components/plugins/lib.rs
@@ -34,8 +34,6 @@ use syntax::symbol::Symbol;
/// Handles the auto-deriving for `#[derive(JSTraceable)]`
pub mod jstraceable;
pub mod lints;
-/// Autogenerates implementations of DomObject on DOM structs
-pub mod reflector;
/// Utilities for writing plugins
mod utils;
@@ -45,10 +43,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
Symbol::intern("dom_struct"),
MultiModifier(box jstraceable::expand_dom_struct));
- reg.register_syntax_extension(
- Symbol::intern("_generate_reflector"),
- MultiDecorator(box reflector::expand_reflector));
-
reg.register_late_lint_pass(box lints::unrooted_must_root::UnrootedPass::new());
reg.register_late_lint_pass(box lints::privatize::PrivatizePass);
reg.register_late_lint_pass(box lints::inheritance_integrity::InheritancePass);
diff --git a/components/plugins/reflector.rs b/components/plugins/reflector.rs
deleted file mode 100644
index 768e65e59eb..00000000000
--- a/components/plugins/reflector.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-use syntax::ast::{ItemKind, MetaItem};
-use syntax::codemap::Span;
-use syntax::ext::base::{Annotatable, ExtCtxt};
-use utils::match_ty_unwrap;
-
-
-pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: &Annotatable,
- push: &mut FnMut(Annotatable)) {
- if let &Annotatable::Item(ref item) = annotatable {
- if let ItemKind::Struct(ref def, _) = item.node {
- if def.fields().is_empty() {
- cx.span_err(span, "#[dom_struct] should have a reflector or \
- parent dom struct as its first field");
- return;
- }
- let struct_name = item.ident;
- // This path has to be hardcoded, unfortunately, since we can't resolve paths at expansion time
- match def.fields().iter().find(
- |f| match_ty_unwrap(&*f.ty, &["dom", "bindings", "reflector", "Reflector"]).is_some()) {
- // If it has a field that is a Reflector, use that
- Some(f) => {
- let field_name = f.ident;
- let impl_item = quote_item!(cx,
- impl ::dom::bindings::reflector::DomObject for $struct_name {
- fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
- &self.$field_name
- }
- }
- );
- let impl_item_mut = quote_item!(cx,
- impl ::dom::bindings::reflector::MutDomObject for $struct_name {
- fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
- self.$field_name.set_jsobject(obj);
- }
- }
- );
- impl_item.map(|it| push(Annotatable::Item(it)));
- impl_item_mut.map(|it| push(Annotatable::Item(it)))
- },
- // Or just call it on the first field (supertype).
- None => {
- let field_name = def.fields()[0].ident;
- let impl_item = quote_item!(cx,
- impl ::dom::bindings::reflector::DomObject for $struct_name {
- fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
- self.$field_name.reflector()
- }
- }
- );
- let impl_item_mut = quote_item!(cx,
- impl ::dom::bindings::reflector::MutDomObject for $struct_name {
- fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
- self.$field_name.init_reflector(obj);
- }
- }
- );
- impl_item.map(|it| push(Annotatable::Item(it)));
- impl_item_mut.map(|it| push(Annotatable::Item(it)))
- }
- };
-
- let impl_item = quote_item!(cx,
- impl ::js::conversions::ToJSValConvertible for $struct_name {
- #[allow(unsafe_code)]
- unsafe fn to_jsval(&self,
- cx: *mut ::js::jsapi::JSContext,
- rval: ::js::jsapi::MutableHandleValue) {
- let object = ::dom::bindings::reflector::DomObject::reflector(self).get_jsobject();
- object.to_jsval(cx, rval)
- }
- }
- );
- impl_item.map(|it| push(Annotatable::Item(it)));
- } else {
- cx.span_err(span, "#[dom_struct] seems to have been applied to a non-struct");
- }
- }
-}
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 57ea9b4b648..6e77113094b 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -36,6 +36,7 @@ caseless = "0.1.0"
cookie = {version = "0.2.5", features = ["serialize-rustc"]}
cssparser = {version = "0.7", features = ["heap_size", "serde-serialization"]}
devtools_traits = {path = "../devtools_traits"}
+domobject_derive = {path = "../domobject_derive"}
encoding = "0.2"
euclid = "0.10.1"
fnv = "1.0"
diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs
index 4f342070707..40d894ccd00 100644
--- a/components/script/dom/bindings/reflector.rs
+++ b/components/script/dom/bindings/reflector.rs
@@ -83,8 +83,20 @@ pub trait DomObject {
}
}
+impl DomObject for Reflector {
+ fn reflector(&self) -> &Self {
+ self
+ }
+}
+
/// A trait to initialize the `Reflector` for a DOM object.
pub trait MutDomObject: DomObject {
/// Initializes the Reflector
fn init_reflector(&mut self, obj: *mut JSObject);
}
+
+impl MutDomObject for Reflector {
+ fn init_reflector(&mut self, obj: *mut JSObject) {
+ self.set_jsobject(obj)
+ }
+}
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 7126d53653e..3242e0ccf01 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -39,6 +39,8 @@ extern crate core;
#[macro_use]
extern crate cssparser;
extern crate devtools_traits;
+#[macro_use]
+extern crate domobject_derive;
extern crate encoding;
extern crate euclid;
extern crate fnv;