swc_xml_codegen_macros/
lib.rs1#![deny(clippy::all)]
2
3extern crate proc_macro;
4
5use quote::ToTokens;
6use syn::{parse_quote, FnArg, ImplItemFn, Type, TypeReference};
7
8#[proc_macro_attribute]
9pub fn emitter(
10 _attr: proc_macro::TokenStream,
11 item: proc_macro::TokenStream,
12) -> proc_macro::TokenStream {
13 let item: ImplItemFn = syn::parse(item).expect("failed to parse input as an item");
14 let item = expand(item);
15
16 item.into_token_stream().into()
17}
18
19fn expand(i: ImplItemFn) -> ImplItemFn {
20 let mtd_name = i.sig.ident.clone();
21 assert!(
22 format!("{}", i.sig.ident).starts_with("emit_"),
23 "#[emitter] methods should start with `emit_`"
24 );
25 let block = {
26 let node_type = {
27 i.sig
28 .inputs
29 .clone()
30 .into_iter()
31 .nth(1)
32 .and_then(|arg| match arg {
33 FnArg::Typed(ty) => Some(ty.ty),
34 _ => None,
35 })
36 .map(|ty| {
37 match *ty {
39 Type::Reference(TypeReference { elem, .. }) => *elem,
40 _ => panic!(
41 "Type of node parameter should be reference but got {}",
42 ty.into_token_stream()
43 ),
44 }
45 })
46 .expect(
47 "#[emitter] methods should have signature of
48fn (&mut self, node: Node) -> Result;
49 ",
50 )
51 };
52
53 let block = &i.block;
54 parse_quote!({
55 impl<W> crate::Emit<#node_type> for crate::CodeGenerator<'_, W>
56 where W: crate::writer::XmlWriter,
57 {
58 fn emit(&mut self, n: &#node_type) -> crate::Result {
59 self.#mtd_name(n)
60 }
61 }
62
63 #block
64
65 #[allow(unreachable_code)]
68 {
69 return Ok(());
70 }
71 })
72 };
73
74 ImplItemFn { block, ..i }
75}