Use Result/Err(()) in Selector parsing.

… get rid of some custom `enum` types for parsing return values.
`Option<Option<T>>` was ridiculous, but `Result<Option<T>, ()>`
make perfect sense.

Also, we can now take advantage of the `try!()` macro.
This commit is contained in:
Simon Sapin 2014-08-11 21:50:47 +01:00
parent d9278e3f6a
commit 9564d91b5e
5 changed files with 145 additions and 173 deletions

View file

@ -29,7 +29,7 @@ servo-test-$(1): $$(DEPS_$(1))
.PHONY: check-servo-$(1)
check-servo-$(1): servo-test-$(1)
@$$(call E, check: $(1))
$$(Q)./servo-test-$(1)
$$(Q)./servo-test-$(1) $(TESTNAME)
endef
$(foreach lib_crate,$(SERVO_LIB_CRATES),\

View file

@ -778,8 +778,8 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
let namespace = NamespaceMap::new();
match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(),
&namespace) {
None => return Err(Syntax),
Some(ref selectors) => {
Err(()) => return Err(Syntax),
Ok(ref selectors) => {
let root: &JSRef<Node> = NodeCast::from_ref(self);
for selector in selectors.iter() {
let mut shareable = false;

View file

@ -614,9 +614,9 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
let namespace = NamespaceMap::new();
match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(), &namespace) {
// Step 2.
None => return Err(Syntax),
Err(()) => return Err(Syntax),
// Step 3.
Some(ref selectors) => {
Ok(ref selectors) => {
let root = self.ancestors().last().unwrap_or(self.clone());
for selector in selectors.iter() {
assert!(selector.pseudo_element.is_none());
@ -641,9 +641,9 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
let namespace = NamespaceMap::new();
match parse_selector_list(tokenize(selectors.as_slice()).map(|(token, _)| token).collect(), &namespace) {
// Step 2.
None => return Err(Syntax),
Err(()) => return Err(Syntax),
// Step 3.
Some(ref selectors) => {
Ok(ref selectors) => {
for selector in selectors.iter() {
assert!(selector.pseudo_element.is_none());
for node in root.traverse_preorder().filter(|node| node.is_element()) {

View file

@ -115,13 +115,9 @@ type Iter = iter::Peekable<ComponentValue, vec::MoveItems<ComponentValue>>;
///
/// Return the Selectors or None if there is an invalid selector.
pub fn parse_selector_list(input: Vec<ComponentValue>, namespaces: &NamespaceMap)
-> Option<Vec<Selector>> {
-> Result<Vec<Selector>, ()> {
let iter = &mut input.move_iter().peekable();
let first = match parse_selector(iter, namespaces) {
None => return None,
Some(result) => result
};
let mut results = vec!(first);
let mut results = vec![try!(parse_selector(iter, namespaces))];
loop {
skip_whitespace(iter);
@ -130,14 +126,11 @@ pub fn parse_selector_list(input: Vec<ComponentValue>, namespaces: &NamespaceMap
Some(&Comma) => {
iter.next();
}
_ => return None,
}
match parse_selector(iter, namespaces) {
Some(selector) => results.push(selector),
None => return None,
_ => return Err(()),
}
results.push(try!(parse_selector(iter, namespaces)));
}
Some(results)
Ok(results)
}
@ -146,13 +139,9 @@ pub fn parse_selector_list(input: Vec<ComponentValue>, namespaces: &NamespaceMap
///
/// None means invalid selector.
fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
-> Option<Selector> {
let (first, pseudo_element) = match parse_simple_selectors(iter, namespaces) {
None => return None,
Some(result) => result
};
-> Result<Selector, ()> {
let (first, mut pseudo_element) = try!(parse_simple_selectors(iter, namespaces));
let mut compound = CompoundSelector{ simple_selectors: first, next: None };
let mut pseudo_element = pseudo_element;
while pseudo_element.is_none() {
let any_whitespace = skip_whitespace(iter);
@ -164,21 +153,17 @@ fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
Some(&Delim('~')) => { iter.next(); LaterSibling },
Some(_) => {
if any_whitespace { Descendant }
else { return None }
else { return Err(()) }
}
};
match parse_simple_selectors(iter, namespaces) {
None => return None,
Some((simple_selectors, pseudo)) => {
compound = CompoundSelector {
simple_selectors: simple_selectors,
next: Some((box compound, combinator))
};
pseudo_element = pseudo;
}
}
let (simple_selectors, pseudo) = try!(parse_simple_selectors(iter, namespaces));
compound = CompoundSelector {
simple_selectors: simple_selectors,
next: Some((box compound, combinator))
};
pseudo_element = pseudo;
}
Some(Selector {
Ok(Selector {
specificity: compute_specificity(&compound, &pseudo_element),
compound_selectors: Arc::new(compound),
pseudo_element: pseudo_element,
@ -245,43 +230,37 @@ fn compute_specificity(mut selector: &CompoundSelector,
/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]*
/// | [ HASH | class | attrib | pseudo | negation ]+
///
/// None means invalid selector
/// `Err(())` means invalid selector
fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
-> Option<(Vec<SimpleSelector>, Option<PseudoElement>)> {
-> Result<(Vec<SimpleSelector>, Option<PseudoElement>), ()> {
let mut empty = true;
let mut simple_selectors = match parse_type_selector(iter, namespaces) {
InvalidTypeSelector => return None,
NotATypeSelector => vec!(),
TypeSelector(s) => { empty = false; s }
let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) {
None => vec![],
Some(s) => { empty = false; s }
};
let mut pseudo_element = None;
loop {
match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false) {
InvalidSimpleSelector => return None,
NotASimpleSelector => break,
SimpleSelectorResult(s) => { simple_selectors.push(s); empty = false },
PseudoElementResult(p) => { pseudo_element = Some(p); empty = false; break },
match try!(parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false)) {
None => break,
Some(SimpleSelectorResult(s)) => { simple_selectors.push(s); empty = false },
Some(PseudoElementResult(p)) => { pseudo_element = Some(p); empty = false; break },
}
}
if empty { None } // An empty selector is invalid
else { Some((simple_selectors, pseudo_element)) }
if empty { Err(()) } // An empty selector is invalid
else { Ok((simple_selectors, pseudo_element)) }
}
enum TypeSelectorParseResult {
InvalidTypeSelector,
NotATypeSelector,
TypeSelector(Vec<SimpleSelector>), // Length 0 (*|*), 1 (*|E or ns|*) or 2 (|E or ns|E)
}
/// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a type selector, could be something else. `iter` was not consumed.
/// * `Ok(Some(vec))`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
-> TypeSelectorParseResult {
-> Result<Option<Vec<SimpleSelector>>, ()> {
skip_whitespace(iter);
match parse_qualified_name(iter, /* in_attr_selector = */ false, namespaces) {
InvalidQualifiedName => InvalidTypeSelector,
NotAQualifiedName => NotATypeSelector,
QualifiedName(namespace, local_name) => {
match try!(parse_qualified_name(iter, /* in_attr_selector = */ false, namespaces)) {
None => Ok(None),
Some((namespace, local_name)) => {
let mut simple_selectors = vec!();
match namespace {
SpecificNamespace(ns) => simple_selectors.push(NamespaceSelector(ns)),
@ -294,114 +273,108 @@ fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
}
None => (),
}
TypeSelector(simple_selectors)
Ok(Some(simple_selectors))
}
}
}
enum SimpleSelectorParseResult {
InvalidSimpleSelector,
NotASimpleSelector,
SimpleSelectorResult(SimpleSelector),
PseudoElementResult(PseudoElement),
}
// Parse a simple selector other than a type selector
/// Parse a simple selector other than a type selector.
///
/// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
-> SimpleSelectorParseResult {
-> Result<Option<SimpleSelectorParseResult>, ()> {
match iter.peek() {
Some(&IDHash(_)) => match iter.next() {
Some(IDHash(id)) => SimpleSelectorResult(IDSelector(Atom::from_slice(id.as_slice()))),
Some(IDHash(id)) => Ok(Some(SimpleSelectorResult(
IDSelector(Atom::from_slice(id.as_slice()))))),
_ => fail!("Implementation error, this should not happen."),
},
Some(&Delim('.')) => {
iter.next();
match iter.next() {
Some(Ident(class)) => SimpleSelectorResult(ClassSelector(Atom::from_slice(class.as_slice()))),
_ => InvalidSimpleSelector,
Some(Ident(class)) => Ok(Some(SimpleSelectorResult(
ClassSelector(Atom::from_slice(class.as_slice()))))),
_ => Err(()),
}
}
Some(&SquareBracketBlock(_)) => match iter.next() {
Some(SquareBracketBlock(content))
=> match parse_attribute_selector(content, namespaces) {
None => InvalidSimpleSelector,
Some(simple_selector) => SimpleSelectorResult(simple_selector),
},
=> Ok(Some(SimpleSelectorResult(try!(parse_attribute_selector(content, namespaces))))),
_ => fail!("Implementation error, this should not happen."),
},
Some(&Colon) => {
iter.next();
match iter.next() {
Some(Ident(name)) => match parse_simple_pseudo_class(name.as_slice()) {
None => {
Err(()) => {
match name.as_slice().to_ascii_lower().as_slice() {
// Supported CSS 2.1 pseudo-elements only.
// ** Do not add to this list! **
"before" => PseudoElementResult(Before),
"after" => PseudoElementResult(After),
"before" => Ok(Some(PseudoElementResult(Before))),
"after" => Ok(Some(PseudoElementResult(After))),
// "first-line" => PseudoElementResult(FirstLine),
// "first-letter" => PseudoElementResult(FirstLetter),
_ => InvalidSimpleSelector
_ => Err(())
}
},
Some(result) => SimpleSelectorResult(result),
},
Some(Function(name, arguments)) => match parse_functional_pseudo_class(
name, arguments, namespaces, inside_negation) {
None => InvalidSimpleSelector,
Some(simple_selector) => SimpleSelectorResult(simple_selector),
Ok(result) => Ok(Some(SimpleSelectorResult(result))),
},
Some(Function(name, arguments))
=> Ok(Some(SimpleSelectorResult(try!(parse_functional_pseudo_class(
name, arguments, namespaces, inside_negation))))),
Some(Colon) => {
match iter.next() {
Some(Ident(name)) => match parse_pseudo_element(name) {
Some(pseudo_element) => PseudoElementResult(pseudo_element),
_ => InvalidSimpleSelector,
},
_ => InvalidSimpleSelector,
Some(Ident(name))
=> Ok(Some(PseudoElementResult(try!(parse_pseudo_element(name))))),
_ => Err(()),
}
}
_ => InvalidSimpleSelector,
_ => Err(()),
}
}
_ => NotASimpleSelector,
_ => Ok(None),
}
}
enum QualifiedNameParseResult {
InvalidQualifiedName,
NotAQualifiedName,
// Namespace URL, local name. None means '*'
QualifiedName(NamespaceConstraint, Option<String>)
}
/// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
/// * `Ok(Some((namespace, local_name)))`: `None` for the local name means a `*` universal selector
fn parse_qualified_name(iter: &mut Iter, in_attr_selector: bool, namespaces: &NamespaceMap)
-> QualifiedNameParseResult {
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
#[inline]
fn default_namespace(namespaces: &NamespaceMap, local_name: Option<String>)
-> QualifiedNameParseResult {
QualifiedName(match namespaces.default {
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
let namespace = match namespaces.default {
Some(ref ns) => SpecificNamespace(ns.clone()),
None => AnyNamespace,
}, local_name)
};
Ok(Some((namespace, local_name)))
}
#[inline]
fn explicit_namespace(iter: &mut Iter, in_attr_selector: bool, namespace: NamespaceConstraint)
-> QualifiedNameParseResult {
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
assert!(iter.next() == Some(Delim('|')),
"Implementation error, this should not happen.");
match iter.peek() {
Some(&Delim('*')) if !in_attr_selector => {
iter.next();
QualifiedName(namespace, None)
Ok(Some((namespace, None)))
},
Some(&Ident(_)) => {
let local_name = get_next_ident(iter);
QualifiedName(namespace, Some(local_name))
Ok(Some((namespace, Some(local_name))))
},
_ => InvalidQualifiedName,
_ => Err(()),
}
}
@ -411,13 +384,13 @@ fn parse_qualified_name(iter: &mut Iter, in_attr_selector: bool, namespaces: &Na
match iter.peek() {
Some(&Delim('|')) => {
let namespace = match namespaces.prefix_map.find(&value) {
None => return InvalidQualifiedName, // Undeclared namespace prefix
None => return Err(()), // Undeclared namespace prefix
Some(ref ns) => (*ns).clone(),
};
explicit_namespace(iter, in_attr_selector, SpecificNamespace(namespace))
},
_ if in_attr_selector => QualifiedName(
SpecificNamespace(namespace::Null), Some(value)),
_ if in_attr_selector => Ok(Some(
(SpecificNamespace(namespace::Null), Some(value)))),
_ => default_namespace(namespaces, Some(value)),
}
},
@ -427,24 +400,24 @@ fn parse_qualified_name(iter: &mut Iter, in_attr_selector: bool, namespaces: &Na
Some(&Delim('|')) => explicit_namespace(iter, in_attr_selector, AnyNamespace),
_ => {
if !in_attr_selector { default_namespace(namespaces, None) }
else { InvalidQualifiedName }
else { Err(()) }
},
}
},
Some(&Delim('|')) => explicit_namespace(
iter, in_attr_selector, SpecificNamespace(namespace::Null)),
_ => NotAQualifiedName,
_ => Ok(None),
}
}
fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &NamespaceMap)
-> Option<SimpleSelector> {
-> Result<SimpleSelector, ()> {
let iter = &mut content.move_iter().peekable();
let attr = match parse_qualified_name(iter, /* in_attr_selector = */ true, namespaces) {
InvalidQualifiedName | NotAQualifiedName => return None,
QualifiedName(_, None) => fail!("Implementation error, this should not happen."),
QualifiedName(namespace, Some(local_name)) => AttrSelector {
let attr = match try!(parse_qualified_name(iter, /* in_attr_selector = */ true, namespaces)) {
None => return Err(()),
Some((_, None)) => fail!("Implementation error, this should not happen."),
Some((namespace, Some(local_name))) => AttrSelector {
namespace: namespace,
lower_name: local_name.as_slice().to_ascii_lower(),
name: local_name,
@ -456,7 +429,7 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace
skip_whitespace(iter);
match iter.next() {
Some(Ident(value)) | Some(String(value)) => value,
_ => return None,
_ => return Err(())
}
}};)
let result = match iter.next() {
@ -471,87 +444,86 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace
Some(PrefixMatch) => AttrPrefixMatch(attr, (get_value!())), // [foo^=bar]
Some(SubstringMatch) => AttrSubstringMatch(attr, (get_value!())), // [foo*=bar]
Some(SuffixMatch) => AttrSuffixMatch(attr, (get_value!())), // [foo$=bar]
_ => return None
_ => return Err(())
};
skip_whitespace(iter);
if iter.next().is_none() { Some(result) } else { None }
if iter.next().is_none() { Ok(result) } else { Err(()) }
}
fn parse_simple_pseudo_class(name: &str) -> Option<SimpleSelector> {
fn parse_simple_pseudo_class(name: &str) -> Result<SimpleSelector, ()> {
match name.to_ascii_lower().as_slice() {
"any-link" => Some(AnyLink),
"link" => Some(Link),
"visited" => Some(Visited),
"hover" => Some(Hover),
"disabled" => Some(Disabled),
"enabled" => Some(Enabled),
"first-child" => Some(FirstChild),
"last-child" => Some(LastChild),
"only-child" => Some(OnlyChild),
"root" => Some(Root),
"first-of-type" => Some(FirstOfType),
"last-of-type" => Some(LastOfType),
"only-of-type" => Some(OnlyOfType),
// "empty" => Some(Empty),
_ => None
"any-link" => Ok(AnyLink),
"link" => Ok(Link),
"visited" => Ok(Visited),
"hover" => Ok(Hover),
"disabled" => Ok(Disabled),
"enabled" => Ok(Enabled),
"first-child" => Ok(FirstChild),
"last-child" => Ok(LastChild),
"only-child" => Ok(OnlyChild),
"root" => Ok(Root),
"first-of-type" => Ok(FirstOfType),
"last-of-type" => Ok(LastOfType),
"only-of-type" => Ok(OnlyOfType),
// "empty" => Ok(Empty),
_ => Err(())
}
}
fn parse_functional_pseudo_class(name: String, arguments: Vec<ComponentValue>,
namespaces: &NamespaceMap, inside_negation: bool)
-> Option<SimpleSelector> {
-> Result<SimpleSelector, ()> {
match name.as_slice().to_ascii_lower().as_slice() {
// "lang" => parse_lang(arguments),
"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)).ok(),
"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)).ok(),
"not" => if inside_negation { None } else { parse_negation(arguments, namespaces) },
_ => None
"nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)),
"nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)),
"nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)),
"nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)),
"not" => if inside_negation { Err(()) } else { parse_negation(arguments, namespaces) },
_ => Err(())
}
}
fn parse_pseudo_element(name: String) -> Option<PseudoElement> {
fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> {
match name.as_slice().to_ascii_lower().as_slice() {
// All supported pseudo-elements
"before" => Some(Before),
"after" => Some(After),
"before" => Ok(Before),
"after" => Ok(After),
// "first-line" => Some(FirstLine),
// "first-letter" => Some(FirstLetter),
_ => None
_ => Err(())
}
}
//fn parse_lang(arguments: vec!(ComponentValue)) -> Option<SimpleSelector> {
//fn parse_lang(arguments: vec!(ComponentValue)) -> Result<SimpleSelector, ()> {
// let mut iter = arguments.move_skip_whitespace();
// match iter.next() {
// Some(Ident(value)) => {
// if "" == value || iter.next().is_some() { None }
// else { Some(Lang(value)) }
// else { Ok(Lang(value)) }
// },
// _ => None,
// _ => Err(()),
// }
//}
// Level 3: Parse ONE simple_selector
/// Level 3: Parse **one** simple_selector
fn parse_negation(arguments: Vec<ComponentValue>, namespaces: &NamespaceMap)
-> Option<SimpleSelector> {
-> Result<SimpleSelector, ()> {
let iter = &mut arguments.move_iter().peekable();
Some(Negation(match parse_type_selector(iter, namespaces) {
InvalidTypeSelector => return None,
TypeSelector(s) => s,
NotATypeSelector => {
match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true) {
SimpleSelectorResult(s) => vec!(s),
_ => return None
match try!(parse_type_selector(iter, namespaces)) {
Some(type_selector) => Ok(Negation(type_selector)),
None => {
match try!(parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true)) {
Some(SimpleSelectorResult(simple_selector)) => Ok(Negation(vec![simple_selector])),
_ => Err(())
}
},
}))
}
}
@ -585,11 +557,11 @@ mod tests {
use namespaces::NamespaceMap;
use super::*;
fn parse(input: &str) -> Option<Vec<Selector>> {
fn parse(input: &str) -> Result<Vec<Selector>, ()> {
parse_ns(input, &NamespaceMap::new())
}
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Option<Vec<Selector>> {
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> {
parse_selector_list(
cssparser::tokenize(input).map(|(v, _)| v).collect(),
namespaces)
@ -601,8 +573,8 @@ mod tests {
#[test]
fn test_parsing() {
assert!(parse("") == None)
assert!(parse("e") == Some(vec!(Selector{
assert!(parse("") == Err(()))
assert!(parse("e") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(LocalNameSelector(Atom::from_slice("e"))),
next: None,
@ -610,7 +582,7 @@ mod tests {
pseudo_element: None,
specificity: specificity(0, 0, 1),
})))
assert!(parse(".foo") == Some(vec!(Selector{
assert!(parse(".foo") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(ClassSelector(Atom::from_slice("foo"))),
next: None,
@ -618,7 +590,7 @@ mod tests {
pseudo_element: None,
specificity: specificity(0, 1, 0),
})))
assert!(parse("#bar") == Some(vec!(Selector{
assert!(parse("#bar") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))),
next: None,
@ -626,7 +598,7 @@ mod tests {
pseudo_element: None,
specificity: specificity(1, 0, 0),
})))
assert!(parse("e.foo#bar") == Some(vec!(Selector{
assert!(parse("e.foo#bar") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(LocalNameSelector(Atom::from_slice("e")),
ClassSelector(Atom::from_slice("foo")),
@ -636,7 +608,7 @@ mod tests {
pseudo_element: None,
specificity: specificity(1, 1, 1),
})))
assert!(parse("e.foo #bar") == Some(vec!(Selector{
assert!(parse("e.foo #bar") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))),
next: Some((box CompoundSelector {
@ -651,7 +623,7 @@ mod tests {
// Default namespace does not apply to attribute selectors
// https://github.com/mozilla/servo/pull/1652
let mut namespaces = NamespaceMap::new();
assert!(parse_ns("[Foo]", &namespaces) == Some(vec!(Selector{
assert!(parse_ns("[Foo]", &namespaces) == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(AttrExists(AttrSelector {
name: "Foo".to_string(),
@ -666,7 +638,7 @@ mod tests {
// Default namespace does not apply to attribute selectors
// https://github.com/mozilla/servo/pull/1652
namespaces.default = Some(namespace::MathML);
assert!(parse_ns("[Foo]", &namespaces) == Some(vec!(Selector{
assert!(parse_ns("[Foo]", &namespaces) == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(AttrExists(AttrSelector {
name: "Foo".to_string(),
@ -679,7 +651,7 @@ mod tests {
specificity: specificity(0, 1, 0),
})))
// Default namespace does apply to type selectors
assert!(parse_ns("e", &namespaces) == Some(vec!(Selector{
assert!(parse_ns("e", &namespaces) == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(
NamespaceSelector(namespace::MathML),
@ -691,7 +663,7 @@ mod tests {
specificity: specificity(0, 0, 1),
})))
// https://github.com/mozilla/servo/issues/1723
assert!(parse("::before") == Some(vec!(Selector{
assert!(parse("::before") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(),
next: None,
@ -699,7 +671,7 @@ mod tests {
pseudo_element: Some(Before),
specificity: specificity(0, 0, 1),
})))
assert!(parse("div :after") == Some(vec!(Selector{
assert!(parse("div :after") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(),
next: Some((box CompoundSelector {

View file

@ -130,11 +130,11 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut Vec<CSSRule>,
// FIXME: avoid doing this for valid selectors
let serialized = prelude.iter().to_css();
match selectors::parse_selector_list(prelude, namespaces) {
Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
selectors: selectors,
declarations: properties::parse_property_declaration_list(block.move_iter(), base_url)
})),
None => log_css_error(location, format!(
Err(()) => log_css_error(location, format!(
"Invalid/unsupported selector: {}", serialized).as_slice()),
}
}