diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/style/parser.rs | 13 | ||||
-rw-r--r-- | components/style_derive/parse.rs | 42 | ||||
-rw-r--r-- | components/style_derive/to_css.rs | 1 |
3 files changed, 49 insertions, 7 deletions
diff --git a/components/style/parser.rs b/components/style/parser.rs index 26f4aeea071..1b7c65e2559 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -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 /// 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 { /// Parse a value of this type. /// diff --git a/components/style_derive/parse.rs b/components/style_derive/parse.rs index 7727d6b89bb..8b9044fb495 100644 --- a/components/style_derive/parse.rs +++ b/components/style_derive/parse.rs @@ -12,6 +12,7 @@ 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!( @@ -29,12 +30,17 @@ pub fn derive(input: DeriveInput) -> Tokens { ); 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, @@ -43,25 +49,51 @@ pub fn derive(input: DeriveInput) -> Tokens { 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! { diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 0caef8b01a7..4853f41ee53 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -235,6 +235,7 @@ pub struct CssVariantAttrs { pub dimension: bool, pub keyword: Option<String>, pub aliases: Option<String>, + pub parse_condition: Option<Path>, pub skip: bool, } |