style: Add support for property value aliases.

For keyword-typed properties with aliases but no extra_specified values,
the storage of the specified and computed values could be the same,
since value aliases are resolved at parse time.  But to prevent
computed_value::T::parse from recognizing these aliases, we keep the
specified and computed value types distinct.
This commit is contained in:
Cameron McCormack 2017-04-15 20:10:02 +10:00
parent 533853fdce
commit 10f2d3c38e
3 changed files with 103 additions and 13 deletions

View file

@ -33,10 +33,20 @@ def to_camel_case(ident):
return re.sub("(^|_|-)([a-z])", lambda m: m.group(2).upper(), ident.strip("_").strip("-")) return re.sub("(^|_|-)([a-z])", lambda m: m.group(2).upper(), ident.strip("_").strip("-"))
def parse_aliases(value):
aliases = {}
for pair in value.split():
[a, v] = pair.split("=")
aliases[a] = v
return aliases
class Keyword(object): class Keyword(object):
def __init__(self, name, values, gecko_constant_prefix=None, def __init__(self, name, values, gecko_constant_prefix=None,
gecko_enum_prefix=None, custom_consts=None, gecko_enum_prefix=None, custom_consts=None,
extra_gecko_values=None, extra_servo_values=None, extra_gecko_values=None, extra_servo_values=None,
aliases=None,
extra_gecko_aliases=None, extra_servo_aliases=None,
gecko_strip_moz_prefix=True, gecko_strip_moz_prefix=True,
gecko_inexhaustive=None): gecko_inexhaustive=None):
self.name = name self.name = name
@ -48,6 +58,9 @@ class Keyword(object):
self.gecko_enum_prefix = gecko_enum_prefix self.gecko_enum_prefix = gecko_enum_prefix
self.extra_gecko_values = (extra_gecko_values or "").split() self.extra_gecko_values = (extra_gecko_values or "").split()
self.extra_servo_values = (extra_servo_values or "").split() self.extra_servo_values = (extra_servo_values or "").split()
self.aliases = parse_aliases(aliases or "")
self.extra_gecko_aliases = parse_aliases(extra_gecko_aliases or "")
self.extra_servo_aliases = parse_aliases(extra_servo_aliases or "")
self.consts_map = {} if custom_consts is None else custom_consts self.consts_map = {} if custom_consts is None else custom_consts
self.gecko_strip_moz_prefix = gecko_strip_moz_prefix self.gecko_strip_moz_prefix = gecko_strip_moz_prefix
self.gecko_inexhaustive = gecko_inexhaustive or (gecko_enum_prefix is None) self.gecko_inexhaustive = gecko_inexhaustive or (gecko_enum_prefix is None)
@ -58,6 +71,16 @@ class Keyword(object):
def servo_values(self): def servo_values(self):
return self.values + self.extra_servo_values return self.values + self.extra_servo_values
def gecko_aliases(self):
aliases = self.aliases.copy()
aliases.update(self.extra_gecko_aliases)
return aliases
def servo_aliases(self):
aliases = self.aliases.copy()
aliases.update(self.extra_servo_aliases)
return aliases
def values_for(self, product): def values_for(self, product):
if product == "gecko": if product == "gecko":
return self.gecko_values() return self.gecko_values()
@ -66,6 +89,14 @@ class Keyword(object):
else: else:
raise Exception("Bad product: " + product) raise Exception("Bad product: " + product)
def aliases_for(self, product):
if product == "gecko":
return self.gecko_aliases()
elif product == "servo":
return self.servo_aliases()
else:
raise Exception("Bad product: " + product)
def gecko_constant(self, value): def gecko_constant(self, value):
moz_stripped = value.replace("-moz-", '') if self.gecko_strip_moz_prefix else value.replace("-moz-", 'moz-') moz_stripped = value.replace("-moz-", '') if self.gecko_strip_moz_prefix else value.replace("-moz-", 'moz-')
mapped = self.consts_map.get(value) mapped = self.consts_map.get(value)

View file

@ -395,9 +395,33 @@
<%def name="single_keyword(name, values, vector=False, **kwargs)"> <%def name="single_keyword(name, values, vector=False, **kwargs)">
<%call expr="single_keyword_computed(name, values, vector, **kwargs)"> <%call expr="single_keyword_computed(name, values, vector, **kwargs)">
use values::computed::ComputedValueAsSpecified; % if not "extra_specified" in kwargs and ("aliases" in kwargs or (("extra_%s_aliases" % product) in kwargs)):
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, _context: &Context) -> computed_value::T {
match *self {
% for value in data.longhands_by_name[name].keyword.values_for(product):
SpecifiedValue::${to_rust_ident(value)} => computed_value::T::${to_rust_ident(value)},
% endfor
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
match *computed {
% for value in data.longhands_by_name[name].keyword.values_for(product):
computed_value::T::${to_rust_ident(value)} => SpecifiedValue::${to_rust_ident(value)},
% endfor
}
}
}
% else:
use values::computed::ComputedValueAsSpecified;
impl ComputedValueAsSpecified for SpecifiedValue {}
% endif
use values::HasViewportPercentage; use values::HasViewportPercentage;
impl ComputedValueAsSpecified for SpecifiedValue {}
no_viewport_percentage!(SpecifiedValue); no_viewport_percentage!(SpecifiedValue);
</%call> </%call>
</%def> </%def>
@ -444,17 +468,25 @@
keyword_kwargs = {a: kwargs.pop(a, None) for a in [ keyword_kwargs = {a: kwargs.pop(a, None) for a in [
'gecko_constant_prefix', 'gecko_enum_prefix', 'gecko_constant_prefix', 'gecko_enum_prefix',
'extra_gecko_values', 'extra_servo_values', 'extra_gecko_values', 'extra_servo_values',
'aliases', 'extra_gecko_aliases', 'extra_servo_aliases',
'custom_consts', 'gecko_inexhaustive', 'custom_consts', 'gecko_inexhaustive',
]} ]}
%> %>
<%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)"> <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)">
% if extra_specified: % if extra_specified or keyword.aliases_for(product):
use style_traits::ToCss; use style_traits::ToCss;
define_css_keyword_enum! { SpecifiedValue: define_css_keyword_enum! { SpecifiedValue:
% for value in keyword.values_for(product) + extra_specified.split(): values {
"${value}" => ${to_rust_ident(value)}, % for value in keyword.values_for(product) + (extra_specified or "").split():
% endfor "${value}" => ${to_rust_ident(value)},
% endfor
}
aliases {
% for alias, value in keyword.aliases_for(product).iteritems():
"${alias}" => ${to_rust_ident(value)},
% endfor
}
} }
% else: % else:
pub use self::computed_value::T as SpecifiedValue; pub use self::computed_value::T as SpecifiedValue;
@ -493,6 +525,7 @@
conversion_values = keyword.values_for(product) conversion_values = keyword.values_for(product)
if extra_specified: if extra_specified:
conversion_values += extra_specified.split() conversion_values += extra_specified.split()
conversion_values += keyword.aliases_for(product).keys()
%> %>
${gecko_keyword_conversion(keyword, values=conversion_values)} ${gecko_keyword_conversion(keyword, values=conversion_values)}
% endif % endif

View file

@ -82,20 +82,43 @@ impl_to_css_for_predefined_type!(::cssparser::UnicodeRange);
#[macro_export] #[macro_export]
macro_rules! define_css_keyword_enum { macro_rules! define_css_keyword_enum {
($name: ident: values { $( $css: expr => $variant: ident),+, }
aliases { $( $alias: expr => $alias_variant: ident ),+, }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),+ ]);
};
($name: ident: values { $( $css: expr => $variant: ident),+, }
aliases { $( $alias: expr => $alias_variant: ident ),* }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]);
};
($name: ident: values { $( $css: expr => $variant: ident),+ }
aliases { $( $alias: expr => $alias_variant: ident ),+, }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),+ ]);
};
($name: ident: values { $( $css: expr => $variant: ident),+ }
aliases { $( $alias: expr => $alias_variant: ident ),* }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]);
};
($name: ident: $( $css: expr => $variant: ident ),+,) => { ($name: ident: $( $css: expr => $variant: ident ),+,) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]); __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] []);
}; };
($name: ident: $( $css: expr => $variant: ident ),+) => { ($name: ident: $( $css: expr => $variant: ident ),+) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]); __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] []);
}; };
} }
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[macro_export] #[macro_export]
macro_rules! __define_css_keyword_enum__add_optional_traits { macro_rules! __define_css_keyword_enum__add_optional_traits {
($name: ident [ $( $css: expr => $variant: ident ),+ ]) => { ($name: ident [ $( $css: expr => $variant: ident ),+ ]
[ $( $alias: expr => $alias_variant: ident),* ]) => {
__define_css_keyword_enum__actual! { __define_css_keyword_enum__actual! {
$name [ Deserialize, Serialize, HeapSizeOf ] [ $( $css => $variant ),+ ] $name [ Deserialize, Serialize, HeapSizeOf ]
[ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]
} }
}; };
} }
@ -103,16 +126,18 @@ macro_rules! __define_css_keyword_enum__add_optional_traits {
#[cfg(not(feature = "servo"))] #[cfg(not(feature = "servo"))]
#[macro_export] #[macro_export]
macro_rules! __define_css_keyword_enum__add_optional_traits { macro_rules! __define_css_keyword_enum__add_optional_traits {
($name: ident [ $( $css: expr => $variant: ident ),+ ]) => { ($name: ident [ $( $css: expr => $variant: ident ),+ ] [ $( $alias: expr => $alias_variant: ident),* ]) => {
__define_css_keyword_enum__actual! { __define_css_keyword_enum__actual! {
$name [] [ $( $css => $variant ),+ ] $name [] [ $( $css => $variant ),+ ] [ $( $alias => $alias_variant ),* ]
} }
}; };
} }
#[macro_export] #[macro_export]
macro_rules! __define_css_keyword_enum__actual { macro_rules! __define_css_keyword_enum__actual {
($name: ident [ $( $derived_trait: ident),* ] [ $( $css: expr => $variant: ident ),+ ]) => { ($name: ident [ $( $derived_trait: ident),* ]
[ $( $css: expr => $variant: ident ),+ ]
[ $( $alias: expr => $alias_variant: ident ),* ]) => {
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq $(, $derived_trait )* )] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq $(, $derived_trait )* )]
pub enum $name { pub enum $name {
@ -130,6 +155,7 @@ macro_rules! __define_css_keyword_enum__actual {
pub fn from_ident(ident: &str) -> Result<$name, ()> { pub fn from_ident(ident: &str) -> Result<$name, ()> {
match_ignore_ascii_case! { ident, match_ignore_ascii_case! { ident,
$( $css => Ok($name::$variant), )+ $( $css => Ok($name::$variant), )+
$( $alias => Ok($name::$alias_variant), )*
_ => Err(()) _ => Err(())
} }
} }