#![crate_name = "quickcheck_macros"]
#![crate_type = "dylib"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/quickcheck")]
#![allow(unstable)]
#![feature(plugin_registrar)]
extern crate syntax;
extern crate rustc;
use syntax::ast;
use syntax::ast::Ty_::TyBareFn;
use syntax::codemap;
use syntax::parse::token;
use syntax::ext::base::{ExtCtxt, Modifier};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
use rustc::plugin::Registry;
#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(token::intern("quickcheck"),
Modifier(Box::new(expand_meta_quickcheck)));
}
fn expand_meta_quickcheck(cx: &mut ExtCtxt,
span: codemap::Span,
_: &ast::MetaItem,
item: P<ast::Item>) -> P<ast::Item> {
match item.node {
ast::ItemFn(ref decl, unsafety, abi, _, _) => {
let prop_ident = cx.expr_ident(span, item.ident);
let prop_ty = cx.ty(span, TyBareFn(P(ast::BareFnTy {
unsafety: unsafety,
abi: abi,
lifetimes: vec![],
decl: decl.clone(),
})));
let inner_ident = cx.expr_cast(span, prop_ident, prop_ty);
return wrap_item(cx, span, &*item, inner_ident);
},
ast::ItemStatic(..) => {
let inner_ident = cx.expr_ident(span, item.ident);
return wrap_item(cx, span, &*item, inner_ident);
},
_ => {
cx.span_err(
span, "#[quickcheck] only supported on statics and functions");
}
}
item
}
fn wrap_item(cx: &mut ExtCtxt,
span: codemap::Span,
item: &ast::Item,
inner_ident: P<ast::Expr>) -> P<ast::Item> {
let prop = P(ast::Item {attrs: Vec::new(), ..item.clone()});
let check_ident = token::str_to_ident("quickcheck");
let check_path = vec!(check_ident, check_ident);
let fn_decl =
P(codemap::respan(span, ast::DeclItem(prop.clone())));
let inner_fn =
P(codemap::respan(
span, ast::StmtDecl(fn_decl, ast::DUMMY_NODE_ID)));
let check_call =
cx.expr_call_global(span, check_path, vec![inner_ident]);
let body = cx.block(span, vec![inner_fn], Some(check_call));
let nil = P(ast::Ty {
id: ast::DUMMY_NODE_ID,
node: ast::TyTup(vec![]),
span: codemap::DUMMY_SP,
});
let test = cx.item_fn(span, item.ident, Vec::new(), nil, body);
let mut attrs = item.attrs.clone();
attrs.push(cx.attribute(
span, cx.meta_word(
span, token::intern_and_get_ident("test"))));
P(ast::Item {attrs: attrs, ..(*test).clone()})
}