Use Result/Err(()) instead of Option/None to indicate a CSS parse error.

This commit is contained in:
Simon Sapin 2014-08-11 20:06:17 +01:00
parent 061e7e1620
commit d9278e3f6a
6 changed files with 223 additions and 212 deletions

View file

@ -61,7 +61,7 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
"font-family" => { "font-family" => {
// FIXME(#2802): Share code with the font-family parser. // FIXME(#2802): Share code with the font-family parser.
match one_component_value(value.as_slice()) { match one_component_value(value.as_slice()) {
Some(&String(ref string_value)) => { Ok(&String(ref string_value)) => {
maybe_family = Some(string_value.clone()); maybe_family = Some(string_value.clone());
}, },
_ => { _ => {

View file

@ -7,15 +7,18 @@ use std::ascii::StrAsciiExt;
use cssparser::ast::{ComponentValue, Ident, SkipWhitespaceIterable}; use cssparser::ast::{ComponentValue, Ident, SkipWhitespaceIterable};
pub fn one_component_value<'a>(input: &'a [ComponentValue]) -> Option<&'a ComponentValue> { pub fn one_component_value<'a>(input: &'a [ComponentValue]) -> Result<&'a ComponentValue, ()> {
let mut iter = input.skip_whitespace(); let mut iter = input.skip_whitespace();
iter.next().filtered(|_| iter.next().is_none()) match iter.next() {
Some(value) => if iter.next().is_none() { Ok(value) } else { Err(()) },
None => Err(())
}
} }
pub fn get_ident_lower(component_value: &ComponentValue) -> Option<String> { pub fn get_ident_lower(component_value: &ComponentValue) -> Result<String, ()> {
match component_value { match component_value {
&Ident(ref value) => Some(value.as_slice().to_ascii_lower()), &Ident(ref value) => Ok(value.as_slice().to_ascii_lower()),
_ => None, _ => Err(()),
} }
} }

View file

@ -40,32 +40,32 @@ pub mod specified {
static AU_PER_PC: CSSFloat = AU_PER_PT * 12.; static AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
impl Length { impl Length {
#[inline] #[inline]
fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> { fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Result<Length, ()> {
match input { match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()), => Length::parse_dimension(value.value, unit.as_slice()),
&Number(ref value) if value.value == 0. => Some(Au_(Au(0))), &Number(ref value) if value.value == 0. => Ok(Au_(Au(0))),
_ => None _ => Err(())
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn parse(input: &ComponentValue) -> Option<Length> { pub fn parse(input: &ComponentValue) -> Result<Length, ()> {
Length::parse_internal(input, /* negative_ok = */ true) Length::parse_internal(input, /* negative_ok = */ true)
} }
pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> { pub fn parse_non_negative(input: &ComponentValue) -> Result<Length, ()> {
Length::parse_internal(input, /* negative_ok = */ false) Length::parse_internal(input, /* negative_ok = */ false)
} }
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Option<Length> { pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
match unit.to_ascii_lower().as_slice() { match unit.to_ascii_lower().as_slice() {
"px" => Some(Length::from_px(value)), "px" => Ok(Length::from_px(value)),
"in" => Some(Au_(Au((value * AU_PER_IN) as i32))), "in" => Ok(Au_(Au((value * AU_PER_IN) as i32))),
"cm" => Some(Au_(Au((value * AU_PER_CM) as i32))), "cm" => Ok(Au_(Au((value * AU_PER_CM) as i32))),
"mm" => Some(Au_(Au((value * AU_PER_MM) as i32))), "mm" => Ok(Au_(Au((value * AU_PER_MM) as i32))),
"pt" => Some(Au_(Au((value * AU_PER_PT) as i32))), "pt" => Ok(Au_(Au((value * AU_PER_PT) as i32))),
"pc" => Some(Au_(Au((value * AU_PER_PC) as i32))), "pc" => Ok(Au_(Au((value * AU_PER_PC) as i32))),
"em" => Some(Em(value)), "em" => Ok(Em(value)),
"ex" => Some(Ex(value)), "ex" => Ok(Ex(value)),
_ => None _ => Err(())
} }
} }
#[inline] #[inline]
@ -81,23 +81,23 @@ pub mod specified {
} }
impl LengthOrPercentage { impl LengthOrPercentage {
fn parse_internal(input: &ComponentValue, negative_ok: bool) fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Option<LengthOrPercentage> { -> Result<LengthOrPercentage, ()> {
match input { match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LP_Length), => Length::parse_dimension(value.value, unit.as_slice()).map(LP_Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0. &ast::Percentage(ref value) if negative_ok || value.value >= 0.
=> Some(LP_Percentage(value.value / 100.)), => Ok(LP_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Some(LP_Length(Au_(Au(0)))), &Number(ref value) if value.value == 0. => Ok(LP_Length(Au_(Au(0)))),
_ => None _ => Err(())
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
#[inline] #[inline]
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> { pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentage, ()> {
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true) LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
} }
#[inline] #[inline]
pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentage> { pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentage, ()> {
LengthOrPercentage::parse_internal(input, /* negative_ok = */ false) LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
} }
} }
@ -110,23 +110,23 @@ pub mod specified {
} }
impl LengthOrPercentageOrAuto { impl LengthOrPercentageOrAuto {
fn parse_internal(input: &ComponentValue, negative_ok: bool) fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Option<LengthOrPercentageOrAuto> { -> Result<LengthOrPercentageOrAuto, ()> {
match input { match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LPA_Length), => Length::parse_dimension(value.value, unit.as_slice()).map(LPA_Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0. &ast::Percentage(ref value) if negative_ok || value.value >= 0.
=> Some(LPA_Percentage(value.value / 100.)), => Ok(LPA_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Some(LPA_Length(Au_(Au(0)))), &Number(ref value) if value.value == 0. => Ok(LPA_Length(Au_(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("auto") => Some(LPA_Auto), &Ident(ref value) if value.as_slice().eq_ignore_ascii_case("auto") => Ok(LPA_Auto),
_ => None _ => Err(())
} }
} }
#[inline] #[inline]
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> { pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentageOrAuto, ()> {
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true) LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
} }
#[inline] #[inline]
pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> { pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentageOrAuto, ()> {
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false) LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
} }
} }
@ -139,24 +139,24 @@ pub mod specified {
} }
impl LengthOrPercentageOrNone { impl LengthOrPercentageOrNone {
fn parse_internal(input: &ComponentValue, negative_ok: bool) fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Option<LengthOrPercentageOrNone> { -> Result<LengthOrPercentageOrNone, ()> {
match input { match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LPN_Length), => Length::parse_dimension(value.value, unit.as_slice()).map(LPN_Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0. &ast::Percentage(ref value) if negative_ok || value.value >= 0.
=> Some(LPN_Percentage(value.value / 100.)), => Ok(LPN_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Some(LPN_Length(Au_(Au(0)))), &Number(ref value) if value.value == 0. => Ok(LPN_Length(Au_(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Some(LPN_None), &Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Ok(LPN_None),
_ => None _ => Err(())
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
#[inline] #[inline]
pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> { pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentageOrNone, ()> {
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true) LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
} }
#[inline] #[inline]
pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentageOrNone> { pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentageOrNone, ()> {
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ false) LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ false)
} }
} }

View file

@ -118,12 +118,13 @@ pub mod longhands {
${caller.body()} ${caller.body()}
% if derived_from is None: % if derived_from is None:
pub fn parse_declared(input: &[ComponentValue], base_url: &Url) pub fn parse_declared(input: &[ComponentValue], base_url: &Url)
-> Option<DeclaredValue<SpecifiedValue>> { -> Result<DeclaredValue<SpecifiedValue>, ()> {
match CSSWideKeyword::parse(input) { match CSSWideKeyword::parse(input) {
Some(Some(keyword)) => Some(CSSWideKeyword(keyword)), Ok(InheritKeyword) => Ok(Inherit),
Some(None) => Some(CSSWideKeyword(${ Ok(InitialKeyword) => Ok(Initial),
"Inherit" if THIS_STYLE_STRUCT.inherited else "Initial"})), Ok(UnsetKeyword) => Ok(${
None => parse_specified(input, base_url), "Inherit" if THIS_STYLE_STRUCT.inherited else "Initial"}),
Err(()) => parse_specified(input, base_url),
} }
} }
% endif % endif
@ -136,7 +137,7 @@ pub mod longhands {
${caller.body()} ${caller.body()}
% if derived_from is None: % if derived_from is None:
pub fn parse_specified(_input: &[ComponentValue], _base_url: &Url) pub fn parse_specified(_input: &[ComponentValue], _base_url: &Url)
-> Option<DeclaredValue<SpecifiedValue>> { -> Result<DeclaredValue<SpecifiedValue>, ()> {
parse(_input, _base_url).map(super::SpecifiedValue) parse(_input, _base_url).map(super::SpecifiedValue)
} }
% endif % endif
@ -147,7 +148,7 @@ pub mod longhands {
<%self:longhand name="${name}" derived_from="${derived_from}" <%self:longhand name="${name}" derived_from="${derived_from}"
experimental="${experimental}"> experimental="${experimental}">
${caller.body()} ${caller.body()}
pub fn parse(input: &[ComponentValue], base_url: &Url) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue], base_url: &Url) -> Result<SpecifiedValue, ()> {
one_component_value(input).and_then(|c| from_component_value(c, base_url)) one_component_value(input).and_then(|c| from_component_value(c, base_url))
} }
</%self:longhand> </%self:longhand>
@ -170,13 +171,13 @@ pub mod longhands {
${to_rust_ident(values.split()[0])} ${to_rust_ident(values.split()[0])}
} }
pub fn from_component_value(v: &ComponentValue, _base_url: &Url) pub fn from_component_value(v: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
get_ident_lower(v).and_then(|keyword| { get_ident_lower(v).and_then(|keyword| {
match keyword.as_slice() { match keyword.as_slice() {
% for value in values.split(): % for value in values.split():
"${value}" => Some(${to_rust_ident(value)}), "${value}" => Ok(${to_rust_ident(value)}),
% endfor % endfor
_ => None, _ => Err(()),
} }
}) })
} }
@ -201,7 +202,7 @@ pub mod longhands {
} }
#[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} } #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
#[inline] pub fn from_component_value(v: &ComponentValue, _base_url: &Url) #[inline] pub fn from_component_value(v: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
specified::${type}::${parse_method}(v) specified::${type}::${parse_method}(v)
} }
</%self:single_component_value> </%self:single_component_value>
@ -244,14 +245,14 @@ pub mod longhands {
% endfor % endfor
pub fn parse_border_width(component_value: &ComponentValue, _base_url: &Url) pub fn parse_border_width(component_value: &ComponentValue, _base_url: &Url)
-> Option<specified::Length> { -> Result<specified::Length, ()> {
match component_value { match component_value {
&Ident(ref value) => { &Ident(ref value) => {
match value.as_slice().to_ascii_lower().as_slice() { match value.as_slice().to_ascii_lower().as_slice() {
"thin" => Some(specified::Length::from_px(1.)), "thin" => Ok(specified::Length::from_px(1.)),
"medium" => Some(specified::Length::from_px(3.)), "medium" => Ok(specified::Length::from_px(3.)),
"thick" => Some(specified::Length::from_px(5.)), "thick" => Ok(specified::Length::from_px(5.)),
_ => None _ => Err(())
} }
}, },
_ => specified::Length::parse_non_negative(component_value) _ => specified::Length::parse_non_negative(component_value)
@ -267,7 +268,7 @@ pub mod longhands {
#[inline] pub fn get_initial_value() -> computed_value::T { #[inline] pub fn get_initial_value() -> computed_value::T {
Au::from_px(3) // medium Au::from_px(3) // medium
} }
pub fn parse(input: &[ComponentValue], base_url: &Url) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue], base_url: &Url) -> Result<SpecifiedValue, ()> {
one_component_value(input).and_then(|c| parse_border_width(c, base_url)) one_component_value(input).and_then(|c| parse_border_width(c, base_url))
} }
#[inline] #[inline]
@ -346,7 +347,7 @@ pub mod longhands {
pub fn get_initial_value() -> computed_value::T { computed::LPA_Auto } pub fn get_initial_value() -> computed_value::T { computed::LPA_Auto }
#[inline] #[inline]
pub fn from_component_value(v: &ComponentValue, _base_url: &Url) pub fn from_component_value(v: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
specified::LengthOrPercentageOrAuto::parse_non_negative(v) specified::LengthOrPercentageOrAuto::parse_non_negative(v)
} }
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
@ -387,18 +388,18 @@ pub mod longhands {
} }
/// normal | <number> | <length> | <percentage> /// normal | <number> | <length> | <percentage>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
match input { match input {
&ast::Number(ref value) if value.value >= 0. &ast::Number(ref value) if value.value >= 0.
=> Some(SpecifiedNumber(value.value)), => Ok(SpecifiedNumber(value.value)),
&ast::Percentage(ref value) if value.value >= 0. &ast::Percentage(ref value) if value.value >= 0.
=> Some(SpecifiedLength(specified::Em(value.value / 100.))), => Ok(SpecifiedLength(specified::Em(value.value / 100.))),
&Dimension(ref value, ref unit) if value.value >= 0. &Dimension(ref value, ref unit) if value.value >= 0.
=> specified::Length::parse_dimension(value.value, unit.as_slice()) => specified::Length::parse_dimension(value.value, unit.as_slice())
.map(SpecifiedLength), .map(SpecifiedLength),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("normal") &Ident(ref value) if value.as_slice().eq_ignore_ascii_case("normal")
=> Some(SpecifiedNormal), => Ok(SpecifiedNormal),
_ => None, _ => Err(()),
} }
} }
pub mod computed_value { pub mod computed_value {
@ -474,14 +475,14 @@ pub mod longhands {
/// baseline | sub | super | top | text-top | middle | bottom | text-bottom /// baseline | sub | super | top | text-top | middle | bottom | text-bottom
/// | <percentage> | <length> /// | <percentage> | <length>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
match input { match input {
&Ident(ref value) => { &Ident(ref value) => {
match value.as_slice().to_ascii_lower().as_slice() { match value.as_slice().to_ascii_lower().as_slice() {
% for keyword in vertical_align_keywords: % for keyword in vertical_align_keywords:
"${keyword}" => Some(Specified_${to_rust_ident(keyword)}), "${keyword}" => Ok(Specified_${to_rust_ident(keyword)}),
% endfor % endfor
_ => None, _ => Err(()),
} }
}, },
_ => specified::LengthOrPercentage::parse_non_negative(input) _ => specified::LengthOrPercentage::parse_non_negative(input)
@ -552,12 +553,12 @@ pub mod longhands {
// normal | none | [ <string> ]+ // normal | none | [ <string> ]+
// TODO: <uri>, <counter>, attr(<identifier>), open-quote, close-quote, no-open-quote, no-close-quote // TODO: <uri>, <counter>, attr(<identifier>), open-quote, close-quote, no-open-quote, no-close-quote
pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Result<SpecifiedValue, ()> {
match one_component_value(input) { match one_component_value(input) {
Some(&Ident(ref keyword)) => { Ok(&Ident(ref keyword)) => {
match keyword.as_slice().to_ascii_lower().as_slice() { match keyword.as_slice().to_ascii_lower().as_slice() {
"normal" => return Some(normal), "normal" => return Ok(normal),
"none" => return Some(none), "none" => return Ok(none),
_ => () _ => ()
} }
}, },
@ -568,10 +569,10 @@ pub mod longhands {
match component_value { match component_value {
&String(ref value) &String(ref value)
=> content.push(StringContent(value.clone())), => content.push(StringContent(value.clone())),
_ => return None // invalid/unsupported value _ => return Err(()) // invalid/unsupported value
} }
} }
Some(Content(content)) Ok(Content(content))
} }
</%self:longhand> </%self:longhand>
// CSS 2.1, Section 13 - Paged media // CSS 2.1, Section 13 - Paged media
@ -593,14 +594,16 @@ pub mod longhands {
#[inline] pub fn get_initial_value() -> SpecifiedValue { #[inline] pub fn get_initial_value() -> SpecifiedValue {
None None
} }
pub fn from_component_value(component_value: &ComponentValue, base_url: &Url) -> Option<SpecifiedValue> { pub fn from_component_value(component_value: &ComponentValue, base_url: &Url)
-> Result<SpecifiedValue, ()> {
match component_value { match component_value {
&ast::URL(ref url) => { &ast::URL(ref url) => {
let image_url = parse_url(url.as_slice(), base_url); let image_url = parse_url(url.as_slice(), base_url);
Some(Some(image_url)) Ok(Some(image_url))
}, },
&ast::Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Some(None), &ast::Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none")
_ => None, => Ok(None),
_ => Err(()),
} }
} }
</%self:single_component_value> </%self:single_component_value>
@ -643,36 +646,29 @@ pub mod longhands {
// FIXME(#1997, pcwalton): Support complete CSS2 syntax. // FIXME(#1997, pcwalton): Support complete CSS2 syntax.
pub fn parse_horizontal_and_vertical(horiz: &ComponentValue, vert: &ComponentValue) pub fn parse_horizontal_and_vertical(horiz: &ComponentValue, vert: &ComponentValue)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
let horiz = match specified::LengthOrPercentage::parse_non_negative(horiz) { let horiz = try!(specified::LengthOrPercentage::parse_non_negative(horiz));
None => return None, let vert = try!(specified::LengthOrPercentage::parse_non_negative(vert));
Some(value) => value,
};
let vert = match specified::LengthOrPercentage::parse_non_negative(vert) { Ok(SpecifiedValue {
None => return None,
Some(value) => value,
};
Some(SpecifiedValue {
horizontal: horiz, horizontal: horiz,
vertical: vert, vertical: vert,
}) })
} }
pub fn parse(input: &[ComponentValue], _: &Url) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue], _: &Url) -> Result<SpecifiedValue, ()> {
let mut input_iter = input.skip_whitespace(); let mut input_iter = input.skip_whitespace();
let horizontal = input_iter.next(); let horizontal = input_iter.next();
let vertical = input_iter.next(); let vertical = input_iter.next();
if input_iter.next().is_some() { if input_iter.next().is_some() {
return None return Err(())
} }
match (horizontal, vertical) { match (horizontal, vertical) {
(Some(horizontal), Some(vertical)) => { (Some(horizontal), Some(vertical)) => {
parse_horizontal_and_vertical(horizontal, vertical) parse_horizontal_and_vertical(horizontal, vertical)
} }
_ => None _ => Err(())
} }
} }
</%self:longhand> </%self:longhand>
@ -693,11 +689,11 @@ pub mod longhands {
RGBA { red: 0., green: 0., blue: 0., alpha: 1. } /* black */ RGBA { red: 0., green: 0., blue: 0., alpha: 1. } /* black */
} }
pub fn parse_specified(input: &[ComponentValue], _base_url: &Url) pub fn parse_specified(input: &[ComponentValue], _base_url: &Url)
-> Option<DeclaredValue<SpecifiedValue>> { -> Result<DeclaredValue<SpecifiedValue>, ()> {
match one_component_value(input).and_then(Color::parse) { match one_component_value(input).and_then(Color::parse) {
Some(RGBA(rgba)) => Some(SpecifiedValue(rgba)), Ok(RGBA(rgba)) => Ok(SpecifiedValue(rgba)),
Some(CurrentColor) => Some(CSSWideKeyword(Inherit)), Ok(CurrentColor) => Ok(Inherit),
None => None, Err(()) => Err(()),
} }
} }
</%self:raw_longhand> </%self:raw_longhand>
@ -726,10 +722,10 @@ pub mod longhands {
/// <familiy-name># /// <familiy-name>#
/// <familiy-name> = <string> | [ <ident>+ ] /// <familiy-name> = <string> | [ <ident>+ ]
/// TODO: <generic-familiy> /// TODO: <generic-familiy>
pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Result<SpecifiedValue, ()> {
from_iter(input.skip_whitespace()) from_iter(input.skip_whitespace())
} }
pub fn from_iter<'a>(mut iter: SkipWhitespaceIterator<'a>) -> Option<SpecifiedValue> { pub fn from_iter<'a>(mut iter: SkipWhitespaceIterator<'a>) -> Result<SpecifiedValue, ()> {
let mut result = vec!(); let mut result = vec!();
macro_rules! add( macro_rules! add(
($value: expr, $b: expr) => { ($value: expr, $b: expr) => {
@ -738,7 +734,7 @@ pub mod longhands {
match iter.next() { match iter.next() {
Some(&Comma) => (), Some(&Comma) => (),
None => $b, None => $b,
_ => return None, _ => return Err(()),
} }
} }
} }
@ -767,16 +763,16 @@ pub mod longhands {
result.push(FamilyName(idents.connect(" "))); result.push(FamilyName(idents.connect(" ")));
break 'outer break 'outer
}, },
_ => return None, _ => return Err(()),
} }
} }
} }
} }
} }
_ => return None, _ => return Err(()),
} }
} }
Some(result) Ok(result)
} }
</%self:longhand> </%self:longhand>
@ -795,30 +791,30 @@ pub mod longhands {
} }
/// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
match input { match input {
&Ident(ref value) => { &Ident(ref value) => {
match value.as_slice().to_ascii_lower().as_slice() { match value.as_slice().to_ascii_lower().as_slice() {
"bold" => Some(SpecifiedWeight700), "bold" => Ok(SpecifiedWeight700),
"normal" => Some(SpecifiedWeight400), "normal" => Ok(SpecifiedWeight400),
"bolder" => Some(Bolder), "bolder" => Ok(Bolder),
"lighter" => Some(Lighter), "lighter" => Ok(Lighter),
_ => None, _ => Err(()),
} }
}, },
&Number(ref value) => match value.int_value { &Number(ref value) => match value.int_value {
Some(100) => Some(SpecifiedWeight100), Some(100) => Ok(SpecifiedWeight100),
Some(200) => Some(SpecifiedWeight200), Some(200) => Ok(SpecifiedWeight200),
Some(300) => Some(SpecifiedWeight300), Some(300) => Ok(SpecifiedWeight300),
Some(400) => Some(SpecifiedWeight400), Some(400) => Ok(SpecifiedWeight400),
Some(500) => Some(SpecifiedWeight500), Some(500) => Ok(SpecifiedWeight500),
Some(600) => Some(SpecifiedWeight600), Some(600) => Ok(SpecifiedWeight600),
Some(700) => Some(SpecifiedWeight700), Some(700) => Ok(SpecifiedWeight700),
Some(800) => Some(SpecifiedWeight800), Some(800) => Ok(SpecifiedWeight800),
Some(900) => Some(SpecifiedWeight900), Some(900) => Ok(SpecifiedWeight900),
_ => None, _ => Err(()),
}, },
_ => None _ => Err(())
} }
} }
pub mod computed_value { pub mod computed_value {
@ -890,7 +886,7 @@ pub mod longhands {
/// <length> | <percentage> /// <length> | <percentage>
/// TODO: support <absolute-size> and <relative-size> /// TODO: support <absolute-size> and <relative-size>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url) pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Option<SpecifiedValue> { -> Result<SpecifiedValue, ()> {
specified::LengthOrPercentage::parse_non_negative(input).map(|value| { specified::LengthOrPercentage::parse_non_negative(input).map(|value| {
match value { match value {
specified::LP_Length(value) => value, specified::LP_Length(value) => value,
@ -927,7 +923,7 @@ pub mod longhands {
none none
} }
/// none | [ underline || overline || line-through || blink ] /// none | [ underline || overline || line-through || blink ]
pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Option<SpecifiedValue> { pub fn parse(input: &[ComponentValue], _base_url: &Url) -> Result<SpecifiedValue, ()> {
let mut result = SpecifiedValue { let mut result = SpecifiedValue {
underline: false, overline: false, line_through: false, underline: false, overline: false, line_through: false,
}; };
@ -935,22 +931,22 @@ pub mod longhands {
let mut empty = true; let mut empty = true;
for component_value in input.skip_whitespace() { for component_value in input.skip_whitespace() {
match get_ident_lower(component_value) { match get_ident_lower(component_value) {
None => return None, Err(()) => return Err(()),
Some(keyword) => match keyword.as_slice() { Ok(keyword) => match keyword.as_slice() {
"underline" => if result.underline { return None } "underline" => if result.underline { return Err(()) }
else { empty = false; result.underline = true }, else { empty = false; result.underline = true },
"overline" => if result.overline { return None } "overline" => if result.overline { return Err(()) }
else { empty = false; result.overline = true }, else { empty = false; result.overline = true },
"line-through" => if result.line_through { return None } "line-through" => if result.line_through { return Err(()) }
else { empty = false; result.line_through = true }, else { empty = false; result.line_through = true },
"blink" => if blink { return None } "blink" => if blink { return Err(()) }
else { empty = false; blink = true }, else { empty = false; blink = true },
"none" => return if empty { Some(result) } else { None }, "none" => return if empty { Ok(result) } else { Err(()) },
_ => return None, _ => return Err(()),
} }
} }
} }
if !empty { Some(result) } else { None } if !empty { Ok(result) } else { Err(()) }
} }
</%self:longhand> </%self:longhand>
@ -1070,7 +1066,7 @@ pub mod shorthands {
pub ${sub_property.ident}: Option<${sub_property.ident}::SpecifiedValue>, pub ${sub_property.ident}: Option<${sub_property.ident}::SpecifiedValue>,
% endfor % endfor
} }
pub fn parse(input: &[ComponentValue], base_url: &Url) -> Option<Longhands> { pub fn parse(input: &[ComponentValue], base_url: &Url) -> Result<Longhands, ()> {
${caller.body()} ${caller.body()}
} }
} }
@ -1080,7 +1076,7 @@ pub mod shorthands {
<%self:shorthand name="${name}" sub_properties="${ <%self:shorthand name="${name}" sub_properties="${
' '.join(sub_property_pattern % side ' '.join(sub_property_pattern % side
for side in ['top', 'right', 'bottom', 'left'])}"> for side in ['top', 'right', 'bottom', 'left'])}">
let mut iter = input.skip_whitespace().map(|c| ${parser_function}(c, base_url)); let mut iter = input.skip_whitespace().map(|c| ${parser_function}(c, base_url).ok());
// zero or more than four values is invalid. // zero or more than four values is invalid.
// one value sets them all // one value sets them all
// two values set (top, bottom) and (left, right) // two values set (top, bottom) and (left, right)
@ -1092,13 +1088,13 @@ pub mod shorthands {
let left = iter.next().unwrap_or(right); let left = iter.next().unwrap_or(right);
if top.is_some() && right.is_some() && bottom.is_some() && left.is_some() if top.is_some() && right.is_some() && bottom.is_some() && left.is_some()
&& iter.next().is_none() { && iter.next().is_none() {
Some(Longhands { Ok(Longhands {
% for side in ["top", "right", "bottom", "left"]: % for side in ["top", "right", "bottom", "left"]:
${to_rust_ident(sub_property_pattern % side)}: ${side}, ${to_rust_ident(sub_property_pattern % side)}: ${side},
% endfor % endfor
}) })
} else { } else {
None Err(())
} }
</%self:shorthand> </%self:shorthand>
</%def> </%def>
@ -1116,46 +1112,46 @@ pub mod shorthands {
for component_value in input.skip_whitespace() { for component_value in input.skip_whitespace() {
if color.is_none() { if color.is_none() {
match background_color::from_component_value(component_value, base_url) { match background_color::from_component_value(component_value, base_url) {
Some(v) => { Ok(v) => {
color = Some(v); color = Some(v);
any = true; any = true;
continue continue
}, },
None => () Err(()) => ()
} }
} }
if image.is_none() { if image.is_none() {
match background_image::from_component_value(component_value, base_url) { match background_image::from_component_value(component_value, base_url) {
Some(v) => { Ok(v) => {
image = Some(v); image = Some(v);
any = true; any = true;
continue continue
}, },
None => (), Err(()) => (),
} }
} }
if repeat.is_none() { if repeat.is_none() {
match background_repeat::from_component_value(component_value, base_url) { match background_repeat::from_component_value(component_value, base_url) {
Some(v) => { Ok(v) => {
repeat = Some(v); repeat = Some(v);
any = true; any = true;
continue continue
}, },
None => () Err(()) => ()
} }
} }
if attachment.is_none() { if attachment.is_none() {
match background_attachment::from_component_value(component_value, match background_attachment::from_component_value(component_value,
base_url) { base_url) {
Some(v) => { Ok(v) => {
attachment = Some(v); attachment = Some(v);
any = true; any = true;
continue continue
}, },
None => () Err(()) => ()
} }
} }
@ -1165,17 +1161,17 @@ pub mod shorthands {
match background_position::parse_horizontal_and_vertical( match background_position::parse_horizontal_and_vertical(
saved_component_value, saved_component_value,
component_value) { component_value) {
Some(v) => { Ok(v) => {
position = Some(v); position = Some(v);
any = true; any = true;
continue continue
}, },
None => (), Err(()) => (),
} }
} }
// If we get here, parsing failed. // If we get here, parsing failed.
return None return Err(())
} }
None => { None => {
// Save the component value. // Save the component value.
@ -1185,7 +1181,7 @@ pub mod shorthands {
} }
if any && last_component_value.is_none() { if any && last_component_value.is_none() {
Some(Longhands { Ok(Longhands {
background_color: color, background_color: color,
background_image: image, background_image: image,
background_position: position, background_position: position,
@ -1193,14 +1189,14 @@ pub mod shorthands {
background_attachment: attachment, background_attachment: attachment,
}) })
} else { } else {
None Err(())
} }
</%self:shorthand> </%self:shorthand>
${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")} ${four_sides_shorthand("margin", "margin-%s", "margin_top::from_component_value")}
${four_sides_shorthand("padding", "padding-%s", "padding_top::from_component_value")} ${four_sides_shorthand("padding", "padding-%s", "padding_top::from_component_value")}
pub fn parse_color(value: &ComponentValue, _base_url: &Url) -> Option<specified::CSSColor> { pub fn parse_color(value: &ComponentValue, _base_url: &Url) -> Result<specified::CSSColor, ()> {
specified::CSSColor::parse(value) specified::CSSColor::parse(value)
} }
${four_sides_shorthand("border-color", "border-%s-color", "parse_color")} ${four_sides_shorthand("border-color", "border-%s-color", "parse_color")}
@ -1209,9 +1205,9 @@ pub mod shorthands {
${four_sides_shorthand("border-width", "border-%s-width", "parse_border_width")} ${four_sides_shorthand("border-width", "border-%s-width", "parse_border_width")}
pub fn parse_border(input: &[ComponentValue], base_url: &Url) pub fn parse_border(input: &[ComponentValue], base_url: &Url)
-> Option<(Option<specified::CSSColor>, -> Result<(Option<specified::CSSColor>,
Option<border_top_style::SpecifiedValue>, Option<border_top_style::SpecifiedValue>,
Option<specified::Length>)> { Option<specified::Length>), ()> {
let mut color = None; let mut color = None;
let mut style = None; let mut style = None;
let mut width = None; let mut width = None;
@ -1219,25 +1215,25 @@ pub mod shorthands {
for component_value in input.skip_whitespace() { for component_value in input.skip_whitespace() {
if color.is_none() { if color.is_none() {
match specified::CSSColor::parse(component_value) { match specified::CSSColor::parse(component_value) {
Some(c) => { color = Some(c); any = true; continue }, Ok(c) => { color = Some(c); any = true; continue },
None => () Err(()) => ()
} }
} }
if style.is_none() { if style.is_none() {
match border_top_style::from_component_value(component_value, base_url) { match border_top_style::from_component_value(component_value, base_url) {
Some(s) => { style = Some(s); any = true; continue }, Ok(s) => { style = Some(s); any = true; continue },
None => () Err(()) => ()
} }
} }
if width.is_none() { if width.is_none() {
match parse_border_width(component_value, base_url) { match parse_border_width(component_value, base_url) {
Some(w) => { width = Some(w); any = true; continue }, Ok(w) => { width = Some(w); any = true; continue },
None => () Err(()) => ()
} }
} }
return None return Err(())
} }
if any { Some((color, style, width)) } else { None } if any { Ok((color, style, width)) } else { Err(()) }
} }
@ -1286,7 +1282,7 @@ pub mod shorthands {
// font-style, font-weight and font-variant. // font-style, font-weight and font-variant.
// Leaves the values to None, 'normal' is the initial value for each of them. // Leaves the values to None, 'normal' is the initial value for each of them.
match get_ident_lower(component_value) { match get_ident_lower(component_value) {
Some(ref ident) if ident.as_slice().eq_ignore_ascii_case("normal") => { Ok(ref ident) if ident.as_slice().eq_ignore_ascii_case("normal") => {
nb_normals += 1; nb_normals += 1;
continue; continue;
} }
@ -1294,25 +1290,25 @@ pub mod shorthands {
} }
if style.is_none() { if style.is_none() {
match font_style::from_component_value(component_value, base_url) { match font_style::from_component_value(component_value, base_url) {
Some(s) => { style = Some(s); continue }, Ok(s) => { style = Some(s); continue },
None => () Err(()) => ()
} }
} }
if weight.is_none() { if weight.is_none() {
match font_weight::from_component_value(component_value, base_url) { match font_weight::from_component_value(component_value, base_url) {
Some(w) => { weight = Some(w); continue }, Ok(w) => { weight = Some(w); continue },
None => () Err(()) => ()
} }
} }
if variant.is_none() { if variant.is_none() {
match font_variant::from_component_value(component_value, base_url) { match font_variant::from_component_value(component_value, base_url) {
Some(v) => { variant = Some(v); continue }, Ok(v) => { variant = Some(v); continue },
None => () Err(()) => ()
} }
} }
match font_size::from_component_value(component_value, base_url) { match font_size::from_component_value(component_value, base_url) {
Some(s) => { size = Some(s); break }, Ok(s) => { size = Some(s); break },
None => return None Err(()) => return Err(())
} }
} }
#[inline] #[inline]
@ -1323,23 +1319,23 @@ pub mod shorthands {
} }
} }
if size.is_none() || (count(&style) + count(&weight) + count(&variant) + nb_normals) > 3 { if size.is_none() || (count(&style) + count(&weight) + count(&variant) + nb_normals) > 3 {
return None return Err(())
} }
let mut copied_iter = iter.clone(); let mut copied_iter = iter.clone();
match copied_iter.next() { match copied_iter.next() {
Some(&Delim('/')) => { Some(&Delim('/')) => {
iter = copied_iter; iter = copied_iter;
line_height = match iter.next() { line_height = match iter.next() {
Some(v) => line_height::from_component_value(v, base_url), Some(v) => line_height::from_component_value(v, base_url).ok(),
_ => return None, _ => return Err(()),
}; };
if line_height.is_none() { return None } if line_height.is_none() { return Err(()) }
} }
_ => () _ => ()
} }
let family = font_family::from_iter(iter); let family = font_family::from_iter(iter).ok();
if family.is_none() { return None } if family.is_none() { return Err(()) }
Some(Longhands { Ok(Longhands {
font_style: style, font_style: style,
font_variant: variant, font_variant: variant,
font_weight: weight, font_weight: weight,
@ -1459,20 +1455,20 @@ pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &U
} }
#[deriving(Clone)]
pub enum CSSWideKeyword { pub enum CSSWideKeyword {
Initial, InitialKeyword,
Inherit, InheritKeyword,
UnsetKeyword,
} }
impl CSSWideKeyword { impl CSSWideKeyword {
pub fn parse(input: &[ComponentValue]) -> Option<Option<CSSWideKeyword>> { pub fn parse(input: &[ComponentValue]) -> Result<CSSWideKeyword, ()> {
one_component_value(input).and_then(get_ident_lower).and_then(|keyword| { one_component_value(input).and_then(get_ident_lower).and_then(|keyword| {
match keyword.as_slice() { match keyword.as_slice() {
"initial" => Some(Some(Initial)), "initial" => Ok(InitialKeyword),
"inherit" => Some(Some(Inherit)), "inherit" => Ok(InheritKeyword),
"unset" => Some(None), "unset" => Ok(UnsetKeyword),
_ => None _ => Err(())
} }
}) })
} }
@ -1482,7 +1478,11 @@ impl CSSWideKeyword {
#[deriving(Clone)] #[deriving(Clone)]
pub enum DeclaredValue<T> { pub enum DeclaredValue<T> {
SpecifiedValue(T), SpecifiedValue(T),
CSSWideKeyword(CSSWideKeyword), Initial,
Inherit,
// There is no Unset variant here.
// The 'unset' keyword is represented as either Initial or Inherit,
// depending on whether the property is inherited.
} }
#[deriving(Clone)] #[deriving(Clone)]
@ -1521,12 +1521,12 @@ impl PropertyDeclaration {
return ValidOrIgnoredDeclaration return ValidOrIgnoredDeclaration
} }
match longhands::${property.ident}::parse_declared(value, base_url) { match longhands::${property.ident}::parse_declared(value, base_url) {
Some(value) => { Ok(value) => {
seen.set_${property.ident}(); seen.set_${property.ident}();
result_list.push(${property.camel_case}Declaration(value)); result_list.push(${property.camel_case}Declaration(value));
ValidOrIgnoredDeclaration ValidOrIgnoredDeclaration
}, },
None => InvalidValue, Err(()) => InvalidValue,
} }
}, },
% else: % else:
@ -1540,45 +1540,53 @@ impl PropertyDeclaration {
return ValidOrIgnoredDeclaration return ValidOrIgnoredDeclaration
} }
match CSSWideKeyword::parse(value) { match CSSWideKeyword::parse(value) {
Some(Some(keyword)) => { Ok(InheritKeyword) => {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() { if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}(); seen.set_${sub_property.ident}();
result_list.push(${sub_property.camel_case}Declaration( result_list.push(
CSSWideKeyword(keyword))); ${sub_property.camel_case}Declaration(Inherit));
} }
% endfor % endfor
ValidOrIgnoredDeclaration ValidOrIgnoredDeclaration
}, },
Some(None) => { Ok(InitialKeyword) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(
${sub_property.camel_case}Declaration(Initial));
}
% endfor
ValidOrIgnoredDeclaration
},
Ok(UnsetKeyword) => {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() { if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}(); seen.set_${sub_property.ident}();
result_list.push(${sub_property.camel_case}Declaration( result_list.push(${sub_property.camel_case}Declaration(
CSSWideKeyword(
${"Inherit" if sub_property.style_struct.inherited else "Initial"} ${"Inherit" if sub_property.style_struct.inherited else "Initial"}
)
)); ));
} }
% endfor % endfor
ValidOrIgnoredDeclaration ValidOrIgnoredDeclaration
}, },
None => match shorthands::${shorthand.ident}::parse(value, base_url) { Err(()) => match shorthands::${shorthand.ident}::parse(value, base_url) {
Some(result) => { Ok(result) => {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() { if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}(); seen.set_${sub_property.ident}();
result_list.push(${sub_property.camel_case}Declaration( result_list.push(${sub_property.camel_case}Declaration(
match result.${sub_property.ident} { match result.${sub_property.ident} {
Some(value) => SpecifiedValue(value), Some(value) => SpecifiedValue(value),
None => CSSWideKeyword(Initial), None => Initial,
} }
)); ));
} }
% endfor % endfor
ValidOrIgnoredDeclaration ValidOrIgnoredDeclaration
}, },
None => InvalidValue, Err(()) => InvalidValue,
} }
} }
}, },
@ -1824,9 +1832,9 @@ fn cascade_with_cached_declarations(applicable_declarations: &[MatchedProperty],
(*specified_value).clone(), (*specified_value).clone(),
context context
), ),
CSSWideKeyword(Initial) Initial
=> longhands::${property.ident}::get_initial_value(), => longhands::${property.ident}::get_initial_value(),
CSSWideKeyword(Inherit) => { Inherit => {
// This is a bit slow, but this is rare so it shouldn't // This is a bit slow, but this is rare so it shouldn't
// matter. // matter.
// //
@ -1934,8 +1942,8 @@ pub fn cascade(applicable_declarations: &[MatchedProperty],
($style_struct_getter: ident, $property: ident, $declared_value: expr) => { ($style_struct_getter: ident, $property: ident, $declared_value: expr) => {
match *$declared_value { match *$declared_value {
SpecifiedValue(specified_value) => specified_value, SpecifiedValue(specified_value) => specified_value,
CSSWideKeyword(Initial) => longhands::$property::get_initial_value(), Initial => longhands::$property::get_initial_value(),
CSSWideKeyword(Inherit) => inherited_style.$style_struct_getter().$property.clone(), Inherit => inherited_style.$style_struct_getter().$property.clone(),
} }
}; };
) )
@ -1950,8 +1958,8 @@ pub fn cascade(applicable_declarations: &[MatchedProperty],
context.font_size = match *value { context.font_size = match *value {
SpecifiedValue(specified_value) => computed::compute_Au_with_font_size( SpecifiedValue(specified_value) => computed::compute_Au_with_font_size(
specified_value, context.inherited_font_size), specified_value, context.inherited_font_size),
CSSWideKeyword(Initial) => longhands::font_size::get_initial_value(), Initial => longhands::font_size::get_initial_value(),
CSSWideKeyword(Inherit) => context.inherited_font_size, Inherit => context.inherited_font_size,
} }
} }
ColorDeclaration(ref value) => { ColorDeclaration(ref value) => {
@ -2031,9 +2039,9 @@ pub fn cascade(applicable_declarations: &[MatchedProperty],
(*specified_value).clone(), (*specified_value).clone(),
&context &context
), ),
CSSWideKeyword(Initial) Initial
=> longhands::${property.ident}::get_initial_value(), => longhands::${property.ident}::get_initial_value(),
CSSWideKeyword(Inherit) => { Inherit => {
// This is a bit slow, but this is rare so it shouldn't // This is a bit slow, but this is rare so it shouldn't
// matter. // matter.
// //

View file

@ -504,10 +504,10 @@ fn parse_functional_pseudo_class(name: String, arguments: Vec<ComponentValue>,
-> Option<SimpleSelector> { -> Option<SimpleSelector> {
match name.as_slice().to_ascii_lower().as_slice() { match name.as_slice().to_ascii_lower().as_slice() {
// "lang" => parse_lang(arguments), // "lang" => parse_lang(arguments),
"nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)), "nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)).ok(),
"nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)), "nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)).ok(),
"nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)), "nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)).ok(),
"nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)), "nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)).ok(),
"not" => if inside_negation { None } else { parse_negation(arguments, namespaces) }, "not" => if inside_negation { None } else { parse_negation(arguments, namespaces) },
_ => None _ => None
} }

@ -1 +1 @@
Subproject commit 918bae60d4703e3db7f306b6c4a09de0670b9472 Subproject commit 48e517b40c8aad55b5f2b7072d092102b48797bc