mirror of
https://github.com/servo/servo.git
synced 2025-08-09 23:45:35 +01:00
Fix SimonSapin/servo-style#2: failed assertion in selector parsing.
Add a test: "parse bootstrap.css without failing"
This commit is contained in:
parent
8abab6f546
commit
25d6448f28
5 changed files with 6831 additions and 12 deletions
25
selectors.rs
25
selectors.rs
|
@ -214,8 +214,8 @@ fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
|
|
||||||
|
|
||||||
// None means invalid selector
|
// None means invalid selector
|
||||||
// Some(None) means no type selector
|
// Some(None) means no type selector.
|
||||||
// Some(Some([...])) is a type selector. Might be empty for *|*
|
// Some(Some(~[...])) is a type selector. Might be empty for *|*
|
||||||
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
-> Option<Option<~[SimpleSelector]>> {
|
-> Option<Option<~[SimpleSelector]>> {
|
||||||
skip_whitespace(iter);
|
skip_whitespace(iter);
|
||||||
|
@ -242,6 +242,10 @@ fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
|
||||||
|
|
||||||
|
|
||||||
// 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>>> {
|
-> Option<Option<Either<SimpleSelector, PseudoElement>>> {
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
|
@ -292,6 +296,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// None means invalid selector
|
// None means invalid selector
|
||||||
// Some(None) means not a qualified name
|
// Some(None) means not a qualified name
|
||||||
// Some(Some((None, None)) means *|*
|
// Some(Some((None, None)) means *|*
|
||||||
|
@ -304,16 +309,14 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam
|
||||||
#[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>)>> {
|
-> Option<Option<(Option<~str>, Option<~str>)>> {
|
||||||
match namespaces.default {
|
Some(Some((namespaces.default.map(|url| url.to_owned()), local_name)))
|
||||||
None => Some(Some((None, local_name))),
|
|
||||||
Some(ref url) => Some(Some((Some(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>)>> {
|
-> Option<Option<(Option<~str>, Option<~str>)>> {
|
||||||
assert!(iter.next() == Some(Delim('|')));
|
assert!(iter.next() == Some(Delim('|')),
|
||||||
|
"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();
|
||||||
|
@ -331,24 +334,24 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam
|
||||||
Some(&Ident(_)) => {
|
Some(&Ident(_)) => {
|
||||||
let value = get_next_ident(iter);
|
let value = get_next_ident(iter);
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&Delim('|')) => default_namespace(namespaces, Some(value)),
|
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 None, // Undeclared namespace prefix: invalid selector
|
||||||
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))
|
||||||
},
|
},
|
||||||
|
_ => default_namespace(namespaces, Some(value)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(&Delim('*')) => {
|
Some(&Delim('*')) => {
|
||||||
iter.next(); // Consume '*'
|
iter.next(); // Consume '*'
|
||||||
match iter.peek() {
|
match iter.peek() {
|
||||||
Some(&Delim('|')) => {
|
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 { None }
|
||||||
},
|
},
|
||||||
_ => explicit_namespace(iter, allow_universal, None),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),
|
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),
|
||||||
|
|
|
@ -15,3 +15,6 @@ pub mod properties;
|
||||||
pub mod namespaces;
|
pub mod namespaces;
|
||||||
pub mod media_queries;
|
pub mod media_queries;
|
||||||
pub mod parsing_utils;
|
pub mod parsing_utils;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub struct StyleRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_stylesheet(css: &str) -> Stylesheet {
|
pub fn parse_stylesheet(css: &str) -> Stylesheet {
|
||||||
static STATE_CHARSET: uint = 1;
|
static STATE_CHARSET: uint = 1;
|
||||||
static STATE_IMPORTS: uint = 2;
|
static STATE_IMPORTS: uint = 2;
|
||||||
static STATE_NAMESPACES: uint = 3;
|
static STATE_NAMESPACES: uint = 3;
|
||||||
|
|
6805
tests/bootstrap-v3.0.0.css
vendored
Normal file
6805
tests/bootstrap-v3.0.0.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
8
tests/mod.rs
Normal file
8
tests/mod.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
use super::stylesheets::parse_stylesheet;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bootstrap() {
|
||||||
|
// Test that parsing bootstrap does not trigger an assertion or otherwise fail.
|
||||||
|
let stylesheet = parse_stylesheet(include_str!("bootstrap-v3.0.0.css"));
|
||||||
|
assert!(stylesheet.rules.len() > 100); // This depends on whet selectors are supported.
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue