aboutsummaryrefslogtreecommitdiffstats
path: root/components/plugins/jstraceable.rs
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2014-09-24 01:15:12 +0530
committerManish Goregaokar <manishsmail@gmail.com>2014-09-24 01:15:22 +0530
commit3b7e07699e060887c1254228a7d8307da0ae0e14 (patch)
tree5a1f4efb4b0f247d0d06b7043e3af22ffb4cf471 /components/plugins/jstraceable.rs
parent27f3bcd7183d836bd454e687706b4e76d6d3b312 (diff)
downloadservo-3b7e07699e060887c1254228a7d8307da0ae0e14.tar.gz
servo-3b7e07699e060887c1254228a7d8307da0ae0e14.zip
Add #[jstraceable] syntax extension
Diffstat (limited to 'components/plugins/jstraceable.rs')
-rw-r--r--components/plugins/jstraceable.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/components/plugins/jstraceable.rs b/components/plugins/jstraceable.rs
new file mode 100644
index 00000000000..5a113ab1691
--- /dev/null
+++ b/components/plugins/jstraceable.rs
@@ -0,0 +1,76 @@
+/* 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::ext::base::ExtCtxt;
+use syntax::codemap::Span;
+use syntax::ptr::P;
+use syntax::ast::{Item, MetaItem, Expr};
+use syntax::ast;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty};
+
+ pub fn expand_jstraceable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Item, push: |P<Item>|) {
+ let trait_def = TraitDef {
+ span: span,
+ attributes: Vec::new(),
+ path: ty::Path::new(vec!("dom","bindings","trace","JSTraceable")),
+ additional_bounds: Vec::new(),
+ generics: ty::LifetimeBounds::empty(),
+ methods: vec!(
+ MethodDef {
+ name: "trace",
+ generics: ty::LifetimeBounds::empty(),
+ explicit_self: ty::borrowed_explicit_self(),
+ args: vec!(ty::Ptr(box ty::Literal(ty::Path::new(vec!("js","jsapi","JSTracer"))), ty::Raw(ast::MutMutable))),
+ ret_ty: ty::nil_ty(),
+ attributes: vec!(),
+ combine_substructure: combine_substructure(|a, b, c| {
+ jstraceable_substructure(a, b, c)
+ })
+ }
+ )
+ };
+ trait_def.expand(cx, mitem, item, push)
+}
+
+// Mostly copied from syntax::ext::deriving::hash
+fn jstraceable_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
+ let state_expr = match substr.nonself_args {
+ [ref state_expr] => state_expr,
+ _ => cx.span_bug(trait_span, "incorrect number of arguments in `jstraceable`")
+ };
+ let hash_ident = substr.method_ident;
+ let call_hash = |span, thing_expr| {
+ let expr = cx.expr_method_call(span, thing_expr, hash_ident, vec!(state_expr.clone()));
+ cx.stmt_expr(expr)
+ };
+ let mut stmts = Vec::new();
+
+ let fields = match *substr.fields {
+ Struct(ref fs) => fs,
+ EnumMatching(index, variant, ref fs) => {
+ // Determine the discriminant. We will feed this value to the byte
+ // iteration function.
+ let discriminant = match variant.node.disr_expr {
+ Some(ref d) => d.clone(),
+ None => cx.expr_uint(trait_span, index)
+ };
+
+ stmts.push(call_hash(trait_span, discriminant));
+
+ fs
+ }
+ _ => cx.span_bug(trait_span, "impossible substructure in `jstraceable`")
+ };
+
+ for &FieldInfo { ref self_, span, .. } in fields.iter() {
+ stmts.push(call_hash(span, self_.clone()));
+ }
+
+ if stmts.len() == 0 {
+ cx.span_bug(trait_span, "#[jstraceable] needs at least one field");
+ }
+
+ cx.expr_block(cx.block(trait_span, stmts, None))
+}