Bug 1466609: #[parse(..)]. r?xidorn draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 04 Jun 2018 19:24:43 +0200
changeset 803676 42e693b53a8d66036da8288913b261aedc908a4f
parent 803675 21c710ac95f99ba69834a96c9d61af8843d79648
child 803677 50e5960bd977031a405a0cc00445ea27882586ff
push id112164
push userbmo:emilio@crisal.io
push dateMon, 04 Jun 2018 18:13:16 +0000
reviewersxidorn
bugs1466609
milestone62.0a1
Bug 1466609: #[parse(..)]. r?xidorn I need to admit I'm ambivalent about this one :). MozReview-Commit-ID: F1jlfnQKXwo
servo/components/style/parser.rs
servo/components/style/properties/helpers.mako.rs
servo/components/style/values/specified/box.rs
servo/components/style_derive/lib.rs
servo/components/style_derive/parse.rs
servo/components/style_derive/specified_value_info.rs
servo/components/style_derive/to_css.rs
servo/components/style_traits/specified_value_info.rs
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -152,21 +152,21 @@ impl<'a> ParserContext<'a> {
 
 /// A trait to abstract parsing of a specified value given a `ParserContext` and
 /// CSS input.
 ///
 /// This can be derived on keywords with `#[derive(Parse)]`.
 ///
 /// The derive code understands the following attributes on each of the variants:
 ///
-///  * `#[css(aliases = "foo,bar")]` can be used to alias a value with another
+///  * `#[parse(aliases = "foo,bar")]` can be used to alias a value with another
 ///    at parse-time.
 ///
-///  * `#[css(parse_condition = "function")]` can be used to make the parsing of
-///    the value conditional on `function`, which will be invoked with a
+///  * `#[parse(condition = "function")]` can be used to make the parsing of the
+///    value conditional on `function`, which will be invoked with a
 ///    `&ParserContext` reference.
 pub trait Parse: Sized {
     /// Parse a value of this type.
     ///
     /// Returns an error on failure.
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -589,17 +589,17 @@
             % if include_aliases:
             <%
                 aliases = []
                 for alias, v in keyword.aliases_for(product).iteritems():
                     if variant == v:
                         aliases.append(alias)
             %>
             % if aliases:
-            #[css(aliases = "${','.join(aliases)}")]
+            #[parse(aliases = "${','.join(aliases)}")]
             % endif
             % endif
             ${to_camel_case(variant)},
             % endfor
         </%def>
         % if extra_specified:
             #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
             #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -48,19 +48,19 @@ pub enum Display {
     TableFooterGroup,
     TableRow,
     TableColumnGroup,
     TableColumn,
     TableCell,
     TableCaption,
     ListItem,
     None,
-    #[css(aliases = "-webkit-flex")]
+    #[parse(aliases = "-webkit-flex")]
     Flex,
-    #[css(aliases = "-webkit-inline-flex")]
+    #[parse(aliases = "-webkit-inline-flex")]
     InlineFlex,
     #[cfg(feature = "gecko")]
     Grid,
     #[cfg(feature = "gecko")]
     InlineGrid,
     #[cfg(feature = "gecko")]
     Ruby,
     #[cfg(feature = "gecko")]
@@ -79,41 +79,41 @@ pub enum Display {
     WebkitBox,
     #[cfg(feature = "gecko")]
     WebkitInlineBox,
     #[cfg(feature = "gecko")]
     MozBox,
     #[cfg(feature = "gecko")]
     MozInlineBox,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGrid,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozInlineGrid,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGridGroup,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGridLine,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozStack,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozInlineStack,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozDeck,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozPopup,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGroupbox,
 }
 
 impl Display {
     /// The initial display value.
     #[inline]
     pub fn inline() -> Self {
         Display::Inline
--- a/servo/components/style_derive/lib.rs
+++ b/servo/components/style_derive/lib.rs
@@ -35,17 +35,17 @@ pub fn derive_compute_squared_distance(s
 }
 
 #[proc_macro_derive(ToAnimatedValue)]
 pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     to_animated_value::derive(input).into()
 }
 
-#[proc_macro_derive(Parse, attributes(css))]
+#[proc_macro_derive(Parse, attributes(css, parse))]
 pub fn derive_parse(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     parse::derive(input).into()
 }
 
 #[proc_macro_derive(ToAnimatedZero, attributes(animation, zero))]
 pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
@@ -59,13 +59,13 @@ pub fn derive_to_computed_value(stream: 
 }
 
 #[proc_macro_derive(ToCss, attributes(css))]
 pub fn derive_to_css(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     to_css::derive(input).into()
 }
 
-#[proc_macro_derive(SpecifiedValueInfo, attributes(css, value_info))]
+#[proc_macro_derive(SpecifiedValueInfo, attributes(css, parse, value_info))]
 pub fn derive_specified_value_info(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     specified_value_info::derive(input).into()
 }
--- a/servo/components/style_derive/parse.rs
+++ b/servo/components/style_derive/parse.rs
@@ -1,52 +1,62 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cg;
 use quote::Tokens;
-use syn::DeriveInput;
+use syn::{DeriveInput, Path};
 use synstructure;
 use to_css::CssVariantAttrs;
 
+#[darling(attributes(parse), default)]
+#[derive(Default, FromVariant)]
+pub struct ParseVariantAttrs {
+    pub aliases: Option<String>,
+    pub condition: Option<Path>,
+}
+
 pub fn derive(input: DeriveInput) -> Tokens {
     let name = &input.ident;
     let s = synstructure::Structure::new(&input);
 
     let mut saw_condition = false;
     let match_body = s.variants().iter().fold(quote!(), |match_body, variant| {
         let bindings = variant.bindings();
         assert!(
             bindings.is_empty(),
             "Parse is only supported for single-variant enums for now"
         );
 
-        let variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
-        if variant_attrs.skip {
+        let css_variant_attrs =
+            cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
+        let parse_attrs =
+            cg::parse_variant_attrs_from_ast::<ParseVariantAttrs>(&variant.ast());
+        if css_variant_attrs.skip {
             return match_body;
         }
 
         let identifier = cg::to_css_identifier(
-            &variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
+            &css_variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
         );
         let ident = &variant.ast().ident;
 
-        saw_condition |= variant_attrs.parse_condition.is_some();
-        let condition = match variant_attrs.parse_condition {
+        saw_condition |= parse_attrs.condition.is_some();
+        let condition = match parse_attrs.condition {
             Some(ref p) => quote! { if #p(context) },
             None => quote! { },
         };
 
         let mut body = quote! {
             #match_body
             #identifier #condition => Ok(#name::#ident),
         };
 
-        let aliases = match variant_attrs.aliases {
+        let aliases = match parse_attrs.aliases {
             Some(aliases) => aliases,
             None => return body,
         };
 
         for alias in aliases.split(",") {
             body = quote! {
                 #body
                 #alias #condition => Ok(#name::#ident),
--- a/servo/components/style_derive/specified_value_info.rs
+++ b/servo/components/style_derive/specified_value_info.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cg;
 use quote::Tokens;
 use syn::{Data, DeriveInput, Fields, Ident, Type};
 use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs};
+use parse::ParseVariantAttrs;
 
 pub fn derive(mut input: DeriveInput) -> Tokens {
     let css_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
     let mut types = vec![];
     let mut values = vec![];
 
     let input_ident = input.ident;
     let input_name = || cg::to_css_identifier(input_ident.as_ref());
@@ -28,20 +29,21 @@ pub fn derive(mut input: DeriveInput) ->
         }
         input.generics.where_clause = where_clause;
 
         match input.data {
             Data::Enum(ref e) => {
                 for v in e.variants.iter() {
                     let css_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v);
                     let info_attrs = cg::parse_variant_attrs::<ValueInfoVariantAttrs>(&v);
+                    let parse_attrs = cg::parse_variant_attrs::<ParseVariantAttrs>(&v);
                     if css_attrs.skip {
                         continue;
                     }
-                    if let Some(aliases) = css_attrs.aliases {
+                    if let Some(aliases) = parse_attrs.aliases {
                         for alias in aliases.split(",") {
                             values.push(alias.to_string());
                         }
                     }
                     if let Some(other_values) = info_attrs.other_values {
                         for value in other_values.split(",") {
                             values.push(value.to_string());
                         }
--- a/servo/components/style_derive/to_css.rs
+++ b/servo/components/style_derive/to_css.rs
@@ -229,18 +229,16 @@ pub struct CssInputAttrs {
 
 #[darling(attributes(css), default)]
 #[derive(Default, FromVariant)]
 pub struct CssVariantAttrs {
     pub function: Option<Override<String>>,
     pub comma: bool,
     pub dimension: bool,
     pub keyword: Option<String>,
-    pub aliases: Option<String>,
-    pub parse_condition: Option<Path>,
     pub skip: bool,
 }
 
 #[darling(attributes(css), default)]
 #[derive(Default, FromField)]
 pub struct CssFieldAttrs {
     pub if_empty: Option<String>,
     pub field_bound: bool,
--- a/servo/components/style_traits/specified_value_info.rs
+++ b/servo/components/style_traits/specified_value_info.rs
@@ -38,17 +38,17 @@ pub type KeywordsCollectFn<'a> = &'a mut
 /// names following the same rule as `ToCss` in that method.
 ///
 /// Some attributes of `ToCss` can affect the behavior, specifically:
 /// * If `#[css(function)]` is found, the content inside the annotated
 ///   variant (or the whole type) isn't traversed, only the function
 ///   name is listed in `collect_completion_keywords`.
 /// * If `#[css(skip)]` is found, the content inside the variant or
 ///   field is ignored.
-/// * Values listed in `#[css(if_empty)]`, `#[css(aliases)]`, and
+/// * Values listed in `#[css(if_empty)]`, `#[parse(aliases)]`, and
 ///   `#[css(keyword)]` are added into `collect_completion_keywords`.
 ///
 /// In addition to `css` attributes, it also has `value_info` helper
 /// attributes, including:
 /// * `#[value_info(ty = "TYPE")]` can be used to specify a constant
 ///   from `CssType` to `SUPPORTED_TYPES`.
 /// * `#[value_info(other_values = "value1,value2")]` can be used to
 ///   add other values related to a field, variant, or the type itself