1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 use cg;
6 use quote::Tokens;
7 use syn::DeriveInput;
8 use synstructure;
9 use to_css::CssVariantAttrs;
10
derive(input: DeriveInput) -> Tokens11 pub fn derive(input: DeriveInput) -> Tokens {
12 let name = &input.ident;
13 let s = synstructure::Structure::new(&input);
14
15 let match_body = s.variants().iter().fold(quote!(), |match_body, variant| {
16 let bindings = variant.bindings();
17 assert!(
18 bindings.is_empty(),
19 "Parse is only supported for single-variant enums for now"
20 );
21
22 let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&variant.ast());
23 let identifier = cg::to_css_identifier(
24 &variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
25 );
26 let ident = &variant.ast().ident;
27
28 let mut body = quote! {
29 #match_body
30 #identifier => Ok(#name::#ident),
31 };
32
33
34 let aliases = match variant_attrs.aliases {
35 Some(aliases) => aliases,
36 None => return body,
37 };
38
39 for alias in aliases.split(",") {
40 body = quote! {
41 #body
42 #alias => Ok(#name::#ident),
43 };
44 }
45
46 body
47 });
48
49 let parse_trait_impl = quote! {
50 impl ::parser::Parse for #name {
51 #[inline]
52 fn parse<'i, 't>(
53 _: &::parser::ParserContext,
54 input: &mut ::cssparser::Parser<'i, 't>,
55 ) -> Result<Self, ::style_traits::ParseError<'i>> {
56 Self::parse(input)
57 }
58 }
59 };
60
61 // TODO(emilio): It'd be nice to get rid of these, but that makes the
62 // conversion harder...
63 let methods_impl = quote! {
64 impl #name {
65 /// Parse this keyword.
66 #[inline]
67 pub fn parse<'i, 't>(
68 input: &mut ::cssparser::Parser<'i, 't>,
69 ) -> Result<Self, ::style_traits::ParseError<'i>> {
70 let location = input.current_source_location();
71 let ident = input.expect_ident()?;
72 Self::from_ident(ident.as_ref()).map_err(|()| {
73 location.new_unexpected_token_error(
74 ::cssparser::Token::Ident(ident.clone())
75 )
76 })
77 }
78
79 /// Parse this keyword from a string slice.
80 #[inline]
81 pub fn from_ident(ident: &str) -> Result<Self, ()> {
82 match_ignore_ascii_case! { ident,
83 #match_body
84 _ => Err(()),
85 }
86 }
87 }
88 };
89
90 quote! {
91 #parse_trait_impl
92 #methods_impl
93 }
94 }
95