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
extern crate proc_macro;
use pmutil::{smart_quote, Quote, ToTokensExt};
use proc_macro::TokenStream;
use swc_macros_common::prelude::*;
use syn::{self, fold::Fold, *};
mod fold;
#[proc_macro_attribute]
pub fn emitter(_attr: TokenStream, item: TokenStream) -> TokenStream {
let item: ImplItemMethod = syn::parse(item).expect("failed to parse input as an item");
let item = fold::InjectSelf { parser: None }.fold_impl_item_method(item);
let item = expand(item);
print("emitter", item.dump())
}
fn expand(i: ImplItemMethod) -> ImplItemMethod {
let mtd_name = i.sig.ident.clone();
assert!(
format!("{}", i.sig.ident).starts_with("emit_"),
"#[emitter] methods should start with `emit_`"
);
let block = {
let node_type = {
i.sig
.inputs
.clone()
.into_iter()
.nth(1)
.and_then(|arg| match arg {
FnArg::Typed(ty) => Some(ty.ty),
_ => None,
})
.map(|ty| {
match *ty {
Type::Reference(TypeReference { elem, .. }) => *elem,
_ => panic!(
"Type of node parameter should be reference but got {}",
ty.dump()
),
}
})
.expect(
"#[emitter] methods should have signature of
fn (&mut self, node: Node) -> Result;
",
)
};
Quote::new_call_site()
.quote_with(smart_quote!(
Vars {
block: &i.block,
NodeType: &node_type,
mtd_name,
},
{
{
impl crate::Node for NodeType {
fn emit_with<W, S: swc_common::SourceMapper>(&self, e: &mut crate::Emitter<'_, W, S>) -> Result
where
W: crate::text_writer::WriteJs,
S: swc_ecma_ast::SourceMapperExt
{
e.mtd_name(self)
}
}
block
#[allow(unreachable_code)]
{
return Ok(());
}
}
}
))
.parse()
};
ImplItemMethod { block, ..i }
}