mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
auto merge of #1147 : SimonSapin/servo/refactor-selector-parsing, r=pcwalton
This commit is contained in:
commit
69699600e4
1 changed files with 67 additions and 63 deletions
|
@ -203,18 +203,18 @@ fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
-> Option<(~[SimpleSelector], Option<PseudoElement>)> {
|
-> Option<(~[SimpleSelector], Option<PseudoElement>)> {
|
||||||
let mut empty = true;
|
let mut empty = true;
|
||||||
let mut simple_selectors = match parse_type_selector(iter, namespaces) {
|
let mut simple_selectors = match parse_type_selector(iter, namespaces) {
|
||||||
None => return None, // invalid selector
|
InvalidTypeSelector => return None,
|
||||||
Some(None) => ~[],
|
NotATypeSelector => ~[],
|
||||||
Some(Some(s)) => { empty = false; s }
|
TypeSelector(s) => { empty = false; s }
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pseudo_element = None;
|
let mut pseudo_element = None;
|
||||||
loop {
|
loop {
|
||||||
match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false) {
|
match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ false) {
|
||||||
None => return None, // invalid selector
|
InvalidSimpleSelector => return None,
|
||||||
Some(None) => break,
|
NotASimpleSelector => break,
|
||||||
Some(Some(Left(s))) => { simple_selectors.push(s); empty = false },
|
SimpleSelectorResult(s) => { simple_selectors.push(s); empty = false },
|
||||||
Some(Some(Right(p))) => { pseudo_element = Some(p); break },
|
PseudoElementResult(p) => { pseudo_element = Some(p); break },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if empty { None } // An empty selector is invalid
|
if empty { None } // An empty selector is invalid
|
||||||
|
@ -222,16 +222,19 @@ fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// None means invalid selector
|
enum TypeSelectorParseResult {
|
||||||
// Some(None) means no type selector.
|
InvalidTypeSelector,
|
||||||
// Some(Some(~[...])) is a type selector. Might be empty for *|*
|
NotATypeSelector,
|
||||||
|
TypeSelector(~[SimpleSelector]), // 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(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
-> Option<Option<~[SimpleSelector]>> {
|
-> TypeSelectorParseResult {
|
||||||
skip_whitespace(iter);
|
skip_whitespace(iter);
|
||||||
match parse_qualified_name(iter, /* allow_universal = */ true, namespaces) {
|
match parse_qualified_name(iter, /* allow_universal = */ true, namespaces) {
|
||||||
None => None, // invalid selector
|
InvalidQualifiedName => InvalidTypeSelector,
|
||||||
Some(None) => Some(None),
|
NotAQualifiedName => NotATypeSelector,
|
||||||
Some(Some((namespace, local_name))) => {
|
QualifiedName(namespace, local_name) => {
|
||||||
let mut simple_selectors = ~[];
|
let mut simple_selectors = ~[];
|
||||||
match namespace {
|
match namespace {
|
||||||
Some(url) => simple_selectors.push(NamespaceSelector(url)),
|
Some(url) => simple_selectors.push(NamespaceSelector(url)),
|
||||||
|
@ -241,36 +244,39 @@ fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
Some(name) => simple_selectors.push(LocalNameSelector(name)),
|
Some(name) => simple_selectors.push(LocalNameSelector(name)),
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
Some(Some(simple_selectors))
|
TypeSelector(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
|
||||||
// None means invalid selector
|
|
||||||
// Some(None) means not a simple name
|
|
||||||
// Some(Some(Left(s)) is a simple selector
|
|
||||||
// Some(Some(Right(p)) is a pseudo-element
|
|
||||||
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
|
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
|
||||||
-> Option<Option<Either<SimpleSelector, PseudoElement>>> {
|
-> SimpleSelectorParseResult {
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&IDHash(_)) => match iter.next() {
|
Some(&IDHash(_)) => match iter.next() {
|
||||||
Some(IDHash(id)) => Some(Some(Left(IDSelector(id)))),
|
Some(IDHash(id)) => SimpleSelectorResult(IDSelector(id)),
|
||||||
_ => fail!("Implementation error, this should not happen."),
|
_ => fail!("Implementation error, this should not happen."),
|
||||||
},
|
},
|
||||||
Some(&Delim('.')) => {
|
Some(&Delim('.')) => {
|
||||||
iter.next();
|
iter.next();
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ident(class)) => Some(Some(Left(ClassSelector(class)))),
|
Some(Ident(class)) => SimpleSelectorResult(ClassSelector(class)),
|
||||||
_ => None, // invalid selector
|
_ => InvalidSimpleSelector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(&SquareBracketBlock(_)) => match iter.next() {
|
Some(&SquareBracketBlock(_)) => match iter.next() {
|
||||||
Some(SquareBracketBlock(content))
|
Some(SquareBracketBlock(content))
|
||||||
=> match parse_attribute_selector(content, namespaces) {
|
=> match parse_attribute_selector(content, namespaces) {
|
||||||
None => None,
|
None => InvalidSimpleSelector,
|
||||||
Some(simple_selector) => Some(Some(Left(simple_selector))),
|
Some(simple_selector) => SimpleSelectorResult(simple_selector),
|
||||||
},
|
},
|
||||||
_ => fail!("Implementation error, this should not happen."),
|
_ => fail!("Implementation error, this should not happen."),
|
||||||
},
|
},
|
||||||
|
@ -281,66 +287,65 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
|
||||||
None => match name.to_ascii_lower().as_slice() {
|
None => match name.to_ascii_lower().as_slice() {
|
||||||
// Supported CSS 2.1 pseudo-elements only.
|
// Supported CSS 2.1 pseudo-elements only.
|
||||||
// ** Do not add to this list! **
|
// ** Do not add to this list! **
|
||||||
"before" => Some(Some(Right(Before))),
|
"before" => PseudoElementResult(Before),
|
||||||
"after" => Some(Some(Right(After))),
|
"after" => PseudoElementResult(After),
|
||||||
"first-line" => Some(Some(Right(FirstLine))),
|
"first-line" => PseudoElementResult(FirstLine),
|
||||||
"first-letter" => Some(Some(Right(FirstLetter))),
|
"first-letter" => PseudoElementResult(FirstLetter),
|
||||||
_ => None
|
_ => InvalidSimpleSelector
|
||||||
},
|
},
|
||||||
Some(result) => Some(Some(Left(result))),
|
Some(result) => SimpleSelectorResult(result),
|
||||||
},
|
},
|
||||||
Some(Function(name, arguments)) => match parse_functional_pseudo_class(
|
Some(Function(name, arguments)) => match parse_functional_pseudo_class(
|
||||||
name, arguments, namespaces, inside_negation) {
|
name, arguments, namespaces, inside_negation) {
|
||||||
None => None,
|
None => InvalidSimpleSelector,
|
||||||
Some(simple_selector) => Some(Some(Left(simple_selector))),
|
Some(simple_selector) => SimpleSelectorResult(simple_selector),
|
||||||
},
|
},
|
||||||
Some(Colon) => {
|
Some(Colon) => {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(Ident(name)) => match parse_pseudo_element(name) {
|
Some(Ident(name)) => match parse_pseudo_element(name) {
|
||||||
Some(pseudo_element) => Some(Some(Right(pseudo_element))),
|
Some(pseudo_element) => PseudoElementResult(pseudo_element),
|
||||||
_ => None,
|
_ => InvalidSimpleSelector,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => InvalidSimpleSelector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => InvalidSimpleSelector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Some(None),
|
_ => NotASimpleSelector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// None means invalid selector
|
enum QualifiedNameParseResult {
|
||||||
// Some(None) means not a qualified name
|
InvalidQualifiedName,
|
||||||
// Some(Some((None, None)) means *|*
|
NotAQualifiedName,
|
||||||
// Some(Some((Some(url), None)) means prefix|*
|
QualifiedName(Option<~str>, Option<~str>) // Namespace URL, local name. None means '*'
|
||||||
// Some(Some((None, Some(name)) means *|name
|
}
|
||||||
// Some(Some((Some(url), Some(name))) means prefix|name
|
|
||||||
// ... or equivalent
|
|
||||||
fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &NamespaceMap)
|
fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &NamespaceMap)
|
||||||
-> Option<Option<(Option<~str>, Option<~str>)>> {
|
-> QualifiedNameParseResult {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default_namespace(namespaces: &NamespaceMap, local_name: Option<~str>)
|
fn default_namespace(namespaces: &NamespaceMap, local_name: Option<~str>)
|
||||||
-> Option<Option<(Option<~str>, Option<~str>)>> {
|
-> QualifiedNameParseResult {
|
||||||
Some(Some((namespaces.default.as_ref().map(|url| url.to_owned()), local_name)))
|
QualifiedName(namespaces.default.as_ref().map(|url| url.to_owned()), local_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn explicit_namespace(iter: &mut Iter, allow_universal: bool, namespace_url: Option<~str>)
|
fn explicit_namespace(iter: &mut Iter, allow_universal: bool, namespace_url: Option<~str>)
|
||||||
-> Option<Option<(Option<~str>, Option<~str>)>> {
|
-> QualifiedNameParseResult {
|
||||||
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() {
|
||||||
Some(&Delim('*')) if allow_universal => {
|
Some(&Delim('*')) if allow_universal => {
|
||||||
iter.next();
|
iter.next();
|
||||||
Some(Some((namespace_url, None)))
|
QualifiedName(namespace_url, None)
|
||||||
},
|
},
|
||||||
Some(&Ident(_)) => {
|
Some(&Ident(_)) => {
|
||||||
let local_name = get_next_ident(iter);
|
let local_name = get_next_ident(iter);
|
||||||
Some(Some((namespace_url, Some(local_name))))
|
QualifiedName(namespace_url, Some(local_name))
|
||||||
},
|
},
|
||||||
_ => None, // invalid selector
|
_ => InvalidQualifiedName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,7 +355,7 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&Delim('|')) => {
|
Some(&Delim('|')) => {
|
||||||
let namespace_url = match namespaces.prefix_map.find(&value) {
|
let namespace_url = match namespaces.prefix_map.find(&value) {
|
||||||
None => return None, // Undeclared namespace prefix: invalid selector
|
None => return InvalidQualifiedName, // Undeclared namespace prefix
|
||||||
Some(ref url) => url.to_owned(),
|
Some(ref url) => url.to_owned(),
|
||||||
};
|
};
|
||||||
explicit_namespace(iter, allow_universal, Some(namespace_url))
|
explicit_namespace(iter, allow_universal, Some(namespace_url))
|
||||||
|
@ -364,12 +369,12 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam
|
||||||
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, None),
|
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, None),
|
||||||
_ => {
|
_ => {
|
||||||
if allow_universal { default_namespace(namespaces, None) }
|
if allow_universal { default_namespace(namespaces, None) }
|
||||||
else { None }
|
else { InvalidQualifiedName }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),
|
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),
|
||||||
_ => Some(None),
|
_ => NotAQualifiedName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,10 +383,9 @@ fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMa
|
||||||
-> Option<SimpleSelector> {
|
-> Option<SimpleSelector> {
|
||||||
let iter = &mut content.move_iter().peekable();
|
let iter = &mut content.move_iter().peekable();
|
||||||
let attr = match parse_qualified_name(iter, /* allow_universal = */ false, namespaces) {
|
let attr = match parse_qualified_name(iter, /* allow_universal = */ false, namespaces) {
|
||||||
None => return None, // invalid selector
|
InvalidQualifiedName | NotAQualifiedName => return None,
|
||||||
Some(None) => return None,
|
QualifiedName(_, None) => fail!("Implementation error, this should not happen."),
|
||||||
Some(Some((_, None))) => fail!("Implementation error, this should not happen."),
|
QualifiedName(namespace, Some(local_name)) => AttrSelector {
|
||||||
Some(Some((namespace, Some(local_name)))) => AttrSelector {
|
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
name: local_name,
|
name: local_name,
|
||||||
},
|
},
|
||||||
|
@ -465,11 +469,11 @@ fn parse_negation(arguments: ~[ComponentValue], namespaces: &NamespaceMap)
|
||||||
-> Option<SimpleSelector> {
|
-> Option<SimpleSelector> {
|
||||||
let iter = &mut arguments.move_iter().peekable();
|
let iter = &mut arguments.move_iter().peekable();
|
||||||
Some(Negation(match parse_type_selector(iter, namespaces) {
|
Some(Negation(match parse_type_selector(iter, namespaces) {
|
||||||
None => return None, // invalid selector
|
InvalidTypeSelector => return None,
|
||||||
Some(Some(s)) => s,
|
TypeSelector(s) => s,
|
||||||
Some(None) => {
|
NotATypeSelector => {
|
||||||
match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true) {
|
match parse_one_simple_selector(iter, namespaces, /* inside_negation = */ true) {
|
||||||
Some(Some(Left(s))) => ~[s],
|
SimpleSelectorResult(s) => ~[s],
|
||||||
_ => return None
|
_ => return None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue