diff options
author | Simon Sapin <simon.sapin@exyr.org> | 2015-01-28 16:29:35 +0100 |
---|---|---|
committer | Simon Sapin <simon.sapin@exyr.org> | 2015-01-30 15:07:29 +0100 |
commit | 966af0030a246dfa407d5d17a66020cd331f326d (patch) | |
tree | 43c64db6d1f04dd4f37dc1b4e4d472f712ce8c8f /components | |
parent | 7359f99f201a359aaebf334a1787d1975c9fa7d4 (diff) | |
download | servo-966af0030a246dfa407d5d17a66020cd331f326d.tar.gz servo-966af0030a246dfa407d5d17a66020cd331f326d.zip |
Upgrade to rust-cssparser master.
* Use associated types
* Avoid mutation to gather parsing results.
Diffstat (limited to 'components')
-rw-r--r-- | components/servo/Cargo.lock | 2 | ||||
-rw-r--r-- | components/style/font_face.rs | 48 | ||||
-rw-r--r-- | components/style/lib.rs | 1 | ||||
-rw-r--r-- | components/style/namespaces.rs | 49 | ||||
-rw-r--r-- | components/style/parser.rs | 22 | ||||
-rw-r--r-- | components/style/properties/mod.rs.mako | 55 | ||||
-rw-r--r-- | components/style/selector_matching.rs | 8 | ||||
-rw-r--r-- | components/style/selectors.rs | 31 | ||||
-rw-r--r-- | components/style/stylesheets.rs | 128 |
9 files changed, 181 insertions, 163 deletions
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 66267664a09..01445776c3c 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -134,7 +134,7 @@ dependencies = [ [[package]] name = "cssparser" version = "0.2.0" -source = "git+https://github.com/servo/rust-cssparser#2a8c9f2c5f568495bae16f44b799be39b8efad39" +source = "git+https://github.com/servo/rust-cssparser#f4214c9a7bfafd6f40a62b0726aa0bde900ef0dc" dependencies = [ "encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/style/font_face.rs b/components/style/font_face.rs index d4d18f7960b..0dde375d602 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -52,13 +52,21 @@ pub struct FontFaceRule { pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser) -> Result<FontFaceRule, ()> { - let parser = FontFaceRuleParser { - context: context, - family: None, - src: None, - }; - match DeclarationListParser::new(input, parser).run() { - FontFaceRuleParser { family: Some(family), src: Some(src), .. } => { + let mut family = None; + let mut src = None; + for declaration in DeclarationListParser::new(input, FontFaceRuleParser { context: context }) { + match declaration { + Err(()) => {} + Ok(FontFaceDescriptorDeclaration::Family(value)) => { + family = Some(value); + } + Ok(FontFaceDescriptorDeclaration::Src(value)) => { + src = Some(value); + } + } + } + match (family, src) { + (Some(family), Some(src)) => { Ok(FontFaceRule { family: family, sources: src, @@ -68,30 +76,36 @@ pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser) } } +enum FontFaceDescriptorDeclaration { + Family(String), + Src(Vec<Source>), +} + struct FontFaceRuleParser<'a, 'b: 'a> { context: &'a ParserContext<'b>, - family: Option<String>, - src: Option<Vec<Source>>, } /// Default methods reject all at rules. -impl<'a, 'b> AtRuleParser<(), ()> for FontFaceRuleParser<'a, 'b> {} +impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> { + type Prelude = (); + type AtRule = FontFaceDescriptorDeclaration; +} -impl<'a, 'b> DeclarationParser<()> for FontFaceRuleParser<'a, 'b> { - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { +impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> { + type Declaration = FontFaceDescriptorDeclaration; + + fn parse_value(&self, name: &str, input: &mut Parser) -> Result<FontFaceDescriptorDeclaration, ()> { match_ignore_ascii_case! { name, "font-family" => { - self.family = Some(try!(parse_one_non_generic_family_name(input))); - Ok(()) + Ok(FontFaceDescriptorDeclaration::Family(try!(parse_one_non_generic_family_name(input)))) }, "src" => { - self.src = Some(try!(input.parse_comma_separated(|input| { + Ok(FontFaceDescriptorDeclaration::Src(try!(input.parse_comma_separated(|input| { parse_one_src(self.context, input) - }))); - Ok(()) + })))) } _ => Err(()) } diff --git a/components/style/lib.rs b/components/style/lib.rs index a9863bc1589..0ad51ef559e 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -68,7 +68,6 @@ pub mod selectors; pub mod selector_matching; #[macro_use] pub mod values; pub mod properties; -pub mod namespaces; pub mod node; pub mod media_queries; pub mod font_face; diff --git a/components/style/namespaces.rs b/components/style/namespaces.rs deleted file mode 100644 index 53b6467db9c..00000000000 --- a/components/style/namespaces.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use cssparser::Parser; -use std::collections::HashMap; -use string_cache::{Atom, Namespace}; -use parser::ParserContext; - - -#[derive(Clone)] -pub struct NamespaceMap { - pub default: Option<Namespace>, - pub prefix_map: HashMap<String, Namespace>, -} - - -impl NamespaceMap { - pub fn new() -> NamespaceMap { - NamespaceMap { default: None, prefix_map: HashMap::new() } - } -} - - -pub fn parse_namespace_rule(context: &mut ParserContext, input: &mut Parser) - -> Result<(Option<String>, Namespace), ()> { - let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned()); - let url = try!(input.expect_url_or_string()); - try!(input.expect_exhausted()); - - let namespace = Namespace(Atom::from_slice(url.as_slice())); - let is_duplicate = match prefix { - Some(ref prefix) => { - context.namespaces.prefix_map.insert(prefix.clone(), namespace.clone()).is_some() - } - None => { - let has_default = context.namespaces.default.is_some(); - if !has_default { - context.namespaces.default = Some(namespace.clone()); - } - has_default - } - }; - if is_duplicate { - Err(()) // "Duplicate @namespace rule" - } else { - Ok((prefix, namespace)) - } -} diff --git a/components/style/parser.rs b/components/style/parser.rs index 6619ffd06dd..5219c667dac 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -3,12 +3,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::collections::HashMap; +use string_cache::Namespace; use cssparser::{Parser, SourcePosition}; use url::{Url, UrlParser}; use log; use stylesheets::Origin; -use namespaces::NamespaceMap; + + +pub struct NamespaceMap { + pub default: Option<Namespace>, + pub prefix_map: HashMap<String, Namespace>, +} pub struct ParserContext<'a> { @@ -17,6 +24,19 @@ pub struct ParserContext<'a> { pub namespaces: NamespaceMap, } +impl<'a> ParserContext<'a> { + pub fn new(stylesheet_origin: Origin, base_url: &'a Url) -> ParserContext<'a> { + ParserContext { + stylesheet_origin: stylesheet_origin, + base_url: base_url, + namespaces: NamespaceMap { + default: None, + prefix_map: HashMap::new() + } + } + } +} + impl<'a> ParserContext<'a> { pub fn in_user_agent_stylesheet(&self) -> bool { diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index fe58a488f9b..54a02289ca8 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -21,7 +21,6 @@ use values::specified::BorderStyle; use values::computed; use selector_matching::DeclarationBlock; use parser::ParserContext; -use namespaces::NamespaceMap; use stylesheets::Origin; use self::property_bit_field::PropertyBitField; @@ -2325,57 +2324,57 @@ pub struct PropertyDeclarationBlock { pub fn parse_style_attribute(input: &str, base_url: &Url) -> PropertyDeclarationBlock { - let context = ParserContext { - stylesheet_origin: Origin::Author, - base_url: base_url, - namespaces: NamespaceMap::new(), - }; + let context = ParserContext::new(Origin::Author, base_url); parse_property_declaration_list(&context, &mut Parser::new(input)) } struct PropertyDeclarationParser<'a, 'b: 'a> { context: &'a ParserContext<'b>, - important_declarations: Vec<PropertyDeclaration>, - normal_declarations: Vec<PropertyDeclaration>, } /// Default methods reject all at rules. -impl<'a, 'b> AtRuleParser<(), ()> for PropertyDeclarationParser<'a, 'b> {} +impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> { + type Prelude = (); + type AtRule = (Vec<PropertyDeclaration>, bool); +} -impl<'a, 'b> DeclarationParser<()> for PropertyDeclarationParser<'a, 'b> { - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { +impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> { + type Declaration = (Vec<PropertyDeclaration>, bool); + + fn parse_value(&self, name: &str, input: &mut Parser) -> Result<(Vec<PropertyDeclaration>, bool), ()> { let mut results = vec![]; - let important = try!(input.parse_entirely(|input| { - match PropertyDeclaration::parse(name, self.context, input, &mut results) { - PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {} - _ => return Err(()) - } - Ok(input.try(parse_important).is_ok()) - })); - if important { - self.important_declarations.push_all(results.as_slice()); - } else { - self.normal_declarations.push_all(results.as_slice()); + match PropertyDeclaration::parse(name, self.context, input, &mut results) { + PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {} + _ => return Err(()) } - Ok(()) + let important = input.try(parse_important).is_ok(); + Ok((results, important)) } } pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser) -> PropertyDeclarationBlock { + let mut important_declarations = Vec::new(); + let mut normal_declarations = Vec::new(); let parser = PropertyDeclarationParser { context: context, - important_declarations: vec![], - normal_declarations: vec![], }; - let parser = DeclarationListParser::new(input, parser).run(); + for declaration in DeclarationListParser::new(input, parser) { + if let Ok((results, important)) = declaration { + if important { + important_declarations.push_all(results.as_slice()); + } else { + normal_declarations.push_all(results.as_slice()); + } + } + } PropertyDeclarationBlock { - important: Arc::new(deduplicate_property_declarations(parser.important_declarations)), - normal: Arc::new(deduplicate_property_declarations(parser.normal_declarations)), + important: Arc::new(deduplicate_property_declarations(important_declarations)), + normal: Arc::new(deduplicate_property_declarations(normal_declarations)), } } diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 3809fd7f818..9b81f20060a 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -1166,16 +1166,12 @@ mod tests { /// Helper method to get some Rules from selector strings. /// Each sublist of the result contains the Rules for one StyleRule. fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> { - use namespaces::NamespaceMap; use selectors::parse_selector_list; use stylesheets::Origin; css_selectors.iter().enumerate().map(|(i, selectors)| { - let context = ParserContext { - stylesheet_origin: Origin::Author, - namespaces: NamespaceMap::new(), - base_url: &Url::parse("about:blank").unwrap(), - }; + let url = Url::parse("about:blank").unwrap(); + let context = ParserContext::new(Origin::Author, &url); parse_selector_list(&context, &mut Parser::new(*selectors)) .unwrap().into_iter().map(|s| { Rule { diff --git a/components/style/selectors.rs b/components/style/selectors.rs index a4c4b0bea53..98eb186eb67 100644 --- a/components/style/selectors.rs +++ b/components/style/selectors.rs @@ -12,7 +12,6 @@ use string_cache::{Atom, Namespace}; use url::Url; use parser::ParserContext; -use namespaces::NamespaceMap; use stylesheets::Origin; @@ -196,11 +195,8 @@ fn compute_specificity(mut selector: &CompoundSelector, pub fn parse_author_origin_selector_list_from_str(input: &str) -> Result<SelectorList,()> { - let context = ParserContext { - stylesheet_origin: Origin::Author, - namespaces: NamespaceMap::new(), - base_url: &Url::parse("about:blank").unwrap(), - }; + let url = Url::parse("about:blank").unwrap(); + let context = ParserContext::new(Origin::Author, &url); parse_selector_list(&context, &mut Parser::new(input)) .map(|s| SelectorList { selectors: s }) } @@ -647,7 +643,6 @@ fn parse_pseudo_element(name: &str) -> Result<PseudoElement, ()> { mod tests { use std::sync::Arc; use cssparser::Parser; - use namespaces::NamespaceMap; use stylesheets::Origin; use string_cache::Atom; use parser::ParserContext; @@ -655,16 +650,11 @@ mod tests { use super::*; fn parse(input: &str) -> Result<Vec<Selector>, ()> { - parse_ns(input, NamespaceMap::new()) + parse_ns(input, &ParserContext::new(Origin::Author, &Url::parse("about:blank").unwrap())) } - fn parse_ns(input: &str, namespaces: NamespaceMap) -> Result<Vec<Selector>, ()> { - let context = ParserContext { - stylesheet_origin: Origin::Author, - namespaces: namespaces, - base_url: &Url::parse("about:blank").unwrap(), - }; - parse_selector_list(&context, &mut Parser::new(input)) + fn parse_ns(input: &str, context: &ParserContext) -> Result<Vec<Selector>, ()> { + parse_selector_list(context, &mut Parser::new(input)) } fn specificity(a: u32, b: u32, c: u32) -> u32 { @@ -728,8 +718,9 @@ mod tests { }))); // Default namespace does not apply to attribute selectors // https://github.com/mozilla/servo/pull/1652 - let mut namespaces = NamespaceMap::new(); - assert_eq!(parse_ns("[Foo]", namespaces.clone()), Ok(vec!(Selector { + let url = Url::parse("about:blank").unwrap(); + let mut context = ParserContext::new(Origin::Author, &url); + assert_eq!(parse_ns("[Foo]", &context), Ok(vec!(Selector { compound_selectors: Arc::new(CompoundSelector { simple_selectors: vec!(SimpleSelector::AttrExists(AttrSelector { name: Atom::from_slice("Foo"), @@ -743,8 +734,8 @@ mod tests { }))); // Default namespace does not apply to attribute selectors // https://github.com/mozilla/servo/pull/1652 - namespaces.default = Some(ns!(MathML)); - assert_eq!(parse_ns("[Foo]", namespaces.clone()), Ok(vec!(Selector { + context.namespaces.default = Some(ns!(MathML)); + assert_eq!(parse_ns("[Foo]", &context), Ok(vec!(Selector { compound_selectors: Arc::new(CompoundSelector { simple_selectors: vec!(SimpleSelector::AttrExists(AttrSelector { name: Atom::from_slice("Foo"), @@ -757,7 +748,7 @@ mod tests { specificity: specificity(0, 1, 0), }))); // Default namespace does apply to type selectors - assert_eq!(parse_ns("e", namespaces), Ok(vec!(Selector { + assert_eq!(parse_ns("e", &context), Ok(vec!(Selector { compound_selectors: Arc::new(CompoundSelector { simple_selectors: vec!( SimpleSelector::Namespace(ns!(MathML)), diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 7d9aeaf0297..bfe6c48cc66 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use std::cell::Cell; use std::iter::Iterator; use std::ascii::AsciiExt; use url::Url; @@ -10,11 +11,10 @@ use encoding::EncodingRef; use cssparser::{Parser, decode_stylesheet_bytes, QualifiedRuleParser, AtRuleParser, RuleListParser, AtRuleType}; -use string_cache::Namespace; +use string_cache::{Atom, Namespace}; use selectors::{Selector, parse_selector_list}; use parser::ParserContext; use properties::{PropertyDeclarationBlock, parse_property_declaration_list}; -use namespaces::{NamespaceMap, parse_namespace_rule}; use media_queries::{self, Device, MediaQueryList, parse_media_query_list}; use font_face::{FontFaceRule, Source, parse_font_face_block, iter_font_face_rules_inner}; @@ -85,18 +85,26 @@ impl Stylesheet { } pub fn from_str<'i>(css: &'i str, base_url: Url, origin: Origin) -> Stylesheet { - let mut context = ParserContext { - stylesheet_origin: origin, - base_url: &base_url, - namespaces: NamespaceMap::new() + let rule_parser = TopLevelRuleParser { + context: ParserContext::new(origin, &base_url), + state: Cell::new(State::Start), }; - let rule_parser = MainRuleParser { - context: &mut context, - state: State::Start, - }; - let rules = RuleListParser::new_for_stylesheet(&mut Parser::new(css), rule_parser) - .filter_map(|result| result.ok()) - .collect(); + let mut input = Parser::new(css); + let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); + let mut rules = Vec::new(); + while let Some(result) = iter.next() { + if let Ok(rule) = result { + if let CSSRule::Namespace(ref prefix, ref namespace) = rule { + if let Some(prefix) = prefix.as_ref() { + iter.parser.context.namespaces.prefix_map.insert( + prefix.clone(), namespace.clone()); + } else { + iter.parser.context.namespaces.default = Some(namespace.clone()); + } + } + rules.push(rule); + } + } Stylesheet { origin: origin, rules: rules, @@ -105,24 +113,19 @@ impl Stylesheet { } -fn parse_nested_rules(context: &mut ParserContext, input: &mut Parser) -> Vec<CSSRule> { - let parser = MainRuleParser { - context: context, - state: State::Body, - }; - RuleListParser::new_for_nested_rule(input, parser) +fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CSSRule> { + RuleListParser::new_for_nested_rule(input, NestedRuleParser { context: context }) .filter_map(|result| result.ok()) .collect() } -struct MainRuleParser<'a, 'b: 'a> { - context: &'a mut ParserContext<'b>, - state: State, +struct TopLevelRuleParser<'a> { + context: ParserContext<'a>, + state: Cell<State>, } - -#[derive(Eq, PartialEq, Ord, PartialOrd)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Copy)] enum State { Start = 1, Imports = 2, @@ -137,14 +140,17 @@ enum AtRulePrelude { } -impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> { - fn parse_prelude(&mut self, name: &str, input: &mut Parser) +impl<'a> AtRuleParser for TopLevelRuleParser<'a> { + type Prelude = AtRulePrelude; + type AtRule = CSSRule; + + fn parse_prelude(&self, name: &str, input: &mut Parser) -> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> { match_ignore_ascii_case! { name, "charset" => { - if self.state <= State::Start { + if self.state.get() <= State::Start { // Valid @charset rules are just ignored - self.state = State::Imports; + self.state.set(State::Imports); let charset = try!(input.expect_string()).into_owned(); return Ok(AtRuleType::WithoutBlock(CSSRule::Charset(charset))) } else { @@ -152,8 +158,8 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> { } }, "import" => { - if self.state <= State::Imports { - self.state = State::Imports; + if self.state.get() <= State::Imports { + self.state.set(State::Imports); // TODO: support @import return Err(()) // "@import is not supported yet" } else { @@ -161,10 +167,12 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> { } }, "namespace" => { - if self.state <= State::Namespaces { - self.state = State::Namespaces; - let (prefix, namespace) = try!(parse_namespace_rule(self.context, input)); - return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, namespace))) + if self.state.get() <= State::Namespaces { + self.state.set(State::Namespaces); + + let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned()); + let url = Namespace(Atom::from_slice(try!(input.expect_url_or_string()).as_slice())); + return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, url))) } else { return Err(()) // "@namespace must be before any rule but @charset and @import" } @@ -172,8 +180,46 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> { _ => {} } - self.state = State::Body; + self.state.set(State::Body); + AtRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, name, input) + } + + #[inline] + fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> { + AtRuleParser::parse_block(&NestedRuleParser { context: &self.context }, prelude, input) + } +} + + +impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> { + type Prelude = Vec<Selector>; + type QualifiedRule = CSSRule; + #[inline] + fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> { + self.state.set(State::Body); + QualifiedRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, input) + } + + #[inline] + fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> { + QualifiedRuleParser::parse_block(&NestedRuleParser { context: &self.context }, + prelude, input) + } +} + + +struct NestedRuleParser<'a, 'b: 'a> { + context: &'a ParserContext<'b>, +} + + +impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { + type Prelude = AtRulePrelude; + type AtRule = CSSRule; + + fn parse_prelude(&self, name: &str, input: &mut Parser) + -> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> { match_ignore_ascii_case! { name, "media" => { let media_queries = parse_media_query_list(input); @@ -186,7 +232,7 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> { } } - fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> { + fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> { match prelude { AtRulePrelude::FontFace => { parse_font_face_block(self.context, input).map(CSSRule::FontFace) @@ -202,13 +248,15 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> { } -impl<'a, 'b> QualifiedRuleParser<Vec<Selector>, CSSRule> for MainRuleParser<'a, 'b> { - fn parse_prelude(&mut self, input: &mut Parser) -> Result<Vec<Selector>, ()> { - self.state = State::Body; +impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { + type Prelude = Vec<Selector>; + type QualifiedRule = CSSRule; + + fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> { parse_selector_list(self.context, input) } - fn parse_block(&mut self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> { + fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> { Ok(CSSRule::Style(StyleRule { selectors: prelude, declarations: parse_property_declaration_list(self.context, input) |