mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Take an iterator when parsing selectors.
This commit is contained in:
parent
5f3dc55f72
commit
4ca385ba10
3 changed files with 35 additions and 38 deletions
|
@ -925,7 +925,7 @@ mod tests {
|
||||||
|
|
||||||
let namespaces = NamespaceMap::new();
|
let namespaces = NamespaceMap::new();
|
||||||
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
||||||
parse_selector_list(tokenize(*selectors).map(|(c, _)| c).collect(), &namespaces)
|
parse_selector_list(tokenize(*selectors).map(|(c, _)| c), &namespaces)
|
||||||
.unwrap().move_iter().map(|s| {
|
.unwrap().move_iter().map(|s| {
|
||||||
Rule {
|
Rule {
|
||||||
selector: s.compound_selectors.clone(),
|
selector: s.compound_selectors.clone(),
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use std::{cmp, iter};
|
use std::{cmp, iter};
|
||||||
use std::ascii::{StrAsciiExt, OwnedStrAsciiExt};
|
use std::ascii::{StrAsciiExt, OwnedStrAsciiExt};
|
||||||
use std::vec;
|
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
use cssparser::ast::*;
|
use cssparser::ast::*;
|
||||||
|
@ -113,13 +112,10 @@ pub enum NamespaceConstraint {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Iter = iter::Peekable<ComponentValue, vec::MoveItems<ComponentValue>>;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_selector_list_from_str(input: &str) -> Result<SelectorList, ()> {
|
pub fn parse_selector_list_from_str(input: &str) -> Result<SelectorList, ()> {
|
||||||
let namespaces = NamespaceMap::new();
|
let namespaces = NamespaceMap::new();
|
||||||
let input = tokenize(input).map(|(token, _)| token).collect();
|
let iter = tokenize(input).map(|(token, _)| token);
|
||||||
parse_selector_list(input, &namespaces).map(|s| SelectorList { selectors: s })
|
parse_selector_list(iter, &namespaces).map(|s| SelectorList { selectors: s })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-exported to script, but opaque.
|
/// Re-exported to script, but opaque.
|
||||||
|
@ -136,9 +132,10 @@ pub fn get_selector_list_selectors<'a>(selector_list: &'a SelectorList) -> &'a [
|
||||||
/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping
|
/// aka Selector Group in http://www.w3.org/TR/css3-selectors/#grouping
|
||||||
///
|
///
|
||||||
/// Return the Selectors or None if there is an invalid selector.
|
/// Return the Selectors or None if there is an invalid selector.
|
||||||
pub fn parse_selector_list(input: Vec<ComponentValue>, namespaces: &NamespaceMap)
|
pub fn parse_selector_list<I: Iterator<ComponentValue>>(
|
||||||
|
iter: I, namespaces: &NamespaceMap)
|
||||||
-> Result<Vec<Selector>, ()> {
|
-> Result<Vec<Selector>, ()> {
|
||||||
let iter = &mut input.move_iter().peekable();
|
let iter = &mut iter.peekable();
|
||||||
let mut results = vec![try!(parse_selector(iter, namespaces))];
|
let mut results = vec![try!(parse_selector(iter, namespaces))];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -156,11 +153,14 @@ pub fn parse_selector_list(input: Vec<ComponentValue>, namespaces: &NamespaceMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Iter<I> = iter::Peekable<ComponentValue, I>;
|
||||||
|
|
||||||
/// Build up a Selector.
|
/// Build up a Selector.
|
||||||
/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
|
/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
|
||||||
///
|
///
|
||||||
/// None means invalid selector.
|
/// `Err` means invalid selector.
|
||||||
fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
fn parse_selector<I: Iterator<ComponentValue>>(
|
||||||
|
iter: &mut Iter<I>, namespaces: &NamespaceMap)
|
||||||
-> Result<Selector, ()> {
|
-> Result<Selector, ()> {
|
||||||
let (first, mut pseudo_element) = try!(parse_simple_selectors(iter, namespaces));
|
let (first, mut pseudo_element) = try!(parse_simple_selectors(iter, namespaces));
|
||||||
let mut compound = CompoundSelector{ simple_selectors: first, next: None };
|
let mut compound = CompoundSelector{ simple_selectors: first, next: None };
|
||||||
|
@ -253,8 +253,9 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
/// | [ HASH | class | attrib | pseudo | negation ]+
|
/// | [ HASH | class | attrib | pseudo | negation ]+
|
||||||
///
|
///
|
||||||
/// `Err(())` means invalid selector
|
/// `Err(())` means invalid selector
|
||||||
fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
|
fn parse_simple_selectors<I: Iterator<ComponentValue>>(
|
||||||
-> Result<(Vec<SimpleSelector>, Option<PseudoElement>), ()> {
|
iter: &mut Iter<I>, namespaces: &NamespaceMap)
|
||||||
|
-> Result<(Vec<SimpleSelector>, Option<PseudoElement>), ()> {
|
||||||
let mut empty = true;
|
let mut empty = true;
|
||||||
let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) {
|
let mut simple_selectors = match try!(parse_type_selector(iter, namespaces)) {
|
||||||
None => vec![],
|
None => vec![],
|
||||||
|
@ -277,7 +278,8 @@ fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
/// * `Err(())`: Invalid selector, abort
|
/// * `Err(())`: Invalid selector, abort
|
||||||
/// * `Ok(None)`: Not a type selector, could be something else. `iter` was not consumed.
|
/// * `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`)
|
/// * `Ok(Some(vec))`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
|
||||||
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
fn parse_type_selector<I: Iterator<ComponentValue>>(
|
||||||
|
iter: &mut Iter<I>, namespaces: &NamespaceMap)
|
||||||
-> Result<Option<Vec<SimpleSelector>>, ()> {
|
-> Result<Option<Vec<SimpleSelector>>, ()> {
|
||||||
skip_whitespace(iter);
|
skip_whitespace(iter);
|
||||||
match try!(parse_qualified_name(iter, /* in_attr_selector = */ false, namespaces)) {
|
match try!(parse_qualified_name(iter, /* in_attr_selector = */ false, namespaces)) {
|
||||||
|
@ -313,8 +315,9 @@ enum SimpleSelectorParseResult {
|
||||||
/// * `Err(())`: Invalid selector, abort
|
/// * `Err(())`: Invalid selector, abort
|
||||||
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
||||||
/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
|
/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
|
||||||
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
|
fn parse_one_simple_selector<I: Iterator<ComponentValue>>(
|
||||||
-> Result<Option<SimpleSelectorParseResult>, ()> {
|
iter: &mut Iter<I>, namespaces: &NamespaceMap, inside_negation: bool)
|
||||||
|
-> Result<Option<SimpleSelectorParseResult>, ()> {
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&IDHash(_)) => match iter.next() {
|
Some(&IDHash(_)) => match iter.next() {
|
||||||
Some(IDHash(id)) => Ok(Some(SimpleSelectorResult(
|
Some(IDHash(id)) => Ok(Some(SimpleSelectorResult(
|
||||||
|
@ -372,21 +375,18 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
|
||||||
/// * `Err(())`: Invalid selector, abort
|
/// * `Err(())`: Invalid selector, abort
|
||||||
/// * `Ok(None)`: Not a simple selector, could be something else. `iter` was not consumed.
|
/// * `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
|
/// * `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)
|
fn parse_qualified_name<I: Iterator<ComponentValue>>(
|
||||||
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
|
iter: &mut Iter<I>, in_attr_selector: bool, namespaces: &NamespaceMap)
|
||||||
#[inline]
|
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
|
||||||
fn default_namespace(namespaces: &NamespaceMap, local_name: Option<String>)
|
let default_namespace = |local_name| {
|
||||||
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
|
|
||||||
let namespace = match namespaces.default {
|
let namespace = match namespaces.default {
|
||||||
Some(ref ns) => SpecificNamespace(ns.clone()),
|
Some(ref ns) => SpecificNamespace(ns.clone()),
|
||||||
None => AnyNamespace,
|
None => AnyNamespace,
|
||||||
};
|
};
|
||||||
Ok(Some((namespace, local_name)))
|
Ok(Some((namespace, local_name)))
|
||||||
}
|
};
|
||||||
|
|
||||||
#[inline]
|
let explicit_namespace = |iter: &mut Iter<I>, namespace| {
|
||||||
fn explicit_namespace(iter: &mut Iter, in_attr_selector: bool, namespace: NamespaceConstraint)
|
|
||||||
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
|
|
||||||
assert!(iter.next() == Some(Delim('|')),
|
assert!(iter.next() == Some(Delim('|')),
|
||||||
"Implementation error, this should not happen.");
|
"Implementation error, this should not happen.");
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
|
@ -400,7 +400,7 @@ fn parse_qualified_name(iter: &mut Iter, in_attr_selector: bool, namespaces: &Na
|
||||||
},
|
},
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&Ident(_)) => {
|
Some(&Ident(_)) => {
|
||||||
|
@ -411,25 +411,24 @@ fn parse_qualified_name(iter: &mut Iter, in_attr_selector: bool, namespaces: &Na
|
||||||
None => return Err(()), // Undeclared namespace prefix
|
None => return Err(()), // Undeclared namespace prefix
|
||||||
Some(ref ns) => (*ns).clone(),
|
Some(ref ns) => (*ns).clone(),
|
||||||
};
|
};
|
||||||
explicit_namespace(iter, in_attr_selector, SpecificNamespace(namespace))
|
explicit_namespace(iter, SpecificNamespace(namespace))
|
||||||
},
|
},
|
||||||
_ if in_attr_selector => Ok(Some(
|
_ if in_attr_selector => Ok(Some(
|
||||||
(SpecificNamespace(namespace::Null), Some(value)))),
|
(SpecificNamespace(namespace::Null), Some(value)))),
|
||||||
_ => default_namespace(namespaces, Some(value)),
|
_ => default_namespace(Some(value)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(&Delim('*')) => {
|
Some(&Delim('*')) => {
|
||||||
iter.next(); // Consume '*'
|
iter.next(); // Consume '*'
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&Delim('|')) => explicit_namespace(iter, in_attr_selector, AnyNamespace),
|
Some(&Delim('|')) => explicit_namespace(iter, AnyNamespace),
|
||||||
_ => {
|
_ => {
|
||||||
if !in_attr_selector { default_namespace(namespaces, None) }
|
if !in_attr_selector { default_namespace(None) }
|
||||||
else { Err(()) }
|
else { Err(()) }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(&Delim('|')) => explicit_namespace(
|
Some(&Delim('|')) => explicit_namespace(iter, SpecificNamespace(namespace::Null)),
|
||||||
iter, in_attr_selector, SpecificNamespace(namespace::Null)),
|
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,7 +552,7 @@ fn parse_negation(arguments: Vec<ComponentValue>, namespaces: &NamespaceMap)
|
||||||
|
|
||||||
/// Assuming the next token is an ident, consume it and return its value
|
/// Assuming the next token is an ident, consume it and return its value
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_next_ident(iter: &mut Iter) -> String {
|
fn get_next_ident<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) -> String {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ident(value)) => value,
|
Some(Ident(value)) => value,
|
||||||
_ => fail!("Implementation error, this should not happen."),
|
_ => fail!("Implementation error, this should not happen."),
|
||||||
|
@ -562,7 +561,7 @@ fn get_next_ident(iter: &mut Iter) -> String {
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn skip_whitespace(iter: &mut Iter) -> bool {
|
fn skip_whitespace<I: Iterator<ComponentValue>>(iter: &mut Iter<I>) -> bool {
|
||||||
let mut any_whitespace = false;
|
let mut any_whitespace = false;
|
||||||
loop {
|
loop {
|
||||||
if iter.peek() != Some(&WhiteSpace) { return any_whitespace }
|
if iter.peek() != Some(&WhiteSpace) { return any_whitespace }
|
||||||
|
@ -586,9 +585,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> {
|
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> {
|
||||||
parse_selector_list(
|
parse_selector_list(cssparser::tokenize(input).map(|(v, _)| v), namespaces)
|
||||||
cssparser::tokenize(input).map(|(v, _)| v).collect(),
|
|
||||||
namespaces)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn specificity(a: u32, b: u32, c: u32) -> u32 {
|
fn specificity(a: u32, b: u32, c: u32) -> u32 {
|
||||||
|
|
|
@ -129,7 +129,7 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut Vec<CSSRule>,
|
||||||
let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
|
let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
|
||||||
// FIXME: avoid doing this for valid selectors
|
// FIXME: avoid doing this for valid selectors
|
||||||
let serialized = prelude.iter().to_css();
|
let serialized = prelude.iter().to_css();
|
||||||
match selectors::parse_selector_list(prelude, namespaces) {
|
match selectors::parse_selector_list(prelude.move_iter(), namespaces) {
|
||||||
Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
|
||||||
selectors: selectors,
|
selectors: selectors,
|
||||||
declarations: properties::parse_property_declaration_list(block.move_iter(), base_url)
|
declarations: properties::parse_property_declaration_list(block.move_iter(), base_url)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue