style: Introduce css(parse_condition).

This will allow us to add a pref for this, and to parse it only on chrome easily.

Bug: 1288572
Reviewed-by: xidorn
MozReview-Commit-ID: L1rsyc2A2hu
This commit is contained in:
Emilio Cobos Álvarez 2018-06-02 18:38:42 +02:00
parent ce5a85d6a1
commit 1da798e65b
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 50 additions and 8 deletions

View file

@ -150,10 +150,19 @@ impl<'a> ParserContext<'a> {
} }
} }
// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and /// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input. /// 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
/// 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
/// `&ParserContext` reference.
pub trait Parse: Sized { pub trait Parse: Sized {
/// Parse a value of this type. /// Parse a value of this type.
/// ///

View file

@ -12,6 +12,7 @@ pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident; let name = &input.ident;
let s = synstructure::Structure::new(&input); let s = synstructure::Structure::new(&input);
let mut saw_condition = false;
let match_body = s.variants().iter().fold(quote!(), |match_body, variant| { let match_body = s.variants().iter().fold(quote!(), |match_body, variant| {
let bindings = variant.bindings(); let bindings = variant.bindings();
assert!( assert!(
@ -29,11 +30,16 @@ pub fn derive(input: DeriveInput) -> Tokens {
); );
let ident = &variant.ast().ident; let ident = &variant.ast().ident;
let mut body = quote! { saw_condition |= variant_attrs.parse_condition.is_some();
#match_body let condition = match variant_attrs.parse_condition {
#identifier => Ok(#name::#ident), 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 variant_attrs.aliases {
Some(aliases) => aliases, Some(aliases) => aliases,
@ -43,25 +49,51 @@ pub fn derive(input: DeriveInput) -> Tokens {
for alias in aliases.split(",") { for alias in aliases.split(",") {
body = quote! { body = quote! {
#body #body
#alias => Ok(#name::#ident), #alias #condition => Ok(#name::#ident),
}; };
} }
body 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! { let parse_trait_impl = quote! {
impl ::parser::Parse for #name { impl ::parser::Parse for #name {
#[inline] #[inline]
fn parse<'i, 't>( fn parse<'i, 't>(
_: &::parser::ParserContext, #context_ident: &::parser::ParserContext,
input: &mut ::cssparser::Parser<'i, 't>, input: &mut ::cssparser::Parser<'i, 't>,
) -> Result<Self, ::style_traits::ParseError<'i>> { ) -> 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 // TODO(emilio): It'd be nice to get rid of these, but that makes the
// conversion harder... // conversion harder...
let methods_impl = quote! { let methods_impl = quote! {

View file

@ -235,6 +235,7 @@ pub struct CssVariantAttrs {
pub dimension: bool, pub dimension: bool,
pub keyword: Option<String>, pub keyword: Option<String>,
pub aliases: Option<String>, pub aliases: Option<String>,
pub parse_condition: Option<Path>,
pub skip: bool, pub skip: bool,
} }