swc/crates/swc_css_codegen_macros/src/lib.rs
2022-01-15 16:43:34 +09:00

87 lines
2.6 KiB
Rust

#![deny(clippy::all)]
extern crate proc_macro;
use pmutil::{smart_quote, Quote, ToTokensExt};
use syn::{FnArg, ImplItemMethod, Type, TypeReference};
#[proc_macro_attribute]
pub fn emitter(
_attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let item: ImplItemMethod = syn::parse(item).expect("failed to parse input as an item");
let item = expand(item);
item.dump().into()
}
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| {
// &Ident -> Ident
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<W> crate::Emit<NodeType> for crate::CodeGenerator<W>
where
W: crate::writer::CssWriter,
{
fn emit(&mut self, n: &NodeType) -> crate::Result {
self.mtd_name(n)
}
}
block
// Emitter methods return Result<_, _>
// We inject this to avoid writing Ok(()) every time.
#[allow(unreachable_code)]
{
return Ok(());
}
}
}
))
.parse()
};
ImplItemMethod { block, ..i }
}