diff --git a/Cargo.lock b/Cargo.lock index 5abc322a15a..3b97eec46b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -314,7 +314,7 @@ version = "0.0.1" dependencies = [ "azure 0.16.0 (git+https://github.com/servo/rust-azure)", "canvas_traits 0.0.1", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -329,7 +329,7 @@ dependencies = [ name = "canvas_traits" version = "0.0.1" dependencies = [ - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -567,14 +567,14 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.13.7" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -586,7 +586,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1005,7 +1005,7 @@ name = "geckoservo" version = "0.0.1" dependencies = [ "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1072,7 +1072,7 @@ dependencies = [ name = "gfx_tests" version = "0.0.1" dependencies = [ - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.0.1", "ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", @@ -2158,7 +2158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "procedural-masquerade" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2371,7 +2371,7 @@ dependencies = [ "caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "deny_public_fields 0.0.1", "devtools_traits 0.0.1", "dom_struct 0.0.1", @@ -2444,7 +2444,7 @@ dependencies = [ "app_units 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "canvas_traits 0.0.1", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2516,7 +2516,7 @@ name = "selectors" version = "0.19.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2898,7 +2898,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2952,7 +2952,7 @@ version = "0.0.1" dependencies = [ "app_units 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2972,10 +2972,11 @@ name = "style_traits" version = "0.0.1" dependencies = [ "app_units 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.19.0", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2985,7 +2986,7 @@ name = "stylo_tests" version = "0.0.1" dependencies = [ "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "geckoservo 0.0.1", @@ -3565,7 +3566,7 @@ dependencies = [ "checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624" "checksum core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead017dcf77f503dc991f6b52de6084eeea60a94b0a652baa9bf88654a28e83f" "checksum core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9719616a10f717628e074744f8c55df7b450f7a34d29c196d14f4498aad05d" -"checksum cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef6124306e5ebc5ab11891d063aeafdd0cdc308079b708c8b566125f3680292b" +"checksum cssparser 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a5ca71edbab09f8dc1e3d1c132717562c3b01c8598ab669183c5195bb1761" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum dbus 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4aee01fb76ada3e5e7ca642ea6664ebf7308a810739ca2aca44909a1191ac254" @@ -3696,7 +3697,7 @@ dependencies = [ "checksum plane-split 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "556929ef77bf07a9f8584d21382bcebcd6e6f5845d311824d369e1df7cf56d54" "checksum png 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3cb773e9a557edb568ce9935cf783e3cdcabe06a9449d41b3e5506d88e582c82" "checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150" -"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260" +"checksum procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c93cdc1fb30af9ddf3debc4afbdb0f35126cbd99daa229dd76cdd5349b41d989" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 111d92f430e..439064f31a1 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" [dependencies] azure = {git = "https://github.com/servo/rust-azure"} canvas_traits = {path = "../canvas_traits"} -cssparser = "0.13.7" +cssparser = "0.14.0" euclid = "0.13" gleam = "0.4" ipc-channel = "0.7" diff --git a/components/canvas_traits/Cargo.toml b/components/canvas_traits/Cargo.toml index 8af2ed34131..3b1c3a0ff02 100644 --- a/components/canvas_traits/Cargo.toml +++ b/components/canvas_traits/Cargo.toml @@ -10,7 +10,7 @@ name = "canvas_traits" path = "lib.rs" [dependencies] -cssparser = "0.13.7" +cssparser = "0.14.0" euclid = "0.13" heapsize = "0.4" heapsize_derive = "0.1" diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index a842c1189a7..44940fc270e 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -35,7 +35,7 @@ byteorder = "1.0" canvas_traits = {path = "../canvas_traits"} caseless = "0.1.0" cookie = "0.6" -cssparser = "0.13.7" +cssparser = "0.14.0" deny_public_fields = {path = "../deny_public_fields"} devtools_traits = {path = "../devtools_traits"} dom_struct = {path = "../dom_struct"} diff --git a/components/script/dom/canvasgradient.rs b/components/script/dom/canvasgradient.rs index 994582f509b..64df591f760 100644 --- a/components/script/dom/canvasgradient.rs +++ b/components/script/dom/canvasgradient.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use canvas_traits::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle}; -use cssparser::{Parser, RGBA}; +use cssparser::{Parser, ParserInput, RGBA}; use cssparser::Color as CSSColor; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::CanvasGradientBinding; @@ -53,7 +53,8 @@ impl CanvasGradientMethods for CanvasGradient { return Err(Error::IndexSize); } - let mut parser = Parser::new(&color); + let mut input = ParserInput::new(&color); + let mut parser = Parser::new(&mut input); let color = CSSColor::parse(&mut parser); let color = if parser.is_exhausted() { match color { diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 348ec08aced..8fb17c90fea 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -6,7 +6,7 @@ use canvas_traits::{Canvas2dMsg, CanvasCommonMsg, CanvasMsg}; use canvas_traits::{CompositionOrBlending, FillOrStrokeStyle, FillRule}; use canvas_traits::{LineCapStyle, LineJoinStyle, LinearGradientStyle}; use canvas_traits::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply}; -use cssparser::{Parser, RGBA}; +use cssparser::{Parser, ParserInput, RGBA}; use cssparser::Color as CSSColor; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; @@ -463,7 +463,8 @@ impl CanvasRenderingContext2D { } fn parse_color(&self, string: &str) -> Result { - let mut parser = Parser::new(&string); + let mut input = ParserInput::new(string); + let mut parser = Parser::new(&mut input); let color = CSSColor::parse(&mut parser); if parser.is_exhausted() { match color { @@ -1314,7 +1315,8 @@ impl Drop for CanvasRenderingContext2D { } pub fn parse_color(string: &str) -> Result { - let mut parser = Parser::new(&string); + let mut input = ParserInput::new(string); + let mut parser = Parser::new(&mut input); match CSSColor::parse(&mut parser) { Ok(CSSColor::RGBA(rgba)) => { if parser.is_exhausted() { diff --git a/components/script/dom/css.rs b/components/script/dom/css.rs index 521c09ed4c2..66f522b2371 100644 --- a/components/script/dom/css.rs +++ b/components/script/dom/css.rs @@ -2,7 +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 cssparser::{Parser, serialize_identifier}; +use cssparser::{Parser, ParserInput, serialize_identifier}; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use dom::bindings::error::Fallible; use dom::bindings::reflector::Reflector; @@ -39,7 +39,8 @@ impl CSS { /// https://drafts.csswg.org/css-conditional/#dom-css-supports pub fn Supports_(win: &Window, condition: DOMString) -> bool { - let mut input = Parser::new(&condition); + let mut input = ParserInput::new(&condition); + let mut input = Parser::new(&mut input); let cond = parse_condition_or_declaration(&mut input); if let Ok(cond) = cond { let url = win.Document().url(); diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index 42cb4b374fa..469f9b7d026 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -2,7 +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 cssparser::Parser; +use cssparser::{Parser, ParserInput}; use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding; use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding::CSSKeyframesRuleMethods; use dom::bindings::error::ErrorResult; @@ -58,7 +58,8 @@ impl CSSKeyframesRule { /// Given a keyframe selector, finds the index of the first corresponding rule if any fn find_rule(&self, selector: &str) -> Option { - let mut input = Parser::new(selector); + let mut input = ParserInput::new(selector); + let mut input = Parser::new(&mut input); if let Ok(sel) = KeyframeSelector::parse(&mut input) { let guard = self.cssrule.shared_lock().read(); // This finds the *last* element matching a selector diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 6986b0fe03d..1f5535f1b3e 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -2,7 +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 cssparser::Parser; +use cssparser::{Parser, ParserInput}; use dom::bindings::codegen::Bindings::CSSMediaRuleBinding; use dom::bindings::codegen::Bindings::CSSMediaRuleBinding::CSSMediaRuleMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; @@ -69,7 +69,8 @@ impl CSSMediaRule { /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface pub fn set_condition_text(&self, text: DOMString) { - let mut input = Parser::new(&text); + let mut input = ParserInput::new(&text); + let mut input = Parser::new(&mut input); let global = self.global(); let win = global.as_window(); let url = win.get_url(); diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs index 5d01c2cfdd3..2897b47b35f 100644 --- a/components/script/dom/csssupportsrule.rs +++ b/components/script/dom/csssupportsrule.rs @@ -2,7 +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 cssparser::Parser; +use cssparser::{Parser, ParserInput}; use dom::bindings::codegen::Bindings::CSSSupportsRuleBinding; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use dom::bindings::js::Root; @@ -55,7 +55,8 @@ impl CSSSupportsRule { /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface pub fn set_condition_text(&self, text: DOMString) { - let mut input = Parser::new(&text); + let mut input = ParserInput::new(&text); + let mut input = Parser::new(&mut input); let cond = SupportsCondition::parse(&mut input); if let Ok(cond) = cond { let global = self.global(); diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 189410ce77a..b4e7be3203a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2061,7 +2061,7 @@ impl ElementMethods for Element { // https://dom.spec.whatwg.org/#dom-element-matches fn Matches(&self, selectors: DOMString) -> Fallible { match SelectorParser::parse_author_origin_no_namespace(&selectors) { - Err(()) => Err(Error::Syntax), + Err(_) => Err(Error::Syntax), Ok(selectors) => { let mut ctx = MatchingContext::new(MatchingMode::Normal, None); Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx)) @@ -2077,7 +2077,7 @@ impl ElementMethods for Element { // https://dom.spec.whatwg.org/#dom-element-closest fn Closest(&self, selectors: DOMString) -> Fallible>> { match SelectorParser::parse_author_origin_no_namespace(&selectors) { - Err(()) => Err(Error::Syntax), + Err(_) => Err(Error::Syntax), Ok(selectors) => { let root = self.upcast::(); for element in root.inclusive_ancestors() { diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index fc1783985f8..da004317179 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -2,7 +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 cssparser::Parser as CssParser; +use cssparser::{Parser as CssParser, ParserInput}; use dom::attr::Attr; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListBinding::DOMTokenListMethods; @@ -278,7 +278,8 @@ impl HTMLLinkElement { None => "", }; - let mut css_parser = CssParser::new(&mq_str); + let mut input = ParserInput::new(&mq_str); + let mut css_parser = CssParser::new(&mut input); let win = document.window(); let doc_url = document.url(); let context = CssParserContext::new_for_cssom(&doc_url, win.css_error_reporter(), Some(CssRuleType::Media), diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 9f7a36c040c..4067cb7439d 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -2,7 +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 cssparser::Parser as CssParser; +use cssparser::{Parser as CssParser, ParserInput}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HTMLStyleElementBinding; use dom::bindings::codegen::Bindings::HTMLStyleElementBinding::HTMLStyleElementMethods; @@ -91,8 +91,9 @@ impl HTMLStyleElement { PARSING_MODE_DEFAULT, doc.quirks_mode()); let shared_lock = node.owner_doc().style_shared_lock().clone(); + let mut input = ParserInput::new(&mq_str); let mq = Arc::new(shared_lock.wrap( - parse_media_query_list(&context, &mut CssParser::new(&mq_str)))); + parse_media_query_list(&context, &mut CssParser::new(&mut input)))); let loader = StylesheetLoader::for_element(self.upcast()); let sheet = Stylesheet::from_str(&data, win.get_url(), Origin::Author, mq, shared_lock, Some(&loader), diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs index 8915615ca37..d77af9dc1b9 100644 --- a/components/script/dom/medialist.rs +++ b/components/script/dom/medialist.rs @@ -2,7 +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 cssparser::Parser; +use cssparser::{Parser, ParserInput}; use dom::bindings::codegen::Bindings::MediaListBinding; use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; @@ -71,7 +71,8 @@ impl MediaListMethods for MediaList { return; } // Step 3 - let mut parser = Parser::new(&value); + let mut input = ParserInput::new(&value); + let mut parser = Parser::new(&mut input); let global = self.global(); let win = global.as_window(); let url = win.get_url(); @@ -107,7 +108,8 @@ impl MediaListMethods for MediaList { // https://drafts.csswg.org/cssom/#dom-medialist-appendmedium fn AppendMedium(&self, medium: DOMString) { // Step 1 - let mut parser = Parser::new(&medium); + let mut input = ParserInput::new(&medium); + let mut parser = Parser::new(&mut input); let global = self.global(); let win = global.as_window(); let url = win.get_url(); @@ -135,7 +137,8 @@ impl MediaListMethods for MediaList { // https://drafts.csswg.org/cssom/#dom-medialist-deletemedium fn DeleteMedium(&self, medium: DOMString) { // Step 1 - let mut parser = Parser::new(&medium); + let mut input = ParserInput::new(&medium); + let mut parser = Parser::new(&mut input); let global = self.global(); let win = global.as_window(); let url = win.get_url(); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 8dde9cc7b01..ec0a1117669 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -717,7 +717,7 @@ impl Node { // Step 1. match SelectorParser::parse_author_origin_no_namespace(&selectors) { // Step 2. - Err(()) => Err(Error::Syntax), + Err(_) => Err(Error::Syntax), // Step 3. Ok(selectors) => { let mut ctx = MatchingContext::new(MatchingMode::Normal, None); @@ -737,7 +737,7 @@ impl Node { // Step 1. match SelectorParser::parse_author_origin_no_namespace(&selectors) { // Step 2. - Err(()) => Err(Error::Syntax), + Err(_) => Err(Error::Syntax), // Step 3. Ok(selectors) => { let mut descendants = self.traverse_preorder(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index e627721bd05..bcc5a749d33 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -5,7 +5,7 @@ use app_units::Au; use base64; use bluetooth_traits::BluetoothRequest; -use cssparser::Parser; +use cssparser::{Parser, ParserInput}; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; @@ -1003,7 +1003,8 @@ impl WindowMethods for Window { // https://drafts.csswg.org/cssom-view/#dom-window-matchmedia fn MatchMedia(&self, query: DOMString) -> Root { - let mut parser = Parser::new(&query); + let mut input = ParserInput::new(&query); + let mut parser = Parser::new(&mut input); let url = self.get_url(); let quirks_mode = self.Document().quirks_mode(); let context = CssParserContext::new_for_cssom(&url, self.css_error_reporter(), Some(CssRuleType::Media), diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 381e9eead66..c2e7ae3ab6f 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -13,7 +13,7 @@ path = "lib.rs" app_units = "0.4.1" atomic_refcell = "0.1" canvas_traits = {path = "../canvas_traits"} -cssparser = "0.13.7" +cssparser = "0.14.0" euclid = "0.13" gfx_traits = {path = "../gfx_traits"} heapsize = "0.4" diff --git a/components/script_layout_interface/reporter.rs b/components/script_layout_interface/reporter.rs index 12157e646a4..432b6a0b037 100644 --- a/components/script_layout_interface/reporter.rs +++ b/components/script_layout_interface/reporter.rs @@ -9,7 +9,7 @@ use msg::constellation_msg::PipelineId; use script_traits::ConstellationControlMsg; use servo_url::ServoUrl; use std::sync::{Mutex, Arc}; -use style::error_reporting::ParseErrorReporter; +use style::error_reporting::{ParseErrorReporter, ContextualParseError}; #[derive(HeapSizeOf, Clone)] pub struct CSSErrorReporter { @@ -22,12 +22,12 @@ pub struct CSSErrorReporter { } impl ParseErrorReporter for CSSErrorReporter { - fn report_error(&self, - input: &mut Parser, - position: SourcePosition, - message: &str, - url: &ServoUrl, - line_number_offset: u64) { + fn report_error<'a>(&self, + input: &mut Parser, + position: SourcePosition, + error: ContextualParseError<'a>, + url: &ServoUrl, + line_number_offset: u64) { let location = input.source_location(position); let line_offset = location.line + line_number_offset as usize; if log_enabled!(log::LogLevel::Info) { @@ -35,7 +35,7 @@ impl ParseErrorReporter for CSSErrorReporter { url.as_str(), line_offset, location.column, - message) + error.to_string()) } //TODO: report a real filename @@ -44,6 +44,6 @@ impl ParseErrorReporter for CSSErrorReporter { "".to_owned(), location.line, location.column, - message.to_owned())); + error.to_string())); } } diff --git a/components/selectors/Cargo.toml b/components/selectors/Cargo.toml index 90ff6ecaa17..3b619db936e 100644 --- a/components/selectors/Cargo.toml +++ b/components/selectors/Cargo.toml @@ -24,7 +24,7 @@ gecko_like_types = [] [dependencies] bitflags = "0.7" matches = "0.1" -cssparser = "0.13.7" +cssparser = "0.14.0" log = "0.3" fnv = "1.0" phf = "0.7.18" diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index ac269312253..39024502b4d 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -4,6 +4,7 @@ use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator}; use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint}; +use cssparser::{ParseError, BasicParseError}; use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter}; use precomputed_hash::PrecomputedHash; use servo_arc::{Arc, HeaderWithLength, ThinArc}; @@ -43,6 +44,30 @@ fn to_ascii_lowercase(s: &str) -> Cow { } } +#[derive(Clone, Debug, PartialEq)] +pub enum SelectorParseError<'i, T> { + PseudoElementInComplexSelector, + NoQualifiedNameInAttributeSelector, + TooManyCompoundSelectorComponentsInNegation, + NegationSelectorComponentNotNamespace, + NegationSelectorComponentNotLocalName, + EmptySelector, + NonSimpleSelectorInNegation, + UnexpectedTokenInAttributeSelector, + PseudoElementExpectedColon, + PseudoElementExpectedIdent, + UnsupportedPseudoClass, + UnexpectedIdent(Cow<'i, str>), + ExpectedNamespace, + Custom(T), +} + +impl<'a, T> Into>> for SelectorParseError<'a, T> { + fn into(self) -> ParseError<'a, SelectorParseError<'a, T>> { + ParseError::Custom(self) + } +} + macro_rules! with_all_bounds { ( [ $( $InSelector: tt )* ] @@ -97,26 +122,30 @@ with_bounds! { [From + for<'a> From<&'a str>] } -pub trait Parser { +pub trait Parser<'i> { type Impl: SelectorImpl; + type Error: 'i; /// This function can return an "Err" pseudo-element in order to support CSS2.1 /// pseudo-elements. - fn parse_non_ts_pseudo_class(&self, _name: Cow) - -> Result<::NonTSPseudoClass, ()> { - Err(()) + fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>) + -> Result<::NonTSPseudoClass, + ParseError<'i, SelectorParseError<'i, Self::Error>>> { + Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) } - fn parse_non_ts_functional_pseudo_class - (&self, _name: Cow, _arguments: &mut CssParser) - -> Result<::NonTSPseudoClass, ()> + fn parse_non_ts_functional_pseudo_class<'t> + (&self, name: Cow<'i, str>, _arguments: &mut CssParser<'i, 't>) + -> Result<::NonTSPseudoClass, + ParseError<'i, SelectorParseError<'i, Self::Error>>> { - Err(()) + Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) } - fn parse_pseudo_element(&self, _name: Cow) - -> Result<::PseudoElement, ()> { - Err(()) + fn parse_pseudo_element(&self, name: Cow<'i, str>) + -> Result<::PseudoElement, + ParseError<'i, SelectorParseError<'i, Self::Error>>> { + Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name))) } fn default_namespace(&self) -> Option<::NamespaceUrl> { @@ -157,8 +186,9 @@ impl SelectorList { /// https://drafts.csswg.org/selectors/#grouping /// /// Return the Selectors or Err if there is an invalid selector. - pub fn parse

(parser: &P, input: &mut CssParser) -> Result - where P: Parser { + pub fn parse<'i, 't, P, E>(parser: &P, input: &mut CssParser<'i, 't>) + -> Result>> + where P: Parser<'i, Impl=Impl, Error=E> { input.parse_comma_separated(|input| parse_selector(parser, input).map(SelectorAndHashes::new)) .map(SelectorList) } @@ -960,11 +990,11 @@ type ParseVec = SmallVec<[Component; 32]>; /// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; /// /// `Err` means invalid selector. -fn parse_selector( +fn parse_selector<'i, 't, P, E, Impl>( parser: &P, - input: &mut CssParser) - -> Result, ()> - where P: Parser, Impl: SelectorImpl + input: &mut CssParser<'i, 't>) + -> Result, ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { let mut sequence = ParseVec::new(); let mut parsed_pseudo_element; @@ -983,7 +1013,7 @@ fn parse_selector( loop { let position = input.position(); match input.next_including_whitespace() { - Err(()) => break 'outer_loop, + Err(_e) => break 'outer_loop, Ok(Token::WhiteSpace(_)) => any_whitespace = true, Ok(Token::Delim('>')) => { combinator = Combinator::Child; @@ -1026,12 +1056,13 @@ fn parse_selector( impl Selector { /// Parse a selector, without any pseudo-element. - pub fn parse

(parser: &P, input: &mut CssParser) -> Result - where P: Parser + pub fn parse<'i, 't, P, E>(parser: &P, input: &mut CssParser<'i, 't>) + -> Result>> + where P: Parser<'i, Impl=Impl, Error=E> { let selector = parse_selector(parser, input)?; if selector.has_pseudo_element() { - return Err(()) + return Err(ParseError::Custom(SelectorParseError::PseudoElementInComplexSelector)) } Ok(selector) } @@ -1040,9 +1071,10 @@ impl Selector { /// * `Err(())`: Invalid selector, abort /// * `Ok(None)`: Not a type selector, could be something else. `input` was not consumed. /// * `Ok(Some(vec))`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`) -fn parse_type_selector(parser: &P, input: &mut CssParser, sequence: &mut ParseVec) - -> Result - where P: Parser, Impl: SelectorImpl +fn parse_type_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParser<'i, 't>, + sequence: &mut ParseVec) + -> Result>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? { None => Ok(false), @@ -1100,11 +1132,12 @@ enum QNamePrefix { /// * `Err(())`: Invalid selector, abort /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. /// * `Ok(Some((namespace, local_name)))`: `None` for the local name means a `*` universal selector -fn parse_qualified_name<'i, 't, P, Impl> +fn parse_qualified_name<'i, 't, P, E, Impl> (parser: &P, input: &mut CssParser<'i, 't>, in_attr_selector: bool) - -> Result, Option>)>, ()> - where P: Parser, Impl: SelectorImpl + -> Result, Option>)>, + ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { let default_namespace = |local_name| { let namespace = match parser.default_namespace() { @@ -1122,7 +1155,8 @@ fn parse_qualified_name<'i, 't, P, Impl> Ok(Token::Ident(local_name)) => { Ok(Some((namespace, Some(local_name)))) }, - _ => Err(()), + Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), + Err(e) => Err(ParseError::Basic(e)), } }; @@ -1134,7 +1168,7 @@ fn parse_qualified_name<'i, 't, P, Impl> Ok(Token::Delim('|')) => { let prefix = from_cow_str(value); let result = parser.namespace_for_prefix(&prefix); - let url = result.ok_or(())?; + let url = result.ok_or(ParseError::Custom(SelectorParseError::ExpectedNamespace))?; explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url)) }, _ => { @@ -1153,10 +1187,13 @@ fn parse_qualified_name<'i, 't, P, Impl> Ok(Token::Delim('|')) => { explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace) } - _ => { + result => { input.reset(position); if in_attr_selector { - Err(()) + match result { + Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), + Err(e) => Err(ParseError::Basic(e)), + } } else { default_namespace(None) } @@ -1174,14 +1211,15 @@ fn parse_qualified_name<'i, 't, P, Impl> } -fn parse_attribute_selector(parser: &P, input: &mut CssParser) - -> Result, ()> - where P: Parser, Impl: SelectorImpl +fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParser<'i, 't>) + -> Result, + ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { let namespace; let local_name; match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { - None => return Err(()), + None => return Err(ParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector)), Some((_, None)) => unreachable!(), Some((ns, Some(ln))) => { local_name = ln; @@ -1209,7 +1247,7 @@ fn parse_attribute_selector(parser: &P, input: &mut CssParser) let never_matches; match input.next() { // [foo] - Err(()) => { + Err(_) => { let local_name_lower = from_cow_str(to_ascii_lowercase(&local_name)); let local_name = from_cow_str(local_name); if let Some(namespace) = namespace { @@ -1264,7 +1302,7 @@ fn parse_attribute_selector(parser: &P, input: &mut CssParser) never_matches = value.is_empty(); operator = AttrSelectorOperator::Suffix; } - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedTokenInAttributeSelector.into()) } let mut case_sensitivity = parse_attribute_flags(input)?; @@ -1310,23 +1348,26 @@ fn parse_attribute_selector(parser: &P, input: &mut CssParser) } -fn parse_attribute_flags(input: &mut CssParser) -> Result { +fn parse_attribute_flags<'i, 't, E>(input: &mut CssParser<'i, 't>) + -> Result>> { match input.next() { - Err(()) => Ok(ParsedCaseSensitivity::CaseSensitive), + Err(_) => Ok(ParsedCaseSensitivity::CaseSensitive), Ok(Token::Ident(ref value)) if value.eq_ignore_ascii_case("i") => { Ok(ParsedCaseSensitivity::AsciiCaseInsensitive) } - _ => Err(()) + Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))) } } /// Level 3: Parse **one** simple_selector. (Though we might insert a second /// implied "|*" type selector.) -fn parse_negation(parser: &P, - input: &mut CssParser) - -> Result, ()> - where P: Parser, Impl: SelectorImpl +fn parse_negation<'i, 't, P, E, Impl>(parser: &P, + input: &mut CssParser<'i, 't>) + -> Result, + ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { let mut v = ParseVec::new(); parse_compound_selector(parser, input, &mut v, /* inside_negation = */ true)?; @@ -1334,7 +1375,7 @@ fn parse_negation(parser: &P, if single_simple_selector(&v) { Ok(Component::Negation(v.into_vec().into_boxed_slice())) } else { - Err(()) + Err(ParseError::Custom(SelectorParseError::NonSimpleSelectorInNegation)) } } @@ -1365,13 +1406,13 @@ fn single_simple_selector(v: &[Component]) -> bool { /// `Err(())` means invalid selector. /// /// The boolean represent whether a pseudo-element has been parsed. -fn parse_compound_selector( +fn parse_compound_selector<'i, 't, P, E, Impl>( parser: &P, - input: &mut CssParser, + input: &mut CssParser<'i, 't>, mut sequence: &mut ParseVec, inside_negation: bool) - -> Result - where P: Parser, Impl: SelectorImpl + -> Result>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { // Consume any leading whitespace. loop { @@ -1412,21 +1453,21 @@ fn parse_compound_selector( loop { match input.next_including_whitespace() { Ok(Token::Colon) => {}, - Ok(Token::WhiteSpace(_)) | Err(()) => break, - _ => return Err(()), + Ok(Token::WhiteSpace(_)) | Err(_) => break, + _ => return Err(SelectorParseError::PseudoElementExpectedColon.into()), } // TODO(emilio): Functional pseudo-classes too? // We don't need it for now. let name = match input.next_including_whitespace() { Ok(Token::Ident(name)) => name, - _ => return Err(()), + _ => return Err(SelectorParseError::PseudoElementExpectedIdent.into()), }; let pseudo_class = P::parse_non_ts_pseudo_class(parser, name)?; if !p.supports_pseudo_class(&pseudo_class) { - return Err(()); + return Err(SelectorParseError::UnsupportedPseudoClass.into()); } state_selectors.push(Component::NonTSPseudoClass(pseudo_class)); } @@ -1448,18 +1489,19 @@ fn parse_compound_selector( } if empty { // An empty selector is invalid. - Err(()) + Err(ParseError::Custom(SelectorParseError::EmptySelector)) } else { Ok(pseudo) } } -fn parse_functional_pseudo_class(parser: &P, - input: &mut CssParser, - name: Cow, - inside_negation: bool) - -> Result, ()> - where P: Parser, Impl: SelectorImpl +fn parse_functional_pseudo_class<'i, 't, P, E, Impl>(parser: &P, + input: &mut CssParser<'i, 't>, + name: Cow<'i, str>, + inside_negation: bool) + -> Result, + ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { match_ignore_ascii_case! { &name, "nth-child" => return parse_nth_pseudo_class(input, Component::NthChild), @@ -1468,7 +1510,7 @@ fn parse_functional_pseudo_class(parser: &P, "nth-last-of-type" => return parse_nth_pseudo_class(input, Component::NthLastOfType), "not" => { if inside_negation { - return Err(()) + return Err(ParseError::Custom(SelectorParseError::UnexpectedIdent("not".into()))); } return parse_negation(parser, input) }, @@ -1479,8 +1521,9 @@ fn parse_functional_pseudo_class(parser: &P, } -fn parse_nth_pseudo_class(input: &mut CssParser, selector: F) - -> Result, ()> +fn parse_nth_pseudo_class<'i, 't, Impl, F, E>(input: &mut CssParser<'i, 't>, selector: F) + -> Result, + ParseError<'i, SelectorParseError<'i, E>>> where Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component { let (a, b) = parse_nth(input)?; Ok(selector(a, b)) @@ -1492,11 +1535,12 @@ where Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component { /// * `Err(())`: Invalid selector, abort /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element -fn parse_one_simple_selector(parser: &P, - input: &mut CssParser, - inside_negation: bool) - -> Result>, ()> - where P: Parser, Impl: SelectorImpl +fn parse_one_simple_selector<'i, 't, P, E, Impl>(parser: &P, + input: &mut CssParser<'i, 't>, + inside_negation: bool) + -> Result>, + ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { let start_position = input.position(); match input.next_including_whitespace() { @@ -1510,7 +1554,8 @@ fn parse_one_simple_selector(parser: &P, let class = Component::Class(from_cow_str(class)); Ok(Some(SimpleSelectorParseResult::SimpleSelector(class))) } - _ => Err(()), + Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), + Err(e) => Err(ParseError::Basic(e)), } } Ok(Token::SquareBracketBlock) => { @@ -1545,10 +1590,12 @@ fn parse_one_simple_selector(parser: &P, let pseudo = P::parse_pseudo_element(parser, name)?; Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo))) } - _ => Err(()) + Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), + Err(e) => Err(ParseError::Basic(e)), } } - _ => Err(()) + Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))), + Err(e) => Err(ParseError::Basic(e)), } } _ => { @@ -1558,8 +1605,10 @@ fn parse_one_simple_selector(parser: &P, } } -fn parse_simple_pseudo_class(parser: &P, name: Cow) -> Result, ()> - where P: Parser, Impl: SelectorImpl +fn parse_simple_pseudo_class<'i, P, E, Impl>(parser: &P, name: Cow<'i, str>) + -> Result, + ParseError<'i, SelectorParseError<'i, E>>> + where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl { (match_ignore_ascii_case! { &name, "first-child" => Ok(Component::FirstChild), @@ -1580,7 +1629,7 @@ fn parse_simple_pseudo_class(parser: &P, name: Cow) -> Result Parser<'i> for DummyParser { type Impl = DummySelectorImpl; + type Error = (); - fn parse_non_ts_pseudo_class(&self, name: Cow) - -> Result { + fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>) + -> Result>> { match_ignore_ascii_case! { &name, "hover" => Ok(PseudoClass::Hover), "active" => Ok(PseudoClass::Active), - _ => Err(()) + _ => Err(SelectorParseError::Custom(()).into()) } } - fn parse_non_ts_functional_pseudo_class(&self, name: Cow, - parser: &mut CssParser) - -> Result { + fn parse_non_ts_functional_pseudo_class<'t>(&self, name: Cow<'i, str>, + parser: &mut CssParser<'i, 't>) + -> Result>> { match_ignore_ascii_case! { &name, "lang" => Ok(PseudoClass::Lang(try!(parser.expect_ident_or_string()).into_owned())), - _ => Err(()) + _ => Err(SelectorParseError::Custom(()).into()) } } - fn parse_pseudo_element(&self, name: Cow) -> Result { + fn parse_pseudo_element(&self, name: Cow<'i, str>) + -> Result>> { match_ignore_ascii_case! { &name, "before" => Ok(PseudoElement::Before), "after" => Ok(PseudoElement::After), - _ => Err(()) + _ => Err(SelectorParseError::Custom(()).into()) } } @@ -1729,13 +1783,16 @@ pub mod tests { } } - fn parse(input: &str) -> Result, ()> { + fn parse<'i>(input: &'i str) -> Result, + ParseError<'i, SelectorParseError<'i, ()>>> { parse_ns(input, &DummyParser::default()) } - fn parse_ns(input: &str, parser: &DummyParser) - -> Result, ()> { - let result = SelectorList::parse(parser, &mut CssParser::new(input)); + fn parse_ns<'i>(input: &'i str, parser: &DummyParser) + -> Result, + ParseError<'i, SelectorParseError<'i, ()>>> { + let mut parser_input = ParserInput::new(input); + let result = SelectorList::parse(parser, &mut CssParser::new(&mut parser_input)); if let Ok(ref selectors) = result { assert_eq!(selectors.0.len(), 1); assert_eq!(selectors.0[0].selector.to_css_string(), input); @@ -1749,7 +1806,8 @@ pub mod tests { #[test] fn test_empty() { - let list = SelectorList::parse(&DummyParser::default(), &mut CssParser::new(":empty")); + let mut input = ParserInput::new(":empty"); + let list = SelectorList::parse(&DummyParser::default(), &mut CssParser::new(&mut input)); assert!(list.is_ok()); } @@ -1758,9 +1816,9 @@ pub mod tests { #[test] fn test_parsing() { - assert_eq!(parse(""), Err(())) ; - assert_eq!(parse(":lang(4)"), Err(())) ; - assert_eq!(parse(":lang(en US)"), Err(())) ; + assert!(parse("").is_err()) ; + assert!(parse(":lang(4)").is_err()) ; + assert!(parse(":lang(en US)").is_err()) ; assert_eq!(parse("EeÉ"), Ok(SelectorList::from_vec(vec!( Selector::from_vec(vec!( Component::LocalName(LocalName { @@ -1846,7 +1904,7 @@ pub mod tests { } ), specificity(0, 1, 0)) )))); - assert_eq!(parse_ns("svg|circle", &parser), Err(())); + assert!(parse_ns("svg|circle", &parser).is_err()); parser.ns_prefixes.insert(DummyAtom("svg".into()), DummyAtom(SVG.into())); assert_eq!(parse_ns("svg|circle", &parser), Ok(SelectorList::from_vec(vec!( Selector::from_vec(vec!( @@ -1960,14 +2018,14 @@ pub mod tests { Component::NonTSPseudoClass(PseudoClass::Hover), ), specificity(0, 2, 1) | HAS_PSEUDO_BIT) )))); - assert_eq!(parse("::before:hover:active"), Err(())); - assert_eq!(parse("::before:hover .foo"), Err(())); - assert_eq!(parse("::before .foo"), Err(())); - assert_eq!(parse("::before ~ bar"), Err(())); - assert_eq!(parse("::before:active"), Err(())); + assert!(parse("::before:hover:active").is_err()); + assert!(parse("::before:hover .foo").is_err()); + assert!(parse("::before .foo").is_err()); + assert!(parse("::before ~ bar").is_err()); + assert!(parse("::before:active").is_err()); // https://github.com/servo/servo/issues/15335 - assert_eq!(parse(":: before"), Err(())); + assert!(parse(":: before").is_err()); assert_eq!(parse("div ::after"), Ok(SelectorList::from_vec(vec!( Selector::from_vec(vec!( Component::LocalName(LocalName { @@ -1986,8 +2044,8 @@ pub mod tests { ), (1 << 20) + (1 << 10) + (0 << 0)) )))); parser.default_ns = None; - assert_eq!(parse(":not(#provel.old)"), Err(())); - assert_eq!(parse(":not(#provel > old)"), Err(())); + assert!(parse(":not(#provel.old)").is_err()); + assert!(parse(":not(#provel > old)").is_err()); assert!(parse("table[rules]:not([rules = \"none\"]):not([rules = \"\"])").is_ok()); assert_eq!(parse(":not(#provel)"), Ok(SelectorList::from_vec(vec!( Selector::from_vec(vec!(Component::Negation(vec!( diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index a8751e1646b..1365cd68b73 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -38,7 +38,7 @@ bitflags = "0.7" bit-vec = "0.4.3" byteorder = "1.0" cfg-if = "0.1.0" -cssparser = "0.13.7" +cssparser = "0.14.0" encoding = {version = "0.2", optional = true} euclid = "0.13" fnv = "1.0" diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index 55d1010259c..c5cc7a9745c 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -8,20 +8,22 @@ use Atom; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser}; -use cssparser::{Parser, Token, serialize_identifier}; +use cssparser::{Parser, Token, serialize_identifier, BasicParseError}; +use error_reporting::ContextualParseError; #[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc; use parser::{ParserContext, log_css_error, Parse}; +use selectors::parser::SelectorParseError; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt; use std::ops::Range; -use style_traits::{ToCss, OneOrMoreCommaSeparated}; +use style_traits::{ToCss, OneOrMoreCommaSeparated, ParseError, StyleParseError}; use values::CustomIdent; /// Parse the prelude of an @counter-style rule -pub fn parse_counter_style_name(input: &mut Parser) -> Result { +pub fn parse_counter_style_name<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { macro_rules! predefined { ($($name: expr,)+) => { { @@ -48,8 +50,8 @@ pub fn parse_counter_style_name(input: &mut Parser) -> Result { } /// Parse the body (inside `{}`) of an @counter-style rule -pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, input: &mut Parser) - -> Result { +pub fn parse_counter_style_body<'i, 't>(name: CustomIdent, context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let start = input.position(); let mut rule = CounterStyleRuleData::empty(name); { @@ -59,11 +61,11 @@ pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, inpu }; let mut iter = DeclarationListParser::new(input, parser); while let Some(declaration) = iter.next() { - if let Err(range) = declaration { - let pos = range.start; - let message = format!("Unsupported @counter-style descriptor declaration: '{}'", - iter.input.slice(range)); - log_css_error(iter.input, pos, &*message, context); + if let Err(err) = declaration { + let pos = err.span.start; + let error = ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration( + iter.input.slice(err.span), err.error); + log_css_error(iter.input, pos, error, context); } } } @@ -75,32 +77,28 @@ pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, inpu ref system @ System::Numeric if rule.symbols.is_none() => { let system = system.to_css_string(); - Some(format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system)) + Some(ContextualParseError::InvalidCounterStyleWithoutSymbols(system)) } ref system @ System::Alphabetic | ref system @ System::Numeric if rule.symbols().unwrap().0.len() < 2 => { let system = system.to_css_string(); - Some(format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", - system)) + Some(ContextualParseError::InvalidCounterStyleNotEnoughSymbols(system)) } System::Additive if rule.additive_symbols.is_none() => { - let s = "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'"; - Some(s.to_owned()) + Some(ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols) } System::Extends(_) if rule.symbols.is_some() => { - let s = "Invalid @counter-style rule: 'system: extends …' with 'symbols'"; - Some(s.to_owned()) + Some(ContextualParseError::InvalidCounterStyleExtendsWithSymbols) } System::Extends(_) if rule.additive_symbols.is_some() => { - let s = "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'"; - Some(s.to_owned()) + Some(ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols) } _ => None }; - if let Some(message) = error { - log_css_error(input, start, &message, context); - Err(()) + if let Some(error) = error { + log_css_error(input, start, error, context); + Err(StyleParseError::UnspecifiedError.into()) } else { Ok(rule) } @@ -112,9 +110,10 @@ struct CounterStyleRuleParser<'a, 'b: 'a> { } /// Default methods reject all at rules. -impl<'a, 'b> AtRuleParser for CounterStyleRuleParser<'a, 'b> { +impl<'a, 'b, 'i> AtRuleParser<'i> for CounterStyleRuleParser<'a, 'b> { type Prelude = (); type AtRule = (); + type Error = SelectorParseError<'i, StyleParseError<'i>>; } macro_rules! accessor { @@ -181,11 +180,13 @@ macro_rules! counter_style_descriptors { } } - impl<'a, 'b> DeclarationParser for CounterStyleRuleParser<'a, 'b> { + impl<'a, 'b, 'i> DeclarationParser<'i> for CounterStyleRuleParser<'a, 'b> { type Declaration = (); + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { - match_ignore_ascii_case! { name, + fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>) + -> Result<(), ParseError<'i>> { + match_ignore_ascii_case! { &*name, $( $name => { // DeclarationParser also calls parse_entirely @@ -196,7 +197,7 @@ macro_rules! counter_style_descriptors { self.rule.$ident = Some(value) } )* - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } Ok(()) } @@ -293,8 +294,9 @@ pub enum System { } impl Parse for System { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - match_ignore_ascii_case! { &input.expect_ident()?, + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "cyclic" => Ok(System::Cyclic), "numeric" => Ok(System::Numeric), "alphabetic" => Ok(System::Alphabetic), @@ -309,7 +311,7 @@ impl Parse for System { Ok(System::Extends(other)) } _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } @@ -349,11 +351,12 @@ pub enum Symbol { } impl Parse for Symbol { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { match input.next() { Ok(Token::QuotedString(s)) => Ok(Symbol::String(s.into_owned())), Ok(Token::Ident(s)) => Ok(Symbol::Ident(s.into_owned())), - _ => Err(()) + Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()), + Err(e) => Err(e.into()), } } } @@ -383,7 +386,7 @@ impl Symbol { pub struct Negative(pub Symbol, pub Option); impl Parse for Negative { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { Ok(Negative( Symbol::parse(context, input)?, input.try(|input| Symbol::parse(context, input)).ok(), @@ -409,7 +412,7 @@ impl ToCss for Negative { pub struct Ranges(pub Vec>>); impl Parse for Ranges { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if input.try(|input| input.expect_ident_matching("auto")).is_ok() { Ok(Ranges(Vec::new())) } else { @@ -418,7 +421,7 @@ impl Parse for Ranges { let opt_end = parse_bound(input)?; if let (Some(start), Some(end)) = (opt_start, opt_end) { if start > end { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } } Ok(opt_start..opt_end) @@ -427,11 +430,12 @@ impl Parse for Ranges { } } -fn parse_bound(input: &mut Parser) -> Result, ()> { +fn parse_bound<'i, 't>(input: &mut Parser<'i, 't>) -> Result, ParseError<'i>> { match input.next() { Ok(Token::Number(ref v)) if v.int_value.is_some() => Ok(Some(v.int_value.unwrap())), Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("infinite") => Ok(None), - _ => Err(()) + Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()), + Err(e) => Err(e.into()), } } @@ -471,13 +475,13 @@ fn bound_to_css(range: Option, dest: &mut W) -> fmt::Result where W: fmt pub struct Pad(pub u32, pub Symbol); impl Parse for Pad { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let pad_with = input.try(|input| Symbol::parse(context, input)); let min_length = input.expect_integer()?; if min_length < 0 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } - let pad_with = pad_with.or_else(|()| Symbol::parse(context, input))?; + let pad_with = pad_with.or_else(|_| Symbol::parse(context, input))?; Ok(Pad(min_length as u32, pad_with)) } } @@ -494,7 +498,7 @@ impl ToCss for Pad { pub struct Fallback(pub CustomIdent); impl Parse for Fallback { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { parse_counter_style_name(input).map(Fallback) } } @@ -510,14 +514,14 @@ impl ToCss for Fallback { pub struct Symbols(pub Vec); impl Parse for Symbols { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let mut symbols = Vec::new(); loop { if let Ok(s) = input.try(|input| Symbol::parse(context, input)) { symbols.push(s) } else { if symbols.is_empty() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } else { return Ok(Symbols(symbols)) } @@ -544,11 +548,11 @@ impl ToCss for Symbols { pub struct AdditiveSymbols(pub Vec); impl Parse for AdditiveSymbols { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let tuples = Vec::::parse(context, input)?; // FIXME maybe? https://github.com/w3c/csswg-drafts/issues/1220 if tuples.windows(2).any(|window| window[0].weight <= window[1].weight) { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } Ok(AdditiveSymbols(tuples)) } @@ -572,13 +576,13 @@ pub struct AdditiveTuple { impl OneOrMoreCommaSeparated for AdditiveTuple {} impl Parse for AdditiveTuple { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let symbol = input.try(|input| Symbol::parse(context, input)); let weight = input.expect_integer()?; if weight < 0 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } - let symbol = symbol.or_else(|()| Symbol::parse(context, input))?; + let symbol = symbol.or_else(|_| Symbol::parse(context, input))?; Ok(AdditiveTuple { weight: weight as u32, symbol: symbol, @@ -611,10 +615,11 @@ pub enum SpeakAs { } impl Parse for SpeakAs { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let mut is_spell_out = false; - let result = input.try(|input| { - match_ignore_ascii_case! { &input.expect_ident()?, + let result: Result<_, ParseError> = input.try(|input| { + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "auto" => Ok(SpeakAs::Auto), "bullets" => Ok(SpeakAs::Bullets), "numbers" => Ok(SpeakAs::Numbers), @@ -624,14 +629,14 @@ impl Parse for SpeakAs { Err(()) } _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) }); if is_spell_out { // spell-out is not supported, but don’t parse it as a . // See bug 1024178. - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } - result.or_else(|()| { + result.or_else(|_| { Ok(SpeakAs::Other(parse_counter_style_name(input)?)) }) } diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 15435e4743d..810382acd64 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -7,14 +7,15 @@ //! [custom]: https://drafts.csswg.org/css-variables/ use Atom; -use cssparser::{Delimiter, Parser, SourcePosition, Token, TokenSerializationType}; +use cssparser::{Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSerializationType}; use parser::ParserContext; use properties::{CSSWideKeyword, DeclaredValue}; +use selectors::parser::SelectorParseError; use std::ascii::AsciiExt; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::fmt; -use style_traits::{HasViewportPercentage, ToCss}; +use style_traits::{HasViewportPercentage, ToCss, StyleParseError, ParseError}; use stylearc::Arc; /// A custom property name is just an `Atom`. @@ -131,7 +132,8 @@ impl ComputedValue { impl SpecifiedValue { /// Parse a custom property SpecifiedValue. - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result, ()> { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result, ParseError<'i>> { let mut references = Some(HashSet::new()); let (first, css, last) = try!(parse_self_contained_declaration_value(input, &mut references)); Ok(Box::new(SpecifiedValue { @@ -146,7 +148,7 @@ impl SpecifiedValue { /// Parse the value of a non-custom property that contains `var()` references. pub fn parse_non_custom_with_var<'i, 't> (input: &mut Parser<'i, 't>) - -> Result<(TokenSerializationType, Cow<'i, str>), ()> { + -> Result<(TokenSerializationType, Cow<'i, str>), ParseError<'i>> { let (first_token_type, css, _) = try!(parse_self_contained_declaration_value(input, &mut None)); Ok((first_token_type, css)) } @@ -158,7 +160,7 @@ fn parse_self_contained_declaration_value<'i, 't> TokenSerializationType, Cow<'i, str>, TokenSerializationType - ), ()> { + ), ParseError<'i>> { let start_position = input.position(); let mut missing_closing_characters = String::new(); let (first, last) = try!( @@ -179,7 +181,7 @@ fn parse_declaration_value<'i, 't> (input: &mut Parser<'i, 't>, references: &mut Option>, missing_closing_characters: &mut String) - -> Result<(TokenSerializationType, TokenSerializationType), ()> { + -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i>> { input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| { // Need at least one token let start_position = input.position(); @@ -192,14 +194,16 @@ fn parse_declaration_value<'i, 't> /// Like parse_declaration_value, but accept `!` and `;` since they are only /// invalid at the top level -fn parse_declaration_value_block(input: &mut Parser, +fn parse_declaration_value_block<'i, 't> + (input: &mut Parser<'i, 't>, references: &mut Option>, missing_closing_characters: &mut String) - -> Result<(TokenSerializationType, TokenSerializationType), ()> { + -> Result<(TokenSerializationType, TokenSerializationType), + ParseError<'i>> { let mut token_start = input.position(); let mut token = match input.next_including_whitespace_and_comments() { Ok(token) => token, - Err(()) => return Ok((TokenSerializationType::nothing(), TokenSerializationType::nothing())) + Err(_) => return Ok((TokenSerializationType::nothing(), TokenSerializationType::nothing())) }; let first_token_type = token.serialization_type(); loop { @@ -226,13 +230,16 @@ fn parse_declaration_value_block(input: &mut Parser, } token.serialization_type() } - Token::BadUrl | - Token::BadString | - Token::CloseParenthesis | - Token::CloseSquareBracket | - Token::CloseCurlyBracket => { - return Err(()) - } + Token::BadUrl => + return Err(StyleParseError::BadUrlInDeclarationValueBlock.into()), + Token::BadString => + return Err(StyleParseError::BadStringInDeclarationValueBlock.into()), + Token::CloseParenthesis => + return Err(StyleParseError::UnbalancedCloseParenthesisInDeclarationValueBlock.into()), + Token::CloseSquareBracket => + return Err(StyleParseError::UnbalancedCloseSquareBracketInDeclarationValueBlock.into()), + Token::CloseCurlyBracket => + return Err(StyleParseError::UnbalancedCloseCurlyBracketInDeclarationValueBlock.into()), Token::Function(ref name) => { if name.eq_ignore_ascii_case("var") { let position = input.position(); @@ -303,9 +310,12 @@ fn parse_declaration_value_block(input: &mut Parser, // If the var function is valid, return Ok((custom_property_name, fallback)) fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Option>) - -> Result<(), ()> { + -> Result<(), ParseError<'i>> { let name = try!(input.expect_ident()); - let name = try!(parse_name(&name)); + let name: Result<_, ParseError> = + parse_name(&name) + .map_err(|()| SelectorParseError::UnexpectedIdent(name.clone()).into()); + let name = try!(name); if input.try(|input| input.expect_comma()).is_ok() { // Exclude `!` and `;` at the top level // https://drafts.csswg.org/css-syntax/#typedef-declaration-value @@ -474,7 +484,8 @@ fn substitute_one(name: &Name, } let computed_value = if specified_value.references.map(|set| set.is_empty()) == Some(false) { let mut partial_computed_value = ComputedValue::empty(); - let mut input = Parser::new(&specified_value.css); + let mut input = ParserInput::new(&specified_value.css); + let mut input = Parser::new(&mut input); let mut position = (input.position(), specified_value.first_token_type); let result = substitute_block( &mut input, &mut position, &mut partial_computed_value, @@ -525,11 +536,11 @@ fn substitute_one(name: &Name, /// /// Return `Err(())` if `input` is invalid at computed-value time. /// or `Ok(last_token_type that was pushed to partial_computed_value)` otherwise. -fn substitute_block(input: &mut Parser, - position: &mut (SourcePosition, TokenSerializationType), - partial_computed_value: &mut ComputedValue, - substitute_one: &mut F) - -> Result +fn substitute_block<'i, 't, F>(input: &mut Parser<'i, 't>, + position: &mut (SourcePosition, TokenSerializationType), + partial_computed_value: &mut ComputedValue, + substitute_one: &mut F) + -> Result> where F: FnMut(&Name, &mut ComputedValue) -> Result { let mut last_token_type = TokenSerializationType::nothing(); let mut set_position_at_next_iteration = false; @@ -539,7 +550,7 @@ fn substitute_block(input: &mut Parser, if set_position_at_next_iteration { *position = (before_this_token, match next { Ok(ref token) => token.serialization_type(), - Err(()) => TokenSerializationType::nothing(), + Err(_) => TokenSerializationType::nothing(), }); set_position_at_next_iteration = false; } @@ -605,11 +616,12 @@ fn substitute_block(input: &mut Parser, /// Replace `var()` functions for a non-custom property. /// Return `Err(())` for invalid at computed time. -pub fn substitute(input: &str, first_token_type: TokenSerializationType, - computed_values_map: &Option>>) - -> Result { +pub fn substitute<'i>(input: &'i str, first_token_type: TokenSerializationType, + computed_values_map: &Option>>) + -> Result> { let mut substituted = ComputedValue::empty(); - let mut input = Parser::new(input); + let mut input = ParserInput::new(input); + let mut input = Parser::new(&mut input); let mut position = (input.position(), first_token_type); let last_token_type = try!(substitute_block( &mut input, &mut position, &mut substituted, &mut |name, substituted| { diff --git a/components/style/error_reporting.rs b/components/style/error_reporting.rs index a7458ecd794..590f25b4eb0 100644 --- a/components/style/error_reporting.rs +++ b/components/style/error_reporting.rs @@ -6,22 +6,150 @@ #![deny(missing_docs)] -use cssparser::{Parser, SourcePosition}; +use cssparser::{Parser, SourcePosition, BasicParseError, Token, NumericValue, PercentageValue}; +use cssparser::ParseError as CssParseError; use log; +use style_traits::ParseError; use stylesheets::UrlExtraData; +/// Errors that can be encountered while parsing CSS. +pub enum ContextualParseError<'a> { + /// A property declaration was not recognized. + UnsupportedPropertyDeclaration(&'a str, ParseError<'a>), + /// A font face descriptor was not recognized. + UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>), + /// A keyframe rule was not valid. + InvalidKeyframeRule(&'a str, ParseError<'a>), + /// A keyframe property declaration was not recognized. + UnsupportedKeyframePropertyDeclaration(&'a str, ParseError<'a>), + /// A rule was invalid for some reason. + InvalidRule(&'a str, ParseError<'a>), + /// A rule was not recognized. + UnsupportedRule(&'a str, ParseError<'a>), + /// A viewport descriptor declaration was not recognized. + UnsupportedViewportDescriptorDeclaration(&'a str, ParseError<'a>), + /// A counter style descriptor declaration was not recognized. + UnsupportedCounterStyleDescriptorDeclaration(&'a str, ParseError<'a>), + /// A counter style rule had no symbols. + InvalidCounterStyleWithoutSymbols(String), + /// A counter style rule had less than two symbols. + InvalidCounterStyleNotEnoughSymbols(String), + /// A counter style rule did not have additive-symbols. + InvalidCounterStyleWithoutAdditiveSymbols, + /// A counter style rule had extends with symbols. + InvalidCounterStyleExtendsWithSymbols, + /// A counter style rule had extends with additive-symbols. + InvalidCounterStyleExtendsWithAdditiveSymbols +} + +impl<'a> ContextualParseError<'a> { + /// Turn a parse error into a string representation. + pub fn to_string(&self) -> String { + fn token_to_str(t: &Token) -> String { + match *t { + Token::Ident(ref i) => format!("identifier {}", i), + Token::AtKeyword(ref kw) => format!("keyword @{}", kw), + Token::Hash(ref h) => format!("hash #{}", h), + Token::IDHash(ref h) => format!("id selector #{}", h), + Token::QuotedString(ref s) => format!("quoted string \"{}\"", s), + Token::UnquotedUrl(ref u) => format!("url {}", u), + Token::Delim(ref d) => format!("delimiter {}", d), + Token::Number(NumericValue { int_value: Some(i), .. }) => format!("number {}", i), + Token::Number(ref n) => format!("number {}", n.value), + Token::Percentage(PercentageValue { int_value: Some(i), .. }) => format!("percentage {}", i), + Token::Percentage(ref p) => format!("percentage {}", p.unit_value), + Token::Dimension(_, ref d) => format!("dimension {}", d), + Token::WhiteSpace(_) => format!("whitespace"), + Token::Comment(_) => format!("comment"), + Token::Colon => format!("colon (:)"), + Token::Semicolon => format!("semicolon (;)"), + Token::Comma => format!("comma (,)"), + Token::IncludeMatch => format!("include match (~=)"), + Token::DashMatch => format!("dash match (|=)"), + Token::PrefixMatch => format!("prefix match (^=)"), + Token::SuffixMatch => format!("suffix match ($=)"), + Token::SubstringMatch => format!("substring match (*=)"), + Token::Column => format!("column (||)"), + Token::CDO => format!("CDO ()"), + Token::Function(ref f) => format!("function {}", f), + Token::ParenthesisBlock => format!("parenthesis ("), + Token::SquareBracketBlock => format!("square bracket ["), + Token::CurlyBracketBlock => format!("curly bracket {{"), + Token::BadUrl => format!("bad url parse error"), + Token::BadString => format!("bad string parse error"), + Token::CloseParenthesis => format!("unmatched close parenthesis"), + Token::CloseSquareBracket => format!("unmatched close square bracket"), + Token::CloseCurlyBracket => format!("unmatched close curly bracket"), + } + } + + fn parse_error_to_str(err: &ParseError) -> String { + match *err { + CssParseError::Basic(BasicParseError::UnexpectedToken(ref t)) => + format!("found unexpected {}", token_to_str(t)), + CssParseError::Basic(BasicParseError::ExpectedToken(ref t)) => + format!("expected {}", token_to_str(t)), + CssParseError::Basic(BasicParseError::EndOfInput) => + format!("unexpected end of input"), + CssParseError::Basic(BasicParseError::AtRuleInvalid) => + format!("@ rule invalid"), + CssParseError::Basic(BasicParseError::QualifiedRuleInvalid) => + format!("qualified rule invalid"), + CssParseError::Custom(ref err) => + format!("{:?}", err) + } + } + + match *self { + ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) => + format!("Unsupported property declaration: '{}', {}", decl, + parse_error_to_str(err)), + ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) => + format!("Unsupported @font-face descriptor declaration: '{}', {}", decl, + parse_error_to_str(err)), + ContextualParseError::InvalidKeyframeRule(rule, ref err) => + format!("Invalid keyframe rule: '{}', {}", rule, + parse_error_to_str(err)), + ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) => + format!("Unsupported keyframe property declaration: '{}', {}", decl, + parse_error_to_str(err)), + ContextualParseError::InvalidRule(rule, ref err) => + format!("Invalid rule: '{}', {}", rule, parse_error_to_str(err)), + ContextualParseError::UnsupportedRule(rule, ref err) => + format!("Unsupported rule: '{}', {}", rule, parse_error_to_str(err)), + ContextualParseError::UnsupportedViewportDescriptorDeclaration(decl, ref err) => + format!("Unsupported @viewport descriptor declaration: '{}', {}", decl, + parse_error_to_str(err)), + ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(decl, ref err) => + format!("Unsupported @counter-style descriptor declaration: '{}', {}", decl, + parse_error_to_str(err)), + ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) => + format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system), + ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) => + format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system), + ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols => + "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'".into(), + ContextualParseError::InvalidCounterStyleExtendsWithSymbols => + "Invalid @counter-style rule: 'system: extends …' with 'symbols'".into(), + ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => + "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'".into(), + } + } +} + /// A generic trait for an error reporter. -pub trait ParseErrorReporter : Sync + Send { +pub trait ParseErrorReporter : Sync { /// Called when the style engine detects an error. /// /// Returns the current input being parsed, the source position it was /// reported from, and a message. - fn report_error(&self, - input: &mut Parser, - position: SourcePosition, - message: &str, - url: &UrlExtraData, - line_number_offset: u64); + fn report_error<'a>(&self, + input: &mut Parser, + position: SourcePosition, + error: ContextualParseError<'a>, + url: &UrlExtraData, + line_number_offset: u64); } /// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log) @@ -33,16 +161,16 @@ pub trait ParseErrorReporter : Sync + Send { pub struct RustLogReporter; impl ParseErrorReporter for RustLogReporter { - fn report_error(&self, - input: &mut Parser, - position: SourcePosition, - message: &str, - url: &UrlExtraData, - line_number_offset: u64) { + fn report_error<'a>(&self, + input: &mut Parser, + position: SourcePosition, + error: ContextualParseError<'a>, + url: &UrlExtraData, + line_number_offset: u64) { if log_enabled!(log::LogLevel::Info) { let location = input.source_location(position); let line_offset = location.line + line_number_offset as usize; - info!("Url:\t{}\n{}:{} {}", url.as_str(), line_offset, location.column, message) + info!("Url:\t{}\n{}:{} {}", url.as_str(), line_offset, location.column, error.to_string()) } } } @@ -51,12 +179,17 @@ impl ParseErrorReporter for RustLogReporter { pub struct NullReporter; impl ParseErrorReporter for NullReporter { - fn report_error(&self, + fn report_error<'a>(&self, _: &mut Parser, _: SourcePosition, - _: &str, + _: ContextualParseError<'a>, _: &UrlExtraData, _: u64) { // do nothing } } + +/// Create an instance of the default error reporter. +pub fn create_error_reporter() -> RustLogReporter { + RustLogReporter +} diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 439642f68c9..8346c801d8d 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -13,12 +13,15 @@ use computed_values::{font_feature_settings, font_stretch, font_style, font_weig use computed_values::font_family::FamilyName; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; use cssparser::SourceLocation; +use error_reporting::ContextualParseError; #[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors; #[cfg(feature = "gecko")] use cssparser::UnicodeRange; use parser::{ParserContext, log_css_error, Parse}; +use selectors::parser::SelectorParseError; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; +use std::borrow::Cow; use std::fmt; -use style_traits::{ToCss, OneOrMoreCommaSeparated}; +use style_traits::{ToCss, OneOrMoreCommaSeparated, ParseError, StyleParseError}; use values::specified::url::SpecifiedUrl; /// A source for a font-face rule. @@ -97,11 +100,11 @@ pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser, locati }; let mut iter = DeclarationListParser::new(input, parser); while let Some(declaration) = iter.next() { - if let Err(range) = declaration { - let pos = range.start; - let message = format!("Unsupported @font-face descriptor declaration: '{}'", - iter.input.slice(range)); - log_css_error(iter.input, pos, &*message, context); + if let Err(err) = declaration { + let pos = err.span.start; + let error = ContextualParseError::UnsupportedFontFaceDescriptor( + iter.input.slice(err.span), err.error); + log_css_error(iter.input, pos, error, context); } } } @@ -154,13 +157,15 @@ struct FontFaceRuleParser<'a, 'b: 'a> { } /// Default methods reject all at rules. -impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> { +impl<'a, 'b, 'i> AtRuleParser<'i> for FontFaceRuleParser<'a, 'b> { type Prelude = (); type AtRule = (); + type Error = SelectorParseError<'i, StyleParseError<'i>>; } impl Parse for Source { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_function_matching("local")).is_ok() { return input.parse_nested_block(|input| { FamilyName::parse(context, input) @@ -247,11 +252,13 @@ macro_rules! font_face_descriptors_common { } } - impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> { - type Declaration = (); + impl<'a, 'b, 'i> DeclarationParser<'i> for FontFaceRuleParser<'a, 'b> { + type Declaration = (); + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { - match_ignore_ascii_case! { name, + fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>) + -> Result<(), ParseError<'i>> { + match_ignore_ascii_case! { &*name, $( $name => { // DeclarationParser also calls parse_entirely @@ -262,7 +269,7 @@ macro_rules! font_face_descriptors_common { self.rule.$ident = Some(value) } )* - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } Ok(()) } diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index cc18f056121..6edd5436adb 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -6,7 +6,7 @@ use app_units::Au; use context::QuirksMode; -use cssparser::{CssStringWriter, Parser, RGBA, Token}; +use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseError}; use euclid::Size2D; use font_metrics::get_metrics_provider_for_product; use gecko::values::convert_nscolor_to_rgba; @@ -19,11 +19,12 @@ use media_queries::MediaType; use parser::ParserContext; use properties::{ComputedValues, StyleBuilder}; use properties::longhands::font_size; +use selectors::parser::SelectorParseError; use std::fmt::{self, Write}; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; use str::starts_with_ignore_ascii_case; use string_cache::Atom; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use style_traits::viewport::ViewportConstraints; use stylearc::Arc; use values::{CSSFloat, specified}; @@ -228,24 +229,25 @@ impl Resolution { } } - fn parse(input: &mut Parser) -> Result { + fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let (value, unit) = match try!(input.next()) { Token::Dimension(value, unit) => { - (value.value, unit) + (value, unit) }, - _ => return Err(()), + t => return Err(BasicParseError::UnexpectedToken(t).into()), }; - if value <= 0. { - return Err(()) + let inner_value = value.value; + if inner_value <= 0. { + return Err(StyleParseError::UnspecifiedError.into()) } - Ok(match_ignore_ascii_case! { &unit, - "dpi" => Resolution::Dpi(value), - "dppx" => Resolution::Dppx(value), - "dpcm" => Resolution::Dpcm(value), - _ => return Err(()) - }) + (match_ignore_ascii_case! { &unit, + "dpi" => Ok(Resolution::Dpi(inner_value)), + "dppx" => Ok(Resolution::Dppx(inner_value)), + "dpcm" => Ok(Resolution::Dpcm(inner_value)), + _ => Err(()) + }).map_err(|()| StyleParseError::UnexpectedDimension(unit).into()) } } @@ -459,44 +461,51 @@ impl Expression { /// ``` /// (media-feature: media-value) /// ``` - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { try!(input.expect_parenthesis_block()); input.parse_nested_block(|input| { let ident = try!(input.expect_ident()); let mut flags = 0; - let mut feature_name = &*ident; + let result = { + let mut feature_name = &*ident; - // TODO(emilio): this is under a pref in Gecko. - if starts_with_ignore_ascii_case(feature_name, "-webkit-") { - feature_name = &feature_name[8..]; - flags |= nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8; - } + // TODO(emilio): this is under a pref in Gecko. + if starts_with_ignore_ascii_case(feature_name, "-webkit-") { + feature_name = &feature_name[8..]; + flags |= nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8; + } - let range = if starts_with_ignore_ascii_case(feature_name, "min-") { - feature_name = &feature_name[4..]; - nsMediaExpression_Range::eMin - } else if starts_with_ignore_ascii_case(feature_name, "max-") { - feature_name = &feature_name[4..]; - nsMediaExpression_Range::eMax - } else { - nsMediaExpression_Range::eEqual - }; - - let atom = Atom::from(feature_name); - let feature = - match find_feature(|f| atom.as_ptr() == unsafe { *f.mName }) { - Some(f) => f, - None => return Err(()), + let range = if starts_with_ignore_ascii_case(feature_name, "min-") { + feature_name = &feature_name[4..]; + nsMediaExpression_Range::eMin + } else if starts_with_ignore_ascii_case(feature_name, "max-") { + feature_name = &feature_name[4..]; + nsMediaExpression_Range::eMax + } else { + nsMediaExpression_Range::eEqual }; + let atom = Atom::from(feature_name); + match find_feature(|f| atom.as_ptr() == unsafe { *f.mName }) { + Some(f) => Ok((f, range)), + None => Err(()), + } + }; + + let (feature, range) = match result { + Ok((feature, range)) => (feature, range), + Err(()) => return Err(SelectorParseError::UnexpectedIdent(ident).into()), + }; + if (feature.mReqFlags & !flags) != 0 { - return Err(()); + return Err(SelectorParseError::UnexpectedIdent(ident).into()); } if range != nsMediaExpression_Range::eEqual && feature.mRangeType != nsMediaFeature_RangeType::eMinMaxAllowed { - return Err(()); + return Err(SelectorParseError::UnexpectedIdent(ident).into()); } // If there's no colon, this is a media query of the form @@ -506,7 +515,7 @@ impl Expression { // reject them here too. if input.try(|i| i.expect_colon()).is_err() { if range != nsMediaExpression_Range::eEqual { - return Err(()) + return Err(StyleParseError::RangedExpressionWithNoValue.into()) } return Ok(Expression::new(feature, None, range)); } @@ -519,14 +528,14 @@ impl Expression { nsMediaFeature_ValueType::eInteger => { let i = input.expect_integer()?; if i < 0 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } MediaExpressionValue::Integer(i as u32) } nsMediaFeature_ValueType::eBoolInteger => { let i = input.expect_integer()?; if i < 0 || i > 1 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } MediaExpressionValue::BoolInteger(i == 1) } @@ -536,14 +545,14 @@ impl Expression { nsMediaFeature_ValueType::eIntRatio => { let a = input.expect_integer()?; if a <= 0 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } input.expect_delim('/')?; let b = input.expect_integer()?; if b <= 0 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } MediaExpressionValue::IntRatio(a as u32, b as u32) } @@ -566,7 +575,7 @@ impl Expression { Some((_kw, value)) => { value } - None => return Err(()), + None => return Err(StyleParseError::UnspecifiedError.into()), }; MediaExpressionValue::Enumerated(value) diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 54beb4a4091..c28fb36d632 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -8,11 +8,12 @@ use cssparser::{Parser, ToCss}; use element_state::ElementState; use gecko_bindings::structs::CSSPseudoClassType; use selector_parser::{SelectorParser, PseudoElementCascadeType}; -use selectors::parser::{Selector, SelectorMethods}; +use selectors::parser::{Selector, SelectorMethods, SelectorParseError}; use selectors::visitor::SelectorVisitor; use std::borrow::Cow; use std::fmt; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; +use style_traits::{ParseError, StyleParseError}; pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT}; pub use gecko::snapshot::SnapshotMap; @@ -238,17 +239,20 @@ impl ::selectors::SelectorImpl for SelectorImpl { type NonTSPseudoClass = NonTSPseudoClass; } -impl<'a> ::selectors::Parser for SelectorParser<'a> { +impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { type Impl = SelectorImpl; + type Error = StyleParseError<'i>; - fn parse_non_ts_pseudo_class(&self, name: Cow) -> Result { + fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>) + -> Result> { macro_rules! pseudo_class_parse { (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($css => NonTSPseudoClass::$name,)* - _ => return Err(()) + _ => return Err(::selectors::parser::SelectorParseError::UnexpectedIdent( + name.clone()).into()) } } } @@ -256,14 +260,14 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> { if !pseudo_class.is_internal() || self.in_user_agent_stylesheet() { Ok(pseudo_class) } else { - Err(()) + Err(SelectorParseError::UnexpectedIdent(name).into()) } } - fn parse_non_ts_functional_pseudo_class(&self, - name: Cow, - parser: &mut Parser) - -> Result { + fn parse_non_ts_functional_pseudo_class<'t>(&self, + name: Cow<'i, str>, + parser: &mut Parser<'i, 't>) + -> Result> { macro_rules! pseudo_class_string_parse { (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*], @@ -289,11 +293,11 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> { })?; // Selectors inside `:-moz-any` may not include combinators. if selectors.iter().flat_map(|x| x.iter_raw()).any(|s| s.is_combinator()) { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent("-moz-any".into()).into()) } NonTSPseudoClass::MozAny(selectors.into_boxed_slice()) } - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } } } @@ -301,13 +305,13 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> { if !pseudo_class.is_internal() || self.in_user_agent_stylesheet() { Ok(pseudo_class) } else { - Err(()) + Err(SelectorParseError::UnexpectedIdent(name).into()) } } - fn parse_pseudo_element(&self, name: Cow) -> Result { + fn parse_pseudo_element(&self, name: Cow<'i, str>) -> Result> { PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) - .ok_or(()) + .ok_or(SelectorParseError::UnexpectedIdent(name.clone()).into()) } fn default_namespace(&self) -> Option { diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index 1dfc04d100b..d083aa9c3da 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -11,7 +11,7 @@ use gecko_bindings::sugar::refptr::RefPtr; use parser::ParserContext; use std::borrow::Cow; use std::fmt::{self, Write}; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError}; use stylearc::Arc; /// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls. @@ -38,7 +38,7 @@ impl SpecifiedUrl { /// Returns `Err` in the case that extra_data is incomplete. pub fn parse_from_string<'a>(url: Cow<'a, str>, context: &ParserContext) - -> Result { + -> Result> { Ok(SpecifiedUrl { serialization: Arc::new(url.into_owned()), extra_data: context.url_data.clone(), diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 6c70013d481..2ac03135421 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -21,7 +21,7 @@ use data::ElementData; use dom::{self, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthesizer}; use element_state::ElementState; -use error_reporting::RustLogReporter; +use error_reporting::create_error_reporter; use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult}; use gecko::data::PerDocumentStyleData; use gecko::global_style_data::GLOBAL_STYLE_DATA; @@ -416,7 +416,7 @@ impl<'le> GeckoElement<'le> { pub fn parse_style_attribute(value: &str, url_data: &UrlExtraData, quirks_mode: QuirksMode) -> PropertyDeclarationBlock { - parse_style_attribute(value, url_data, &RustLogReporter, quirks_mode) + parse_style_attribute(value, url_data, &create_error_reporter(), quirks_mode) } fn flags(&self) -> u32 { diff --git a/components/style/macros.rs b/components/style/macros.rs index 092dc7bb8f2..8280f93adb3 100644 --- a/components/style/macros.rs +++ b/components/style/macros.rs @@ -18,11 +18,14 @@ macro_rules! define_numbered_css_keyword_enum { impl $crate::parser::Parse for $name { #[allow(missing_docs)] - fn parse(_context: &$crate::parser::ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> { - match_ignore_ascii_case! { &try!(input.expect_ident()), + fn parse<'i, 't>(_context: &$crate::parser::ParserContext, + input: &mut ::cssparser::Parser<'i, 't>) + -> Result<$name, ::style_traits::ParseError<'i>> { + let ident = try!(input.expect_ident()); + (match_ignore_ascii_case! { &ident, $( $css => Ok($name::$variant), )+ _ => Err(()) - } + }).map_err(|()| ::selectors::parser::SelectorParseError::UnexpectedIdent(ident).into()) } } @@ -49,9 +52,9 @@ macro_rules! add_impls_for_keyword_enum { ($name:ident) => { impl $crate::parser::Parse for $name { #[inline] - fn parse(_context: &$crate::parser::ParserContext, - input: &mut ::cssparser::Parser) - -> Result { + fn parse<'i, 't>(_context: &$crate::parser::ParserContext, + input: &mut ::cssparser::Parser<'i, 't>) + -> Result> { $name::parse(input) } } @@ -89,10 +92,10 @@ macro_rules! define_keyword_type { } impl $crate::parser::Parse for $name { - fn parse(_context: &$crate::parser::ParserContext, - input: &mut ::cssparser::Parser) - -> Result<$name, ()> { - input.expect_ident_matching($css).map(|_| $name) + fn parse<'i, 't>(_context: &$crate::parser::ParserContext, + input: &mut ::cssparser::Parser<'i, 't>) + -> Result<$name, ::style_traits::ParseError<'i>> { + input.expect_ident_matching($css).map(|_| $name).map_err(|e| e.into()) } } diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index 4f1b3d68a12..2737f7bba35 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -8,12 +8,13 @@ use Atom; use context::QuirksMode; -use cssparser::{Delimiter, Parser, Token}; +use cssparser::{Delimiter, Parser, Token, ParserInput}; use parser::ParserContext; +use selectors::parser::SelectorParseError; use serialize_comma_separated_list; use std::ascii::AsciiExt; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; #[cfg(feature = "servo")] pub use servo::media_queries::{Device, Expression}; @@ -209,7 +210,8 @@ impl MediaQuery { /// Parse a media query given css input. /// /// Returns an error if any of the expressions is unknown. - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut expressions = vec![]; let qualifier = if input.try(|input| input.expect_ident_matching("only")).is_ok() { @@ -221,11 +223,15 @@ impl MediaQuery { }; let media_type = match input.try(|input| input.expect_ident()) { - Ok(ident) => try!(MediaQueryType::parse(&*ident)), - Err(()) => { + Ok(ident) => { + let result: Result<_, ParseError> = MediaQueryType::parse(&*ident) + .map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()); + try!(result) + } + Err(_) => { // Media type is only optional if qualifier is not specified. if qualifier.is_some() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } // Without a media type, require at least one expression. @@ -270,7 +276,7 @@ pub fn parse_media_query_list(context: &ParserContext, input: &mut Parser) -> Me match input.next() { Ok(Token::Comma) => {}, Ok(_) => unreachable!(), - Err(()) => break, + Err(_) => break, } } @@ -311,7 +317,8 @@ impl MediaList { /// /// Returns true if added, false if fail to parse the medium string. pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool { - let mut parser = Parser::new(new_medium); + let mut input = ParserInput::new(new_medium); + let mut parser = Parser::new(&mut input); let new_query = match MediaQuery::parse(&context, &mut parser) { Ok(query) => query, Err(_) => { return false; } @@ -329,7 +336,8 @@ impl MediaList { /// /// Returns true if found and deleted, false otherwise. pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool { - let mut parser = Parser::new(old_medium); + let mut input = ParserInput::new(old_medium); + let mut parser = Parser::new(&mut input); let old_query = match MediaQuery::parse(context, &mut parser) { Ok(query) => query, Err(_) => { return false; } diff --git a/components/style/parser.rs b/components/style/parser.rs index 162c690c87c..420572042da 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -6,8 +6,8 @@ use context::QuirksMode; use cssparser::{Parser, SourcePosition, UnicodeRange}; -use error_reporting::ParseErrorReporter; -use style_traits::OneOrMoreCommaSeparated; +use error_reporting::{ParseErrorReporter, ContextualParseError}; +use style_traits::{OneOrMoreCommaSeparated, ParseError}; use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces}; bitflags! { @@ -164,14 +164,14 @@ impl<'a> ParserContext<'a> { /// Defaults to a no-op. /// Set a `RUST_LOG=style::errors` environment variable /// to log CSS parse errors to stderr. -pub fn log_css_error(input: &mut Parser, - position: SourcePosition, - message: &str, - parsercontext: &ParserContext) { +pub fn log_css_error<'a>(input: &mut Parser, + position: SourcePosition, + error: ContextualParseError<'a>, + parsercontext: &ParserContext) { let url_data = parsercontext.url_data; let line_number_offset = parsercontext.line_number_offset; parsercontext.error_reporter.report_error(input, position, - message, url_data, + error, url_data, line_number_offset); } @@ -183,19 +183,21 @@ pub trait Parse : Sized { /// Parse a value of this type. /// /// Returns an error on failure. - fn parse(context: &ParserContext, input: &mut Parser) -> Result; + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result>; } impl Parse for Vec where T: Parse + OneOrMoreCommaSeparated { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { input.parse_comma_separated(|input| T::parse(context, input)) } } /// Parse a non-empty space-separated or comma-separated list of objects parsed by parse_one -pub fn parse_space_or_comma_separated(input: &mut Parser, mut parse_one: F) - -> Result, ()> - where F: FnMut(&mut Parser) -> Result { +pub fn parse_space_or_comma_separated<'i, 't, F, T>(input: &mut Parser<'i, 't>, mut parse_one: F) + -> Result, ParseError<'i>> + where F: for<'ii, 'tt> FnMut(&mut Parser<'ii, 'tt>) -> Result> { let first = parse_one(input)?; let mut vec = vec![first]; loop { @@ -209,7 +211,8 @@ pub fn parse_space_or_comma_separated(input: &mut Parser, mut parse_one: F Ok(vec) } impl Parse for UnicodeRange { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - UnicodeRange::parse(input) + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { + UnicodeRange::parse(input).map_err(|e| e.into()) } } diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index e219bcc69fc..3c36521ba61 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -7,15 +7,16 @@ #![deny(missing_docs)] use context::QuirksMode; -use cssparser::{DeclarationListParser, parse_important}; +use cssparser::{DeclarationListParser, parse_important, ParserInput}; use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter}; -use error_reporting::ParseErrorReporter; +use error_reporting::{ParseErrorReporter, ContextualParseError}; use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error}; use properties::animated_properties::AnimationValue; +use selectors::parser::SelectorParseError; use shared_lock::Locked; use std::fmt; use std::slice::Iter; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use stylesheets::{CssRuleType, Origin, UrlExtraData}; use stylesheets::{MallocSizeOf, MallocSizeOfFn}; use super::*; @@ -875,7 +876,8 @@ pub fn parse_style_attribute(input: &str, Some(CssRuleType::Style), PARSING_MODE_DEFAULT, quirks_mode); - parse_property_declaration_list(&context, &mut Parser::new(input)) + let mut input = ParserInput::new(input); + parse_property_declaration_list(&context, &mut Parser::new(&mut input)) } /// Parse a given property declaration. Can result in multiple @@ -896,10 +898,11 @@ pub fn parse_one_declaration_into(declarations: &mut SourcePropertyDeclaration, Some(CssRuleType::Style), parsing_mode, quirks_mode); - Parser::new(input).parse_entirely(|parser| { + let mut input = ParserInput::new(input); + Parser::new(&mut input).parse_entirely(|parser| { PropertyDeclaration::parse_into(declarations, id, &context, parser) - .map_err(|_| ()) - }) + .map_err(|e| e.into()) + }).map_err(|_| ()) } /// A struct to parse property declarations. @@ -910,23 +913,26 @@ struct PropertyDeclarationParser<'a, 'b: 'a> { /// Default methods reject all at rules. -impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> { +impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b> { type Prelude = (); type AtRule = Importance; + type Error = SelectorParseError<'i, StyleParseError<'i>>; } -impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> { +impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> { type Declaration = Importance; + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result { - let id = try!(PropertyId::parse(name.into())); + fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>) + -> Result> { + let id = try!(PropertyId::parse(name)); input.parse_until_before(Delimiter::Bang, |input| { PropertyDeclaration::parse_into(self.declarations, id, self.context, input) - .map_err(|_| ()) + .map_err(|e| e.into()) })?; let importance = match input.try(parse_important) { Ok(()) => Importance::Important, - Err(()) => Importance::Normal, + Err(_) => Importance::Normal, }; // In case there is still unparsed text in the declaration, we should roll back. input.expect_exhausted()?; @@ -952,12 +958,12 @@ pub fn parse_property_declaration_list(context: &ParserContext, Ok(importance) => { block.extend(iter.parser.declarations.drain(), importance); } - Err(range) => { + Err(err) => { iter.parser.declarations.clear(); - let pos = range.start; - let message = format!("Unsupported property declaration: '{}'", - iter.input.slice(range)); - log_css_error(iter.input, pos, &*message, &context); + let pos = err.span.start; + let error = ContextualParseError::UnsupportedPropertyDeclaration( + iter.input.slice(err.span), err.error); + log_css_error(iter.input, pos, error, &context); } } } diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index c7031be3ebb..c8502551a0e 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -33,9 +33,9 @@ % endif #[allow(unused_variables)] #[inline] - pub fn parse(context: &ParserContext, - input: &mut Parser) - -> Result { + pub fn parse<'i, 't>(context: &ParserContext, + input: &mut Parser<'i, 't>) + -> Result> { % if allow_quirks: specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes) % elif needs_context: @@ -87,12 +87,16 @@ pub mod single_value { #[allow(unused_imports)] - use cssparser::Parser; + use cssparser::{Parser, BasicParseError}; #[allow(unused_imports)] use parser::{Parse, ParserContext}; #[allow(unused_imports)] use properties::ShorthandId; #[allow(unused_imports)] + use selectors::parser::SelectorParseError; + #[allow(unused_imports)] + use style_traits::{ParseError, StyleParseError}; + #[allow(unused_imports)] use values::computed::{Context, ToComputedValue}; #[allow(unused_imports)] use values::{computed, specified}; @@ -207,7 +211,8 @@ % endif } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { #[allow(unused_imports)] use parser::parse_space_or_comma_separated; @@ -266,7 +271,7 @@ pub mod ${property.ident} { % if not property.derived_from: #[allow(unused_imports)] - use cssparser::Parser; + use cssparser::{Parser, BasicParseError, Token}; #[allow(unused_imports)] use parser::{Parse, ParserContext}; #[allow(unused_imports)] @@ -287,8 +292,12 @@ #[allow(unused_imports)] use properties::style_structs; #[allow(unused_imports)] + use selectors::parser::SelectorParseError; + #[allow(unused_imports)] use stylearc::Arc; #[allow(unused_imports)] + use style_traits::{ParseError, StyleParseError}; + #[allow(unused_imports)] use values::computed::{Context, ToComputedValue}; #[allow(unused_imports)] use values::{computed, generics, specified}; @@ -423,12 +432,12 @@ % endif } % if not property.derived_from: - pub fn parse_specified(context: &ParserContext, input: &mut Parser) + pub fn parse_specified<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) % if property.boxed: - -> Result, ()> { + -> Result, ParseError<'i>> { parse(context, input).map(|result| Box::new(result)) % else: - -> Result { + -> Result> { % if property.allow_quirks: parse_quirky(context, input, specified::AllowQuirks::Yes) % else: @@ -436,11 +445,11 @@ % endif % endif } - pub fn parse_declared(context: &ParserContext, input: &mut Parser) - -> Result { + pub fn parse_declared<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { match input.try(|i| CSSWideKeyword::parse(context, i)) { Ok(keyword) => Ok(PropertyDeclaration::CSSWideKeyword(LonghandId::${property.camel_case}, keyword)), - Err(()) => { + Err(_) => { input.look_for_var_functions(); let start = input.position(); let specified = parse_specified(context, input); @@ -487,7 +496,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; - use style_traits::ToCss; + use style_traits::{ToCss, ParseError}; define_css_keyword_enum! { T: % for value in keyword.values_for(product): "${value}" => ${to_rust_ident(value)}, @@ -495,7 +504,7 @@ } impl Parse for T { - fn parse(_: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { T::parse(input) } } @@ -518,7 +527,7 @@ } } - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { Ok(SpecifiedValue::Keyword(computed_value::T::parse(input)?)) } @@ -716,14 +725,14 @@ SpecifiedValue::${to_rust_ident(values.split()[0])} } #[inline] - pub fn parse(_context: &ParserContext, input: &mut Parser) - -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(input) } impl Parse for SpecifiedValue { #[inline] - fn parse(_context: &ParserContext, input: &mut Parser) - -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(input) } } @@ -764,9 +773,11 @@ use parser::ParserContext; use properties::{PropertyDeclaration, SourcePropertyDeclaration, MaybeBoxed}; use properties::{ShorthandId, LonghandId, UnparsedValue, longhands}; + #[allow(unused_imports)] + use selectors::parser::SelectorParseError; use std::fmt; use stylearc::Arc; - use style_traits::ToCss; + use style_traits::{ToCss, ParseError, StyleParseError}; pub struct Longhands { % for sub_property in shorthand.sub_properties: @@ -838,8 +849,8 @@ /// Parse the given shorthand and fill the result into the /// `declarations` vector. - pub fn parse_into(declarations: &mut SourcePropertyDeclaration, - context: &ParserContext, input: &mut Parser) -> Result<(), ()> { + pub fn parse_into<'i, 't>(declarations: &mut SourcePropertyDeclaration, + context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> { input.look_for_var_functions(); let start = input.position(); let value = input.parse_entirely(|input| parse_value(context, input)); @@ -872,7 +883,7 @@ % endfor Ok(()) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -890,7 +901,8 @@ use values::generics::rect::Rect; use values::specified; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let rect = Rect::parse_with(context, input, |_c, i| { % if allow_quirks: ${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes) @@ -1114,7 +1126,8 @@ use values::computed::${length_type}; ${length_type}::${initial_value} } - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % if logical: let ret = ${length_type}::parse(context, input); % else: @@ -1123,7 +1136,7 @@ // Keyword values don't make sense in the block direction; don't parse them % if "block" in name: if let Ok(${length_type}::ExtremumLength(..)) = ret { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } % endif ret.map(SpecifiedValue) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index eea69199f6b..f89bd2ef2db 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -27,12 +27,13 @@ use properties::longhands::transform::computed_value::T as TransformList; use properties::longhands::vertical_align::computed_value::T as VerticalAlign; use properties::longhands::visibility::computed_value::T as Visibility; #[cfg(feature = "gecko")] use properties::{PropertyDeclarationId, LonghandId}; +use selectors::parser::SelectorParseError; #[cfg(feature = "servo")] use servo_atoms::Atom; use smallvec::SmallVec; use std::cmp; #[cfg(feature = "gecko")] use std::collections::HashMap; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError}; use super::ComputedValues; use values::CSSFloat; use values::{Auto, Either}; @@ -99,9 +100,9 @@ impl TransitionProperty { } /// Parse a transition-property value. - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let ident = try!(input.expect_ident()); - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "all" => Ok(TransitionProperty::All), % for prop in data.longhands: % if prop.animatable: @@ -118,7 +119,7 @@ impl TransitionProperty { None => Ok(TransitionProperty::Unsupported((&*ident).into())) } } - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident.into()).into()) } /// Get a transition property from a property declaration. @@ -476,7 +477,7 @@ impl AnimationValue { /// Construct an AnimationValue from a property declaration pub fn from_declaration(decl: &PropertyDeclaration, context: &mut Context, initial: &ComputedValues) -> Option { - use error_reporting::RustLogReporter; + use error_reporting::create_error_reporter; use properties::LonghandId; use properties::DeclaredValue; @@ -539,7 +540,7 @@ impl AnimationValue { }, PropertyDeclaration::WithVariables(id, ref variables) => { let custom_props = context.style().custom_properties(); - let reporter = RustLogReporter; + let reporter = create_error_reporter(); match id { % for prop in data.longhands: % if prop.animatable: diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 9b799c220b9..105a2fbb9f0 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -128,17 +128,20 @@ ${helpers.predefined_type("background-image", "ImageLayer", } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "repeat-x" => Ok(SpecifiedValue::RepeatX), "repeat-y" => Ok(SpecifiedValue::RepeatY), - _ => { - let horizontal = try!(RepeatKeyword::from_ident(&ident)); - let vertical = input.try(RepeatKeyword::parse).ok(); - Ok(SpecifiedValue::Other(horizontal, vertical)) - } - } + _ => Err(()), + }).or_else(|()| { + let horizontal: Result<_, ParseError> = RepeatKeyword::from_ident(&ident) + .map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()); + let horizontal = try!(horizontal); + let vertical = input.try(RepeatKeyword::parse).ok(); + Ok(SpecifiedValue::Other(horizontal, vertical)) + }) } diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 36bedc41754..3e73df8b1fb 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -161,8 +161,8 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style', } #[inline] - pub fn parse(context: &ParserContext, input: &mut Parser) - -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue::None) } @@ -175,7 +175,7 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style', if !result.is_empty() { Ok(SpecifiedValue::Colors(result)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -272,7 +272,8 @@ ${helpers.predefined_type("border-image-outset", "LengthOrNumberRect", } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let first = try!(RepeatKeyword::parse(input)); let second = input.try(RepeatKeyword::parse).ok(); diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 44d80cf7b15..98bfbd68d20 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -113,16 +113,17 @@ } /// Parse a display value. - pub fn parse(_context: &ParserContext, input: &mut Parser) - -> Result { - match_ignore_ascii_case! { &try!(input.expect_ident()), + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { + let ident = try!(input.expect_ident()); + (match_ignore_ascii_case! { &ident, % for value in values: "${value}" => { Ok(computed_value::T::${to_rust_ident(value)}) }, % endfor _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } impl ComputedValueAsSpecified for SpecifiedValue {} @@ -292,16 +293,18 @@ ${helpers.single_keyword("position", "static absolute relative fixed", } /// baseline | sub | super | top | text-top | middle | bottom | text-bottom /// | | - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { input.try(|i| specified::LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes)) .map(SpecifiedValue::LengthOrPercentage) .or_else(|_| { - match_ignore_ascii_case! { &try!(input.expect_ident()), + let ident = try!(input.expect_ident()); + (match_ignore_ascii_case! { &ident, % for keyword in vertical_align_keywords: "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}), % endfor _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) }) } @@ -500,17 +503,19 @@ ${helpers.predefined_type("transition-delay", } impl Parse for SpecifiedValue { - fn parse(context: &ParserContext, input: &mut ::cssparser::Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut ::cssparser::Parser<'i, 't>) + -> Result> { if let Ok(name) = input.try(|input| KeyframesName::parse(context, input)) { Ok(SpecifiedValue(Some(name))) } else { - input.expect_ident_matching("none").map(|()| SpecifiedValue(None)) + input.expect_ident_matching("none").map(|_| SpecifiedValue(None)).map_err(|e| e.into()) } } } no_viewport_percentage!(SpecifiedValue); - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(context, input) } @@ -560,14 +565,15 @@ ${helpers.predefined_type("animation-timing-function", } impl Parse for SpecifiedValue { - fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut ::cssparser::Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("infinite")).is_ok() { return Ok(SpecifiedValue::Infinite) } let number = try!(input.expect_number()); if number < 0.0 { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(SpecifiedValue::Number(number)) @@ -587,7 +593,8 @@ ${helpers.predefined_type("animation-timing-function", } #[inline] - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(context, input) } @@ -948,8 +955,8 @@ ${helpers.predefined_type("scroll-snap-coordinate", } // Allow unitless zero angle for rotate() and skew() to align with gecko - fn parse_internal(context: &ParserContext, input: &mut Parser, prefixed: bool) - -> Result { + fn parse_internal<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>, prefixed: bool) + -> Result> { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(Vec::new())) } @@ -960,7 +967,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", Ok(name) => name, Err(_) => break, }; - match_ignore_ascii_case! { + let valid_fn = match_ignore_ascii_case! { &name, "matrix" => { try!(input.parse_nested_block(|input| { @@ -970,7 +977,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", specified::parse_number(context, input) })); if values.len() != 6 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } result.push(SpecifiedOperation::Matrix { @@ -981,7 +988,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", e: values[4], f: values[5], }); - return Ok(()); + return Ok(true); } // Non-standard prefixed matrix parsing. @@ -1014,7 +1021,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", e: lengths[0].clone(), f: lengths[1].clone(), }); - Ok(()) + Ok(true) })) }, "matrix3d" => { @@ -1023,7 +1030,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", if !prefixed { let values = try!(input.parse_comma_separated(|i| specified::parse_number(context, i))); if values.len() != 16 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } result.push(SpecifiedOperation::Matrix3D { @@ -1032,7 +1039,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11], m41: values[12], m42: values[13], m43: values[14], m44: values[15] }); - return Ok(()); + return Ok(true); } // Non-standard prefixed matrix3d parsing. @@ -1069,7 +1076,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", m41: lops[0].clone(), m42: lops[1].clone(), m43: length_or_number.unwrap(), m44: values[12] }); - Ok(()) + Ok(true) })) }, "translate" => { @@ -1081,28 +1088,28 @@ ${helpers.predefined_type("scroll-snap-coordinate", } else { result.push(SpecifiedOperation::Translate(sx, None)); } - Ok(()) + Ok(true) })) }, "translatex" => { try!(input.parse_nested_block(|input| { let tx = try!(specified::LengthOrPercentage::parse(context, input)); result.push(SpecifiedOperation::TranslateX(tx)); - Ok(()) + Ok(true) })) }, "translatey" => { try!(input.parse_nested_block(|input| { let ty = try!(specified::LengthOrPercentage::parse(context, input)); result.push(SpecifiedOperation::TranslateY(ty)); - Ok(()) + Ok(true) })) }, "translatez" => { try!(input.parse_nested_block(|input| { let tz = try!(specified::Length::parse(context, input)); result.push(SpecifiedOperation::TranslateZ(tz)); - Ok(()) + Ok(true) })) }, "translate3d" => { @@ -1113,7 +1120,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", try!(input.expect_comma()); let tz = try!(specified::Length::parse(context, input)); result.push(SpecifiedOperation::Translate3D(tx, ty, tz)); - Ok(()) + Ok(true) })) }, "scale" => { @@ -1125,28 +1132,28 @@ ${helpers.predefined_type("scroll-snap-coordinate", } else { result.push(SpecifiedOperation::Scale(sx, None)); } - Ok(()) + Ok(true) })) }, "scalex" => { try!(input.parse_nested_block(|input| { let sx = try!(specified::parse_number(context, input)); result.push(SpecifiedOperation::ScaleX(sx)); - Ok(()) + Ok(true) })) }, "scaley" => { try!(input.parse_nested_block(|input| { let sy = try!(specified::parse_number(context, input)); result.push(SpecifiedOperation::ScaleY(sy)); - Ok(()) + Ok(true) })) }, "scalez" => { try!(input.parse_nested_block(|input| { let sz = try!(specified::parse_number(context, input)); result.push(SpecifiedOperation::ScaleZ(sz)); - Ok(()) + Ok(true) })) }, "scale3d" => { @@ -1157,35 +1164,35 @@ ${helpers.predefined_type("scroll-snap-coordinate", try!(input.expect_comma()); let sz = try!(specified::parse_number(context, input)); result.push(SpecifiedOperation::Scale3D(sx, sy, sz)); - Ok(()) + Ok(true) })) }, "rotate" => { try!(input.parse_nested_block(|input| { let theta = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::Rotate(theta)); - Ok(()) + Ok(true) })) }, "rotatex" => { try!(input.parse_nested_block(|input| { let theta = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::RotateX(theta)); - Ok(()) + Ok(true) })) }, "rotatey" => { try!(input.parse_nested_block(|input| { let theta = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::RotateY(theta)); - Ok(()) + Ok(true) })) }, "rotatez" => { try!(input.parse_nested_block(|input| { let theta = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::RotateZ(theta)); - Ok(()) + Ok(true) })) }, "rotate3d" => { @@ -1199,7 +1206,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", let theta = try!(specified::Angle::parse_with_unitless(context, input)); // TODO(gw): Check the axis can be normalized!! result.push(SpecifiedOperation::Rotate3D(ax, ay, az, theta)); - Ok(()) + Ok(true) })) }, "skew" => { @@ -1211,51 +1218,56 @@ ${helpers.predefined_type("scroll-snap-coordinate", } else { result.push(SpecifiedOperation::Skew(theta_x, None)); } - Ok(()) + Ok(true) })) }, "skewx" => { try!(input.parse_nested_block(|input| { let theta_x = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::SkewX(theta_x)); - Ok(()) + Ok(true) })) }, "skewy" => { try!(input.parse_nested_block(|input| { let theta_y = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::SkewY(theta_y)); - Ok(()) + Ok(true) })) }, "perspective" => { try!(input.parse_nested_block(|input| { let d = try!(specified::Length::parse_non_negative(context, input)); result.push(SpecifiedOperation::Perspective(d)); - Ok(()) + Ok(true) })) }, - _ => return Err(()) + _ => false + }; + if !valid_fn { + return Err(StyleParseError::UnexpectedFunction(name).into()); } } if !result.is_empty() { Ok(SpecifiedValue(result)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } /// Parses `transform` property. #[inline] - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { parse_internal(context, input, false) } /// Parses `-moz-transform` property. This prefixed property also accepts LengthOrPercentage /// in the nondiagonal homogeneous components of matrix and matrix3d. #[inline] - pub fn parse_prefixed(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_prefixed<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { parse_internal(context, input, true) } @@ -1771,7 +1783,8 @@ ${helpers.predefined_type("transform-origin", } /// none | strict | content | [ size || layout || style || paint ] - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = SpecifiedValue::empty(); if input.try(|input| input.expect_ident_matching("none")).is_ok() { @@ -1784,21 +1797,22 @@ ${helpers.predefined_type("transform-origin", while let Ok(name) = input.try(|input| input.expect_ident()) { let flag = match_ignore_ascii_case! { &name, - "layout" => LAYOUT, - "style" => STYLE, - "paint" => PAINT, - _ => return Err(()) + "layout" => Some(LAYOUT), + "style" => Some(STYLE), + "paint" => Some(PAINT), + _ => None + }; + let flag = match flag { + Some(flag) if !result.contains(flag) => flag, + _ => return Err(SelectorParseError::UnexpectedIdent(name).into()) }; - if result.contains(flag) { - return Err(()) - } result.insert(flag); } if !result.is_empty() { Ok(result) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -1900,18 +1914,23 @@ ${helpers.single_keyword("-moz-orient", } /// auto | # - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("auto")).is_ok() { Ok(computed_value::T::Auto) } else { input.parse_comma_separated(|i| { let ident = i.expect_ident()?; - match_ignore_ascii_case! { &ident, + let bad_keyword = match_ignore_ascii_case! { &ident, "will-change" | "none" | "all" | "auto" | - "initial" | "inherit" | "unset" | "default" => return Err(()), - _ => {}, + "initial" | "inherit" | "unset" | "default" => true, + _ => false, + }; + if bad_keyword { + Err(SelectorParseError::UnexpectedIdent(ident.into()).into()) + } else { + Ok(Atom::from(ident)) } - Ok((Atom::from(ident))) }).map(SpecifiedValue::AnimateableFeatures) } } @@ -1976,9 +1995,10 @@ ${helpers.predefined_type("shape-outside", "basic_shape::FloatAreaShape", TOUCH_ACTION_AUTO } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "auto" => Ok(TOUCH_ACTION_AUTO), "none" => Ok(TOUCH_ACTION_NONE), "manipulation" => Ok(TOUCH_ACTION_MANIPULATION), @@ -1997,7 +2017,7 @@ ${helpers.predefined_type("shape-outside", "basic_shape::FloatAreaShape", } }, _ => Err(()), - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } #[cfg(feature = "gecko")] diff --git a/components/style/properties/longhand/color.mako.rs b/components/style/properties/longhand/color.mako.rs index fe5e411801e..7b7db26f021 100644 --- a/components/style/properties/longhand/color.mako.rs +++ b/components/style/properties/longhand/color.mako.rs @@ -43,7 +43,8 @@ pub fn get_initial_value() -> computed_value::T { RGBA::new(0, 0, 0, 255) // black } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { Color::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue) } @@ -118,7 +119,7 @@ } impl SystemColor { - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { #[cfg(feature = "gecko")] use std::ascii::AsciiExt; static PARSE_ARRAY: &'static [(&'static str, SystemColor); ${len(system_colors)}] = &[ @@ -133,7 +134,7 @@ return Ok(color) } } - Err(()) + Err(SelectorParseError::UnexpectedIdent(ident).into()) } } % endif diff --git a/components/style/properties/longhand/counters.mako.rs b/components/style/properties/longhand/counters.mako.rs index 55d054e8a27..e887fd5d716 100644 --- a/components/style/properties/longhand/counters.mako.rs +++ b/components/style/properties/longhand/counters.mako.rs @@ -8,7 +8,6 @@ <%helpers:longhand name="content" boxed="True" animation_value_type="none" spec="https://drafts.csswg.org/css-content/#propdef-content"> - use cssparser::Token; use values::computed::ComputedValueAsSpecified; #[cfg(feature = "gecko")] use values::generics::CounterStyleOrNone; @@ -157,8 +156,8 @@ // normal | none | [ | | open-quote | close-quote | no-open-quote | // no-close-quote ]+ // TODO: , attr() - pub fn parse(context: &ParserContext, input: &mut Parser) - -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("normal")).is_ok() { return Ok(SpecifiedValue::Normal) } @@ -185,43 +184,50 @@ content.push(ContentItem::String(value.into_owned())) } Ok(Token::Function(name)) => { - content.push(try!(match_ignore_ascii_case! { &name, - "counter" => input.parse_nested_block(|input| { + let result = match_ignore_ascii_case! { &name, + "counter" => Some(input.parse_nested_block(|input| { let name = try!(input.expect_ident()).into_owned(); let style = parse_counter_style(context, input); Ok(ContentItem::Counter(name, style)) - }), - "counters" => input.parse_nested_block(|input| { + })), + "counters" => Some(input.parse_nested_block(|input| { let name = try!(input.expect_ident()).into_owned(); try!(input.expect_comma()); let separator = try!(input.expect_string()).into_owned(); let style = parse_counter_style(context, input); Ok(ContentItem::Counters(name, separator, style)) - }), + })), % if product == "gecko": - "attr" => input.parse_nested_block(|input| { + "attr" => Some(input.parse_nested_block(|input| { Ok(ContentItem::Attr(Attr::parse_function(context, input)?)) - }), + })), % endif - _ => return Err(()) - })); + _ => None + }; + match result { + Some(result) => content.push(try!(result)), + None => return Err(StyleParseError::UnexpectedFunction(name).into()) + } } Ok(Token::Ident(ident)) => { - match_ignore_ascii_case! { &ident, - "open-quote" => content.push(ContentItem::OpenQuote), - "close-quote" => content.push(ContentItem::CloseQuote), - "no-open-quote" => content.push(ContentItem::NoOpenQuote), - "no-close-quote" => content.push(ContentItem::NoCloseQuote), + let valid = match_ignore_ascii_case! { &ident, + "open-quote" => { content.push(ContentItem::OpenQuote); true }, + "close-quote" => { content.push(ContentItem::CloseQuote); true }, + "no-open-quote" => { content.push(ContentItem::NoOpenQuote); true }, + "no-close-quote" => { content.push(ContentItem::NoCloseQuote); true }, - _ => return Err(()) + _ => false, + }; + if !valid { + return Err(SelectorParseError::UnexpectedIdent(ident).into()) } } Err(_) => break, - _ => return Err(()) + Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()) } } if content.is_empty() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(SpecifiedValue::Items(content)) } @@ -233,8 +239,6 @@ use style_traits::ToCss; use values::CustomIdent; - use cssparser::Token; - #[derive(Debug, Clone, PartialEq)] pub struct SpecifiedValue(pub Vec<(CustomIdent, specified::Integer)>); @@ -315,11 +319,13 @@ } } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { parse_common(context, 1, input) } - pub fn parse_common(context: &ParserContext, default_value: i32, input: &mut Parser) -> Result { + pub fn parse_common<'i, 't>(context: &ParserContext, default_value: i32, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(Vec::new())) } @@ -328,7 +334,7 @@ loop { let counter_name = match input.next() { Ok(Token::Ident(ident)) => CustomIdent::from_ident(ident, &["none"])?, - Ok(_) => return Err(()), + Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()), Err(_) => break, }; let counter_delta = input.try(|input| specified::parse_integer(context, input)) @@ -339,7 +345,7 @@ if !counters.is_empty() { Ok(SpecifiedValue(counters)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -349,7 +355,8 @@ pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; use super::counter_increment::parse_common; - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { parse_common(context, 0, input) } diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs index ecb6fe0720f..ffafde7f0ed 100644 --- a/components/style/properties/longhand/effects.mako.rs +++ b/components/style/properties/longhand/effects.mako.rs @@ -27,7 +27,8 @@ ${helpers.predefined_type("opacity", pub type T = Shadow; } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { specified::Shadow::parse(context, input, false) } @@ -263,7 +264,8 @@ ${helpers.predefined_type("clip", computed_value::T::new(Vec::new()) } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut filters = Vec::new(); if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(filters)) @@ -290,23 +292,24 @@ ${helpers.predefined_type("clip", "drop-shadow" => specified::Shadow::parse(context, input, true) .map(SpecifiedFilter::DropShadow), % endif - _ => Err(()) + _ => Err(StyleParseError::UnexpectedFunction(function_name.clone()).into()) } }))); } else if filters.is_empty() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } else { return Ok(SpecifiedValue(filters)) } } } - fn parse_factor(input: &mut Parser) -> Result<::values::CSSFloat, ()> { + fn parse_factor<'i, 't>(input: &mut Parser<'i, 't>) -> Result<::values::CSSFloat, ParseError<'i>> { use cssparser::Token; match input.next() { Ok(Token::Number(value)) if value.value.is_sign_positive() => Ok(value.value), Ok(Token::Percentage(value)) if value.unit_value.is_sign_positive() => Ok(value.unit_value), - _ => Err(()) + Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()), + Err(e) => Err(e.into()) } } diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 4deb7111aef..974f213b8a0 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -92,7 +92,7 @@ macro_rules! impl_gecko_keyword_from_trait { use cssparser::{CssStringWriter, Parser, serialize_identifier}; use std::fmt::{self, Write}; use Atom; - use style_traits::ToCss; + use style_traits::{ToCss, ParseError}; pub use self::FontFamily as SingleComputedValue; #[derive(Debug, PartialEq, Eq, Clone, Hash)] @@ -154,7 +154,7 @@ macro_rules! impl_gecko_keyword_from_trait { } /// Parse a font-family value - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { if let Ok(value) = input.try(|input| input.expect_string()) { return Ok(FontFamily::FamilyName(FamilyName { name: Atom::from(&*value), @@ -294,7 +294,8 @@ macro_rules! impl_gecko_keyword_from_trait { /// # /// = | [ + ] /// TODO: - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(input) } @@ -348,7 +349,7 @@ macro_rules! impl_gecko_keyword_from_trait { } } - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue::Values) } } @@ -374,11 +375,11 @@ macro_rules! impl_gecko_keyword_from_trait { /// `FamilyName::parse` is based on `FontFamily::parse` and not the other way around /// because we want the former to exclude generic family keywords. impl Parse for FamilyName { - fn parse(_: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { match FontFamily::parse(input) { Ok(FontFamily::FamilyName(name)) => Ok(name), - Ok(FontFamily::Generic(_)) | - Err(()) => Err(()) + Ok(FontFamily::Generic(_)) => Err(StyleParseError::UnspecifiedError.into()), + Err(e) => Err(e) } } } @@ -444,17 +445,21 @@ ${helpers.single_keyword_system("font-variant-caps", } /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - input.try(|input| { - match_ignore_ascii_case! { &try!(input.expect_ident()), + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { + let result: Result<_, ParseError> = input.try(|input| { + let ident = try!(input.expect_ident()); + (match_ignore_ascii_case! { &ident, "normal" => Ok(SpecifiedValue::Normal), "bold" => Ok(SpecifiedValue::Bold), "bolder" => Ok(SpecifiedValue::Bolder), "lighter" => Ok(SpecifiedValue::Lighter), _ => Err(()) - } - }).or_else(|()| { + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) + }); + result.or_else(|_| { SpecifiedValue::from_int(input.expect_integer()?) + .map_err(|()| StyleParseError::UnspecifiedError.into()) }) } @@ -489,7 +494,7 @@ ${helpers.single_keyword_system("font-variant-caps", /// Used in @font-face, where relative keywords are not allowed. impl Parse for computed_value::T { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { match parse(context, input)? { % for weight in range(100, 901, 100): SpecifiedValue::Weight${weight} => Ok(computed_value::T::Weight${weight}), @@ -497,7 +502,7 @@ ${helpers.single_keyword_system("font-variant-caps", SpecifiedValue::Normal => Ok(computed_value::T::Weight400), SpecifiedValue::Bold => Ok(computed_value::T::Weight700), SpecifiedValue::Bolder | - SpecifiedValue::Lighter => Err(()), + SpecifiedValue::Lighter => Err(StyleParseError::UnspecifiedError.into()), SpecifiedValue::System(..) => unreachable!(), } } @@ -683,17 +688,18 @@ ${helpers.single_keyword_system("font-variant-caps", pub use self::KeywordSize::*; impl KeywordSize { - pub fn parse(input: &mut Parser) -> Result { - Ok(match_ignore_ascii_case! {&*input.expect_ident()?, - "xx-small" => XXSmall, - "x-small" => XSmall, - "small" => Small, - "medium" => Medium, - "large" => Large, - "x-large" => XLarge, - "xx-large" => XXLarge, - _ => return Err(()) - }) + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + let ident = input.expect_ident()?; + (match_ignore_ascii_case! {&*ident, + "xx-small" => Ok(XXSmall), + "x-small" => Ok(XSmall), + "small" => Ok(Small), + "medium" => Ok(Medium), + "large" => Ok(Large), + "x-large" => Ok(XLarge), + "xx-large" => Ok(XXLarge), + _ => Err(()) + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } @@ -906,15 +912,16 @@ ${helpers.single_keyword_system("font-variant-caps", } /// | | | - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { parse_quirky(context, input, AllowQuirks::No) } /// Parses a font-size, with quirks. - pub fn parse_quirky(context: &ParserContext, - input: &mut Parser, - allow_quirks: AllowQuirks) - -> Result { + pub fn parse_quirky<'i, 't>(context: &ParserContext, + input: &mut Parser<'i, 't>, + allow_quirks: AllowQuirks) + -> Result> { use self::specified::LengthOrPercentage; if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) { return Ok(SpecifiedValue::Length(lop)) @@ -924,11 +931,12 @@ ${helpers.single_keyword_system("font-variant-caps", return Ok(SpecifiedValue::Keyword(kw, 1.)) } - match_ignore_ascii_case! {&*input.expect_ident()?, + let ident = input.expect_ident()?; + (match_ignore_ascii_case! {&*ident, "smaller" => Ok(SpecifiedValue::Smaller), "larger" => Ok(SpecifiedValue::Larger), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } impl SpecifiedValue { @@ -1150,7 +1158,8 @@ ${helpers.single_keyword_system("font-variant-caps", } /// none | - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { use values::specified::Number; if input.try(|input| input.expect_ident_matching("none")).is_ok() { @@ -1200,9 +1209,11 @@ ${helpers.single_keyword_system("font-variant-caps", SpecifiedValue { weight: true, style: true } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = SpecifiedValue { weight: false, style: false }; - match_ignore_ascii_case! { &try!(input.expect_ident()), + let ident = try!(input.expect_ident()); + (match_ignore_ascii_case! { &ident, "none" => Ok(result), "weight" => { result.weight = true; @@ -1219,7 +1230,7 @@ ${helpers.single_keyword_system("font-variant-caps", Ok(result) }, _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } #[cfg(feature = "gecko")] @@ -1364,7 +1375,8 @@ ${helpers.single_keyword_system("font-kerning", /// swash() || /// ornaments() || /// annotation() ] - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = VariantAlternates::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { @@ -1373,25 +1385,26 @@ ${helpers.single_keyword_system("font-kerning", while let Ok(ident) = input.try(|input| input.expect_ident()) { let flag = match_ignore_ascii_case! { &ident, - "stylistic" => STYLISTIC, - "historical-forms" => HISTORICAL_FORMS, - "styleset" => STYLESET, - "character-variant" => CHARACTER_VARIANT, - "swash" => SWASH, - "ornaments" => ORNAMENTS, - "annotation" => ANNOTATION, - _ => return Err(()), + "stylistic" => Some(STYLISTIC), + "historical-forms" => Some(HISTORICAL_FORMS), + "styleset" => Some(STYLESET), + "character-variant" => Some(CHARACTER_VARIANT), + "swash" => Some(SWASH), + "ornaments" => Some(ORNAMENTS), + "annotation" => Some(ANNOTATION), + _ => None, + }; + let flag = match flag { + Some(flag) if !result.intersects(flag) => flag, + _ => return Err(SelectorParseError::UnexpectedIdent(ident).into()), }; - if result.intersects(flag) { - return Err(()) - } result.insert(flag); } if !result.is_empty() { Ok(SpecifiedValue::Value(result)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -1400,9 +1413,9 @@ ${helpers.single_keyword_system("font-kerning", macro_rules! exclusive_value { (($value:ident, $set:expr) => $ident:ident) => { if $value.intersects($set) { - return Err(()) + None } else { - $ident + Some($ident) } } } @@ -1507,7 +1520,8 @@ macro_rules! exclusive_value { /// = [ full-width | proportional-width ] <% east_asian_variant_values = "JIS78 | JIS83 | JIS90 | JIS04 | SIMPLIFIED | TRADITIONAL" %> <% east_asian_width_values = "FULL_WIDTH | PROPORTIONAL_WIDTH" %> - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = VariantEastAsian::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { @@ -1534,7 +1548,11 @@ macro_rules! exclusive_value { exclusive_value!((result, ${east_asian_width_values}) => PROPORTIONAL_WIDTH), "ruby" => exclusive_value!((result, RUBY) => RUBY), - _ => return Err(()), + _ => None, + }; + let flag = match flag { + Some(flag) => flag, + None => return Err(SelectorParseError::UnexpectedIdent(ident).into()), }; result.insert(flag); } @@ -1542,7 +1560,7 @@ macro_rules! exclusive_value { if !result.is_empty() { Ok(SpecifiedValue::Value(result)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -1659,7 +1677,8 @@ macro_rules! exclusive_value { <% discretionary_lig_values = "DISCRETIONARY_LIGATURES | NO_DISCRETIONARY_LIGATURES" %> <% historical_lig_values = "HISTORICAL_LIGATURES | NO_HISTORICAL_LIGATURES" %> <% contextual_alt_values = "CONTEXTUAL | NO_CONTEXTUAL" %> - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = VariantLigatures::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { @@ -1687,7 +1706,11 @@ macro_rules! exclusive_value { exclusive_value!((result, ${contextual_alt_values}) => CONTEXTUAL), "no-contextual" => exclusive_value!((result, ${contextual_alt_values}) => NO_CONTEXTUAL), - _ => return Err(()), + _ => None, + }; + let flag = match flag { + Some(flag) => flag, + None => return Err(SelectorParseError::UnexpectedIdent(ident).into()), }; result.insert(flag); } @@ -1695,7 +1718,7 @@ macro_rules! exclusive_value { if !result.is_empty() { Ok(SpecifiedValue::Value(result)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -1808,7 +1831,8 @@ macro_rules! exclusive_value { <% numeric_figure_values = "LINING_NUMS | OLDSTYLE_NUMS" %> <% numeric_spacing_values = "PROPORTIONAL_NUMS | TABULAR_NUMS" %> <% numeric_fraction_values = "DIAGONAL_FRACTIONS | STACKED_FRACTIONS" %> - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = VariantNumeric::empty(); if input.try(|input| input.expect_ident_matching("normal")).is_ok() { @@ -1824,16 +1848,20 @@ macro_rules! exclusive_value { "lining-nums" => exclusive_value!((result, ${numeric_figure_values}) => LINING_NUMS ), "oldstyle-nums" => - exclusive_value!((result, ${numeric_figure_values}) => OLDSTYLE_NUMS ), + exclusive_value!((result, ${numeric_figure_values}) => OLDSTYLE_NUMS), "proportional-nums" => - exclusive_value!((result, ${numeric_spacing_values}) => PROPORTIONAL_NUMS ), + exclusive_value!((result, ${numeric_spacing_values}) => PROPORTIONAL_NUMS), "tabular-nums" => - exclusive_value!((result, ${numeric_spacing_values}) => TABULAR_NUMS ), + exclusive_value!((result, ${numeric_spacing_values}) => TABULAR_NUMS), "diagonal-fractions" => - exclusive_value!((result, ${numeric_fraction_values}) => DIAGONAL_FRACTIONS ), + exclusive_value!((result, ${numeric_fraction_values}) => DIAGONAL_FRACTIONS), "stacked-fractions" => - exclusive_value!((result, ${numeric_fraction_values}) => STACKED_FRACTIONS ), - _ => return Err(()), + exclusive_value!((result, ${numeric_fraction_values}) => STACKED_FRACTIONS), + _ => None, + }; + let flag = match flag { + Some(flag) => flag, + None => return Err(SelectorParseError::UnexpectedIdent(ident).into()), }; result.insert(flag); } @@ -1841,7 +1869,7 @@ macro_rules! exclusive_value { if !result.is_empty() { Ok(SpecifiedValue::Value(result)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -1890,7 +1918,8 @@ ${helpers.single_keyword_system("font-variant-position", } /// normal | # - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { computed_value::T::parse(context, input).map(SpecifiedValue::Value) } @@ -1924,7 +1953,8 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- } /// normal | # - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { computed_value::T::parse(context, input) } @@ -2054,13 +2084,14 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- } /// normal | - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("normal")).is_ok() { Ok(SpecifiedValue::Normal) } else { input.expect_string().map(|cow| { SpecifiedValue::Override(cow.into_owned()) - }) + }).map_err(|e| e.into()) } } @@ -2108,9 +2139,10 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- computed_value::T(atom!("")) } - pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>) + -> Result> { debug_assert!(false, "Should be set directly by presentation attributes only."); - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } @@ -2133,9 +2165,10 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- ::gecko_bindings::structs::NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER as f32 } - pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>) + -> Result> { debug_assert!(false, "Should be set directly by presentation attributes only."); - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } @@ -2206,7 +2239,8 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if let Ok(i) = input.try(|i| i.expect_integer()) { return Ok(SpecifiedValue::Relative(i)) } @@ -2281,9 +2315,10 @@ ${helpers.single_keyword("-moz-math-variant", Au((NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT as f32 * AU_PER_PT) as i32) } - pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>) + -> Result> { debug_assert!(false, "Should be set directly by presentation attributes only."); - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } @@ -2308,7 +2343,9 @@ ${helpers.single_keyword("-moz-math-variant", use app_units::Au; use cssparser::Parser; use properties::longhands; + use selectors::parser::SelectorParseError; use std::hash::{Hash, Hasher}; + use style_traits::ParseError; use values::computed::{ToComputedValue, Context}; <% system_fonts = """caption icon menu message-box small-caption status-bar @@ -2427,13 +2464,14 @@ ${helpers.single_keyword("-moz-math-variant", } impl SystemFont { - pub fn parse(input: &mut Parser) -> Result { - Ok(match_ignore_ascii_case! { &*input.expect_ident()?, + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &*ident, % for font in system_fonts: - "${font}" => SystemFont::${to_camel_case(font)}, + "${font}" => Ok(SystemFont::${to_camel_case(font)}), % endfor - _ => return Err(()) - }) + _ => Err(()) + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } } diff --git a/components/style/properties/longhand/inherited_box.mako.rs b/components/style/properties/longhand/inherited_box.mako.rs index 09c43a20186..a38fa987d0f 100644 --- a/components/style/properties/longhand/inherited_box.mako.rs +++ b/components/style/properties/longhand/inherited_box.mako.rs @@ -174,7 +174,8 @@ ${helpers.single_keyword("image-rendering", } // from-image | | [? flip] - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("from-image")).is_ok() { // Handle from-image Ok(SpecifiedValue { angle: None, flipped: false }) @@ -185,7 +186,7 @@ ${helpers.single_keyword("image-rendering", // Handle | flip let angle = input.try(|input| Angle::parse(context, input)).ok(); if angle.is_none() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok(); diff --git a/components/style/properties/longhand/inherited_svg.mako.rs b/components/style/properties/longhand/inherited_svg.mako.rs index 53affa72515..35177cae0ea 100644 --- a/components/style/properties/longhand/inherited_svg.mako.rs +++ b/components/style/properties/longhand/inherited_svg.mako.rs @@ -183,7 +183,8 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)", } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) { Ok(SpecifiedValue(0)) } else { @@ -195,33 +196,34 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)", loop { - let result = input.try(|i| { - match_ignore_ascii_case! { &i.expect_ident()?, + let result: Result<_, ParseError> = input.try(|i| { + let ident = i.expect_ident()?; + (match_ignore_ascii_case! { &ident, "fill" => Ok(FILL), "stroke" => Ok(STROKE), "markers" => Ok(MARKERS), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident.into()).into()) }); match result { Ok(val) => { if (seen & (1 << val)) != 0 { // don't parse the same ident twice - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } else { value |= val << (pos * SHIFT); seen |= 1 << val; pos += 1; } } - Err(()) => break, + Err(_) => break, } } if value == 0 { // couldn't find any keyword - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } else { // fill in rest for i in pos..COUNT { @@ -285,7 +287,8 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)", } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let i = input.expect_ident()?; CustomIdent::from_ident(i, &["all", "none", "auto"]) } diff --git a/components/style/properties/longhand/inherited_table.mako.rs b/components/style/properties/longhand/inherited_table.mako.rs index 1cf2c14fbe0..d01b7b3fca2 100644 --- a/components/style/properties/longhand/inherited_table.mako.rs +++ b/components/style/properties/longhand/inherited_table.mako.rs @@ -113,11 +113,12 @@ ${helpers.single_keyword("caption-side", "top bottom", } } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut first = None; let mut second = None; match Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes) { - Err(()) => (), + Err(_) => (), Ok(length) => { first = Some(length); if let Ok(len) = input.try(|i| Length::parse_non_negative_quirky(context, i, AllowQuirks::Yes)) { @@ -126,7 +127,7 @@ ${helpers.single_keyword("caption-side", "top bottom", } } match (first, second) { - (None, None) => Err(()), + (None, None) => Err(StyleParseError::UnspecifiedError.into()), (Some(length), None) => { Ok(SpecifiedValue { horizontal: length, diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index ae312a021b3..89a98603e97 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -179,7 +179,8 @@ ${helpers.single_keyword("text-align-last", MatchParent, MozCenterOrInherit, } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { // MozCenterOrInherit cannot be parsed, only set directly on th elements if let Ok(key) = input.try(computed_value::T::parse) { Ok(SpecifiedValue::Keyword(key)) @@ -255,7 +256,8 @@ ${helpers.single_keyword("text-align-last", use values::computed::ComputedValueAsSpecified; impl ComputedValueAsSpecified for SpecifiedValue {} pub use self::computed_value::T as SpecifiedValue; - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { computed_value::T::parse(input) } % endif @@ -415,7 +417,8 @@ ${helpers.predefined_type("word-spacing", pub type T = Shadow; } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { specified::Shadow::parse(context, input, true) } @@ -577,7 +580,8 @@ ${helpers.predefined_type("word-spacing", } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue::None); } @@ -603,7 +607,7 @@ ${helpers.predefined_type("word-spacing", (Some(fill), Ok(shape)) => KeywordValue::FillAndShape(fill,shape), (Some(fill), Err(_)) => KeywordValue::Fill(fill), (None, Ok(shape)) => KeywordValue::Shape(shape), - _ => return Err(()), + _ => return Err(StyleParseError::UnspecifiedError.into()), }; Ok(SpecifiedValue::Keyword(keyword_value)) } @@ -636,7 +640,8 @@ ${helpers.predefined_type("word-spacing", SpecifiedValue(HorizontalWritingModeValue::Over, VerticalWritingModeValue::Right) } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if let Ok(horizontal) = input.try(|input| HorizontalWritingModeValue::parse(input)) { let vertical = try!(VerticalWritingModeValue::parse(input)); Ok(SpecifiedValue(horizontal, vertical)) diff --git a/components/style/properties/longhand/list.mako.rs b/components/style/properties/longhand/list.mako.rs index 649b04c3eaf..6f25334698e 100644 --- a/components/style/properties/longhand/list.mako.rs +++ b/components/style/properties/longhand/list.mako.rs @@ -89,7 +89,8 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu SpecifiedValue::CounterStyle(CounterStyleOrNone::disc()) } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { Ok(if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) { SpecifiedValue::CounterStyle(style) } else { @@ -126,7 +127,8 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu pub fn get_initial_specified_value() -> SpecifiedValue { SpecifiedValue(Either::Second(None_)) } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % if product == "gecko": let mut value = input.try(|input| UrlOrNone::parse(context, input))?; if let Either::First(ref mut url) = value { @@ -142,7 +144,6 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu <%helpers:longhand name="quotes" animation_value_type="none" spec="https://drafts.csswg.org/css-content/#propdef-quotes"> - use cssparser::Token; use std::borrow::Cow; use std::fmt; use style_traits::ToCss; @@ -187,7 +188,8 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu ]) } - pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(Vec::new())) } @@ -196,19 +198,20 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu loop { let first = match input.next() { Ok(Token::QuotedString(value)) => value.into_owned(), - Ok(_) => return Err(()), - Err(()) => break, + Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()), + Err(_) => break, }; let second = match input.next() { Ok(Token::QuotedString(value)) => value.into_owned(), - _ => return Err(()), + Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()), + Err(e) => return Err(e.into()), }; quotes.push((first, second)) } if !quotes.is_empty() { Ok(SpecifiedValue(quotes)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } diff --git a/components/style/properties/longhand/outline.mako.rs b/components/style/properties/longhand/outline.mako.rs index 70f5b920361..d7b62dd3cfc 100644 --- a/components/style/properties/longhand/outline.mako.rs +++ b/components/style/properties/longhand/outline.mako.rs @@ -46,14 +46,15 @@ ${helpers.predefined_type("outline-color", "Color", "computed_value::T::currentc pub type T = super::SpecifiedValue; } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(context, input) .and_then(|result| { if let Either::Second(BorderStyle::hidden) = result { // The outline-style property accepts the same values as // border-style, except that 'hidden' is not a legal outline // style. - Err(()) + Err(SelectorParseError::UnexpectedIdent("hidden".into()).into()) } else { Ok(result) } diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/pointing.mako.rs index 05f014a07da..c4fbb053d37 100644 --- a/components/style/properties/longhand/pointing.mako.rs +++ b/components/style/properties/longhand/pointing.mako.rs @@ -91,37 +91,43 @@ } impl Parse for computed_value::Keyword { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { use std::ascii::AsciiExt; use style_traits::cursor::Cursor; let ident = try!(input.expect_ident()); if ident.eq_ignore_ascii_case("auto") { Ok(computed_value::Keyword::Auto) } else { - Cursor::from_css_keyword(&ident).map(computed_value::Keyword::Cursor) + Cursor::from_css_keyword(&ident) + .map(computed_value::Keyword::Cursor) + .map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } } #[cfg(feature = "gecko")] - fn parse_image(context: &ParserContext, input: &mut Parser) -> Result { + fn parse_image<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { Ok(computed_value::Image { url: try!(SpecifiedUrl::parse(context, input)), hotspot: match input.try(|input| input.expect_number()) { Ok(number) => Some((number, try!(input.expect_number()))), - Err(()) => None, + Err(_) => None, }, }) } #[cfg(not(feature = "gecko"))] - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { computed_value::Keyword::parse(context, input) } /// cursor: [ [ ]?]# [auto | default | ...] #[cfg(feature = "gecko")] - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut images = vec![]; loop { match input.try(|input| parse_image(context, input)) { @@ -129,7 +135,7 @@ image.url.build_image_value(); images.push(image) } - Err(()) => break, + Err(_) => break, } try!(input.expect_comma()); } diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 9a13d1db6f8..56ed70a47b7 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -339,27 +339,32 @@ ${helpers.predefined_type("object-position", } /// [ row | column ] || dense - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { use self::computed_value::AutoFlow; let mut value = None; let mut dense = false; while !input.is_exhausted() { - match_ignore_ascii_case! { &input.expect_ident()?, + let ident = input.expect_ident()?; + let success = match_ignore_ascii_case! { &ident, "row" if value.is_none() => { value = Some(AutoFlow::Row); - continue + true }, "column" if value.is_none() => { value = Some(AutoFlow::Column); - continue + true }, "dense" if !dense => { dense = true; - continue + true }, - _ => return Err(()) + _ => false + }; + if !success { + return Err(SelectorParseError::UnexpectedIdent(ident).into()); } } @@ -369,7 +374,7 @@ ${helpers.predefined_type("object-position", dense: dense, }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -435,7 +440,8 @@ ${helpers.predefined_type("object-position", Either::Second(None_) } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { SpecifiedValue::parse(context, input) } @@ -457,13 +463,15 @@ ${helpers.predefined_type("object-position", impl ComputedValueAsSpecified for TemplateAreas {} impl Parse for TemplateAreas { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut strings = vec![]; while let Ok(string) = input.try(Parser::expect_string) { strings.push(string.into_owned().into_boxed_str()); } TemplateAreas::from_vec(strings) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } } diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index 03e2f557e9f..b2f2b6f2ef6 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -129,7 +129,8 @@ ${helpers.single_keyword("mask-origin", background_size::get_initial_value() } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { background_size::parse(context, input) } diff --git a/components/style/properties/longhand/table.mako.rs b/components/style/properties/longhand/table.mako.rs index fb34efe22c5..584d08032ec 100644 --- a/components/style/properties/longhand/table.mako.rs +++ b/components/style/properties/longhand/table.mako.rs @@ -40,7 +40,8 @@ ${helpers.single_keyword("table-layout", "auto fixed", } // never parse it, only set via presentation attribute - fn parse(_: &ParserContext, _: &mut Parser) -> Result { - Err(()) + fn parse<'i, 't>(_: &ParserContext, _: &mut Parser<'i, 't>) + -> Result> { + Err(StyleParseError::UnspecifiedError.into()) } diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs index 40ee7b0b496..39a1b1f64d3 100644 --- a/components/style/properties/longhand/text.mako.rs +++ b/components/style/properties/longhand/text.mako.rs @@ -104,7 +104,8 @@ sides_are_logical: true, } } - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let first = try!(Side::parse(context, input)); let second = input.try(|input| Side::parse(context, input)).ok(); Ok(SpecifiedValue { @@ -113,13 +114,14 @@ }) } impl Parse for Side { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if let Ok(ident) = input.try(|input| input.expect_ident()) { - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "clip" => Ok(Side::Clip), "ellipsis" => Ok(Side::Ellipsis), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } else { Ok(Side::String(try!(input.expect_string()).into_owned().into_boxed_str())) } @@ -216,34 +218,39 @@ ${helpers.single_keyword("unicode-bidi", SpecifiedValue::empty() } /// none | [ underline || overline || line-through || blink ] - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut result = SpecifiedValue::empty(); if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(result) } let mut empty = true; - while input.try(|input| { - if let Ok(ident) = input.expect_ident() { - match_ignore_ascii_case! { &ident, - "underline" => if result.contains(UNDERLINE) { return Err(()) } - else { empty = false; result.insert(UNDERLINE) }, - "overline" => if result.contains(OVERLINE) { return Err(()) } - else { empty = false; result.insert(OVERLINE) }, - "line-through" => if result.contains(LINE_THROUGH) { return Err(()) } - else { empty = false; result.insert(LINE_THROUGH) }, - "blink" => if result.contains(BLINK) { return Err(()) } - else { empty = false; result.insert(BLINK) }, - _ => return Err(()) + loop { + let result: Result<_, ParseError> = input.try(|input| { + match input.expect_ident() { + Ok(ident) => { + (match_ignore_ascii_case! { &ident, + "underline" => if result.contains(UNDERLINE) { Err(()) } + else { empty = false; result.insert(UNDERLINE); Ok(()) }, + "overline" => if result.contains(OVERLINE) { Err(()) } + else { empty = false; result.insert(OVERLINE); Ok(()) }, + "line-through" => if result.contains(LINE_THROUGH) { Err(()) } + else { empty = false; result.insert(LINE_THROUGH); Ok(()) }, + "blink" => if result.contains(BLINK) { Err(()) } + else { empty = false; result.insert(BLINK); Ok(()) }, + _ => Err(()) + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } - } else { - return Err(()); + Err(e) => return Err(e.into()) } - Ok(()) - }).is_ok() { + }); + if result.is_err() { + break; + } } - if !empty { Ok(result) } else { Err(()) } + if !empty { Ok(result) } else { Err(StyleParseError::UnspecifiedError.into()) } } % if product == "servo": diff --git a/components/style/properties/longhand/ui.mako.rs b/components/style/properties/longhand/ui.mako.rs index 21a349db959..5a190368f04 100644 --- a/components/style/properties/longhand/ui.mako.rs +++ b/components/style/properties/longhand/ui.mako.rs @@ -76,11 +76,12 @@ ${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet" impl ComputedValueAsSpecified for SpecifiedValue {} - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { match try!(input.expect_integer()) { 0 => Ok(computed_value::T(false)), 1 => Ok(computed_value::T(true)), - _ => Err(()), + _ => Err(StyleParseError::UnspecifiedError.into()), } } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index f140e07939b..8bd5ec4680d 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -20,6 +20,7 @@ use stylearc::{Arc, UniqueArc}; use app_units::Au; #[cfg(feature = "servo")] use cssparser::RGBA; use cssparser::{Parser, TokenSerializationType, serialize_identifier}; +use cssparser::ParserInput; use error_reporting::ParseErrorReporter; #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D; use computed_values; @@ -33,9 +34,10 @@ use media_queries::Device; use parser::{PARSING_MODE_DEFAULT, Parse, ParserContext}; use properties::animated_properties::TransitionProperty; #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont; +use selectors::parser::SelectorParseError; #[cfg(feature = "servo")] use servo_config::prefs::PREFS; use shared_lock::StylesheetGuards; -use style_traits::{HasViewportPercentage, ToCss}; +use style_traits::{HasViewportPercentage, ToCss, ParseError, PropertyDeclarationParseError}; use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData}; #[cfg(feature = "servo")] use values::Either; use values::generics::text::LineHeight; @@ -185,6 +187,7 @@ macro_rules! unwrap_or_initial { pub mod shorthands { use cssparser::Parser; use parser::{Parse, ParserContext}; + use style_traits::{ParseError, StyleParseError}; use values::specified; <%include file="/shorthand/serialize.mako.rs" /> @@ -213,9 +216,11 @@ pub mod shorthands { use parser::ParserContext; use properties::{SourcePropertyDeclaration, AllShorthand, ShorthandId, UnparsedValue}; use stylearc::Arc; + use style_traits::{ParseError, StyleParseError}; - pub fn parse_into(declarations: &mut SourcePropertyDeclaration, - context: &ParserContext, input: &mut Parser) -> Result<(), ()> { + pub fn parse_into<'i, 't>(declarations: &mut SourcePropertyDeclaration, + context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result<(), ParseError<'i>> { // This function is like the parse() that is generated by // helpers:shorthand, but since the only values for the 'all' // shorthand when not just a single CSS-wide keyword is one @@ -239,7 +244,7 @@ pub mod shorthands { })); Ok(()) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } } @@ -414,6 +419,7 @@ impl PropertyDeclarationIdSet { { f(& ::custom_properties::substitute(css, first_token_type, custom_properties) + .ok() .and_then(|css| { // As of this writing, only the base URL is used for property values: // @@ -425,7 +431,8 @@ impl PropertyDeclarationIdSet { None, PARSING_MODE_DEFAULT, quirks_mode); - Parser::new(&css).parse_entirely(|input| { + let mut input = ParserInput::new(&css); + Parser::new(&mut input).parse_entirely(|input| { match from_shorthand { None => { longhands::${property.ident} @@ -434,7 +441,7 @@ impl PropertyDeclarationIdSet { Some(ShorthandId::All) => { // No need to parse the 'all' shorthand as anything other than a CSS-wide // keyword, after variable substitution. - Err(()) + Err(SelectorParseError::UnexpectedIdent("all".into()).into()) } % for shorthand in data.shorthands_except_all(): % if property in shorthand.sub_properties: @@ -448,7 +455,7 @@ impl PropertyDeclarationIdSet { % endfor _ => unreachable!() } - }) + }).ok() }) .unwrap_or( // Invalid at computed-value time. @@ -500,10 +507,11 @@ impl CSSWideKeyword { } impl Parse for CSSWideKeyword { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let ident = input.expect_ident()?; input.expect_exhausted()?; - CSSWideKeyword::from_ident(&ident).ok_or(()) + CSSWideKeyword::from_ident(&ident) + .ok_or(SelectorParseError::UnexpectedIdent(ident).into()) } } @@ -946,7 +954,7 @@ impl PropertyId { /// Returns a given property from the string `s`. /// /// Returns Err(()) for unknown non-custom properties - pub fn parse(property_name: Cow) -> Result { + pub fn parse<'i>(property_name: Cow<'i, str>) -> Result> { if let Ok(name) = ::custom_properties::parse_name(&property_name) { return Ok(PropertyId::Custom(::custom_properties::Name::from(name))) } @@ -971,7 +979,7 @@ impl PropertyId { match static_id(&property_name) { Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)), Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)), - None => Err(()), + None => Err(SelectorParseError::UnexpectedIdent(property_name).into()), } } @@ -1095,24 +1103,6 @@ impl HasViewportPercentage for PropertyDeclaration { } } -/// The result of parsing a property declaration. -#[derive(Eq, PartialEq, Copy, Clone)] -pub enum PropertyDeclarationParseError { - /// The property declaration was for an unknown property. - UnknownProperty, - /// The property declaration was for a disabled experimental property. - ExperimentalProperty, - /// The property declaration contained an invalid value. - InvalidValue, - /// The declaration contained an animation property, and we were parsing - /// this as a keyframe block (so that property should be ignored). - /// - /// See: https://drafts.csswg.org/css-animations/#keyframes - AnimationPropertyInKeyframeBlock, - /// The property is not allowed within a page rule. - NotAllowedInPageRule, -} - impl fmt::Debug for PropertyDeclaration { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(self.id().to_css(f)); @@ -1407,9 +1397,9 @@ impl PropertyDeclaration { PropertyId::Custom(name) => { let value = match input.try(|i| CSSWideKeyword::parse(context, i)) { Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword), - Err(()) => match ::custom_properties::SpecifiedValue::parse(context, input) { + Err(_) => match ::custom_properties::SpecifiedValue::parse(context, input) { Ok(value) => DeclaredValueOwned::Value(value), - Err(()) => return Err(PropertyDeclarationParseError::InvalidValue), + Err(_) => return Err(PropertyDeclarationParseError::InvalidValue), } }; declarations.push(PropertyDeclaration::Custom(name, value)); @@ -1442,7 +1432,7 @@ impl PropertyDeclaration { declarations.push(value); Ok(()) }, - Err(()) => Err(PropertyDeclarationParseError::InvalidValue), + Err(_) => Err(PropertyDeclarationParseError::InvalidValue), } % else: Err(PropertyDeclarationParseError::UnknownProperty) @@ -1485,9 +1475,9 @@ impl PropertyDeclaration { % endif Ok(()) }, - Err(()) => { + Err(_) => { shorthands::${shorthand.ident}::parse_into(declarations, context, input) - .map_err(|()| PropertyDeclarationParseError::InvalidValue) + .map_err(|_| PropertyDeclarationParseError::InvalidValue) } } } diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs index 3767d80bed9..2e20d646c5d 100644 --- a/components/style/properties/shorthand/background.mako.rs +++ b/components/style/properties/shorthand/background.mako.rs @@ -32,7 +32,8 @@ } } - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut background_color = None; % for name in "image position_x position_y repeat size attachment origin clip".split(): @@ -42,7 +43,7 @@ // background-color can only be in the last element, so if it // is parsed anywhere before, the value is invalid. if background_color.is_some() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } % for name in "image position repeat size attachment origin clip".split(): @@ -107,7 +108,7 @@ % endfor Ok(()) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } })); @@ -194,7 +195,8 @@ use values::specified::AllowQuirks; use values::specified::position::Position; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut position_x = background_position_x::SpecifiedValue(Vec::new()); let mut position_y = background_position_y::SpecifiedValue(Vec::new()); let mut any = false; @@ -207,7 +209,7 @@ Ok(()) })?; if !any { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(expanded! { diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs index b5ebe773c66..119d34e57c0 100644 --- a/components/style/properties/shorthand/border.mako.rs +++ b/components/style/properties/shorthand/border.mako.rs @@ -20,7 +20,8 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style", use values::generics::rect::Rect; use values::specified::{AllowQuirks, BorderSideWidth}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let rect = Rect::parse_with(context, input, |_, i| { BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes) })?; @@ -43,10 +44,10 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style", -pub fn parse_border(context: &ParserContext, input: &mut Parser) - -> Result<(specified::Color, - specified::BorderStyle, - specified::BorderSideWidth), ()> { +pub fn parse_border<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result<(specified::Color, + specified::BorderStyle, + specified::BorderSideWidth), ParseError<'i>> { use values::specified::{Color, BorderStyle, BorderSideWidth}; let _unused = context; let mut color = None; @@ -82,7 +83,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) style.unwrap_or(BorderStyle::none), width.unwrap_or(BorderSideWidth::Medium))) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -101,7 +102,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) alias="${maybe_moz_logical_alias(product, (side, logical), '-moz-border-%s')}" spec="${spec}"> - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let (color, style, width) = try!(super::parse_border(context, input)); Ok(expanded! { border_${to_rust_ident(side)}_color: color, @@ -139,7 +141,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) _moz_border_bottom_colors, _moz_border_left_colors}; % endif - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice}; use properties::longhands::{border_image_source, border_image_width}; @@ -209,7 +212,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) use values::specified::border::BorderRadius; use parser::Parse; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let radii = try!(BorderRadius::parse(context, input)); Ok(expanded! { border_top_left_radius: radii.top_left, @@ -242,12 +246,13 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice}; use properties::longhands::{border_image_source, border_image_width}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % for name in "outset repeat slice source width".split(): let mut border_image_${name} = border_image_${name}::get_initial_specified_value(); % endfor - try!(input.try(|input| { + let result: Result<_, ParseError> = input.try(|input| { % for name in "outset repeat slice source width".split(): let mut ${name} = None; % endfor @@ -256,7 +261,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) { slice = Some(value); // Parse border image width and outset, if applicable. - let maybe_width_outset: Result<_, ()> = input.try(|input| { + let maybe_width_outset: Result<_, ParseError> = input.try(|input| { try!(input.expect_delim('/')); // Parse border image width, if applicable. @@ -269,7 +274,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) border_image_outset::parse(context, input) }).ok(); if w.is_none() && o.is_none() { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } else { Ok((w, o)) @@ -305,9 +310,10 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) % endfor Ok(()) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } - })); + }); + try!(result); Ok(expanded! { % for name in "outset repeat slice source width".split(): diff --git a/components/style/properties/shorthand/box.mako.rs b/components/style/properties/shorthand/box.mako.rs index e05818e3bcc..cc0d713a7e9 100644 --- a/components/style/properties/shorthand/box.mako.rs +++ b/components/style/properties/shorthand/box.mako.rs @@ -11,29 +11,33 @@ use properties::longhands::overflow_x::SpecifiedValue; % endif - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % if product == "gecko": - let moz_kw_found = input.try(|i| match_ignore_ascii_case! { - &i.expect_ident()?, - "-moz-scrollbars-horizontal" => { - Ok(expanded! { - overflow_x: SpecifiedValue::scroll, - overflow_y: SpecifiedValue::hidden, - }) - } - "-moz-scrollbars-vertical" => { - Ok(expanded! { - overflow_x: SpecifiedValue::hidden, - overflow_y: SpecifiedValue::scroll, - }) - } - "-moz-scrollbars-none" => { - Ok(expanded! { - overflow_x: SpecifiedValue::hidden, - overflow_y: SpecifiedValue::hidden, - }) - } - _ => Err(()) + let moz_kw_found = input.try(|i| { + let ident = i.expect_ident()?; + (match_ignore_ascii_case! { + &ident, + "-moz-scrollbars-horizontal" => { + Ok(expanded! { + overflow_x: SpecifiedValue::scroll, + overflow_y: SpecifiedValue::hidden, + }) + } + "-moz-scrollbars-vertical" => { + Ok(expanded! { + overflow_x: SpecifiedValue::hidden, + overflow_y: SpecifiedValue::scroll, + }) + } + "-moz-scrollbars-none" => { + Ok(expanded! { + overflow_x: SpecifiedValue::hidden, + overflow_y: SpecifiedValue::hidden, + }) + } + _ => Err(()) + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) }); if moz_kw_found.is_ok() { return moz_kw_found @@ -88,14 +92,16 @@ macro_rules! try_parse_one { use properties::longhands::transition_${prop}; % endfor - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { struct SingleTransition { % for prop in "property duration timing_function delay".split(): transition_${prop}: transition_${prop}::SingleSpecifiedValue, % endfor } - fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result { + fn parse_one_transition<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % for prop in "property duration timing_function delay".split(): let mut ${prop} = None; % endfor @@ -123,7 +129,7 @@ macro_rules! try_parse_one { % endfor }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -202,14 +208,16 @@ macro_rules! try_parse_one { use properties::longhands::animation_${prop}; % endfor - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { struct SingleAnimation { % for prop in props: animation_${prop}: animation_${prop}::SingleSpecifiedValue, % endfor } - fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result { + fn parse_one_animation<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % for prop in props: let mut ${prop} = None; % endfor @@ -237,7 +245,7 @@ macro_rules! try_parse_one { // If nothing is parsed, this is an invalid entry. if parsed == 0 { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } else { Ok(SingleAnimation { % for prop in props: @@ -303,7 +311,8 @@ macro_rules! try_parse_one { spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type"> use properties::longhands::scroll_snap_type_x; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let result = try!(scroll_snap_type_x::parse(context, input)); Ok(expanded! { scroll_snap_type_x: result, @@ -331,7 +340,8 @@ macro_rules! try_parse_one { spec="Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/transform"> use properties::longhands::transform; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { Ok(expanded! { transform: transform::parse_prefixed(context, input)?, }) diff --git a/components/style/properties/shorthand/column.mako.rs b/components/style/properties/shorthand/column.mako.rs index 336cad51356..692326056b3 100644 --- a/components/style/properties/shorthand/column.mako.rs +++ b/components/style/properties/shorthand/column.mako.rs @@ -8,7 +8,8 @@ extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns"> use properties::longhands::{column_count, column_width}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut column_count = None; let mut column_width = None; @@ -40,7 +41,7 @@ let values = autos + column_count.iter().len() + column_width.iter().len(); if values == 0 || values > 2 { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } else { Ok(expanded! { column_count: unwrap_or_initial!(column_count), @@ -65,7 +66,8 @@ use properties::longhands::{column_rule_width, column_rule_style}; use properties::longhands::column_rule_color; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % for name in "width style color".split(): let mut column_rule_${name} = None; % endfor @@ -92,7 +94,7 @@ column_rule_color: unwrap_or_initial!(column_rule_color), }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index bcee6228f22..009282a1b91 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -38,7 +38,8 @@ % endif use self::font_family::SpecifiedValue as FontFamily; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut nb_normals = 0; let mut style = None; let mut variant_caps = None; @@ -97,7 +98,7 @@ } if size.is_none() || (count(&style) + count(&weight) + count(&variant_caps) + count(&stretch) + nb_normals) > 4 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } let line_height = if input.try(|input| input.expect_delim('/')).is_ok() { Some(try!(LineHeight::parse(context, input))) @@ -239,7 +240,8 @@ % endfor % endif - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut nb_normals = 0; let mut caps = None; loop { @@ -264,7 +266,7 @@ } let count = count(&caps) + nb_normals; if count == 0 || count > 1 { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } Ok(expanded! { font_variant_caps: unwrap_or_initial!(font_variant_caps, caps), diff --git a/components/style/properties/shorthand/inherited_svg.mako.rs b/components/style/properties/shorthand/inherited_svg.mako.rs index b47e3021fd7..76f1c840f0e 100644 --- a/components/style/properties/shorthand/inherited_svg.mako.rs +++ b/components/style/properties/shorthand/inherited_svg.mako.rs @@ -9,7 +9,8 @@ spec="https://www.w3.org/TR/SVG2/painting.html#MarkerShorthand"> use values::specified::UrlOrNone; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { use parser::Parse; let url = UrlOrNone::parse(context, input)?; diff --git a/components/style/properties/shorthand/inherited_text.mako.rs b/components/style/properties/shorthand/inherited_text.mako.rs index 30ded7c2a7a..ae8a5e21215 100644 --- a/components/style/properties/shorthand/inherited_text.mako.rs +++ b/components/style/properties/shorthand/inherited_text.mako.rs @@ -9,7 +9,8 @@ spec="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-property"> use properties::longhands::{text_emphasis_color, text_emphasis_style}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut color = None; let mut style = None; @@ -34,7 +35,7 @@ text_emphasis_style: unwrap_or_initial!(text_emphasis_style, style), }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -56,7 +57,8 @@ spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke"> use properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut color = None; let mut width = None; loop { @@ -82,7 +84,7 @@ _webkit_text_stroke_width: unwrap_or_initial!(_webkit_text_stroke_width, width), }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } diff --git a/components/style/properties/shorthand/list.mako.rs b/components/style/properties/shorthand/list.mako.rs index cb7cc858160..4ea2647e141 100644 --- a/components/style/properties/shorthand/list.mako.rs +++ b/components/style/properties/shorthand/list.mako.rs @@ -10,7 +10,8 @@ use properties::longhands::{list_style_image, list_style_position, list_style_type}; use values::{Either, None_}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { // `none` is ambiguous until we've finished parsing the shorthands, so we count the number // of times we see it. let mut nones = 0u8; @@ -19,7 +20,7 @@ if input.try(|input| input.expect_ident_matching("none")).is_ok() { nones = nones + 1; if nones > 2 { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent("none".into()).into()) } any = true; continue @@ -104,7 +105,7 @@ list_style_type: unwrap_or_initial!(list_style_type), }) } - _ => Err(()), + _ => Err(StyleParseError::UnspecifiedError.into()), } } diff --git a/components/style/properties/shorthand/mask.mako.rs b/components/style/properties/shorthand/mask.mako.rs index f51720d1e00..00e28dbb9f4 100644 --- a/components/style/properties/shorthand/mask.mako.rs +++ b/components/style/properties/shorthand/mask.mako.rs @@ -35,7 +35,8 @@ } } - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % for name in "image mode position_x position_y size repeat origin clip composite".split(): let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new()); % endfor @@ -103,7 +104,7 @@ % endfor Ok(()) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } })); @@ -180,7 +181,8 @@ use values::specified::position::Position; use parser::Parse; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut position_x = mask_position_x::SpecifiedValue(Vec::new()); let mut position_y = mask_position_y::SpecifiedValue(Vec::new()); let mut any = false; @@ -193,7 +195,7 @@ Ok(()) })?; if any == false { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(expanded! { diff --git a/components/style/properties/shorthand/outline.mako.rs b/components/style/properties/shorthand/outline.mako.rs index 649651c02d9..c81b93ae5a9 100644 --- a/components/style/properties/shorthand/outline.mako.rs +++ b/components/style/properties/shorthand/outline.mako.rs @@ -10,7 +10,8 @@ use values::specified; use parser::Parse; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let _unused = context; let mut color = None; let mut style = None; @@ -47,7 +48,7 @@ outline_width: unwrap_or_initial!(outline_width, width), }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -71,7 +72,8 @@ use values::specified::border::BorderRadius; use parser::Parse; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let radii = try!(BorderRadius::parse(context, input)); Ok(expanded! { _moz_outline_radius_topleft: radii.top_left, diff --git a/components/style/properties/shorthand/position.mako.rs b/components/style/properties/shorthand/position.mako.rs index 6627edd92bf..a66631131d9 100644 --- a/components/style/properties/shorthand/position.mako.rs +++ b/components/style/properties/shorthand/position.mako.rs @@ -8,7 +8,8 @@ spec="https://drafts.csswg.org/css-flexbox/#flex-flow-property"> use properties::longhands::{flex_direction, flex_wrap}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut direction = None; let mut wrap = None; loop { @@ -28,7 +29,7 @@ } if direction.is_none() && wrap.is_none() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } Ok(expanded! { flex_direction: unwrap_or_initial!(flex_direction, direction), @@ -50,14 +51,15 @@ spec="https://drafts.csswg.org/css-flexbox/#flex-property"> use values::specified::Number; - fn parse_flexibility(context: &ParserContext, input: &mut Parser) - -> Result<(Number, Option),()> { + fn parse_flexibility<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result<(Number, Option),ParseError<'i>> { let grow = try!(Number::parse_non_negative(context, input)); let shrink = input.try(|i| Number::parse_non_negative(context, i)).ok(); Ok((grow, shrink)) } - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut grow = None; let mut shrink = None; let mut basis = None; @@ -87,7 +89,7 @@ } if grow.is_none() && basis.is_none() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } Ok(expanded! { flex_grow: grow.unwrap_or(Number::new(1.0)), @@ -118,7 +120,8 @@ products="gecko"> use properties::longhands::{grid_row_gap, grid_column_gap}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let row_gap = grid_row_gap::parse(context, input)?; let column_gap = input.try(|input| grid_column_gap::parse(context, input)).unwrap_or(row_gap.clone()); @@ -152,7 +155,8 @@ // NOTE: Since both the shorthands have the same code, we should (re-)use code from one to implement // the other. This might not be a big deal for now, but we should consider looking into this in the future // to limit the amount of code generated. - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let start = input.try(|i| GridLine::parse(context, i))?; let end = if input.try(|i| i.expect_delim('/')).is_ok() { GridLine::parse(context, input)? @@ -189,7 +193,8 @@ use parser::Parse; // The code is the same as `grid-{row,column}` except that this can have four values at most. - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { fn line_with_ident_from(other: &GridLine) -> GridLine { let mut this = GridLine::default(); if other.line_num.is_none() && !other.is_span { @@ -259,8 +264,9 @@ use values::specified::grid::parse_line_names; /// Parsing for `` shorthand (also used by `grid` shorthand). - pub fn parse_grid_template(context: &ParserContext, input: &mut Parser) - -> Result<(TrackListOrNone, TrackListOrNone, Either), ()> { + pub fn parse_grid_template<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result<(TrackListOrNone, TrackListOrNone, Either), + ParseError<'i>> { if input.try(|i| i.expect_ident_matching("none")).is_ok() { return Ok((Either::Second(None_), Either::Second(None_), Either::Second(None_))) } @@ -295,7 +301,8 @@ line_names.push(vec![]); // should be one longer than track sizes } - let template_areas = TemplateAreas::from_vec(strings)?; + let template_areas = TemplateAreas::from_vec(strings) + .map_err(|()| StyleParseError::UnspecifiedError)?; let template_rows = TrackList { list_type: TrackListType::Normal, values: values, @@ -306,7 +313,7 @@ let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() { let track_list = TrackList::parse(context, input)?; if track_list.list_type != TrackListType::Explicit { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } Either::First(track_list) @@ -326,7 +333,8 @@ } #[inline] - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let (rows, columns, areas) = parse_grid_template(context, input)?; Ok(expanded! { grid_template_rows: rows, @@ -410,7 +418,8 @@ use values::{Either, None_}; use values::specified::{LengthOrPercentage, TrackSize}; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let mut temp_rows = Either::Second(None_); let mut temp_cols = Either::Second(None_); let mut temp_areas = Either::Second(None_); @@ -418,7 +427,8 @@ let mut auto_cols = TrackSize::default(); let mut flow = grid_auto_flow::get_initial_value(); - fn parse_auto_flow(input: &mut Parser, is_row: bool) -> Result { + fn parse_auto_flow<'i, 't>(input: &mut Parser<'i, 't>, is_row: bool) + -> Result> { let mut auto_flow = None; let mut dense = false; for _ in 0..2 { @@ -440,7 +450,7 @@ autoflow: flow, dense: dense, } - }).ok_or(()) + }).ok_or(StyleParseError::UnspecifiedError.into()) } if let Ok((rows, cols, areas)) = input.try(|i| super::grid_template::parse_grid_template(context, i)) { @@ -506,15 +516,16 @@ use properties::longhands::align_content; use properties::longhands::justify_content; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let align = align_content::parse(context, input)?; if align.has_extra_flags() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } let justify = input.try(|input| justify_content::parse(context, input)) .unwrap_or(justify_content::SpecifiedValue::from(align)); if justify.has_extra_flags() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(expanded! { @@ -541,14 +552,15 @@ use values::specified::align::AlignJustifySelf; use parser::Parse; - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let align = AlignJustifySelf::parse(context, input)?; if align.has_extra_flags() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } let justify = input.try(|input| AlignJustifySelf::parse(context, input)).unwrap_or(align.clone()); if justify.has_extra_flags() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(expanded! { @@ -582,15 +594,16 @@ } } - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let align = AlignItems::parse(context, input)?; if align.has_extra_flags() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } let justify = input.try(|input| JustifyItems::parse(context, input)) .unwrap_or(JustifyItems::from(align)); if justify.has_extra_flags() { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(expanded! { diff --git a/components/style/properties/shorthand/text.mako.rs b/components/style/properties/shorthand/text.mako.rs index 111adb4de1b..f8edac923fb 100644 --- a/components/style/properties/shorthand/text.mako.rs +++ b/components/style/properties/shorthand/text.mako.rs @@ -16,7 +16,8 @@ use properties::longhands::text_decoration_line; % endif - pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { % if product == "gecko" or data.testing: let (mut line, mut style, mut color, mut any) = (None, None, None, false); % else: @@ -47,7 +48,7 @@ } if !any { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(expanded! { diff --git a/components/style/selector_parser.rs b/components/style/selector_parser.rs index e1a7a0aecda..a7e99106aa6 100644 --- a/components/style/selector_parser.rs +++ b/components/style/selector_parser.rs @@ -6,10 +6,11 @@ #![deny(missing_docs)] -use cssparser::Parser as CssParser; +use cssparser::{Parser as CssParser, ParserInput}; use selectors::Element; use selectors::parser::SelectorList; use std::fmt::Debug; +use style_traits::ParseError; use stylesheets::{Origin, Namespaces}; /// A convenient alias for the type that represents an attribute value used for @@ -59,13 +60,14 @@ impl<'a> SelectorParser<'a> { /// /// This is used for some DOM APIs like `querySelector`. pub fn parse_author_origin_no_namespace(input: &str) - -> Result, ()> { + -> Result, ParseError> { let namespaces = Namespaces::default(); let parser = SelectorParser { stylesheet_origin: Origin::Author, namespaces: &namespaces, }; - SelectorList::parse(&parser, &mut CssParser::new(input)) + let mut input = ParserInput::new(input); + SelectorList::parse(&parser, &mut CssParser::new(&mut input)) } /// Whether we're parsing selectors in a user-agent stylesheet. diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index bd5210819d1..13c87a6972f 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -13,9 +13,10 @@ use media_queries::MediaType; use parser::ParserContext; use properties::{ComputedValues, StyleBuilder}; use properties::longhands::font_size; +use selectors::parser::SelectorParseError; use std::fmt; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; -use style_traits::{CSSPixel, ToCss}; +use style_traits::{CSSPixel, ToCss, ParseError}; use style_traits::viewport::ViewportConstraints; use values::computed::{self, ToComputedValue}; use values::specified; @@ -151,7 +152,8 @@ impl Expression { /// ``` /// /// Only supports width and width ranges for now. - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { try!(input.expect_parenthesis_block()); input.parse_nested_block(|input| { let name = try!(input.expect_ident()); @@ -167,7 +169,7 @@ impl Expression { "width" => { ExpressionKind::Width(Range::Eq(try!(specified::Length::parse_non_negative(context, input)))) }, - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) })) }) } diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 43d3d5dffa0..026c482f51f 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -16,7 +16,7 @@ use restyle_hints::ElementSnapshot; use selector_parser::{AttrValue as SelectorAttrValue, ElementExt, PseudoElementCascadeType, SelectorParser}; use selectors::Element; use selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; -use selectors::parser::SelectorMethods; +use selectors::parser::{SelectorMethods, SelectorParseError}; use selectors::visitor::SelectorVisitor; use std::ascii::AsciiExt; use std::borrow::Cow; @@ -24,6 +24,7 @@ use std::fmt; use std::fmt::Debug; use std::mem; use std::ops::{Deref, DerefMut}; +use style_traits::{ParseError, StyleParseError}; /// A pseudo-element, both public and private. /// @@ -300,10 +301,12 @@ impl ::selectors::SelectorImpl for SelectorImpl { type BorrowedNamespaceUrl = Namespace; } -impl<'a> ::selectors::Parser for SelectorParser<'a> { +impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { type Impl = SelectorImpl; + type Error = StyleParseError<'i>; - fn parse_non_ts_pseudo_class(&self, name: Cow) -> Result { + fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>) + -> Result> { use self::NonTSPseudoClass::*; let pseudo_class = match_ignore_ascii_case! { &name, "active" => Active, @@ -323,20 +326,21 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> { "visited" => Visited, "-servo-nonzero-border" => { if !self.in_user_agent_stylesheet() { - return Err(()); + return Err(SelectorParseError::UnexpectedIdent( + "-servo-nonzero-border".into()).into()); } ServoNonZeroBorder }, - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()), }; Ok(pseudo_class) } - fn parse_non_ts_functional_pseudo_class(&self, - name: Cow, - parser: &mut CssParser) - -> Result { + fn parse_non_ts_functional_pseudo_class<'t>(&self, + name: Cow<'i, str>, + parser: &mut CssParser<'i, 't>) + -> Result> { use self::NonTSPseudoClass::*; let pseudo_class = match_ignore_ascii_case!{ &name, "lang" => { @@ -344,18 +348,17 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> { } "-servo-case-sensitive-type-attr" => { if !self.in_user_agent_stylesheet() { - return Err(()); + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()); } ServoCaseSensitiveTypeAttr(Atom::from(parser.expect_ident()?)) } - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) }; Ok(pseudo_class) } - fn parse_pseudo_element(&self, name: Cow) - -> Result { + fn parse_pseudo_element(&self, name: Cow<'i, str>) -> Result> { use self::PseudoElement::*; let pseudo_element = match_ignore_ascii_case! { &name, "before" => Before, @@ -363,77 +366,78 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> { "selection" => Selection, "-servo-details-summary" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } DetailsSummary }, "-servo-details-content" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } DetailsContent }, "-servo-text" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoText }, "-servo-input-text" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoInputText }, "-servo-table-wrapper" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoTableWrapper }, "-servo-anonymous-table-wrapper" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoAnonymousTableWrapper }, "-servo-anonymous-table" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoAnonymousTable }, "-servo-anonymous-table-row" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoAnonymousTableRow }, "-servo-anonymous-table-cell" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoAnonymousTableCell }, "-servo-anonymous-block" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoAnonymousBlock }, "-servo-inline-block-wrapper" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoInlineBlockWrapper }, "-servo-input-absolute" => { if !self.in_user_agent_stylesheet() { - return Err(()) + return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) } ServoInlineAbsolute }, - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()) + }; Ok(pseudo_element) diff --git a/components/style/servo/url.rs b/components/style/servo/url.rs index 467f7a45715..4cf791e5512 100644 --- a/components/style/servo/url.rs +++ b/components/style/servo/url.rs @@ -13,7 +13,7 @@ use std::fmt::{self, Write}; // nonzero optimization is important in keeping the size of SpecifiedUrl below // the threshold. use std::sync::Arc; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError}; /// A specified url() value for servo. /// @@ -43,7 +43,7 @@ impl SpecifiedUrl { /// gecko version. pub fn parse_from_string<'a>(url: Cow<'a, str>, context: &ParserContext) - -> Result { + -> Result> { let serialization = Arc::new(url.into_owned()); let resolved = context.url_data.join(&serialization).ok(); Ok(SpecifiedUrl { diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs index f921eeb7631..173af7dcac4 100644 --- a/components/style/stylesheets/document_rule.rs +++ b/components/style/stylesheets/document_rule.rs @@ -6,12 +6,12 @@ //! initially in CSS Conditional Rules Module Level 3, @document has been postponed to the level 4. //! We implement the prefixed `@-moz-document`. -use cssparser::{Parser, Token, SourceLocation}; +use cssparser::{Parser, Token, SourceLocation, BasicParseError}; use media_queries::Device; use parser::{Parse, ParserContext}; use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use stylearc::Arc; use stylesheets::CssRules; use values::specified::url::SpecifiedUrl; @@ -90,9 +90,10 @@ macro_rules! parse_quoted_or_unquoted_string { match input.next() { Ok(Token::QuotedString(value)) => Ok($url_matching_function(value.into_owned())), - _ => Err(()), + Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()), + Err(e) => Err(e.into()), } - }).or_else(|_| { + }).or_else(|_: ParseError| { while let Ok(_) = input.next() {} Ok($url_matching_function(input.slice_from(start).to_string())) }) @@ -102,8 +103,8 @@ macro_rules! parse_quoted_or_unquoted_string { impl UrlMatchingFunction { /// Parse a URL matching function for a`@document` rule's condition. - pub fn parse(context: &ParserContext, input: &mut Parser) - -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if input.try(|input| input.expect_function_matching("url-prefix")).is_ok() { parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix) } else if input.try(|input| input.expect_function_matching("domain")).is_ok() { @@ -115,7 +116,7 @@ impl UrlMatchingFunction { } else if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) { Ok(UrlMatchingFunction::Url(url)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -189,8 +190,8 @@ pub struct DocumentCondition(Vec); impl DocumentCondition { /// Parse a document condition. - pub fn parse(context: &ParserContext, input: &mut Parser) - -> Result { + pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { input.parse_comma_separated(|input| UrlMatchingFunction::parse(context, input)) .map(DocumentCondition) } diff --git a/components/style/stylesheets/keyframes_rule.rs b/components/style/stylesheets/keyframes_rule.rs index 254793c79cc..2f63ec5ad1a 100644 --- a/components/style/stylesheets/keyframes_rule.rs +++ b/components/style/stylesheets/keyframes_rule.rs @@ -4,18 +4,20 @@ //! Keyframes: https://drafts.csswg.org/css-animations/#keyframes -use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser}; +use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser, ParserInput}; use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation}; -use error_reporting::NullReporter; +use error_reporting::{NullReporter, ContextualParseError}; use parser::{PARSING_MODE_DEFAULT, ParserContext, log_css_error}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{PropertyDeclarationId, LonghandId, SourcePropertyDeclaration}; use properties::LonghandIdSet; use properties::animated_properties::TransitionProperty; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; +use selectors::parser::SelectorParseError; use shared_lock::{DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard}; +use std::borrow::Cow; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use stylearc::Arc; use stylesheets::{CssRuleType, Stylesheet}; use stylesheets::rule_parser::VendorPrefix; @@ -61,7 +63,8 @@ impl KeyframesRule { /// Related spec: /// https://drafts.csswg.org/css-animations-1/#interface-csskeyframesrule-findrule pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option { - if let Ok(selector) = Parser::new(selector).parse_entirely(KeyframeSelector::parse) { + let mut input = ParserInput::new(selector); + if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) { for (i, keyframe) in self.keyframes.iter().enumerate().rev() { if keyframe.read_with(guard).selector == selector { return Some(i); @@ -120,7 +123,7 @@ impl KeyframePercentage { KeyframePercentage(value) } - fn parse(input: &mut Parser) -> Result { + fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() { KeyframePercentage::new(0.) } else if input.try(|input| input.expect_ident_matching("to")).is_ok() { @@ -130,7 +133,7 @@ impl KeyframePercentage { if percentage >= 0. && percentage <= 1. { KeyframePercentage::new(percentage) } else { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } }; @@ -168,7 +171,7 @@ impl KeyframeSelector { } /// Parse a keyframe selector from CSS input. - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { input.parse_comma_separated(KeyframePercentage::parse) .map(KeyframeSelector) } @@ -200,8 +203,8 @@ impl ToCssWithGuard for Keyframe { impl Keyframe { /// Parse a CSS keyframe. - pub fn parse(css: &str, parent_stylesheet: &Stylesheet) - -> Result>, ()> { + pub fn parse<'i>(css: &'i str, parent_stylesheet: &Stylesheet) + -> Result>, ParseError<'i>> { let error_reporter = NullReporter; let context = ParserContext::new(parent_stylesheet.origin, &parent_stylesheet.url_data, @@ -209,7 +212,8 @@ impl Keyframe { Some(CssRuleType::Keyframe), PARSING_MODE_DEFAULT, parent_stylesheet.quirks_mode); - let mut input = Parser::new(css); + let mut input = ParserInput::new(css); + let mut input = Parser::new(&mut input); let mut declarations = SourcePropertyDeclaration::new(); let mut rule_parser = KeyframeListParser { @@ -445,29 +449,31 @@ pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser, shared_l } enum Void {} -impl<'a> AtRuleParser for KeyframeListParser<'a> { +impl<'a, 'i> AtRuleParser<'i> for KeyframeListParser<'a> { type Prelude = Void; type AtRule = Arc>; + type Error = SelectorParseError<'i, StyleParseError<'i>>; } -impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { +impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> { type Prelude = KeyframeSelector; type QualifiedRule = Arc>; + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_prelude(&mut self, input: &mut Parser) -> Result { + fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>) -> Result> { let start = input.position(); match KeyframeSelector::parse(input) { Ok(sel) => Ok(sel), - Err(()) => { - let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start)); - log_css_error(input, start, &message, self.context); - Err(()) + Err(e) => { + let error = ContextualParseError::InvalidKeyframeRule(input.slice_from(start), e.clone()); + log_css_error(input, start, error, self.context); + Err(e) } } } - fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser) - -> Result { + fn parse_block<'t>(&mut self, prelude: Self::Prelude, input: &mut Parser<'i, 't>) + -> Result> { let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Keyframe)); let parser = KeyframeDeclarationParser { context: &context, @@ -480,12 +486,12 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { Ok(()) => { block.extend(iter.parser.declarations.drain(), Importance::Normal); } - Err(range) => { + Err(err) => { iter.parser.declarations.clear(); - let pos = range.start; - let message = format!("Unsupported keyframe property declaration: '{}'", - iter.input.slice(range)); - log_css_error(iter.input, pos, &*message, &context); + let pos = err.span.start; + let error = ContextualParseError::UnsupportedKeyframePropertyDeclaration( + iter.input.slice(err.span), err.error); + log_css_error(iter.input, pos, error, &context); } } // `parse_important` is not called here, `!important` is not allowed in keyframe blocks. @@ -503,22 +509,25 @@ struct KeyframeDeclarationParser<'a, 'b: 'a> { } /// Default methods reject all at rules. -impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> { +impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeDeclarationParser<'a, 'b> { type Prelude = (); type AtRule = (); + type Error = SelectorParseError<'i, StyleParseError<'i>>; } -impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> { +impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> { type Declaration = (); + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { + fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>) + -> Result<(), ParseError<'i>> { let id = try!(PropertyId::parse(name.into())); match PropertyDeclaration::parse_into(self.declarations, id, self.context, input) { Ok(()) => { // In case there is still unparsed text in the declaration, we should roll back. - input.expect_exhausted() + input.expect_exhausted().map_err(|e| e.into()) } - Err(_) => Err(()) + Err(_e) => Err(StyleParseError::UnspecifiedError.into()) } } } diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index 83abc51702a..df1bd2ae3c2 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -22,7 +22,7 @@ mod stylesheet; pub mod supports_rule; pub mod viewport_rule; -use cssparser::{parse_one_rule, Parser}; +use cssparser::{parse_one_rule, Parser, ParserInput}; use error_reporting::NullReporter; use parser::{ParserContext, PARSING_MODE_DEFAULT}; use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; @@ -234,7 +234,8 @@ impl CssRule { parent_stylesheet.quirks_mode ); - let mut input = Parser::new(css); + let mut input = ParserInput::new(css); + let mut input = Parser::new(&mut input); let mut guard = parent_stylesheet.namespaces.write(); diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index b1d250ab51a..f8f536b4a06 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -7,6 +7,7 @@ use {Namespace, Prefix}; use counter_style::{parse_counter_style_body, parse_counter_style_name}; use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser, SourceLocation}; +use error_reporting::ContextualParseError; use font_face::parse_font_face_block; use media_queries::{parse_media_query_list, MediaList}; use parking_lot::RwLock; @@ -14,9 +15,12 @@ use parser::{Parse, ParserContext, log_css_error}; use properties::parse_property_declaration_list; use selector_parser::{SelectorImpl, SelectorParser}; use selectors::SelectorList; +use selectors::parser::SelectorParseError; use shared_lock::{Locked, SharedRwLock}; +use std::borrow::Cow; use std::sync::atomic::AtomicBool; use str::starts_with_ignore_ascii_case; +use style_traits::{StyleParseError, ParseError}; use stylearc::Arc; use stylesheets::{CssRule, CssRules, CssRuleType, Origin, StylesheetLoader}; use stylesheets::{DocumentRule, ImportRule, KeyframesRule, MediaRule, NamespaceRule, PageRule}; @@ -132,22 +136,24 @@ fn register_namespace(_: &Namespace) -> Result<(), ()> { Ok(()) // servo doesn't use namespace ids } -impl<'a> AtRuleParser for TopLevelRuleParser<'a> { +impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> { type Prelude = AtRulePrelude; type AtRule = CssRule; + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_prelude( + fn parse_prelude<'t>( &mut self, - name: &str, - input: &mut Parser - ) -> Result, ()> { + name: Cow<'i, str>, + input: &mut Parser<'i, 't> + ) -> Result, ParseError<'i>> { let location = get_location_with_offset(input.current_source_location(), self.context.line_number_offset); - match_ignore_ascii_case! { name, + match_ignore_ascii_case! { &*name, "import" => { if self.state > State::Imports { self.state = State::Invalid; - return Err(()) // "@import must be before any rule but @charset" + // "@import must be before any rule but @charset" + return Err(StyleParseError::UnexpectedImportRule.into()) } self.state = State::Imports; @@ -190,14 +196,16 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { "namespace" => { if self.state > State::Namespaces { self.state = State::Invalid; - return Err(()) // "@namespace must be before any rule but @charset and @import" + // "@namespace must be before any rule but @charset and @import" + return Err(StyleParseError::UnexpectedNamespaceRule.into()) } self.state = State::Namespaces; let prefix_result = input.try(|input| input.expect_ident()); let url = Namespace::from(try!(input.expect_url_or_string())); - let id = register_namespace(&url)?; + let id = register_namespace(&url) + .map_err(|()| StyleParseError::UnspecifiedError)?; let mut namespaces = self.namespaces.as_mut().unwrap(); @@ -222,13 +230,13 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { }, // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet // anything left is invalid. - "charset" => return Err(()), // (insert appropriate error message) + "charset" => return Err(StyleParseError::UnexpectedCharsetRule.into()), _ => {} } // Don't allow starting with an invalid state if self.state > State::Body { self.state = State::Invalid; - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } self.state = State::Body; @@ -242,18 +250,21 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { } #[inline] - fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result { + fn parse_block<'t>(&mut self, prelude: AtRulePrelude, input: &mut Parser<'i, 't>) + -> Result> { AtRuleParser::parse_block(&mut self.nested(), prelude, input) } } -impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> { +impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a> { type Prelude = SelectorList; type QualifiedRule = CssRule; + type Error = SelectorParseError<'i, StyleParseError<'i>>; #[inline] - fn parse_prelude(&mut self, input: &mut Parser) -> Result, ()> { + fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>) + -> Result, ParseError<'i>> { self.state = State::Body; // "Freeze" the namespace map (no more namespace rules can be parsed @@ -267,11 +278,11 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> { } #[inline] - fn parse_block( + fn parse_block<'t>( &mut self, prelude: SelectorList, - input: &mut Parser - ) -> Result { + input: &mut Parser<'i, 't> + ) -> Result> { QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input) } } @@ -302,10 +313,11 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> { while let Some(result) = iter.next() { match result { Ok(rule) => rules.push(rule), - Err(range) => { - let pos = range.start; - let message = format!("Unsupported rule: '{}'", iter.input.slice(range)); - log_css_error(iter.input, pos, &*message, self.context); + Err(err) => { + let pos = err.span.start; + let error = ContextualParseError::UnsupportedRule( + iter.input.slice(err.span), err.error); + log_css_error(iter.input, pos, error, self.context); } } } @@ -324,22 +336,23 @@ fn is_viewport_enabled() -> bool { false // Gecko doesn't support @viewport. } -impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { +impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> { type Prelude = AtRulePrelude; type AtRule = CssRule; + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_prelude( + fn parse_prelude<'t>( &mut self, - name: &str, - input: &mut Parser - ) -> Result, ()> { + name: Cow<'i, str>, + input: &mut Parser<'i, 't> + ) -> Result, ParseError<'i>> { let location = get_location_with_offset( input.current_source_location(), self.context.line_number_offset ); - match_ignore_ascii_case! { name, + match_ignore_ascii_case! { &*name, "media" => { let media_queries = parse_media_query_list(self.context, input); let arc = Arc::new(self.shared_lock.wrap(media_queries)); @@ -355,14 +368,14 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { "counter-style" => { if !cfg!(feature = "gecko") { // Support for this rule is not fully implemented in Servo yet. - return Err(()) + return Err(StyleParseError::UnsupportedAtRule(name.clone()).into()) } let name = parse_counter_style_name(input)?; // ASCII-case-insensitive matches for "decimal" are already // lower-cased by `parse_counter_style_name`, so we can use == // here. if name.0 == atom!("decimal") { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } Ok(AtRuleType::WithBlock(AtRulePrelude::CounterStyle(name))) }, @@ -370,13 +383,13 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { if is_viewport_enabled() { Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport)) } else { - Err(()) + Err(StyleParseError::UnsupportedAtRule(name.clone()).into()) } }, "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => { - let prefix = if starts_with_ignore_ascii_case(name, "-webkit-") { + let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") { Some(VendorPrefix::WebKit) - } else if starts_with_ignore_ascii_case(name, "-moz-") { + } else if starts_with_ignore_ascii_case(&*name, "-moz-") { Some(VendorPrefix::Moz) } else { None @@ -384,7 +397,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { if cfg!(feature = "servo") && prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) { // Servo should not support @-moz-keyframes. - return Err(()) + return Err(StyleParseError::UnsupportedAtRule(name.clone()).into()) } let name = KeyframesName::parse(self.context, input)?; @@ -394,7 +407,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { if cfg!(feature = "gecko") { Ok(AtRuleType::WithBlock(AtRulePrelude::Page(location))) } else { - Err(()) + Err(StyleParseError::UnsupportedAtRule(name.clone()).into()) } }, "-moz-document" => { @@ -402,18 +415,18 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { let cond = DocumentCondition::parse(self.context, input)?; Ok(AtRuleType::WithBlock(AtRulePrelude::Document(cond, location))) } else { - Err(()) + Err(StyleParseError::UnsupportedAtRule(name.clone()).into()) } }, - _ => Err(()) + _ => Err(StyleParseError::UnsupportedAtRule(name.clone()).into()) } } - fn parse_block( + fn parse_block<'t>( &mut self, prelude: AtRulePrelude, - input: &mut Parser - ) -> Result { + input: &mut Parser<'i, 't> + ) -> Result> { match prelude { AtRulePrelude::FontFace(location) => { let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::FontFace)); @@ -478,11 +491,13 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { } } -impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { +impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> { type Prelude = SelectorList; type QualifiedRule = CssRule; + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_prelude(&mut self, input: &mut Parser) -> Result, ()> { + fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>) + -> Result, ParseError<'i>> { let selector_parser = SelectorParser { stylesheet_origin: self.stylesheet_origin, namespaces: self.context.namespaces.unwrap(), @@ -491,11 +506,11 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { SelectorList::parse(&selector_parser, input) } - fn parse_block( + fn parse_block<'t>( &mut self, prelude: SelectorList, - input: &mut Parser - ) -> Result { + input: &mut Parser<'i, 't> + ) -> Result> { let location = get_location_with_offset(input.current_source_location(), self.context.line_number_offset); let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Style)); diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index 5e1e9bb5bad..aefcb0ff926 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -4,8 +4,8 @@ use {Prefix, Namespace}; use context::QuirksMode; -use cssparser::{Parser, RuleListParser}; -use error_reporting::ParseErrorReporter; +use cssparser::{Parser, RuleListParser, ParserInput}; +use error_reporting::{ParseErrorReporter, ContextualParseError}; use fnv::FnvHashMap; use media_queries::{MediaList, Device}; use parking_lot::RwLock; @@ -110,7 +110,8 @@ impl Stylesheet { line_number_offset: u64 ) -> (Vec, bool) { let mut rules = Vec::new(); - let mut input = Parser::new(css); + let mut input = ParserInput::new(css); + let mut input = Parser::new(&mut input); let context = ParserContext::new_with_line_number_offset( @@ -140,10 +141,11 @@ impl Stylesheet { while let Some(result) = iter.next() { match result { Ok(rule) => rules.push(rule), - Err(range) => { - let pos = range.start; - let message = format!("Invalid rule: '{}'", iter.input.slice(range)); - log_css_error(iter.input, pos, &*message, iter.parser.context()); + Err(err) => { + let pos = err.span.start; + let error = ContextualParseError::InvalidRule( + iter.input.slice(err.span), err.error); + log_css_error(iter.input, pos, error, iter.parser.context()); } } } diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs index 7d87f0f4aec..1d9d52055ce 100644 --- a/components/style/stylesheets/supports_rule.rs +++ b/components/style/stylesheets/supports_rule.rs @@ -4,12 +4,14 @@ //! [@supports rules](https://drafts.csswg.org/css-conditional-3/#at-supports) +use cssparser::{BasicParseError, ParseError as CssParseError, ParserInput}; use cssparser::{Delimiter, parse_important, Parser, SourceLocation, Token}; use parser::ParserContext; use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration}; +use selectors::parser::SelectorParseError; use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use stylearc::Arc; use stylesheets::{CssRuleType, CssRules}; @@ -81,7 +83,7 @@ impl SupportsCondition { /// Parse a condition /// /// https://drafts.csswg.org/css-conditional/#supports_condition - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) { let inner = SupportsCondition::parse_in_parens(input)?; return Ok(SupportsCondition::Not(Box::new(inner))); @@ -90,7 +92,7 @@ impl SupportsCondition { let in_parens = SupportsCondition::parse_in_parens(input)?; let (keyword, wrapper) = match input.next() { - Err(()) => { + Err(_) => { // End of input return Ok(in_parens) } @@ -98,10 +100,10 @@ impl SupportsCondition { match_ignore_ascii_case! { &ident, "and" => ("and", SupportsCondition::And as fn(_) -> _), "or" => ("or", SupportsCondition::Or as fn(_) -> _), - _ => return Err(()) + _ => return Err(SelectorParseError::UnexpectedIdent(ident.clone()).into()) } } - _ => return Err(()) + Ok(t) => return Err(CssParseError::Basic(BasicParseError::UnexpectedToken(t))) }; let mut conditions = Vec::with_capacity(2); @@ -118,7 +120,7 @@ impl SupportsCondition { } /// https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens - fn parse_in_parens(input: &mut Parser) -> Result { + fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { // Whitespace is normally taken care of in `Parser::next`, // but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases. while input.try(Parser::expect_whitespace).is_ok() {} @@ -127,17 +129,18 @@ impl SupportsCondition { Token::ParenthesisBlock => { input.parse_nested_block(|input| { // `input.try()` not needed here since the alternative uses `consume_all()`. - parse_condition_or_declaration(input).or_else(|()| { + parse_condition_or_declaration(input).or_else(|_| { consume_all(input); Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned())) }) }) } Token::Function(_) => { - input.parse_nested_block(|i| Ok(consume_all(i))).unwrap(); + let result: Result<_, ParseError> = input.parse_nested_block(|i| Ok(consume_all(i))); + result.unwrap(); Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned())) } - _ => Err(()) + t => Err(CssParseError::Basic(BasicParseError::UnexpectedToken(t))) } } @@ -156,7 +159,8 @@ impl SupportsCondition { /// supports_condition | declaration /// https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext -pub fn parse_condition_or_declaration(input: &mut Parser) -> Result { +pub fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>) + -> Result> { if let Ok(condition) = input.try(SupportsCondition::parse) { Ok(SupportsCondition::Parenthesized(Box::new(condition))) } else { @@ -244,7 +248,7 @@ fn consume_all(input: &mut Parser) { impl Declaration { /// Parse a declaration - pub fn parse(input: &mut Parser) -> Result { + pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let prop = input.expect_ident()?.into_owned(); input.expect_colon()?; let val = parse_anything(input); @@ -260,12 +264,13 @@ impl Declaration { } else { return false }; - let mut input = Parser::new(&self.val); + let mut input = ParserInput::new(&self.val); + let mut input = Parser::new(&mut input); let context = ParserContext::new_with_rule_type(cx, Some(CssRuleType::Style)); let mut declarations = SourcePropertyDeclaration::new(); let res = input.parse_until_before(Delimiter::Bang, |input| { PropertyDeclaration::parse_into(&mut declarations, id, &context, input) - .map_err(|_| ()) + .map_err(|e| StyleParseError::PropertyDeclaration(e).into()) }); let _ = input.try(parse_important); res.is_ok() && input.is_exhausted() diff --git a/components/style/stylesheets/viewport_rule.rs b/components/style/stylesheets/viewport_rule.rs index a510ea5f27c..e9af7a74673 100644 --- a/components/style/stylesheets/viewport_rule.rs +++ b/components/style/stylesheets/viewport_rule.rs @@ -11,18 +11,20 @@ use app_units::Au; use context::QuirksMode; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important}; use cssparser::ToCss as ParserToCss; +use error_reporting::ContextualParseError; use euclid::size::TypedSize2D; use font_metrics::get_metrics_provider_for_product; use media_queries::Device; use parser::{Parse, ParserContext, log_css_error}; use properties::StyleBuilder; +use selectors::parser::SelectorParseError; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt; use std::iter::Enumerate; use std::str::Chars; -use style_traits::{PinchZoomFactor, ToCss}; +use style_traits::{PinchZoomFactor, ToCss, ParseError, StyleParseError}; use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom}; use stylearc::Arc; use stylesheets::{Stylesheet, Origin}; @@ -167,7 +169,8 @@ impl FromMeta for ViewportLength { } impl ViewportLength { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { // we explicitly do not accept 'extend-to-zoom', since it is a UA // internal value for viewport translation LengthOrPercentageOrAuto::parse_non_negative(context, input).map(ViewportLength::Specified) @@ -246,23 +249,27 @@ impl ToCss for ViewportDescriptorDeclaration { } } -fn parse_shorthand(context: &ParserContext, input: &mut Parser) -> Result<(ViewportLength, ViewportLength), ()> { +fn parse_shorthand<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result<(ViewportLength, ViewportLength), ParseError<'i>> { let min = try!(ViewportLength::parse(context, input)); match input.try(|i| ViewportLength::parse(context, i)) { - Err(()) => Ok((min.clone(), min)), + Err(_) => Ok((min.clone(), min)), Ok(max) => Ok((min, max)) } } -impl<'a, 'b> AtRuleParser for ViewportRuleParser<'a, 'b> { +impl<'a, 'b, 'i> AtRuleParser<'i> for ViewportRuleParser<'a, 'b> { type Prelude = (); type AtRule = Vec; + type Error = SelectorParseError<'i, StyleParseError<'i>>; } -impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> { +impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> { type Declaration = Vec; + type Error = SelectorParseError<'i, StyleParseError<'i>>; - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result, ()> { + fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>) + -> Result, ParseError<'i>> { macro_rules! declaration { ($declaration:ident($parse:expr)) => { declaration!($declaration(value: try!($parse(input)), @@ -289,7 +296,7 @@ impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> { }} } - match_ignore_ascii_case! { name, + match_ignore_ascii_case! { &*name, "min-width" => ok!(MinWidth(|i| ViewportLength::parse(self.context, i))), "max-width" => ok!(MaxWidth(|i| ViewportLength::parse(self.context, i))), "width" => ok!(shorthand -> [MinWidth, MaxWidth]), @@ -301,7 +308,7 @@ impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> { "max-zoom" => ok!(MaxZoom(Zoom::parse)), "user-zoom" => ok!(UserZoom(UserZoom::parse)), "orientation" => ok!(Orientation(Orientation::parse)), - _ => Err(()), + _ => Err(SelectorParseError::UnexpectedIdent(name.clone()).into()), } } } @@ -328,7 +335,7 @@ fn is_whitespace_separator_or_equals(c: &char) -> bool { } impl Parse for ViewportRule { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let parser = ViewportRuleParser { context: context }; let mut cascade = Cascade::new(); @@ -340,11 +347,11 @@ impl Parse for ViewportRule { cascade.add(Cow::Owned(declarations)) } } - Err(range) => { - let pos = range.start; - let message = format!("Unsupported @viewport descriptor declaration: '{}'", - parser.input.slice(range)); - log_css_error(parser.input, pos, &*message, &context); + Err(err) => { + let pos = err.span.start; + let error = ContextualParseError::UnsupportedViewportDescriptorDeclaration( + parser.input.slice(err.span), err.error); + log_css_error(parser.input, pos, error, &context); } } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 6374737f157..7f91855c4fc 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -10,7 +10,7 @@ use context::{QuirksMode, SharedStyleContext}; use data::ComputedStyle; use dom::TElement; use element_state::ElementState; -use error_reporting::RustLogReporter; +use error_reporting::create_error_reporter; use font_metrics::FontMetricsProvider; #[cfg(feature = "gecko")] use gecko_bindings::structs::{nsIAtom, StyleRuleInclusion}; @@ -595,7 +595,7 @@ impl Stylist { parent.map(|p| &**p), None, None, - &RustLogReporter, + &create_error_reporter(), font_metrics, cascade_flags, self.quirks_mode); @@ -676,7 +676,7 @@ impl Stylist { Some(parent_style), None, None, - &RustLogReporter, + &create_error_reporter(), font_metrics, CascadeFlags::empty(), self.quirks_mode); @@ -1216,7 +1216,7 @@ impl Stylist { Some(parent_style), None, None, - &RustLogReporter, + &create_error_reporter(), &metrics, CascadeFlags::empty(), self.quirks_mode)) diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 3775bb30597..c90dca1f10d 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -7,8 +7,9 @@ use cssparser::{Parser, serialize_identifier}; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; use std::{fmt, mem, usize}; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use values::{CSSFloat, CustomIdent}; use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue}; use values::specified::Integer; @@ -70,7 +71,7 @@ impl ToCss for GridLine { } impl Parse for GridLine { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let mut grid_line = Default::default(); if input.try(|i| i.expect_ident_matching("auto")).is_ok() { return Ok(grid_line) @@ -85,7 +86,7 @@ impl Parse for GridLine { for _ in 0..3 { // Maximum possible entities for if input.try(|i| i.expect_ident_matching("span")).is_ok() { if grid_line.is_span { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } if grid_line.line_num.is_some() || grid_line.ident.is_some() { @@ -95,14 +96,14 @@ impl Parse for GridLine { grid_line.is_span = true; } else if let Ok(i) = input.try(|i| Integer::parse(context, i)) { if i.value() == 0 || val_before_span || grid_line.line_num.is_some() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } grid_line.line_num = Some(i); } else if let Ok(name) = input.try(|i| i.expect_ident()) { if val_before_span || grid_line.ident.is_some() || CustomIdent::from_ident((&*name).into(), &[]).is_err() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } grid_line.ident = Some(name.into_owned()); @@ -112,18 +113,18 @@ impl Parse for GridLine { } if grid_line.is_auto() { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } if grid_line.is_span { if let Some(i) = grid_line.line_num { if i.value() <= 0 { // disallow negative integers for grid spans - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } } else if grid_line.ident.is_some() { // integer could be omitted grid_line.line_num = Some(Integer::new(1)); } else { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } } @@ -341,19 +342,20 @@ pub enum RepeatCount { } impl Parse for RepeatCount { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if let Ok(i) = input.try(|i| Integer::parse(context, i)) { if i.value() > 0 { Ok(RepeatCount::Number(i)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } else { - match_ignore_ascii_case! { &input.expect_ident()?, + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "auto-fill" => Ok(RepeatCount::AutoFill), "auto-fit" => Ok(RepeatCount::AutoFit), _ => Err(()), - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } } diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index da0ba4a4301..ffcf3a769f7 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -8,8 +8,9 @@ use counter_style::{Symbols, parse_counter_style_name}; use cssparser::Parser; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; use std::fmt; -use style_traits::{OneOrMoreCommaSeparated, ToCss}; +use style_traits::{OneOrMoreCommaSeparated, ToCss, ParseError, StyleParseError}; use super::CustomIdent; use values::specified::url::SpecifiedUrl; @@ -79,7 +80,7 @@ impl CounterStyleOrNone { no_viewport_percentage!(CounterStyleOrNone); impl Parse for CounterStyleOrNone { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if let Ok(name) = input.try(|i| parse_counter_style_name(i)) { return Ok(CounterStyleOrNone::Name(name)); } @@ -95,16 +96,16 @@ impl Parse for CounterStyleOrNone { // numeric system. if (symbols_type == SymbolsType::Alphabetic || symbols_type == SymbolsType::Numeric) && symbols.0.len() < 2 { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } // Identifier is not allowed in symbols() function. if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) { - return Err(()); + return Err(StyleParseError::UnspecifiedError.into()); } Ok(CounterStyleOrNone::Symbols(symbols_type, symbols)) }); } - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -159,7 +160,7 @@ impl Parse for FontSettingTag { /// settings-control-the-font-variation-settings-property /// [ on | off | ] /// - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { use byteorder::{ReadBytesExt, BigEndian}; use std::io::Cursor; @@ -169,7 +170,7 @@ impl Parse for FontSettingTag { if tag.len() != 4 || tag.chars().any(|c| c < ' ' || c > '~') { - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } let mut raw = Cursor::new(tag.as_bytes()); @@ -192,7 +193,7 @@ pub enum FontSettings { impl Parse for FontSettings { /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if input.try(|i| i.expect_ident_matching("normal")).is_ok() { return Ok(FontSettings::Normal); } @@ -227,13 +228,13 @@ impl ToCss for FontSettingTagInt { } impl Parse for FontSettingTagInt { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if let Ok(value) = input.try(|input| input.expect_integer()) { // handle integer, throw if it is negative if value >= 0 { Ok(FontSettingTagInt(value as u32)) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) { // on is an alias for '1' @@ -250,8 +251,8 @@ impl Parse for FontSettingTagInt { impl Parse for FontSettingTagFloat { - fn parse(_: &ParserContext, input: &mut Parser) -> Result { - input.expect_number().map(FontSettingTagFloat) + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { + input.expect_number().map(FontSettingTagFloat).map_err(|e| e.into()) } } @@ -326,18 +327,19 @@ impl SVGPaint { impl SVGPaintKind { /// Parse a keyword value only - fn parse_ident(input: &mut Parser) -> Result { - Ok(match_ignore_ascii_case! { &input.expect_ident()?, - "none" => SVGPaintKind::None, - "context-fill" => SVGPaintKind::ContextFill, - "context-stroke" => SVGPaintKind::ContextStroke, - _ => return Err(()) - }) + fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, + "none" => Ok(SVGPaintKind::None), + "context-fill" => Ok(SVGPaintKind::ContextFill), + "context-stroke" => Ok(SVGPaintKind::ContextStroke), + _ => Err(()) + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } impl Parse for SVGPaint { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) { let fallback = input.try(|i| ColorType::parse(context, i)); Ok(SVGPaint { @@ -363,7 +365,7 @@ impl Parse for SVGPaint { fallback: None, }) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } } diff --git a/components/style/values/generics/rect.rs b/components/style/values/generics/rect.rs index a0a63b7144e..1ac00766f88 100644 --- a/components/style/values/generics/rect.rs +++ b/components/style/values/generics/rect.rs @@ -7,7 +7,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError}; /// A CSS value made of four components, where its `ToCss` impl will try to /// serialize as few components as possible, like for example in `border-width`. @@ -26,12 +26,12 @@ impl Rect where T: Clone { /// Parses a new `Rect` value with the given parse function. - pub fn parse_with( + pub fn parse_with<'i, 't, Parse>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, parse: Parse) - -> Result - where Parse: Fn(&ParserContext, &mut Parser) -> Result + -> Result> + where Parse: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result> { let first = parse(context, input)?; let second = if let Ok(second) = input.try(|i| parse(context, i)) { second } else { @@ -64,7 +64,7 @@ impl Parse for Rect where T: Clone + Parse { #[inline] - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { Self::parse_with(context, input, T::parse) } } diff --git a/components/style/values/generics/text.rs b/components/style/values/generics/text.rs index 5a5a10bb9d9..cb6230be633 100644 --- a/components/style/values/generics/text.rs +++ b/components/style/values/generics/text.rs @@ -9,7 +9,7 @@ use cssparser::Parser; use parser::ParserContext; use properties::animated_properties::Animatable; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError}; /// A generic value for the `initial-letter` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -71,12 +71,12 @@ impl Spacing { /// Parses. #[inline] - pub fn parse_with( + pub fn parse_with<'i, 't, F>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, parse: F) - -> Result - where F: FnOnce(&ParserContext, &mut Parser) -> Result + -> Result> + where F: FnOnce(&ParserContext, &mut Parser<'i, 't>) -> Result> { if input.try(|i| i.expect_ident_matching("normal")).is_ok() { return Ok(Spacing::Normal); diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index 32b7df063c9..962f8ecc0eb 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -9,13 +9,14 @@ #![deny(missing_docs)] use Atom; -pub use cssparser::{RGBA, Token, Parser, serialize_identifier}; +pub use cssparser::{RGBA, Token, Parser, serialize_identifier, BasicParseError}; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt::{self, Debug}; use std::hash; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; pub mod computed; pub mod generics; @@ -54,7 +55,8 @@ impl Debug for Either { } impl Parse for Either { - fn parse(context: &ParserContext, input: &mut Parser) -> Result, ()> { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result, ParseError<'i>> { if let Ok(v) = input.try(|i| A::parse(context, i)) { Ok(Either::First(v)) } else { @@ -91,13 +93,16 @@ pub struct CustomIdent(pub Atom); impl CustomIdent { /// Parse an already-tokenizer identifier - pub fn from_ident(ident: Cow, excluding: &[&str]) -> Result { - match_ignore_ascii_case! { &ident, - "initial" | "inherit" | "unset" | "default" => return Err(()), - _ => {} + pub fn from_ident<'i>(ident: Cow<'i, str>, excluding: &[&str]) -> Result> { + let valid = match_ignore_ascii_case! { &ident, + "initial" | "inherit" | "unset" | "default" => false, + _ => true }; + if !valid { + return Err(SelectorParseError::UnexpectedIdent(ident).into()); + } if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } else { Ok(CustomIdent(ident.into())) } @@ -125,7 +130,7 @@ impl KeyframesName { pub fn from_ident(value: String) -> Self { match CustomIdent::from_ident((&*value).into(), &["none"]) { Ok(ident) => KeyframesName::Ident(ident), - Err(()) => KeyframesName::QuotedString(value.into()), + Err(_) => KeyframesName::QuotedString(value.into()), } } @@ -153,11 +158,12 @@ impl hash::Hash for KeyframesName { } impl Parse for KeyframesName { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { match input.next() { Ok(Token::Ident(s)) => Ok(KeyframesName::Ident(CustomIdent::from_ident(s, &["none"])?)), Ok(Token::QuotedString(s)) => Ok(KeyframesName::QuotedString(s.into())), - _ => Err(()) + Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()), + Err(e) => Err(e.into()), } } } diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index 0d202ea0db5..4d24227b090 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -9,9 +9,10 @@ use cssparser::Parser; use gecko_bindings::structs; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; use std::ascii::AsciiExt; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; bitflags! { /// Constants shared by multiple CSS Box Alignment properties @@ -177,7 +178,7 @@ no_viewport_percentage!(AlignJustifyContent); impl Parse for AlignJustifyContent { // normal | | // [ || [ ? && ] ] - fn parse(_: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { // normal | if let Ok(value) = input.try(|input| parse_normal_or_baseline(input)) { return Ok(AlignJustifyContent::new(value)) @@ -198,7 +199,7 @@ impl Parse for AlignJustifyContent { } return Ok(AlignJustifyContent::new(fallback)) } - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -227,7 +228,7 @@ no_viewport_percentage!(AlignJustifySelf); impl Parse for AlignJustifySelf { // auto | normal | stretch | | // [ ? && ] - fn parse(_: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { // auto | normal | stretch | if let Ok(value) = input.try(parse_auto_normal_stretch_baseline) { return Ok(AlignJustifySelf(value)) @@ -236,7 +237,7 @@ impl Parse for AlignJustifySelf { if let Ok(value) = input.try(parse_overflow_self_position) { return Ok(AlignJustifySelf(value)) } - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -265,7 +266,7 @@ no_viewport_percentage!(AlignItems); impl Parse for AlignItems { // normal | stretch | | // [ ? && ] - fn parse(_: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { // normal | stretch | if let Ok(value) = input.try(parse_normal_stretch_baseline) { return Ok(AlignItems(value)) @@ -274,7 +275,7 @@ impl Parse for AlignItems { if let Ok(value) = input.try(parse_overflow_self_position) { return Ok(AlignItems(value)) } - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -304,7 +305,7 @@ impl Parse for JustifyItems { // auto | normal | stretch | | // [ ? && ] // [ legacy && [ left | right | center ] ] - fn parse(_: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { // auto | normal | stretch | if let Ok(value) = input.try(parse_auto_normal_stretch_baseline) { return Ok(JustifyItems(value)) @@ -317,7 +318,7 @@ impl Parse for JustifyItems { if let Ok(value) = parse_overflow_self_position(input) { return Ok(JustifyItems(value)) } - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } @@ -336,72 +337,73 @@ impl From for u16 { } // auto | normal | stretch | -fn parse_auto_normal_stretch_baseline(input: &mut Parser) -> Result { +fn parse_auto_normal_stretch_baseline<'i, 't>(input: &mut Parser<'i, 't>) + -> Result> { if let Ok(baseline) = input.try(parse_baseline) { return Ok(baseline); } let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "auto" => Ok(ALIGN_AUTO), "normal" => Ok(ALIGN_NORMAL), "stretch" => Ok(ALIGN_STRETCH), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // normal | stretch | -fn parse_normal_stretch_baseline(input: &mut Parser) -> Result { +fn parse_normal_stretch_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { if let Ok(baseline) = input.try(parse_baseline) { return Ok(baseline); } let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "normal" => Ok(ALIGN_NORMAL), "stretch" => Ok(ALIGN_STRETCH), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // normal | -fn parse_normal_or_baseline(input: &mut Parser) -> Result { +fn parse_normal_or_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { if let Ok(baseline) = input.try(parse_baseline) { return Ok(baseline); } let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "normal" => Ok(ALIGN_NORMAL), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // -fn parse_baseline(input: &mut Parser) -> Result { +fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "baseline" => Ok(ALIGN_BASELINE), - "first" => input.expect_ident_matching("baseline").map(|_| ALIGN_BASELINE), - "last" => input.expect_ident_matching("baseline").map(|_| ALIGN_LAST_BASELINE), + "first" => return input.expect_ident_matching("baseline").map(|_| ALIGN_BASELINE).map_err(|e| e.into()), + "last" => return input.expect_ident_matching("baseline").map(|_| ALIGN_LAST_BASELINE).map_err(|e| e.into()), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // -fn parse_content_distribution(input: &mut Parser) -> Result { +fn parse_content_distribution<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "stretch" => Ok(ALIGN_STRETCH), "space-between" => Ok(ALIGN_SPACE_BETWEEN), "space-around" => Ok(ALIGN_SPACE_AROUND), "space-evenly" => Ok(ALIGN_SPACE_EVENLY), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // [ ? && ] -fn parse_overflow_content_position(input: &mut Parser) -> Result { +fn parse_overflow_content_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { // followed by optional if let Ok(mut content) = input.try(parse_content_position) { if let Ok(overflow) = input.try(parse_overflow_position) { @@ -415,13 +417,13 @@ fn parse_overflow_content_position(input: &mut Parser) -> Result return Ok(overflow | content) } } - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } // -fn parse_content_position(input: &mut Parser) -> Result { +fn parse_content_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "start" => Ok(ALIGN_START), "end" => Ok(ALIGN_END), "flex-start" => Ok(ALIGN_FLEX_START), @@ -430,21 +432,21 @@ fn parse_content_position(input: &mut Parser) -> Result { "left" => Ok(ALIGN_LEFT), "right" => Ok(ALIGN_RIGHT), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // -fn parse_overflow_position(input: &mut Parser) -> Result { +fn parse_overflow_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "safe" => Ok(ALIGN_SAFE), "unsafe" => Ok(ALIGN_UNSAFE), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // [ ? && ] -fn parse_overflow_self_position(input: &mut Parser) -> Result { +fn parse_overflow_self_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { // followed by optional if let Ok(mut self_position) = input.try(parse_self_position) { if let Ok(overflow) = input.try(parse_overflow_position) { @@ -458,13 +460,13 @@ fn parse_overflow_self_position(input: &mut Parser) -> Result { return Ok(overflow | self_position) } } - return Err(()) + return Err(StyleParseError::UnspecifiedError.into()) } // -fn parse_self_position(input: &mut Parser) -> Result { +fn parse_self_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let ident = input.expect_ident()?; - match_ignore_ascii_case! { &ident, + (match_ignore_ascii_case! { &ident, "start" => Ok(ALIGN_START), "end" => Ok(ALIGN_END), "flex-start" => Ok(ALIGN_FLEX_START), @@ -475,28 +477,28 @@ fn parse_self_position(input: &mut Parser) -> Result { "self-start" => Ok(ALIGN_SELF_START), "self-end" => Ok(ALIGN_SELF_END), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } // [ legacy && [ left | right | center ] ] -fn parse_legacy(input: &mut Parser) -> Result { +fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { let a = input.expect_ident()?; let b = input.expect_ident()?; if a.eq_ignore_ascii_case("legacy") { - match_ignore_ascii_case! { &b, + (match_ignore_ascii_case! { &b, "left" => Ok(ALIGN_LEGACY | ALIGN_LEFT), "right" => Ok(ALIGN_LEGACY | ALIGN_RIGHT), "center" => Ok(ALIGN_LEGACY | ALIGN_CENTER), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(b).into()) } else if b.eq_ignore_ascii_case("legacy") { - match_ignore_ascii_case! { &a, + (match_ignore_ascii_case! { &a, "left" => Ok(ALIGN_LEGACY | ALIGN_LEFT), "right" => Ok(ALIGN_LEGACY | ALIGN_RIGHT), "center" => Ok(ALIGN_LEGACY | ALIGN_CENTER), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(a).into()) } else { - Err(()) + Err(StyleParseError::UnspecifiedError.into()) } } diff --git a/components/style/values/specified/background.rs b/components/style/values/specified/background.rs index 3bafe5af22f..db38b873381 100644 --- a/components/style/values/specified/background.rs +++ b/components/style/values/specified/background.rs @@ -6,6 +6,8 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; +use style_traits::ParseError; use values::generics::background::BackgroundSize as GenericBackgroundSize; use values::specified::length::LengthOrPercentageOrAuto; @@ -13,17 +15,18 @@ use values::specified::length::LengthOrPercentageOrAuto; pub type BackgroundSize = GenericBackgroundSize; impl Parse for BackgroundSize { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if let Ok(width) = input.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) { let height = input .try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) .unwrap_or(LengthOrPercentageOrAuto::Auto); return Ok(GenericBackgroundSize::Explicit { width: width, height: height }); } - match_ignore_ascii_case! { &input.expect_ident()?, + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "cover" => Ok(GenericBackgroundSize::Cover), "contain" => Ok(GenericBackgroundSize::Contain), _ => Err(()), - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 237db2cd2a1..3156d6e778e 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -9,9 +9,10 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; use std::borrow::Cow; use std::fmt; -use style_traits::ToCss; +use style_traits::{ToCss, ParseError, StyleParseError}; use values::generics::basic_shape::{Circle as GenericCircle}; use values::generics::basic_shape::{ClippingShape as GenericClippingShape, Ellipse as GenericEllipse}; use values::generics::basic_shape::{FillRule, BasicShape as GenericBasicShape}; @@ -49,7 +50,7 @@ pub type ShapeRadius = GenericShapeRadius; pub type Polygon = GenericPolygon; impl Parse for ShapeSource { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if input.try(|i| i.expect_ident_matching("none")).is_ok() { return Ok(ShapeSource::None) } @@ -80,42 +81,43 @@ impl Parse for ShapeSource { return Ok(ShapeSource::Shape(shp, ref_box)) } - ref_box.map(|v| ShapeSource::Box(v)).ok_or(()) + ref_box.map(|v| ShapeSource::Box(v)).ok_or(StyleParseError::UnspecifiedError.into()) } } impl Parse for GeometryBox { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if let Ok(shape_box) = input.try(|i| ShapeBox::parse(i)) { return Ok(GeometryBox::ShapeBox(shape_box)) } - match_ignore_ascii_case! { &input.expect_ident()?, + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "fill-box" => Ok(GeometryBox::FillBox), "stroke-box" => Ok(GeometryBox::StrokeBox), "view-box" => Ok(GeometryBox::ViewBox), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } impl Parse for BasicShape { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let function = input.expect_function()?; - input.parse_nested_block(|i| { - match_ignore_ascii_case! { &function, - "inset" => InsetRect::parse_function_arguments(context, i).map(GenericBasicShape::Inset), - "circle" => Circle::parse_function_arguments(context, i).map(GenericBasicShape::Circle), - "ellipse" => Ellipse::parse_function_arguments(context, i).map(GenericBasicShape::Ellipse), - "polygon" => Polygon::parse_function_arguments(context, i).map(GenericBasicShape::Polygon), + input.parse_nested_block(move |i| { + (match_ignore_ascii_case! { &function, + "inset" => return InsetRect::parse_function_arguments(context, i).map(GenericBasicShape::Inset), + "circle" => return Circle::parse_function_arguments(context, i).map(GenericBasicShape::Circle), + "ellipse" => return Ellipse::parse_function_arguments(context, i).map(GenericBasicShape::Ellipse), + "polygon" => return Polygon::parse_function_arguments(context, i).map(GenericBasicShape::Polygon), _ => Err(()) - } + }).map_err(|()| StyleParseError::UnexpectedFunction(function).into()) }) } } impl Parse for InsetRect { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { input.expect_function_matching("inset")?; input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) } @@ -123,7 +125,8 @@ impl Parse for InsetRect { impl InsetRect { /// Parse the inner function arguments of `inset()` - pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let rect = Rect::parse_with(context, input, LengthOrPercentage::parse)?; let round = if input.try(|i| i.expect_ident_matching("round")).is_ok() { Some(BorderRadius::parse(context, input)?) @@ -138,7 +141,8 @@ impl InsetRect { } impl Parse for Circle { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { input.expect_function_matching("circle")?; input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) } @@ -146,7 +150,8 @@ impl Parse for Circle { impl Circle { #[allow(missing_docs)] - pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result { + pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { let radius = input.try(|i| ShapeRadius::parse(context, i)).ok().unwrap_or_default(); let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() { Position::parse(context, input)? @@ -176,7 +181,7 @@ impl ToCss for Circle { } impl Parse for Ellipse { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { input.expect_function_matching("ellipse")?; input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) } @@ -184,8 +189,9 @@ impl Parse for Ellipse { impl Ellipse { #[allow(missing_docs)] - pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result { - let (a, b) = input.try(|i| -> Result<_, ()> { + pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { + let (a, b) = input.try(|i| -> Result<_, ParseError> { Ok((ShapeRadius::parse(context, i)?, ShapeRadius::parse(context, i)?)) }).ok().unwrap_or_default(); let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() { @@ -219,16 +225,18 @@ impl ToCss for Ellipse { } impl Parse for ShapeRadius { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { return Ok(GenericShapeRadius::Length(lop)) } - match_ignore_ascii_case! { &input.expect_ident()?, + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "closest-side" => Ok(GenericShapeRadius::ClosestSide), "farthest-side" => Ok(GenericShapeRadius::FarthestSide), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } @@ -300,7 +308,7 @@ fn serialize_basicshape_position(position: &Position, dest: &mut W) -> fmt::R } impl Parse for Polygon { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { input.expect_function_matching("polygon")?; input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) } @@ -308,8 +316,9 @@ impl Parse for Polygon { impl Polygon { /// Parse the inner arguments of a `polygon` function. - pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result { - let fill = input.try(|i| -> Result<_, ()> { + pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { + let fill = input.try(|i| -> Result<_, ParseError> { let fill = FillRule::parse(i)?; i.expect_comma()?; // only eat the comma if there is something before it Ok(fill) diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index 53260bc8e33..3c19c5d304e 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -7,6 +7,8 @@ use app_units::Au; use cssparser::Parser; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseError; +use style_traits::ParseError; use values::computed::{Context, ToComputedValue}; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; @@ -47,26 +49,27 @@ pub type BorderCornerRadius = GenericBorderCornerRadius; impl BorderSideWidth { /// Parses, with quirks. - pub fn parse_quirky( + pub fn parse_quirky<'i, 't>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, allow_quirks: AllowQuirks) - -> Result + -> Result> { if let Ok(length) = input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) { return Ok(BorderSideWidth::Length(length)); } - match_ignore_ascii_case! { &input.expect_ident()?, + let ident = input.expect_ident()?; + (match_ignore_ascii_case! { &ident, "thin" => Ok(BorderSideWidth::Thin), "medium" => Ok(BorderSideWidth::Medium), "thick" => Ok(BorderSideWidth::Thick), _ => Err(()) - } + }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into()) } } impl Parse for BorderSideWidth { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { Self::parse_quirky(context, input, AllowQuirks::No) } } @@ -102,7 +105,7 @@ impl BorderImageSideWidth { } impl Parse for BorderImageSideWidth { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { if input.try(|i| i.expect_ident_matching("auto")).is_ok() { return Ok(GenericBorderImageSideWidth::Auto); } @@ -117,7 +120,7 @@ impl Parse for BorderImageSideWidth { } impl Parse for BorderImageSlice { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?; if !fill { @@ -131,7 +134,7 @@ impl Parse for BorderImageSlice { } impl Parse for BorderRadius { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?; let heights = if input.try(|i| i.expect_delim('/')).is_ok() { Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)? @@ -149,11 +152,11 @@ impl Parse for BorderRadius { } impl Parse for BorderCornerRadius { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { let first = LengthOrPercentage::parse_non_negative(context, input)?; let second = input .try(|i| LengthOrPercentage::parse_non_negative(context, i)) - .unwrap_or_else(|()| first.clone()); + .unwrap_or_else(|_| first.clone()); Ok(Self::new(first, second)) } } diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index d8c66e29a51..f1cf9bc2f61 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -7,11 +7,11 @@ //! [calc]: https://drafts.csswg.org/css-values/#calc-notation use app_units::Au; -use cssparser::{Parser, Token}; +use cssparser::{Parser, Token, BasicParseError}; use parser::ParserContext; use std::ascii::AsciiExt; use std::fmt; -use style_traits::{HasViewportPercentage, ToCss}; +use style_traits::{HasViewportPercentage, ToCss, ParseError, StyleParseError}; use style_traits::values::specified::AllowedLengthType; use values::{CSSInteger, CSSFloat}; use values::specified::{Angle, Time}; @@ -142,11 +142,11 @@ impl CalcNode { /// /// May return a "complex" `CalcNode`, in the presence of a parenthesized /// expression, for example. - fn parse_one( + fn parse_one<'i, 't>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, expected_unit: CalcUnit) - -> Result + -> Result> { match (try!(input.next()), expected_unit) { (Token::Number(ref value), _) => Ok(CalcNode::Number(value.value)), @@ -154,18 +154,21 @@ impl CalcNode { (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => { NoCalcLength::parse_dimension(context, value.value, unit) .map(CalcNode::Length) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => { Angle::parse_dimension(value.value, unit, /* from_calc = */ true) .map(CalcNode::Angle) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } (Token::Dimension(ref value, ref unit), CalcUnit::Time) => { Time::parse_dimension(value.value, unit, /* from_calc = */ true) .map(CalcNode::Time) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) => { Ok(CalcNode::Percentage(value.unit_value)) @@ -180,18 +183,18 @@ impl CalcNode { CalcNode::parse(context, i, expected_unit) }) } - _ => Err(()) + (t, _) => Err(BasicParseError::UnexpectedToken(t).into()) } } /// Parse a top-level `calc` expression, with all nested sub-expressions. /// /// This is in charge of parsing, for example, `2 + 3 * 100%`. - fn parse( + fn parse<'i, 't>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, expected_unit: CalcUnit) - -> Result + -> Result> { let mut root = Self::parse_product(context, input, expected_unit)?; @@ -217,7 +220,7 @@ impl CalcNode { CalcNode::Sub(Box::new(root), Box::new(rhs)); root = new_root; } - _ => return Err(()), + t => return Err(BasicParseError::UnexpectedToken(t).into()), } } _ => { @@ -239,11 +242,11 @@ impl CalcNode { /// * `2 * 2` /// * `2 * 2 + 2` (but will leave the `+ 2` unparsed). /// - fn parse_product( + fn parse_product<'i, 't>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, expected_unit: CalcUnit) - -> Result + -> Result> { let mut root = Self::parse_one(context, input, expected_unit)?; @@ -491,65 +494,71 @@ impl CalcNode { } /// Convenience parsing function for integers. - pub fn parse_integer( + pub fn parse_integer<'i, 't>( context: &ParserContext, - input: &mut Parser) - -> Result + input: &mut Parser<'i, 't>) + -> Result> { Self::parse(context, input, CalcUnit::Integer)? .to_number() .map(|n| n as CSSInteger) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } /// Convenience parsing function for ` | `. - pub fn parse_length_or_percentage( + pub fn parse_length_or_percentage<'i, 't>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, clamping_mode: AllowedLengthType) - -> Result + -> Result> { Self::parse(context, input, CalcUnit::LengthOrPercentage)? .to_length_or_percentage(clamping_mode) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } /// Convenience parsing function for ``. - pub fn parse_length( + pub fn parse_length<'i, 't>( context: &ParserContext, - input: &mut Parser, + input: &mut Parser<'i, 't>, clamping_mode: AllowedLengthType) - -> Result + -> Result> { Self::parse(context, input, CalcUnit::Length)? .to_length_or_percentage(clamping_mode) + .map_err(|()| StyleParseError::UnspecifiedError.into()) } /// Convenience parsing function for ``. - pub fn parse_number( + pub fn parse_number<'i, 't>( context: &ParserContext, - input: &mut Parser) - -> Result + input: &mut Parser<'i, 't>) + -> Result> { Self::parse(context, input, CalcUnit::Number)? .to_number() + .map_err(|()| StyleParseError::UnspecifiedError.into()) } /// Convenience parsing function for ``. - pub fn parse_angle( + pub fn parse_angle<'i, 't>( context: &ParserContext, - input: &mut Parser) - -> Result + input: &mut Parser<'i, 't>) + -> Result> { Self::parse(context, input, CalcUnit::Angle)? .to_angle() + .map_err(|()| StyleParseError::UnspecifiedError.into()) } /// Convenience parsing function for `