Bug 1288572: Introduce css(parse_condition). r?xidorn draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 02 Jun 2018 18:38:42 +0200
changeset 803294 3290f32071d6667d4fb503c867b2d9abb66c6ad0
parent 803293 c8189bb421d0773ff7d3e8277e46cadd291e039e
child 803295 440c3de97b8313e12a4a893ecf72a88182e0b939
child 803335 9cd8445b6b4ef3a41f99464b891a6021fb73120b
push id112061
push userbmo:emilio@crisal.io
push dateSat, 02 Jun 2018 17:36:20 +0000
reviewersxidorn
bugs1288572
milestone62.0a1
Bug 1288572: Introduce css(parse_condition). r?xidorn This will allow us to add a pref for this, and to parse it only on chrome easily. MozReview-Commit-ID: L1rsyc2A2hu
servo/components/style_derive/parse.rs
servo/components/style_derive/to_css.rs
--- a/servo/components/style_derive/parse.rs
+++ b/servo/components/style_derive/parse.rs
@@ -7,16 +7,17 @@ use quote::Tokens;
 use syn::DeriveInput;
 use synstructure;
 use to_css::CssVariantAttrs;
 
 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());
@@ -24,49 +25,80 @@ pub fn derive(input: DeriveInput) -> Tok
             return match_body;
         }
 
         let identifier = cg::to_css_identifier(
             &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 {
+            Some(ref p) => quote! { if #p(context) },
+            None => quote! { },
+        };
+
         let mut body = quote! {
             #match_body
-            #identifier => Ok(#name::#ident),
+            #identifier #condition => Ok(#name::#ident),
         };
 
-
         let aliases = match variant_attrs.aliases {
             Some(aliases) => aliases,
             None => return body,
         };
 
         for alias in aliases.split(",") {
             body = quote! {
                 #body
-                #alias => Ok(#name::#ident),
+                #alias #condition => Ok(#name::#ident),
             };
         }
 
         body
     });
 
+    let context_ident = if saw_condition {
+        quote! { context }
+    } else {
+        quote! { _ }
+    };
+
+    let parse_body = if saw_condition {
+        quote! {
+            let location = input.current_source_location();
+            let ident = input.expect_ident()?;
+            match_ignore_ascii_case! { &ident,
+                #match_body
+                _ => Err(location.new_unexpected_token_error(
+                    ::cssparser::Token::Ident(ident.clone())
+                ))
+            }
+        }
+    } else {
+        quote! { Self::parse(input) }
+    };
+
+
     let parse_trait_impl = quote! {
         impl ::parser::Parse for #name {
             #[inline]
             fn parse<'i, 't>(
-                _: &::parser::ParserContext,
+                #context_ident: &::parser::ParserContext,
                 input: &mut ::cssparser::Parser<'i, 't>,
             ) -> Result<Self, ::style_traits::ParseError<'i>> {
-                Self::parse(input)
+                #parse_body
             }
         }
     };
 
+    if saw_condition {
+        return parse_trait_impl;
+    }
+
     // TODO(emilio): It'd be nice to get rid of these, but that makes the
     // conversion harder...
     let methods_impl = quote! {
         impl #name {
             /// Parse this keyword.
             #[inline]
             pub fn parse<'i, 't>(
                 input: &mut ::cssparser::Parser<'i, 't>,
--- a/servo/components/style_derive/to_css.rs
+++ b/servo/components/style_derive/to_css.rs
@@ -230,16 +230,17 @@ 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,