format components/selectors

This commit is contained in:
Anshul Malik 2018-09-12 00:24:20 +05:30
parent 9667298d29
commit a28c642fc7
4 changed files with 342 additions and 401 deletions

View file

@ -318,8 +318,9 @@ fn create_and_insert_some_stuff() {
assert!(bf.might_contain_hash(hash_as_str(i))); assert!(bf.might_contain_hash(hash_as_str(i)));
} }
let false_positives = let false_positives = (1001_usize..2000)
(1001_usize..2000).filter(|i| bf.might_contain_hash(hash_as_str(*i))).count(); .filter(|i| bf.might_contain_hash(hash_as_str(*i)))
.count();
assert!(false_positives < 190, "{} is not < 190", false_positives); // 19%. assert!(false_positives < 190, "{} is not < 190", false_positives); // 19%.
@ -331,7 +332,9 @@ fn create_and_insert_some_stuff() {
assert!(bf.might_contain_hash(hash_as_str(i))); assert!(bf.might_contain_hash(hash_as_str(i)));
} }
let false_positives = (0_usize..100).filter(|i| bf.might_contain_hash(hash_as_str(*i))).count(); let false_positives = (0_usize..100)
.filter(|i| bf.might_contain_hash(hash_as_str(*i)))
.count();
assert!(false_positives < 20, "{} is not < 20", false_positives); // 20%. assert!(false_positives < 20, "{} is not < 20", false_positives); // 20%.

View file

@ -161,7 +161,8 @@ struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> { impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() + self.current_simple_selectors.len() +
self.rest_of_simple_selectors.len() +
self.combinators.len() self.combinators.len()
} }
} }
@ -228,7 +229,6 @@ struct Specificity {
element_selectors: u32, element_selectors: u32,
} }
impl AddAssign for Specificity { impl AddAssign for Specificity {
#[inline] #[inline]
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
@ -306,10 +306,9 @@ where
Component::Combinator(ref combinator) => { Component::Combinator(ref combinator) => {
unreachable!( unreachable!(
"Found combinator {:?} in simple selectors vector? {:?}", "Found combinator {:?} in simple selectors vector? {:?}",
combinator, combinator, builder,
builder,
); );
} },
Component::PseudoElement(..) | Component::LocalName(..) => { Component::PseudoElement(..) | Component::LocalName(..) => {
specificity.element_selectors += 1 specificity.element_selectors += 1
}, },
@ -329,7 +328,7 @@ where
// See: https://github.com/w3c/csswg-drafts/issues/1915 // See: https://github.com/w3c/csswg-drafts/issues/1915
*specificity += Specificity::from(selector.specificity()); *specificity += Specificity::from(selector.specificity());
} }
} },
Component::ID(..) => { Component::ID(..) => {
specificity.id_selectors += 1; specificity.id_selectors += 1;
}, },

View file

@ -261,8 +261,7 @@ where
let iter = selector.iter_from(selector.len() - from_offset); let iter = selector.iter_from(selector.len() - from_offset);
debug_assert!( debug_assert!(
iter.clone().next().is_some() || iter.clone().next().is_some() ||
(from_offset != selector.len() && (from_offset != selector.len() && matches!(
matches!(
selector.combinator_at_parse_order(from_offset), selector.combinator_at_parse_order(from_offset),
Combinator::SlotAssignment | Combinator::PseudoElement Combinator::SlotAssignment | Combinator::PseudoElement
)), )),
@ -663,8 +662,9 @@ where
Component::Combinator(_) => unreachable!(), Component::Combinator(_) => unreachable!(),
Component::Slotted(ref selector) => { Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables. // <slots> are never flattened tree slottables.
!element.is_html_slot_element() && element.assigned_slot().is_some() && !element.is_html_slot_element() && element.assigned_slot().is_some() && context
context.shared.nest(|context| { .shared
.nest(|context| {
matches_complex_selector(selector.iter(), element, context, flags_setter) matches_complex_selector(selector.iter(), element, context, flags_setter)
}) })
}, },
@ -729,7 +729,7 @@ where
None => { None => {
empty_string = ::parser::namespace_empty_string::<E::Impl>(); empty_string = ::parser::namespace_empty_string::<E::Impl>();
NamespaceConstraint::Specific(&empty_string) NamespaceConstraint::Specific(&empty_string)
} },
}; };
element.attr_matches( element.attr_matches(
&namespace, &namespace,
@ -750,7 +750,8 @@ where
}, },
Component::NonTSPseudoClass(ref pc) => { Component::NonTSPseudoClass(ref pc) => {
if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes && if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &&
!context.shared.is_nested() && pc.is_active_or_hover() && !context.shared.is_nested() &&
pc.is_active_or_hover() &&
!element.is_link() !element.is_link()
{ {
return false; return false;

View file

@ -231,9 +231,10 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
{ {
let mut values = SmallVec::new(); let mut values = SmallVec::new();
loop { loop {
values values.push(
.push(input input
.parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?); .parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?,
);
match input.next() { match input.next() {
Err(_) => return Ok(SelectorList(values)), Err(_) => return Ok(SelectorList(values)),
Ok(&Token::Comma) => continue, Ok(&Token::Comma) => continue,
@ -434,7 +435,8 @@ where
ref local_name, ref local_name,
never_matches, never_matches,
.. ..
} if !never_matches => }
if !never_matches =>
{ {
if !visitor.visit_attribute_selector( if !visitor.visit_attribute_selector(
&NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()), &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
@ -451,7 +453,7 @@ where
None => { None => {
empty_string = ::parser::namespace_empty_string::<Impl>(); empty_string = ::parser::namespace_empty_string::<Impl>();
NamespaceConstraint::Specific(&empty_string) NamespaceConstraint::Specific(&empty_string)
} },
}; };
if !visitor.visit_attribute_selector( if !visitor.visit_attribute_selector(
&namespace, &namespace,
@ -536,7 +538,8 @@ impl<Impl: SelectorImpl> Selector<Impl> {
self.iter_raw_match_order().all(|c| { self.iter_raw_match_order().all(|c| {
matches!( matches!(
*c, *c,
Component::ExplicitUniversalType | Component::ExplicitAnyNamespace | Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace |
Component::Combinator(Combinator::PseudoElement) | Component::Combinator(Combinator::PseudoElement) |
Component::PseudoElement(..) Component::PseudoElement(..)
) )
@ -571,7 +574,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
None => return false, None => return false,
Some(combinator) => { Some(combinator) => {
debug_assert_eq!(combinator, Combinator::PseudoElement); debug_assert_eq!(combinator, Combinator::PseudoElement);
} },
} }
iter.is_featureless_host_selector() iter.is_featureless_host_selector()
@ -785,7 +788,9 @@ impl Combinator {
pub fn is_ancestor(&self) -> bool { pub fn is_ancestor(&self) -> bool {
matches!( matches!(
*self, *self,
Combinator::Child | Combinator::Descendant | Combinator::PseudoElement | Combinator::Child |
Combinator::Descendant |
Combinator::PseudoElement |
Combinator::SlotAssignment Combinator::SlotAssignment
) )
} }
@ -976,7 +981,8 @@ impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
W: fmt::Write, W: fmt::Write,
{ {
let mut iter = self.0.iter(); let mut iter = self.0.iter();
let first = iter.next() let first = iter
.next()
.expect("Empty SelectorList, should contain at least one selector"); .expect("Empty SelectorList, should contain at least one selector");
first.to_css(dest)?; first.to_css(dest)?;
for selector in iter { for selector in iter {
@ -1004,10 +1010,12 @@ impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
// which we need for |split|. So we split by combinators on a match-order // which we need for |split|. So we split by combinators on a match-order
// sequence and then reverse. // sequence and then reverse.
let mut combinators = self.iter_raw_match_order() let mut combinators = self
.iter_raw_match_order()
.rev() .rev()
.filter_map(|x| x.as_combinator()); .filter_map(|x| x.as_combinator());
let compound_selectors = self.iter_raw_match_order() let compound_selectors = self
.iter_raw_match_order()
.as_slice() .as_slice()
.split(|x| x.is_combinator()) .split(|x| x.is_combinator())
.rev(); .rev();
@ -1261,7 +1269,7 @@ impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
dest.write_char('|')? dest.write_char('|')?
}, },
Some(NamespaceConstraint::Any) => dest.write_str("*|")?, Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
None => {} None => {},
} }
display_to_css_identifier(&self.local_name, dest)?; display_to_css_identifier(&self.local_name, dest)?;
match self.operation { match self.operation {
@ -1701,8 +1709,7 @@ where
{ {
let local_name_lower_cow = to_ascii_lowercase(&local_name); let local_name_lower_cow = to_ascii_lowercase(&local_name);
if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity { if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
if namespace.is_none() && if namespace.is_none() && include!(concat!(
include!(concat!(
env!("OUT_DIR"), env!("OUT_DIR"),
"/ascii_case_insensitive_html_attributes.rs" "/ascii_case_insensitive_html_attributes.rs"
)).contains(&*local_name_lower_cow) )).contains(&*local_name_lower_cow)
@ -1798,7 +1805,9 @@ where
} }
// Success. // Success.
Ok(Component::Negation(sequence.into_vec().into_boxed_slice().into())) Ok(Component::Negation(
sequence.into_vec().into_boxed_slice().into(),
))
} }
/// simple_selector_sequence /// simple_selector_sequence
@ -2041,9 +2050,7 @@ where
} }
} else { } else {
SimpleSelectorParseResult::PseudoElement(P::parse_pseudo_element( SimpleSelectorParseResult::PseudoElement(P::parse_pseudo_element(
parser, parser, location, name,
location,
name,
)?) )?)
}; };
Ok(Some(parse_result)) Ok(Some(parse_result))
@ -2363,22 +2370,17 @@ pub mod tests {
assert!(parse(":lang(en US)").is_err()); assert!(parse(":lang(en US)").is_err());
assert_eq!( assert_eq!(
parse("EeÉ"), parse("EeÉ"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::LocalName(LocalName {
vec![
Component::LocalName(LocalName {
name: DummyAtom::from("EeÉ"), name: DummyAtom::from("EeÉ"),
lower_name: DummyAtom::from("eeÉ"), lower_name: DummyAtom::from("eeÉ"),
}), }), ],
],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("|e"), parse("|e"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::ExplicitNoNamespace, Component::ExplicitNoNamespace,
Component::LocalName(LocalName { Component::LocalName(LocalName {
@ -2387,24 +2389,19 @@ pub mod tests {
}), }),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
// When the default namespace is not set, *| should be elided. // When the default namespace is not set, *| should be elided.
// https://github.com/servo/servo/pull/17537 // https://github.com/servo/servo/pull/17537
assert_eq!( assert_eq!(
parse_expected("*|e", Some("e")), parse_expected("*|e", Some("e")),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::LocalName(LocalName {
vec![
Component::LocalName(LocalName {
name: DummyAtom::from("e"), name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e"), lower_name: DummyAtom::from("e"),
}), }), ],
],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
// When the default namespace is set, *| should _not_ be elided (as foo // When the default namespace is set, *| should _not_ be elided (as foo
// is no longer equivalent to *|foo--the former is only for foo in the // is no longer equivalent to *|foo--the former is only for foo in the
@ -2415,8 +2412,7 @@ pub mod tests {
"*|e", "*|e",
&DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")) &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
), ),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::ExplicitAnyNamespace, Component::ExplicitAnyNamespace,
Component::LocalName(LocalName { Component::LocalName(LocalName {
@ -2425,73 +2421,65 @@ pub mod tests {
}), }),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("*"), parse("*"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(vec![Component::ExplicitUniversalType], specificity(0, 0, 0)), vec![Component::ExplicitUniversalType],
])) specificity(0, 0, 0)
), ]))
); );
assert_eq!( assert_eq!(
parse("|*"), parse("|*"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::ExplicitNoNamespace, Component::ExplicitNoNamespace,
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_expected("*|*", Some("*")), parse_expected("*|*", Some("*")),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(vec![Component::ExplicitUniversalType], specificity(0, 0, 0)), vec![Component::ExplicitUniversalType],
])) specificity(0, 0, 0)
), ]))
); );
assert_eq!( assert_eq!(
parse_ns( parse_ns(
"*|*", "*|*",
&DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")) &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
), ),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::ExplicitAnyNamespace, Component::ExplicitAnyNamespace,
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse(".foo:lang(en-US)"), parse(".foo:lang(en-US)"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::Class(DummyAtom::from("foo")), Component::Class(DummyAtom::from("foo")),
Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())), Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
], ],
specificity(0, 2, 0), specificity(0, 2, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("#bar"), parse("#bar"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![Component::ID(DummyAtom::from("bar"))], vec![Component::ID(DummyAtom::from("bar"))],
specificity(1, 0, 0), specificity(1, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("e.foo#bar"), parse("e.foo#bar"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::LocalName(LocalName { Component::LocalName(LocalName {
name: DummyAtom::from("e"), name: DummyAtom::from("e"),
@ -2501,13 +2489,11 @@ pub mod tests {
Component::ID(DummyAtom::from("bar")), Component::ID(DummyAtom::from("bar")),
], ],
specificity(1, 1, 1), specificity(1, 1, 1),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("e.foo #bar"), parse("e.foo #bar"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::LocalName(LocalName { Component::LocalName(LocalName {
name: DummyAtom::from("e"), name: DummyAtom::from("e"),
@ -2518,25 +2504,20 @@ pub mod tests {
Component::ID(DummyAtom::from("bar")), Component::ID(DummyAtom::from("bar")),
], ],
specificity(1, 1, 1), specificity(1, 1, 1),
), ), ]))
]))
); );
// Default namespace does not apply to attribute selectors // Default namespace does not apply to attribute selectors
// https://github.com/mozilla/servo/pull/1652 // https://github.com/mozilla/servo/pull/1652
let mut parser = DummyParser::default(); let mut parser = DummyParser::default();
assert_eq!( assert_eq!(
parse_ns("[Foo]", &parser), parse_ns("[Foo]", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::AttributeInNoNamespaceExists {
vec![
Component::AttributeInNoNamespaceExists {
local_name: DummyAtom::from("Foo"), local_name: DummyAtom::from("Foo"),
local_name_lower: DummyAtom::from("foo"), local_name_lower: DummyAtom::from("foo"),
}, }, ],
],
specificity(0, 1, 0), specificity(0, 1, 0),
), ), ]))
]))
); );
assert!(parse_ns("svg|circle", &parser).is_err()); assert!(parse_ns("svg|circle", &parser).is_err());
parser parser
@ -2544,8 +2525,7 @@ pub mod tests {
.insert(DummyAtom("svg".into()), DummyAtom(SVG.into())); .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
assert_eq!( assert_eq!(
parse_ns("svg|circle", &parser), parse_ns("svg|circle", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()), Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::LocalName(LocalName { Component::LocalName(LocalName {
@ -2554,20 +2534,17 @@ pub mod tests {
}), }),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns("svg|*", &parser), parse_ns("svg|*", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()), Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
// Default namespace does not apply to attribute selectors // Default namespace does not apply to attribute selectors
// https://github.com/mozilla/servo/pull/1652 // https://github.com/mozilla/servo/pull/1652
@ -2576,8 +2553,7 @@ pub mod tests {
parser.default_ns = Some(MATHML.into()); parser.default_ns = Some(MATHML.into());
assert_eq!( assert_eq!(
parse_ns("[Foo]", &parser), parse_ns("[Foo]", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::AttributeInNoNamespaceExists { Component::AttributeInNoNamespaceExists {
@ -2586,14 +2562,12 @@ pub mod tests {
}, },
], ],
specificity(0, 1, 0), specificity(0, 1, 0),
), ), ]))
]))
); );
// Default namespace does apply to type selectors // Default namespace does apply to type selectors
assert_eq!( assert_eq!(
parse_ns("e", &parser), parse_ns("e", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::LocalName(LocalName { Component::LocalName(LocalName {
@ -2602,70 +2576,63 @@ pub mod tests {
}), }),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns("*", &parser), parse_ns("*", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns("*|*", &parser), parse_ns("*|*", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::ExplicitAnyNamespace, Component::ExplicitAnyNamespace,
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
// Default namespace applies to universal and type selectors inside :not and :matches, // Default namespace applies to universal and type selectors inside :not and :matches,
// but not otherwise. // but not otherwise.
assert_eq!( assert_eq!(
parse_ns(":not(.cl)", &parser), parse_ns(":not(.cl)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::Negation( Component::Negation(
vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice().into(), vec![Component::Class(DummyAtom::from("cl"))]
.into_boxed_slice()
.into(),
), ),
], ],
specificity(0, 1, 0), specificity(0, 1, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(*)", &parser), parse_ns(":not(*)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::Negation( Component::Negation(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
].into_boxed_slice().into(), ].into_boxed_slice()
.into(),
), ),
], ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(e)", &parser), parse_ns(":not(e)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::DefaultNamespace(MATHML.into()), Component::DefaultNamespace(MATHML.into()),
Component::Negation( Component::Negation(
@ -2675,64 +2642,54 @@ pub mod tests {
name: DummyAtom::from("e"), name: DummyAtom::from("e"),
lower_name: DummyAtom::from("e"), lower_name: DummyAtom::from("e"),
}), }),
].into_boxed_slice().into(), ].into_boxed_slice()
.into(),
), ),
], ],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("[attr|=\"foo\"]"), parse("[attr|=\"foo\"]"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::AttributeInNoNamespace {
vec![
Component::AttributeInNoNamespace {
local_name: DummyAtom::from("attr"), local_name: DummyAtom::from("attr"),
operator: AttrSelectorOperator::DashMatch, operator: AttrSelectorOperator::DashMatch,
value: DummyAtom::from("foo"), value: DummyAtom::from("foo"),
never_matches: false, never_matches: false,
case_sensitivity: ParsedCaseSensitivity::CaseSensitive, case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
}, }, ],
],
specificity(0, 1, 0), specificity(0, 1, 0),
), ), ]))
]))
); );
// https://github.com/mozilla/servo/issues/1723 // https://github.com/mozilla/servo/issues/1723
assert_eq!( assert_eq!(
parse("::before"), parse("::before"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![Component::PseudoElement(PseudoElement::Before)], vec![Component::PseudoElement(PseudoElement::Before)],
specificity(0, 0, 1) | HAS_PSEUDO_BIT, specificity(0, 0, 1) | HAS_PSEUDO_BIT,
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("::before:hover"), parse("::before:hover"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::PseudoElement(PseudoElement::Before), Component::PseudoElement(PseudoElement::Before),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
], ],
specificity(0, 1, 1) | HAS_PSEUDO_BIT, specificity(0, 1, 1) | HAS_PSEUDO_BIT,
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("::before:hover:hover"), parse("::before:hover:hover"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::PseudoElement(PseudoElement::Before), Component::PseudoElement(PseudoElement::Before),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
], ],
specificity(0, 2, 1) | HAS_PSEUDO_BIT, specificity(0, 2, 1) | HAS_PSEUDO_BIT,
), ), ]))
]))
); );
assert!(parse("::before:hover:active").is_err()); assert!(parse("::before:hover:active").is_err());
assert!(parse("::before:hover .foo").is_err()); assert!(parse("::before:hover .foo").is_err());
@ -2744,8 +2701,7 @@ pub mod tests {
assert!(parse(":: before").is_err()); assert!(parse(":: before").is_err());
assert_eq!( assert_eq!(
parse("div ::after"), parse("div ::after"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::LocalName(LocalName { Component::LocalName(LocalName {
name: DummyAtom::from("div"), name: DummyAtom::from("div"),
@ -2756,21 +2712,18 @@ pub mod tests {
Component::PseudoElement(PseudoElement::After), Component::PseudoElement(PseudoElement::After),
], ],
specificity(0, 0, 2) | HAS_PSEUDO_BIT, specificity(0, 0, 2) | HAS_PSEUDO_BIT,
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse("#d1 > .ok"), parse("#d1 > .ok"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec(
vec![ vec![
Component::ID(DummyAtom::from("d1")), Component::ID(DummyAtom::from("d1")),
Component::Combinator(Combinator::Child), Component::Combinator(Combinator::Child),
Component::Class(DummyAtom::from("ok")), Component::Class(DummyAtom::from("ok")),
], ],
(1 << 20) + (1 << 10) + (0 << 0), (1 << 20) + (1 << 10) + (0 << 0),
), ), ]))
]))
); );
parser.default_ns = None; parser.default_ns = None;
assert!(parse(":not(#provel.old)").is_err()); assert!(parse(":not(#provel.old)").is_err());
@ -2778,96 +2731,81 @@ pub mod tests {
assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok()); assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
assert_eq!( assert_eq!(
parse(":not(#provel)"), parse(":not(#provel)"),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::Negation(
vec![ vec![Component::ID(DummyAtom::from("provel"))]
Component::Negation( .into_boxed_slice()
vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice().into(), .into(),
), ), ],
],
specificity(1, 0, 0), specificity(1, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(svg|circle)", &parser), parse_ns(":not(svg|circle)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::Negation(
vec![
Component::Negation(
vec![ vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()), Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::LocalName(LocalName { Component::LocalName(LocalName {
name: DummyAtom::from("circle"), name: DummyAtom::from("circle"),
lower_name: DummyAtom::from("circle"), lower_name: DummyAtom::from("circle"),
}), }),
].into_boxed_slice().into(), ].into_boxed_slice()
), .into(),
], ), ],
specificity(0, 0, 1), specificity(0, 0, 1),
), ), ]))
]))
); );
// https://github.com/servo/servo/issues/16017 // https://github.com/servo/servo/issues/16017
assert_eq!( assert_eq!(
parse_ns(":not(*)", &parser), parse_ns(":not(*)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::Negation(
vec![ vec![Component::ExplicitUniversalType]
Component::Negation( .into_boxed_slice()
vec![Component::ExplicitUniversalType].into_boxed_slice().into(), .into(),
), ), ],
],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(|*)", &parser), parse_ns(":not(|*)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::Negation(
vec![
Component::Negation(
vec![ vec![
Component::ExplicitNoNamespace, Component::ExplicitNoNamespace,
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
].into_boxed_slice().into(), ].into_boxed_slice()
), .into(),
], ), ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
// *| should be elided if there is no default namespace. // *| should be elided if there is no default namespace.
// https://github.com/servo/servo/pull/17537 // https://github.com/servo/servo/pull/17537
assert_eq!( assert_eq!(
parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")), parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::Negation(
vec![ vec![Component::ExplicitUniversalType]
Component::Negation( .into_boxed_slice()
vec![Component::ExplicitUniversalType].into_boxed_slice().into(), .into(),
), ), ],
],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert_eq!( assert_eq!(
parse_ns(":not(svg|*)", &parser), parse_ns(":not(svg|*)", &parser),
Ok(SelectorList::from_vec(vec![ Ok(SelectorList::from_vec(vec![Selector::from_vec(
Selector::from_vec( vec![Component::Negation(
vec![
Component::Negation(
vec![ vec![
Component::Namespace(DummyAtom("svg".into()), SVG.into()), Component::Namespace(DummyAtom("svg".into()), SVG.into()),
Component::ExplicitUniversalType, Component::ExplicitUniversalType,
].into_boxed_slice().into(), ].into_boxed_slice()
), .into(),
], ), ],
specificity(0, 0, 0), specificity(0, 0, 0),
), ), ]))
]))
); );
assert!(parse("::slotted()").is_err()); assert!(parse("::slotted()").is_err());