use swc_macros_common::prelude::*;
use input::*;
use std::{fmt::Display, ops::AddAssign};
use syn::synom::Synom;
use util::is_bool;
impl From<DeriveInput> for Input {
fn from(
DeriveInput {
ident: name,
vis,
attrs,
generics,
data,
}: DeriveInput,
) -> Self {
let variants = match data {
Data::Enum(data) => data.variants.into_iter().map(From::from).collect(),
_ => panic!("#[derive(Kind)] only works for enums"),
};
Input {
name,
vis,
generics,
attrs: parse_attrs(attrs),
variants,
}
}
}
impl Synom for EnumAttrs {
named!(parse -> Self, do_parse!(
_function: syn!(Ident) >>
fns: parens!(
call!(Punctuated::parse_terminated)
) >>
({
let fns: Punctuated<_, token::Comma> = fns.1;
EnumAttrs {
fns: fns.into_iter().collect(),
extras: Default::default(),
}
})
));
}
impl AddAssign<Result<Self, Attribute>> for EnumAttrs {
fn add_assign(&mut self, rhs: Result<Self, Attribute>) {
match rhs {
Ok(attr) => {
self.fns.extend(attr.fns);
self.extras.extend(attr.extras);
}
Err(attr) => self.extras.push(attr),
}
}
}
impl FnDef {
fn def_value_for_type(ty: &Type) -> Option<Expr> {
if is_bool(ty) {
return Some(Expr::Lit(ExprLit {
attrs: Default::default(),
lit: Lit::Bool(LitBool {
value: false,
span: Span::def_site(),
}),
}));
}
None
}
}
impl Synom for FnDef {
named!(parse -> Self, do_parse!(
name: syn!(Ident) >>
syn!(token::Eq) >>
return_type: syn!(LitStr) >>
({
if name == "delegate" {
panic!("function name cannot be `delegate`")
}
let return_type = parse_str_as_tokens(return_type);
FnDef {
default_value: FnDef::def_value_for_type(&return_type),
name,
return_type,
}
})
));
}
impl From<Variant> for EnumVar {
fn from(
Variant {
attrs,
fields,
ident: name,
..
}: Variant,
) -> Self {
EnumVar {
name,
data: fields,
attrs: parse_attrs(attrs),
}
}
}
impl Synom for VariantAttrs {
named!(parse -> Self, do_parse!(
fn_values: call!(Punctuated::parse_terminated)
>>
({
let fn_values: Punctuated<_, token::Comma> = fn_values;
let has_delegate = fn_values.iter()
.any(|f: &VariantAttr| f.fn_name == "delegate");
VariantAttrs {
fn_values: fn_values.into_iter().collect(),
extras: Default::default(),
has_delegate,
}
})
));
}
impl AddAssign<Result<Self, Attribute>> for VariantAttrs {
fn add_assign(&mut self, rhs: Result<Self, Attribute>) {
match rhs {
Ok(attr) => {
self.fn_values.extend(attr.fn_values);
self.extras.extend(attr.extras);
self.has_delegate = self.has_delegate || attr.has_delegate;
}
Err(attr) => self.extras.push(attr),
}
}
}
impl Synom for VariantAttr {
named!(parse -> Self, do_parse!(
fn_name: syn!(Ident) >>
value: option!(
do_parse!(
syn!(token::Eq) >>
p: syn!(LitStr) >>
({
parse_str_as_tokens(p)
})
)
) >>
(VariantAttr{ fn_name, value, })
)
);
}
fn parse_attrs<T>(attrs: Vec<Attribute>) -> T
where
T: Default + Synom + AddAssign<Result<T, Attribute>>,
{
fn unwrap_paren<I>(tts: I) -> TokenStream
where
I: IntoIterator<Item = TokenTree>,
{
let mut tts = tts.into_iter();
let tt = tts.next();
match tt {
Some(TokenTree::Group(ref g)) if g.delimiter() == Delimiter::Parenthesis => {
if tts.next().is_none() {
return g.stream();
}
g.stream()
}
tt => panic!(
"expected tokens to be wrapped in a paren like #[kind(tokens)]\ngot {}",
match tt {
Some(ref tt) => tt as &Display,
None => &"None" as &Display,
}
),
}
}
let mut res = Default::default();
for attr in attrs {
if attr.is_sugared_doc {
continue;
}
if is_attr_name(&attr, "kind") {
let tts = unwrap_paren(attr.tts);
let parsed: T = parse(tts.into())
.unwrap_or_else(|err| panic!("failed to parse attribute: {}", err));
res += Ok(parsed);
} else {
res += Err(attr)
}
}
res
}
fn parse_str_as_tokens<T>(lit: LitStr) -> T
where
T: Synom,
{
let span = lit.span();
let tt = lit.value();
let tts = tt
.replace("\"", "")
.parse::<TokenStream>()
.expect("failed to create TokenStream for return type")
.into_iter()
.map(|mut tt| {
tt.set_span(span);
tt
})
.collect::<TokenStream>();
parse(tts.into()).expect("failed to parse string literal")
}