auto merge of #1147 : SimonSapin/servo/refactor-selector-parsing, r=pcwalton

This commit is contained in:
bors-servo 2013-10-29 16:57:55 -07:00
commit 69699600e4

View file

@ -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
} }
}, },