1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
extern crate syntex; extern crate syntex_syntax as syntax; extern crate postgres_derive_internals; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::codemap::Span; use syntax::ast::MetaItem; use syntax::print::pprust; use syntax::parse; pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error> where S: AsRef<std::path::Path>, D: AsRef<std::path::Path>, { let mut registry = syntex::Registry::new(); register(&mut registry); registry.expand("", src.as_ref(), dst.as_ref()) } pub fn register(reg: &mut syntex::Registry) { use syntax::{ast, fold}; fn strip_attributes(krate: ast::Crate) -> ast::Crate { struct StripAttributeFolder; impl fold::Folder for StripAttributeFolder { fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> { match attr.node.value.node { ast::MetaItemKind::List(ref n, _) if n == &"postgres" => return None, _ => {} } Some(attr) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { fold::noop_fold_mac(mac, self) } } fold::Folder::fold_crate(&mut StripAttributeFolder, krate) } reg.add_attr("feature(custom_derive)"); reg.add_attr("feature(custom_attribute)"); reg.add_decorator("derive_ToSql", expand_tosql); reg.add_decorator("derive_FromSql", expand_fromsql); reg.add_post_expansion_pass(strip_attributes); } fn expand_tosql(ctx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: &Annotatable, push: &mut FnMut(Annotatable)) { expand_inner(ctx, span, "ToSql", annotatable, push, postgres_derive_internals::expand_derive_tosql); } fn expand_fromsql(ctx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: &Annotatable, push: &mut FnMut(Annotatable)) { expand_inner(ctx, span, "FromSql", annotatable, push, postgres_derive_internals::expand_derive_fromsql); } fn expand_inner(ctx: &mut ExtCtxt, span: Span, trait_: &str, annotatable: &Annotatable, push: &mut FnMut(Annotatable), expand: fn(&str) -> Result<String, String>) { let item = match *annotatable { Annotatable::Item(ref item) => item, _ => { ctx.span_err(span, &format!("#[derive({})] can only be applied to structs, single field \ tuple structs, and enums", trait_)); return; } }; let item = pprust::item_to_string(item); match expand(&item) { Ok(source) => { let mut parser = parse::new_parser_from_source_str(&ctx.parse_sess, "<macro src>".to_owned(), source); while let Some(item) = parser.parse_item().unwrap() { push(Annotatable::Item(item)); } } Err(err) => ctx.span_err(span, &err), } }