Thread ParseError return values through CSS parsing.

This commit is contained in:
Josh Matthews 2017-04-28 00:35:22 -04:00
parent 58e39bfffa
commit 27ae1ef2e7
121 changed files with 2133 additions and 1505 deletions

35
Cargo.lock generated
View file

@ -314,7 +314,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"azure 0.16.0 (git+https://github.com/servo/rust-azure)", "azure 0.16.0 (git+https://github.com/servo/rust-azure)",
"canvas_traits 0.0.1", "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)", "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)", "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)", "ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -329,7 +329,7 @@ dependencies = [
name = "canvas_traits" name = "canvas_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ 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)", "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 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)", "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -567,14 +567,14 @@ dependencies = [
[[package]] [[package]]
name = "cssparser" name = "cssparser"
version = "0.13.7" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "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)", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1005,7 +1005,7 @@ name = "geckoservo"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1072,7 +1072,7 @@ dependencies = [
name = "gfx_tests" name = "gfx_tests"
version = "0.0.1" version = "0.0.1"
dependencies = [ 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", "gfx 0.0.1",
"ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"style 0.0.1", "style 0.0.1",
@ -2158,7 +2158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "procedural-masquerade" name = "procedural-masquerade"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -2371,7 +2371,7 @@ dependencies = [
"caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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", "deny_public_fields 0.0.1",
"devtools_traits 0.0.1", "devtools_traits 0.0.1",
"dom_struct 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)", "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)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1", "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)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1", "gfx_traits 0.0.1",
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2516,7 +2516,7 @@ name = "selectors"
version = "0.19.0" version = "0.19.0"
dependencies = [ dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "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)", "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)", "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)", "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)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2952,7 +2952,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"app_units 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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" version = "0.0.1"
dependencies = [ dependencies = [
"app_units 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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 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)", "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 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)", "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" version = "0.0.1"
dependencies = [ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"geckoservo 0.0.1", "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-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-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 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 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 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" "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 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 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 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 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 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" "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"

View file

@ -12,7 +12,7 @@ path = "lib.rs"
[dependencies] [dependencies]
azure = {git = "https://github.com/servo/rust-azure"} azure = {git = "https://github.com/servo/rust-azure"}
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
cssparser = "0.13.7" cssparser = "0.14.0"
euclid = "0.13" euclid = "0.13"
gleam = "0.4" gleam = "0.4"
ipc-channel = "0.7" ipc-channel = "0.7"

View file

@ -10,7 +10,7 @@ name = "canvas_traits"
path = "lib.rs" path = "lib.rs"
[dependencies] [dependencies]
cssparser = "0.13.7" cssparser = "0.14.0"
euclid = "0.13" euclid = "0.13"
heapsize = "0.4" heapsize = "0.4"
heapsize_derive = "0.1" heapsize_derive = "0.1"

View file

@ -35,7 +35,7 @@ byteorder = "1.0"
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
caseless = "0.1.0" caseless = "0.1.0"
cookie = "0.6" cookie = "0.6"
cssparser = "0.13.7" cssparser = "0.14.0"
deny_public_fields = {path = "../deny_public_fields"} deny_public_fields = {path = "../deny_public_fields"}
devtools_traits = {path = "../devtools_traits"} devtools_traits = {path = "../devtools_traits"}
dom_struct = {path = "../dom_struct"} dom_struct = {path = "../dom_struct"}

View file

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use canvas_traits::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle}; use canvas_traits::{CanvasGradientStop, FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle};
use cssparser::{Parser, RGBA}; use cssparser::{Parser, ParserInput, RGBA};
use cssparser::Color as CSSColor; use cssparser::Color as CSSColor;
use dom::bindings::cell::DOMRefCell; use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CanvasGradientBinding; use dom::bindings::codegen::Bindings::CanvasGradientBinding;
@ -53,7 +53,8 @@ impl CanvasGradientMethods for CanvasGradient {
return Err(Error::IndexSize); 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 = CSSColor::parse(&mut parser);
let color = if parser.is_exhausted() { let color = if parser.is_exhausted() {
match color { match color {

View file

@ -6,7 +6,7 @@ use canvas_traits::{Canvas2dMsg, CanvasCommonMsg, CanvasMsg};
use canvas_traits::{CompositionOrBlending, FillOrStrokeStyle, FillRule}; use canvas_traits::{CompositionOrBlending, FillOrStrokeStyle, FillRule};
use canvas_traits::{LineCapStyle, LineJoinStyle, LinearGradientStyle}; use canvas_traits::{LineCapStyle, LineJoinStyle, LinearGradientStyle};
use canvas_traits::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply}; use canvas_traits::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply};
use cssparser::{Parser, RGBA}; use cssparser::{Parser, ParserInput, RGBA};
use cssparser::Color as CSSColor; use cssparser::Color as CSSColor;
use dom::bindings::cell::DOMRefCell; use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods; use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
@ -463,7 +463,8 @@ impl CanvasRenderingContext2D {
} }
fn parse_color(&self, string: &str) -> Result<RGBA, ()> { fn parse_color(&self, string: &str) -> Result<RGBA, ()> {
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); let color = CSSColor::parse(&mut parser);
if parser.is_exhausted() { if parser.is_exhausted() {
match color { match color {
@ -1314,7 +1315,8 @@ impl Drop for CanvasRenderingContext2D {
} }
pub fn parse_color(string: &str) -> Result<RGBA, ()> { pub fn parse_color(string: &str) -> Result<RGBA, ()> {
let mut parser = Parser::new(&string); let mut input = ParserInput::new(string);
let mut parser = Parser::new(&mut input);
match CSSColor::parse(&mut parser) { match CSSColor::parse(&mut parser) {
Ok(CSSColor::RGBA(rgba)) => { Ok(CSSColor::RGBA(rgba)) => {
if parser.is_exhausted() { if parser.is_exhausted() {

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::reflector::Reflector; use dom::bindings::reflector::Reflector;
@ -39,7 +39,8 @@ impl CSS {
/// https://drafts.csswg.org/css-conditional/#dom-css-supports /// https://drafts.csswg.org/css-conditional/#dom-css-supports
pub fn Supports_(win: &Window, condition: DOMString) -> bool { 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); let cond = parse_condition_or_declaration(&mut input);
if let Ok(cond) = cond { if let Ok(cond) = cond {
let url = win.Document().url(); let url = win.Document().url();

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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;
use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding::CSSKeyframesRuleMethods; use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding::CSSKeyframesRuleMethods;
use dom::bindings::error::ErrorResult; 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 /// Given a keyframe selector, finds the index of the first corresponding rule if any
fn find_rule(&self, selector: &str) -> Option<usize> { fn find_rule(&self, selector: &str) -> Option<usize> {
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) { if let Ok(sel) = KeyframeSelector::parse(&mut input) {
let guard = self.cssrule.shared_lock().read(); let guard = self.cssrule.shared_lock().read();
// This finds the *last* element matching a selector // This finds the *last* element matching a selector

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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;
use dom::bindings::codegen::Bindings::CSSMediaRuleBinding::CSSMediaRuleMethods; use dom::bindings::codegen::Bindings::CSSMediaRuleBinding::CSSMediaRuleMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
@ -69,7 +69,8 @@ impl CSSMediaRule {
/// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface
pub fn set_condition_text(&self, text: DOMString) { 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 global = self.global();
let win = global.as_window(); let win = global.as_window();
let url = win.get_url(); let url = win.get_url();

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::CSSSupportsRuleBinding;
use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use dom::bindings::js::Root; use dom::bindings::js::Root;
@ -55,7 +55,8 @@ impl CSSSupportsRule {
/// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
pub fn set_condition_text(&self, text: DOMString) { 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); let cond = SupportsCondition::parse(&mut input);
if let Ok(cond) = cond { if let Ok(cond) = cond {
let global = self.global(); let global = self.global();

View file

@ -2061,7 +2061,7 @@ impl ElementMethods for Element {
// https://dom.spec.whatwg.org/#dom-element-matches // https://dom.spec.whatwg.org/#dom-element-matches
fn Matches(&self, selectors: DOMString) -> Fallible<bool> { fn Matches(&self, selectors: DOMString) -> Fallible<bool> {
match SelectorParser::parse_author_origin_no_namespace(&selectors) { match SelectorParser::parse_author_origin_no_namespace(&selectors) {
Err(()) => Err(Error::Syntax), Err(_) => Err(Error::Syntax),
Ok(selectors) => { Ok(selectors) => {
let mut ctx = MatchingContext::new(MatchingMode::Normal, None); let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
Ok(matches_selector_list(&selectors, &Root::from_ref(self), &mut ctx)) 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 // https://dom.spec.whatwg.org/#dom-element-closest
fn Closest(&self, selectors: DOMString) -> Fallible<Option<Root<Element>>> { fn Closest(&self, selectors: DOMString) -> Fallible<Option<Root<Element>>> {
match SelectorParser::parse_author_origin_no_namespace(&selectors) { match SelectorParser::parse_author_origin_no_namespace(&selectors) {
Err(()) => Err(Error::Syntax), Err(_) => Err(Error::Syntax),
Ok(selectors) => { Ok(selectors) => {
let root = self.upcast::<Node>(); let root = self.upcast::<Node>();
for element in root.inclusive_ancestors() { for element in root.inclusive_ancestors() {

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::attr::Attr;
use dom::bindings::cell::DOMRefCell; use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListBinding::DOMTokenListMethods; use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListBinding::DOMTokenListMethods;
@ -278,7 +278,8 @@ impl HTMLLinkElement {
None => "", 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 win = document.window();
let doc_url = document.url(); let doc_url = document.url();
let context = CssParserContext::new_for_cssom(&doc_url, win.css_error_reporter(), Some(CssRuleType::Media), let context = CssParserContext::new_for_cssom(&doc_url, win.css_error_reporter(), Some(CssRuleType::Media),

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLStyleElementBinding; use dom::bindings::codegen::Bindings::HTMLStyleElementBinding;
use dom::bindings::codegen::Bindings::HTMLStyleElementBinding::HTMLStyleElementMethods; use dom::bindings::codegen::Bindings::HTMLStyleElementBinding::HTMLStyleElementMethods;
@ -91,8 +91,9 @@ impl HTMLStyleElement {
PARSING_MODE_DEFAULT, PARSING_MODE_DEFAULT,
doc.quirks_mode()); doc.quirks_mode());
let shared_lock = node.owner_doc().style_shared_lock().clone(); let shared_lock = node.owner_doc().style_shared_lock().clone();
let mut input = ParserInput::new(&mq_str);
let mq = Arc::new(shared_lock.wrap( 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 loader = StylesheetLoader::for_element(self.upcast());
let sheet = Stylesheet::from_str(&data, win.get_url(), Origin::Author, mq, let sheet = Stylesheet::from_str(&data, win.get_url(), Origin::Author, mq,
shared_lock, Some(&loader), shared_lock, Some(&loader),

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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;
use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods; use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
@ -71,7 +71,8 @@ impl MediaListMethods for MediaList {
return; return;
} }
// Step 3 // 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 global = self.global();
let win = global.as_window(); let win = global.as_window();
let url = win.get_url(); let url = win.get_url();
@ -107,7 +108,8 @@ impl MediaListMethods for MediaList {
// https://drafts.csswg.org/cssom/#dom-medialist-appendmedium // https://drafts.csswg.org/cssom/#dom-medialist-appendmedium
fn AppendMedium(&self, medium: DOMString) { fn AppendMedium(&self, medium: DOMString) {
// Step 1 // 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 global = self.global();
let win = global.as_window(); let win = global.as_window();
let url = win.get_url(); let url = win.get_url();
@ -135,7 +137,8 @@ impl MediaListMethods for MediaList {
// https://drafts.csswg.org/cssom/#dom-medialist-deletemedium // https://drafts.csswg.org/cssom/#dom-medialist-deletemedium
fn DeleteMedium(&self, medium: DOMString) { fn DeleteMedium(&self, medium: DOMString) {
// Step 1 // 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 global = self.global();
let win = global.as_window(); let win = global.as_window();
let url = win.get_url(); let url = win.get_url();

View file

@ -717,7 +717,7 @@ impl Node {
// Step 1. // Step 1.
match SelectorParser::parse_author_origin_no_namespace(&selectors) { match SelectorParser::parse_author_origin_no_namespace(&selectors) {
// Step 2. // Step 2.
Err(()) => Err(Error::Syntax), Err(_) => Err(Error::Syntax),
// Step 3. // Step 3.
Ok(selectors) => { Ok(selectors) => {
let mut ctx = MatchingContext::new(MatchingMode::Normal, None); let mut ctx = MatchingContext::new(MatchingMode::Normal, None);
@ -737,7 +737,7 @@ impl Node {
// Step 1. // Step 1.
match SelectorParser::parse_author_origin_no_namespace(&selectors) { match SelectorParser::parse_author_origin_no_namespace(&selectors) {
// Step 2. // Step 2.
Err(()) => Err(Error::Syntax), Err(_) => Err(Error::Syntax),
// Step 3. // Step 3.
Ok(selectors) => { Ok(selectors) => {
let mut descendants = self.traverse_preorder(); let mut descendants = self.traverse_preorder();

View file

@ -5,7 +5,7 @@
use app_units::Au; use app_units::Au;
use base64; use base64;
use bluetooth_traits::BluetoothRequest; use bluetooth_traits::BluetoothRequest;
use cssparser::Parser; use cssparser::{Parser, ParserInput};
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType}; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
use dom::bindings::cell::DOMRefCell; use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; 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 // https://drafts.csswg.org/cssom-view/#dom-window-matchmedia
fn MatchMedia(&self, query: DOMString) -> Root<MediaQueryList> { fn MatchMedia(&self, query: DOMString) -> Root<MediaQueryList> {
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 url = self.get_url();
let quirks_mode = self.Document().quirks_mode(); let quirks_mode = self.Document().quirks_mode();
let context = CssParserContext::new_for_cssom(&url, self.css_error_reporter(), Some(CssRuleType::Media), let context = CssParserContext::new_for_cssom(&url, self.css_error_reporter(), Some(CssRuleType::Media),

View file

@ -13,7 +13,7 @@ path = "lib.rs"
app_units = "0.4.1" app_units = "0.4.1"
atomic_refcell = "0.1" atomic_refcell = "0.1"
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
cssparser = "0.13.7" cssparser = "0.14.0"
euclid = "0.13" euclid = "0.13"
gfx_traits = {path = "../gfx_traits"} gfx_traits = {path = "../gfx_traits"}
heapsize = "0.4" heapsize = "0.4"

View file

@ -9,7 +9,7 @@ use msg::constellation_msg::PipelineId;
use script_traits::ConstellationControlMsg; use script_traits::ConstellationControlMsg;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::sync::{Mutex, Arc}; use std::sync::{Mutex, Arc};
use style::error_reporting::{ParseErrorReporter, ParseError}; use style::error_reporting::{ParseErrorReporter, ContextualParseError};
#[derive(HeapSizeOf, Clone)] #[derive(HeapSizeOf, Clone)]
pub struct CSSErrorReporter { pub struct CSSErrorReporter {
@ -25,7 +25,7 @@ impl ParseErrorReporter for CSSErrorReporter {
fn report_error<'a>(&self, fn report_error<'a>(&self,
input: &mut Parser, input: &mut Parser,
position: SourcePosition, position: SourcePosition,
error: ParseError<'a>, error: ContextualParseError<'a>,
url: &ServoUrl, url: &ServoUrl,
line_number_offset: u64) { line_number_offset: u64) {
let location = input.source_location(position); let location = input.source_location(position);

View file

@ -24,7 +24,7 @@ gecko_like_types = []
[dependencies] [dependencies]
bitflags = "0.7" bitflags = "0.7"
matches = "0.1" matches = "0.1"
cssparser = "0.13.7" cssparser = "0.14.0"
log = "0.3" log = "0.3"
fnv = "1.0" fnv = "1.0"
phf = "0.7.18" phf = "0.7.18"

View file

@ -4,6 +4,7 @@
use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator}; use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator};
use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint}; use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint};
use cssparser::{ParseError, BasicParseError};
use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter}; use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter};
use precomputed_hash::PrecomputedHash; use precomputed_hash::PrecomputedHash;
use servo_arc::{Arc, HeaderWithLength, ThinArc}; use servo_arc::{Arc, HeaderWithLength, ThinArc};
@ -43,6 +44,30 @@ fn to_ascii_lowercase(s: &str) -> Cow<str> {
} }
} }
#[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<ParseError<'a, SelectorParseError<'a, T>>> for SelectorParseError<'a, T> {
fn into(self) -> ParseError<'a, SelectorParseError<'a, T>> {
ParseError::Custom(self)
}
}
macro_rules! with_all_bounds { macro_rules! with_all_bounds {
( (
[ $( $InSelector: tt )* ] [ $( $InSelector: tt )* ]
@ -97,26 +122,30 @@ with_bounds! {
[From<String> + for<'a> From<&'a str>] [From<String> + for<'a> From<&'a str>]
} }
pub trait Parser { pub trait Parser<'i> {
type Impl: SelectorImpl; type Impl: SelectorImpl;
type Error: 'i;
/// This function can return an "Err" pseudo-element in order to support CSS2.1 /// This function can return an "Err" pseudo-element in order to support CSS2.1
/// pseudo-elements. /// pseudo-elements.
fn parse_non_ts_pseudo_class(&self, _name: Cow<str>) fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>)
-> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ()> { -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass,
Err(()) ParseError<'i, SelectorParseError<'i, Self::Error>>> {
Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name)))
} }
fn parse_non_ts_functional_pseudo_class fn parse_non_ts_functional_pseudo_class<'t>
(&self, _name: Cow<str>, _arguments: &mut CssParser) (&self, name: Cow<'i, str>, _arguments: &mut CssParser<'i, 't>)
-> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ()> -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass,
ParseError<'i, SelectorParseError<'i, Self::Error>>>
{ {
Err(()) Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name)))
} }
fn parse_pseudo_element(&self, _name: Cow<str>) fn parse_pseudo_element(&self, name: Cow<'i, str>)
-> Result<<Self::Impl as SelectorImpl>::PseudoElement, ()> { -> Result<<Self::Impl as SelectorImpl>::PseudoElement,
Err(()) ParseError<'i, SelectorParseError<'i, Self::Error>>> {
Err(ParseError::Custom(SelectorParseError::UnexpectedIdent(name)))
} }
fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> { fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
@ -157,8 +186,9 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
/// https://drafts.csswg.org/selectors/#grouping /// https://drafts.csswg.org/selectors/#grouping
/// ///
/// Return the Selectors or Err if there is an invalid selector. /// Return the Selectors or Err if there is an invalid selector.
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()> pub fn parse<'i, 't, P, E>(parser: &P, input: &mut CssParser<'i, 't>)
where P: Parser<Impl=Impl> { -> Result<Self, ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E> {
input.parse_comma_separated(|input| parse_selector(parser, input).map(SelectorAndHashes::new)) input.parse_comma_separated(|input| parse_selector(parser, input).map(SelectorAndHashes::new))
.map(SelectorList) .map(SelectorList)
} }
@ -960,11 +990,11 @@ type ParseVec<Impl> = SmallVec<[Component<Impl>; 32]>;
/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; /// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
/// ///
/// `Err` means invalid selector. /// `Err` means invalid selector.
fn parse_selector<P, Impl>( fn parse_selector<'i, 't, P, E, Impl>(
parser: &P, parser: &P,
input: &mut CssParser) input: &mut CssParser<'i, 't>)
-> Result<Selector<Impl>, ()> -> Result<Selector<Impl>, ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<Impl=Impl>, Impl: SelectorImpl where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
let mut sequence = ParseVec::new(); let mut sequence = ParseVec::new();
let mut parsed_pseudo_element; let mut parsed_pseudo_element;
@ -983,7 +1013,7 @@ fn parse_selector<P, Impl>(
loop { loop {
let position = input.position(); let position = input.position();
match input.next_including_whitespace() { match input.next_including_whitespace() {
Err(()) => break 'outer_loop, Err(_e) => break 'outer_loop,
Ok(Token::WhiteSpace(_)) => any_whitespace = true, Ok(Token::WhiteSpace(_)) => any_whitespace = true,
Ok(Token::Delim('>')) => { Ok(Token::Delim('>')) => {
combinator = Combinator::Child; combinator = Combinator::Child;
@ -1026,12 +1056,13 @@ fn parse_selector<P, Impl>(
impl<Impl: SelectorImpl> Selector<Impl> { impl<Impl: SelectorImpl> Selector<Impl> {
/// Parse a selector, without any pseudo-element. /// Parse a selector, without any pseudo-element.
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()> pub fn parse<'i, 't, P, E>(parser: &P, input: &mut CssParser<'i, 't>)
where P: Parser<Impl=Impl> -> Result<Self, ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>
{ {
let selector = parse_selector(parser, input)?; let selector = parse_selector(parser, input)?;
if selector.has_pseudo_element() { if selector.has_pseudo_element() {
return Err(()) return Err(ParseError::Custom(SelectorParseError::PseudoElementInComplexSelector))
} }
Ok(selector) Ok(selector)
} }
@ -1040,9 +1071,10 @@ impl<Impl: SelectorImpl> Selector<Impl> {
/// * `Err(())`: Invalid selector, abort /// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a type selector, could be something else. `input` was not consumed. /// * `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`) /// * `Ok(Some(vec))`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
fn parse_type_selector<P, Impl>(parser: &P, input: &mut CssParser, sequence: &mut ParseVec<Impl>) fn parse_type_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParser<'i, 't>,
-> Result<bool, ()> sequence: &mut ParseVec<Impl>)
where P: Parser<Impl=Impl>, Impl: SelectorImpl -> Result<bool, ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? { match parse_qualified_name(parser, input, /* in_attr_selector = */ false)? {
None => Ok(false), None => Ok(false),
@ -1100,11 +1132,12 @@ enum QNamePrefix<Impl: SelectorImpl> {
/// * `Err(())`: Invalid selector, abort /// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. /// * `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 /// * `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>, (parser: &P, input: &mut CssParser<'i, 't>,
in_attr_selector: bool) in_attr_selector: bool)
-> Result<Option<(QNamePrefix<Impl>, Option<Cow<'i, str>>)>, ()> -> Result<Option<(QNamePrefix<Impl>, Option<Cow<'i, str>>)>,
where P: Parser<Impl=Impl>, Impl: SelectorImpl ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
let default_namespace = |local_name| { let default_namespace = |local_name| {
let namespace = match parser.default_namespace() { let namespace = match parser.default_namespace() {
@ -1122,7 +1155,8 @@ fn parse_qualified_name<'i, 't, P, Impl>
Ok(Token::Ident(local_name)) => { Ok(Token::Ident(local_name)) => {
Ok(Some((namespace, Some(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('|')) => { Ok(Token::Delim('|')) => {
let prefix = from_cow_str(value); let prefix = from_cow_str(value);
let result = parser.namespace_for_prefix(&prefix); 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)) explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
}, },
_ => { _ => {
@ -1153,10 +1187,13 @@ fn parse_qualified_name<'i, 't, P, Impl>
Ok(Token::Delim('|')) => { Ok(Token::Delim('|')) => {
explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace) explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
} }
_ => { result => {
input.reset(position); input.reset(position);
if in_attr_selector { if in_attr_selector {
Err(()) match result {
Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
Err(e) => Err(ParseError::Basic(e)),
}
} else { } else {
default_namespace(None) default_namespace(None)
} }
@ -1174,14 +1211,15 @@ fn parse_qualified_name<'i, 't, P, Impl>
} }
fn parse_attribute_selector<P, Impl>(parser: &P, input: &mut CssParser) fn parse_attribute_selector<'i, 't, P, E, Impl>(parser: &P, input: &mut CssParser<'i, 't>)
-> Result<Component<Impl>, ()> -> Result<Component<Impl>,
where P: Parser<Impl=Impl>, Impl: SelectorImpl ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
let namespace; let namespace;
let local_name; let local_name;
match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
None => return Err(()), None => return Err(ParseError::Custom(SelectorParseError::NoQualifiedNameInAttributeSelector)),
Some((_, None)) => unreachable!(), Some((_, None)) => unreachable!(),
Some((ns, Some(ln))) => { Some((ns, Some(ln))) => {
local_name = ln; local_name = ln;
@ -1209,7 +1247,7 @@ fn parse_attribute_selector<P, Impl>(parser: &P, input: &mut CssParser)
let never_matches; let never_matches;
match input.next() { match input.next() {
// [foo] // [foo]
Err(()) => { Err(_) => {
let local_name_lower = from_cow_str(to_ascii_lowercase(&local_name)); let local_name_lower = from_cow_str(to_ascii_lowercase(&local_name));
let local_name = from_cow_str(local_name); let local_name = from_cow_str(local_name);
if let Some(namespace) = namespace { if let Some(namespace) = namespace {
@ -1264,7 +1302,7 @@ fn parse_attribute_selector<P, Impl>(parser: &P, input: &mut CssParser)
never_matches = value.is_empty(); never_matches = value.is_empty();
operator = AttrSelectorOperator::Suffix; operator = AttrSelectorOperator::Suffix;
} }
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedTokenInAttributeSelector.into())
} }
let mut case_sensitivity = parse_attribute_flags(input)?; let mut case_sensitivity = parse_attribute_flags(input)?;
@ -1310,23 +1348,26 @@ fn parse_attribute_selector<P, Impl>(parser: &P, input: &mut CssParser)
} }
fn parse_attribute_flags(input: &mut CssParser) -> Result<ParsedCaseSensitivity, ()> { fn parse_attribute_flags<'i, 't, E>(input: &mut CssParser<'i, 't>)
-> Result<ParsedCaseSensitivity,
ParseError<'i, SelectorParseError<'i, E>>> {
match input.next() { match input.next() {
Err(()) => Ok(ParsedCaseSensitivity::CaseSensitive), Err(_) => Ok(ParsedCaseSensitivity::CaseSensitive),
Ok(Token::Ident(ref value)) if value.eq_ignore_ascii_case("i") => { Ok(Token::Ident(ref value)) if value.eq_ignore_ascii_case("i") => {
Ok(ParsedCaseSensitivity::AsciiCaseInsensitive) Ok(ParsedCaseSensitivity::AsciiCaseInsensitive)
} }
_ => Err(()) Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t)))
} }
} }
/// Level 3: Parse **one** simple_selector. (Though we might insert a second /// Level 3: Parse **one** simple_selector. (Though we might insert a second
/// implied "<defaultns>|*" type selector.) /// implied "<defaultns>|*" type selector.)
fn parse_negation<P, Impl>(parser: &P, fn parse_negation<'i, 't, P, E, Impl>(parser: &P,
input: &mut CssParser) input: &mut CssParser<'i, 't>)
-> Result<Component<Impl>, ()> -> Result<Component<Impl>,
where P: Parser<Impl=Impl>, Impl: SelectorImpl ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
let mut v = ParseVec::new(); let mut v = ParseVec::new();
parse_compound_selector(parser, input, &mut v, /* inside_negation = */ true)?; parse_compound_selector(parser, input, &mut v, /* inside_negation = */ true)?;
@ -1334,7 +1375,7 @@ fn parse_negation<P, Impl>(parser: &P,
if single_simple_selector(&v) { if single_simple_selector(&v) {
Ok(Component::Negation(v.into_vec().into_boxed_slice())) Ok(Component::Negation(v.into_vec().into_boxed_slice()))
} else { } else {
Err(()) Err(ParseError::Custom(SelectorParseError::NonSimpleSelectorInNegation))
} }
} }
@ -1365,13 +1406,13 @@ fn single_simple_selector<Impl: SelectorImpl>(v: &[Component<Impl>]) -> bool {
/// `Err(())` means invalid selector. /// `Err(())` means invalid selector.
/// ///
/// The boolean represent whether a pseudo-element has been parsed. /// The boolean represent whether a pseudo-element has been parsed.
fn parse_compound_selector<P, Impl>( fn parse_compound_selector<'i, 't, P, E, Impl>(
parser: &P, parser: &P,
input: &mut CssParser, input: &mut CssParser<'i, 't>,
mut sequence: &mut ParseVec<Impl>, mut sequence: &mut ParseVec<Impl>,
inside_negation: bool) inside_negation: bool)
-> Result<bool, ()> -> Result<bool, ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<Impl=Impl>, Impl: SelectorImpl where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
// Consume any leading whitespace. // Consume any leading whitespace.
loop { loop {
@ -1412,21 +1453,21 @@ fn parse_compound_selector<P, Impl>(
loop { loop {
match input.next_including_whitespace() { match input.next_including_whitespace() {
Ok(Token::Colon) => {}, Ok(Token::Colon) => {},
Ok(Token::WhiteSpace(_)) | Err(()) => break, Ok(Token::WhiteSpace(_)) | Err(_) => break,
_ => return Err(()), _ => return Err(SelectorParseError::PseudoElementExpectedColon.into()),
} }
// TODO(emilio): Functional pseudo-classes too? // TODO(emilio): Functional pseudo-classes too?
// We don't need it for now. // We don't need it for now.
let name = match input.next_including_whitespace() { let name = match input.next_including_whitespace() {
Ok(Token::Ident(name)) => name, Ok(Token::Ident(name)) => name,
_ => return Err(()), _ => return Err(SelectorParseError::PseudoElementExpectedIdent.into()),
}; };
let pseudo_class = let pseudo_class =
P::parse_non_ts_pseudo_class(parser, name)?; P::parse_non_ts_pseudo_class(parser, name)?;
if !p.supports_pseudo_class(&pseudo_class) { if !p.supports_pseudo_class(&pseudo_class) {
return Err(()); return Err(SelectorParseError::UnsupportedPseudoClass.into());
} }
state_selectors.push(Component::NonTSPseudoClass(pseudo_class)); state_selectors.push(Component::NonTSPseudoClass(pseudo_class));
} }
@ -1448,18 +1489,19 @@ fn parse_compound_selector<P, Impl>(
} }
if empty { if empty {
// An empty selector is invalid. // An empty selector is invalid.
Err(()) Err(ParseError::Custom(SelectorParseError::EmptySelector))
} else { } else {
Ok(pseudo) Ok(pseudo)
} }
} }
fn parse_functional_pseudo_class<P, Impl>(parser: &P, fn parse_functional_pseudo_class<'i, 't, P, E, Impl>(parser: &P,
input: &mut CssParser, input: &mut CssParser<'i, 't>,
name: Cow<str>, name: Cow<'i, str>,
inside_negation: bool) inside_negation: bool)
-> Result<Component<Impl>, ()> -> Result<Component<Impl>,
where P: Parser<Impl=Impl>, Impl: SelectorImpl ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
"nth-child" => return parse_nth_pseudo_class(input, Component::NthChild), "nth-child" => return parse_nth_pseudo_class(input, Component::NthChild),
@ -1468,7 +1510,7 @@ fn parse_functional_pseudo_class<P, Impl>(parser: &P,
"nth-last-of-type" => return parse_nth_pseudo_class(input, Component::NthLastOfType), "nth-last-of-type" => return parse_nth_pseudo_class(input, Component::NthLastOfType),
"not" => { "not" => {
if inside_negation { if inside_negation {
return Err(()) return Err(ParseError::Custom(SelectorParseError::UnexpectedIdent("not".into())));
} }
return parse_negation(parser, input) return parse_negation(parser, input)
}, },
@ -1479,8 +1521,9 @@ fn parse_functional_pseudo_class<P, Impl>(parser: &P,
} }
fn parse_nth_pseudo_class<Impl, F>(input: &mut CssParser, selector: F) fn parse_nth_pseudo_class<'i, 't, Impl, F, E>(input: &mut CssParser<'i, 't>, selector: F)
-> Result<Component<Impl>, ()> -> Result<Component<Impl>,
ParseError<'i, SelectorParseError<'i, E>>>
where Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component<Impl> { where Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component<Impl> {
let (a, b) = parse_nth(input)?; let (a, b) = parse_nth(input)?;
Ok(selector(a, b)) Ok(selector(a, b))
@ -1492,11 +1535,12 @@ where Impl: SelectorImpl, F: FnOnce(i32, i32) -> Component<Impl> {
/// * `Err(())`: Invalid selector, abort /// * `Err(())`: Invalid selector, abort
/// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed.
/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
fn parse_one_simple_selector<P, Impl>(parser: &P, fn parse_one_simple_selector<'i, 't, P, E, Impl>(parser: &P,
input: &mut CssParser, input: &mut CssParser<'i, 't>,
inside_negation: bool) inside_negation: bool)
-> Result<Option<SimpleSelectorParseResult<Impl>>, ()> -> Result<Option<SimpleSelectorParseResult<Impl>>,
where P: Parser<Impl=Impl>, Impl: SelectorImpl ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
let start_position = input.position(); let start_position = input.position();
match input.next_including_whitespace() { match input.next_including_whitespace() {
@ -1510,7 +1554,8 @@ fn parse_one_simple_selector<P, Impl>(parser: &P,
let class = Component::Class(from_cow_str(class)); let class = Component::Class(from_cow_str(class));
Ok(Some(SimpleSelectorParseResult::SimpleSelector(class))) Ok(Some(SimpleSelectorParseResult::SimpleSelector(class)))
} }
_ => Err(()), Ok(t) => Err(ParseError::Basic(BasicParseError::UnexpectedToken(t))),
Err(e) => Err(ParseError::Basic(e)),
} }
} }
Ok(Token::SquareBracketBlock) => { Ok(Token::SquareBracketBlock) => {
@ -1545,10 +1590,12 @@ fn parse_one_simple_selector<P, Impl>(parser: &P,
let pseudo = P::parse_pseudo_element(parser, name)?; let pseudo = P::parse_pseudo_element(parser, name)?;
Ok(Some(SimpleSelectorParseResult::PseudoElement(pseudo))) 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<P, Impl>(parser: &P,
} }
} }
fn parse_simple_pseudo_class<P, Impl>(parser: &P, name: Cow<str>) -> Result<Component<Impl>, ()> fn parse_simple_pseudo_class<'i, P, E, Impl>(parser: &P, name: Cow<'i, str>)
where P: Parser<Impl=Impl>, Impl: SelectorImpl -> Result<Component<Impl>,
ParseError<'i, SelectorParseError<'i, E>>>
where P: Parser<'i, Impl=Impl, Error=E>, Impl: SelectorImpl
{ {
(match_ignore_ascii_case! { &name, (match_ignore_ascii_case! { &name,
"first-child" => Ok(Component::FirstChild), "first-child" => Ok(Component::FirstChild),
@ -1580,7 +1629,7 @@ fn parse_simple_pseudo_class<P, Impl>(parser: &P, name: Cow<str>) -> Result<Comp
// NB: pub module in order to access the DummyParser // NB: pub module in order to access the DummyParser
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use cssparser::{Parser as CssParser, ToCss, serialize_identifier}; use cssparser::{Parser as CssParser, ToCss, serialize_identifier, ParserInput};
use parser; use parser;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
@ -1691,32 +1740,37 @@ pub mod tests {
} }
} }
impl Parser for DummyParser { impl<'i> Parser<'i> for DummyParser {
type Impl = DummySelectorImpl; type Impl = DummySelectorImpl;
type Error = ();
fn parse_non_ts_pseudo_class(&self, name: Cow<str>) fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>)
-> Result<PseudoClass, ()> { -> Result<PseudoClass,
ParseError<'i, SelectorParseError<'i, ()>>> {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
"hover" => Ok(PseudoClass::Hover), "hover" => Ok(PseudoClass::Hover),
"active" => Ok(PseudoClass::Active), "active" => Ok(PseudoClass::Active),
_ => Err(()) _ => Err(SelectorParseError::Custom(()).into())
} }
} }
fn parse_non_ts_functional_pseudo_class(&self, name: Cow<str>, fn parse_non_ts_functional_pseudo_class<'t>(&self, name: Cow<'i, str>,
parser: &mut CssParser) parser: &mut CssParser<'i, 't>)
-> Result<PseudoClass, ()> { -> Result<PseudoClass,
ParseError<'i, SelectorParseError<'i, ()>>> {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
"lang" => Ok(PseudoClass::Lang(try!(parser.expect_ident_or_string()).into_owned())), "lang" => Ok(PseudoClass::Lang(try!(parser.expect_ident_or_string()).into_owned())),
_ => Err(()) _ => Err(SelectorParseError::Custom(()).into())
} }
} }
fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> { fn parse_pseudo_element(&self, name: Cow<'i, str>)
-> Result<PseudoElement,
ParseError<'i, SelectorParseError<'i, ()>>> {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
"before" => Ok(PseudoElement::Before), "before" => Ok(PseudoElement::Before),
"after" => Ok(PseudoElement::After), "after" => Ok(PseudoElement::After),
_ => Err(()) _ => Err(SelectorParseError::Custom(()).into())
} }
} }
@ -1729,13 +1783,16 @@ pub mod tests {
} }
} }
fn parse(input: &str) -> Result<SelectorList<DummySelectorImpl>, ()> { fn parse<'i>(input: &'i str) -> Result<SelectorList<DummySelectorImpl>,
ParseError<'i, SelectorParseError<'i, ()>>> {
parse_ns(input, &DummyParser::default()) parse_ns(input, &DummyParser::default())
} }
fn parse_ns(input: &str, parser: &DummyParser) fn parse_ns<'i>(input: &'i str, parser: &DummyParser)
-> Result<SelectorList<DummySelectorImpl>, ()> { -> Result<SelectorList<DummySelectorImpl>,
let result = SelectorList::parse(parser, &mut CssParser::new(input)); 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 { if let Ok(ref selectors) = result {
assert_eq!(selectors.0.len(), 1); assert_eq!(selectors.0.len(), 1);
assert_eq!(selectors.0[0].selector.to_css_string(), input); assert_eq!(selectors.0[0].selector.to_css_string(), input);
@ -1749,7 +1806,8 @@ pub mod tests {
#[test] #[test]
fn test_empty() { 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()); assert!(list.is_ok());
} }
@ -1758,9 +1816,9 @@ pub mod tests {
#[test] #[test]
fn test_parsing() { fn test_parsing() {
assert_eq!(parse(""), Err(())) ; assert!(parse("").is_err()) ;
assert_eq!(parse(":lang(4)"), Err(())) ; assert!(parse(":lang(4)").is_err()) ;
assert_eq!(parse(":lang(en US)"), Err(())) ; assert!(parse(":lang(en US)").is_err()) ;
assert_eq!(parse("EeÉ"), Ok(SelectorList::from_vec(vec!( assert_eq!(parse("EeÉ"), Ok(SelectorList::from_vec(vec!(
Selector::from_vec(vec!( Selector::from_vec(vec!(
Component::LocalName(LocalName { Component::LocalName(LocalName {
@ -1846,7 +1904,7 @@ pub mod tests {
} }
), specificity(0, 1, 0)) ), 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())); parser.ns_prefixes.insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
assert_eq!(parse_ns("svg|circle", &parser), Ok(SelectorList::from_vec(vec!( assert_eq!(parse_ns("svg|circle", &parser), Ok(SelectorList::from_vec(vec!(
Selector::from_vec(vec!( Selector::from_vec(vec!(
@ -1960,14 +2018,14 @@ pub mod tests {
Component::NonTSPseudoClass(PseudoClass::Hover), Component::NonTSPseudoClass(PseudoClass::Hover),
), specificity(0, 2, 1) | HAS_PSEUDO_BIT) ), specificity(0, 2, 1) | HAS_PSEUDO_BIT)
)))); ))));
assert_eq!(parse("::before:hover:active"), Err(())); assert!(parse("::before:hover:active").is_err());
assert_eq!(parse("::before:hover .foo"), Err(())); assert!(parse("::before:hover .foo").is_err());
assert_eq!(parse("::before .foo"), Err(())); assert!(parse("::before .foo").is_err());
assert_eq!(parse("::before ~ bar"), Err(())); assert!(parse("::before ~ bar").is_err());
assert_eq!(parse("::before:active"), Err(())); assert!(parse("::before:active").is_err());
// https://github.com/servo/servo/issues/15335 // 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!( assert_eq!(parse("div ::after"), Ok(SelectorList::from_vec(vec!(
Selector::from_vec(vec!( Selector::from_vec(vec!(
Component::LocalName(LocalName { Component::LocalName(LocalName {
@ -1986,8 +2044,8 @@ pub mod tests {
), (1 << 20) + (1 << 10) + (0 << 0)) ), (1 << 20) + (1 << 10) + (0 << 0))
)))); ))));
parser.default_ns = None; parser.default_ns = None;
assert_eq!(parse(":not(#provel.old)"), Err(())); assert!(parse(":not(#provel.old)").is_err());
assert_eq!(parse(":not(#provel > old)"), Err(())); assert!(parse(":not(#provel > old)").is_err());
assert!(parse("table[rules]:not([rules = \"none\"]):not([rules = \"\"])").is_ok()); assert!(parse("table[rules]:not([rules = \"none\"]):not([rules = \"\"])").is_ok());
assert_eq!(parse(":not(#provel)"), Ok(SelectorList::from_vec(vec!( assert_eq!(parse(":not(#provel)"), Ok(SelectorList::from_vec(vec!(
Selector::from_vec(vec!(Component::Negation(vec!( Selector::from_vec(vec!(Component::Negation(vec!(

View file

@ -38,7 +38,7 @@ bitflags = "0.7"
bit-vec = "0.4.3" bit-vec = "0.4.3"
byteorder = "1.0" byteorder = "1.0"
cfg-if = "0.1.0" cfg-if = "0.1.0"
cssparser = "0.13.7" cssparser = "0.14.0"
encoding = {version = "0.2", optional = true} encoding = {version = "0.2", optional = true}
euclid = "0.13" euclid = "0.13"
fnv = "1.0" fnv = "1.0"

View file

@ -8,21 +8,22 @@
use Atom; use Atom;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser}; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser};
use cssparser::{Parser, Token, serialize_identifier}; use cssparser::{Parser, Token, serialize_identifier, BasicParseError};
use error_reporting::ParseError; use error_reporting::ContextualParseError;
#[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors; #[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
use parser::{ParserContext, log_css_error, Parse}; use parser::{ParserContext, log_css_error, Parse};
use selectors::parser::SelectorParseError;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::ops::Range; use std::ops::Range;
use style_traits::{ToCss, OneOrMoreCommaSeparated}; use style_traits::{ToCss, OneOrMoreCommaSeparated, ParseError, StyleParseError};
use values::CustomIdent; use values::CustomIdent;
/// Parse the prelude of an @counter-style rule /// Parse the prelude of an @counter-style rule
pub fn parse_counter_style_name(input: &mut Parser) -> Result<CustomIdent, ()> { pub fn parse_counter_style_name<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CustomIdent, ParseError<'i>> {
macro_rules! predefined { macro_rules! predefined {
($($name: expr,)+) => { ($($name: expr,)+) => {
{ {
@ -49,8 +50,8 @@ pub fn parse_counter_style_name(input: &mut Parser) -> Result<CustomIdent, ()> {
} }
/// Parse the body (inside `{}`) of an @counter-style rule /// Parse the body (inside `{}`) of an @counter-style rule
pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, input: &mut Parser) pub fn parse_counter_style_body<'i, 't>(name: CustomIdent, context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<CounterStyleRuleData, ()> { -> Result<CounterStyleRuleData, ParseError<'i>> {
let start = input.position(); let start = input.position();
let mut rule = CounterStyleRuleData::empty(name); let mut rule = CounterStyleRuleData::empty(name);
{ {
@ -60,9 +61,10 @@ pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, inpu
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
if let Err(range) = declaration { if let Err(err) = declaration {
let pos = range.start; let pos = err.span.start;
let error = ParseError::UnsupportedViewportDescriptorDeclaration(iter.input.slice(range)); let error = ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(
iter.input.slice(err.span), err.error);
log_css_error(iter.input, pos, error, context); log_css_error(iter.input, pos, error, context);
} }
} }
@ -75,28 +77,28 @@ pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, inpu
ref system @ System::Numeric ref system @ System::Numeric
if rule.symbols.is_none() => { if rule.symbols.is_none() => {
let system = system.to_css_string(); let system = system.to_css_string();
Some(ParseError::InvalidCounterStyleWithoutSymbols(system)) Some(ContextualParseError::InvalidCounterStyleWithoutSymbols(system))
} }
ref system @ System::Alphabetic | ref system @ System::Alphabetic |
ref system @ System::Numeric ref system @ System::Numeric
if rule.symbols().unwrap().0.len() < 2 => { if rule.symbols().unwrap().0.len() < 2 => {
let system = system.to_css_string(); let system = system.to_css_string();
Some(ParseError::InvalidCounterStyleNotEnoughSymbols(system)) Some(ContextualParseError::InvalidCounterStyleNotEnoughSymbols(system))
} }
System::Additive if rule.additive_symbols.is_none() => { System::Additive if rule.additive_symbols.is_none() => {
Some(ParseError::InvalidCounterStyleWithoutAdditiveSymbols) Some(ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols)
} }
System::Extends(_) if rule.symbols.is_some() => { System::Extends(_) if rule.symbols.is_some() => {
Some(ParseError::InvalidCounterStyleExtendsWithSymbols) Some(ContextualParseError::InvalidCounterStyleExtendsWithSymbols)
} }
System::Extends(_) if rule.additive_symbols.is_some() => { System::Extends(_) if rule.additive_symbols.is_some() => {
Some(ParseError::InvalidCounterStyleExtendsWithAdditiveSymbols) Some(ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols)
} }
_ => None _ => None
}; };
if let Some(error) = error { if let Some(error) = error {
log_css_error(input, start, error, context); log_css_error(input, start, error, context);
Err(()) Err(StyleParseError::UnspecifiedError.into())
} else { } else {
Ok(rule) Ok(rule)
} }
@ -108,9 +110,10 @@ struct CounterStyleRuleParser<'a, 'b: 'a> {
} }
/// Default methods reject all at rules. /// 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 Prelude = ();
type AtRule = (); type AtRule = ();
type Error = SelectorParseError<'i, StyleParseError<'i>>;
} }
macro_rules! accessor { macro_rules! accessor {
@ -177,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 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>)
match_ignore_ascii_case! { name, -> Result<(), ParseError<'i>> {
match_ignore_ascii_case! { &*name,
$( $(
$name => { $name => {
// DeclarationParser also calls parse_entirely // DeclarationParser also calls parse_entirely
@ -192,7 +197,7 @@ macro_rules! counter_style_descriptors {
self.rule.$ident = Some(value) self.rule.$ident = Some(value)
} }
)* )*
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
Ok(()) Ok(())
} }
@ -289,8 +294,9 @@ pub enum System {
} }
impl Parse for System { impl Parse for System {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match_ignore_ascii_case! { &input.expect_ident()?, let ident = input.expect_ident()?;
(match_ignore_ascii_case! { &ident,
"cyclic" => Ok(System::Cyclic), "cyclic" => Ok(System::Cyclic),
"numeric" => Ok(System::Numeric), "numeric" => Ok(System::Numeric),
"alphabetic" => Ok(System::Alphabetic), "alphabetic" => Ok(System::Alphabetic),
@ -305,7 +311,7 @@ impl Parse for System {
Ok(System::Extends(other)) Ok(System::Extends(other))
} }
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
@ -345,11 +351,12 @@ pub enum Symbol {
} }
impl Parse for Symbol { impl Parse for Symbol {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match input.next() { match input.next() {
Ok(Token::QuotedString(s)) => Ok(Symbol::String(s.into_owned())), Ok(Token::QuotedString(s)) => Ok(Symbol::String(s.into_owned())),
Ok(Token::Ident(s)) => Ok(Symbol::Ident(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()),
} }
} }
} }
@ -379,7 +386,7 @@ impl Symbol {
pub struct Negative(pub Symbol, pub Option<Symbol>); pub struct Negative(pub Symbol, pub Option<Symbol>);
impl Parse for Negative { impl Parse for Negative {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Ok(Negative( Ok(Negative(
Symbol::parse(context, input)?, Symbol::parse(context, input)?,
input.try(|input| Symbol::parse(context, input)).ok(), input.try(|input| Symbol::parse(context, input)).ok(),
@ -405,7 +412,7 @@ impl ToCss for Negative {
pub struct Ranges(pub Vec<Range<Option<i32>>>); pub struct Ranges(pub Vec<Range<Option<i32>>>);
impl Parse for Ranges { impl Parse for Ranges {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() { if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
Ok(Ranges(Vec::new())) Ok(Ranges(Vec::new()))
} else { } else {
@ -414,7 +421,7 @@ impl Parse for Ranges {
let opt_end = parse_bound(input)?; let opt_end = parse_bound(input)?;
if let (Some(start), Some(end)) = (opt_start, opt_end) { if let (Some(start), Some(end)) = (opt_start, opt_end) {
if start > end { if start > end {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
} }
Ok(opt_start..opt_end) Ok(opt_start..opt_end)
@ -423,11 +430,12 @@ impl Parse for Ranges {
} }
} }
fn parse_bound(input: &mut Parser) -> Result<Option<i32>, ()> { fn parse_bound<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Option<i32>, ParseError<'i>> {
match input.next() { match input.next() {
Ok(Token::Number(ref v)) if v.int_value.is_some() => Ok(Some(v.int_value.unwrap())), 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), 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()),
} }
} }
@ -467,13 +475,13 @@ fn bound_to_css<W>(range: Option<i32>, dest: &mut W) -> fmt::Result where W: fmt
pub struct Pad(pub u32, pub Symbol); pub struct Pad(pub u32, pub Symbol);
impl Parse for Pad { impl Parse for Pad {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let pad_with = input.try(|input| Symbol::parse(context, input)); let pad_with = input.try(|input| Symbol::parse(context, input));
let min_length = input.expect_integer()?; let min_length = input.expect_integer()?;
if min_length < 0 { 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)) Ok(Pad(min_length as u32, pad_with))
} }
} }
@ -490,7 +498,7 @@ impl ToCss for Pad {
pub struct Fallback(pub CustomIdent); pub struct Fallback(pub CustomIdent);
impl Parse for Fallback { impl Parse for Fallback {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
parse_counter_style_name(input).map(Fallback) parse_counter_style_name(input).map(Fallback)
} }
} }
@ -506,14 +514,14 @@ impl ToCss for Fallback {
pub struct Symbols(pub Vec<Symbol>); pub struct Symbols(pub Vec<Symbol>);
impl Parse for Symbols { impl Parse for Symbols {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let mut symbols = Vec::new(); let mut symbols = Vec::new();
loop { loop {
if let Ok(s) = input.try(|input| Symbol::parse(context, input)) { if let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
symbols.push(s) symbols.push(s)
} else { } else {
if symbols.is_empty() { if symbols.is_empty() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} else { } else {
return Ok(Symbols(symbols)) return Ok(Symbols(symbols))
} }
@ -540,11 +548,11 @@ impl ToCss for Symbols {
pub struct AdditiveSymbols(pub Vec<AdditiveTuple>); pub struct AdditiveSymbols(pub Vec<AdditiveTuple>);
impl Parse for AdditiveSymbols { impl Parse for AdditiveSymbols {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let tuples = Vec::<AdditiveTuple>::parse(context, input)?; let tuples = Vec::<AdditiveTuple>::parse(context, input)?;
// FIXME maybe? https://github.com/w3c/csswg-drafts/issues/1220 // FIXME maybe? https://github.com/w3c/csswg-drafts/issues/1220
if tuples.windows(2).any(|window| window[0].weight <= window[1].weight) { if tuples.windows(2).any(|window| window[0].weight <= window[1].weight) {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(AdditiveSymbols(tuples)) Ok(AdditiveSymbols(tuples))
} }
@ -568,13 +576,13 @@ pub struct AdditiveTuple {
impl OneOrMoreCommaSeparated for AdditiveTuple {} impl OneOrMoreCommaSeparated for AdditiveTuple {}
impl Parse for AdditiveTuple { impl Parse for AdditiveTuple {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let symbol = input.try(|input| Symbol::parse(context, input)); let symbol = input.try(|input| Symbol::parse(context, input));
let weight = input.expect_integer()?; let weight = input.expect_integer()?;
if weight < 0 { 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 { Ok(AdditiveTuple {
weight: weight as u32, weight: weight as u32,
symbol: symbol, symbol: symbol,
@ -607,10 +615,11 @@ pub enum SpeakAs {
} }
impl Parse for SpeakAs { impl Parse for SpeakAs {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let mut is_spell_out = false; let mut is_spell_out = false;
let result = input.try(|input| { let result: Result<_, ParseError> = input.try(|input| {
match_ignore_ascii_case! { &input.expect_ident()?, let ident = input.expect_ident()?;
(match_ignore_ascii_case! { &ident,
"auto" => Ok(SpeakAs::Auto), "auto" => Ok(SpeakAs::Auto),
"bullets" => Ok(SpeakAs::Bullets), "bullets" => Ok(SpeakAs::Bullets),
"numbers" => Ok(SpeakAs::Numbers), "numbers" => Ok(SpeakAs::Numbers),
@ -620,14 +629,14 @@ impl Parse for SpeakAs {
Err(()) Err(())
} }
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
}); });
if is_spell_out { if is_spell_out {
// spell-out is not supported, but dont parse it as a <counter-style-name>. // spell-out is not supported, but dont parse it as a <counter-style-name>.
// See bug 1024178. // See bug 1024178.
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
result.or_else(|()| { result.or_else(|_| {
Ok(SpeakAs::Other(parse_counter_style_name(input)?)) Ok(SpeakAs::Other(parse_counter_style_name(input)?))
}) })
} }

View file

@ -7,14 +7,15 @@
//! [custom]: https://drafts.csswg.org/css-variables/ //! [custom]: https://drafts.csswg.org/css-variables/
use Atom; use Atom;
use cssparser::{Delimiter, Parser, SourcePosition, Token, TokenSerializationType}; use cssparser::{Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSerializationType};
use parser::ParserContext; use parser::ParserContext;
use properties::{CSSWideKeyword, DeclaredValue}; use properties::{CSSWideKeyword, DeclaredValue};
use selectors::parser::SelectorParseError;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt; use std::fmt;
use style_traits::{HasViewportPercentage, ToCss}; use style_traits::{HasViewportPercentage, ToCss, StyleParseError, ParseError};
use stylearc::Arc; use stylearc::Arc;
/// A custom property name is just an `Atom`. /// A custom property name is just an `Atom`.
@ -131,7 +132,8 @@ impl ComputedValue {
impl SpecifiedValue { impl SpecifiedValue {
/// Parse a custom property SpecifiedValue. /// Parse a custom property SpecifiedValue.
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Box<Self>, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Box<Self>, ParseError<'i>> {
let mut references = Some(HashSet::new()); let mut references = Some(HashSet::new());
let (first, css, last) = try!(parse_self_contained_declaration_value(input, &mut references)); let (first, css, last) = try!(parse_self_contained_declaration_value(input, &mut references));
Ok(Box::new(SpecifiedValue { Ok(Box::new(SpecifiedValue {
@ -146,7 +148,7 @@ impl SpecifiedValue {
/// Parse the value of a non-custom property that contains `var()` references. /// Parse the value of a non-custom property that contains `var()` references.
pub fn parse_non_custom_with_var<'i, 't> pub fn parse_non_custom_with_var<'i, 't>
(input: &mut Parser<'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)); let (first_token_type, css, _) = try!(parse_self_contained_declaration_value(input, &mut None));
Ok((first_token_type, css)) Ok((first_token_type, css))
} }
@ -158,7 +160,7 @@ fn parse_self_contained_declaration_value<'i, 't>
TokenSerializationType, TokenSerializationType,
Cow<'i, str>, Cow<'i, str>,
TokenSerializationType TokenSerializationType
), ()> { ), ParseError<'i>> {
let start_position = input.position(); let start_position = input.position();
let mut missing_closing_characters = String::new(); let mut missing_closing_characters = String::new();
let (first, last) = try!( let (first, last) = try!(
@ -179,7 +181,7 @@ fn parse_declaration_value<'i, 't>
(input: &mut Parser<'i, 't>, (input: &mut Parser<'i, 't>,
references: &mut Option<HashSet<Name>>, references: &mut Option<HashSet<Name>>,
missing_closing_characters: &mut String) missing_closing_characters: &mut String)
-> Result<(TokenSerializationType, TokenSerializationType), ()> { -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i>> {
input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| { input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| {
// Need at least one token // Need at least one token
let start_position = input.position(); 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 /// Like parse_declaration_value, but accept `!` and `;` since they are only
/// invalid at the top level /// 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<HashSet<Name>>, references: &mut Option<HashSet<Name>>,
missing_closing_characters: &mut String) missing_closing_characters: &mut String)
-> Result<(TokenSerializationType, TokenSerializationType), ()> { -> Result<(TokenSerializationType, TokenSerializationType),
ParseError<'i>> {
let mut token_start = input.position(); let mut token_start = input.position();
let mut token = match input.next_including_whitespace_and_comments() { let mut token = match input.next_including_whitespace_and_comments() {
Ok(token) => token, Ok(token) => token,
Err(()) => return Ok((TokenSerializationType::nothing(), TokenSerializationType::nothing())) Err(_) => return Ok((TokenSerializationType::nothing(), TokenSerializationType::nothing()))
}; };
let first_token_type = token.serialization_type(); let first_token_type = token.serialization_type();
loop { loop {
@ -226,13 +230,16 @@ fn parse_declaration_value_block(input: &mut Parser,
} }
token.serialization_type() token.serialization_type()
} }
Token::BadUrl | Token::BadUrl =>
Token::BadString | return Err(StyleParseError::BadUrlInDeclarationValueBlock.into()),
Token::CloseParenthesis | Token::BadString =>
Token::CloseSquareBracket | return Err(StyleParseError::BadStringInDeclarationValueBlock.into()),
Token::CloseCurlyBracket => { Token::CloseParenthesis =>
return Err(()) return Err(StyleParseError::UnbalancedCloseParenthesisInDeclarationValueBlock.into()),
} Token::CloseSquareBracket =>
return Err(StyleParseError::UnbalancedCloseSquareBracketInDeclarationValueBlock.into()),
Token::CloseCurlyBracket =>
return Err(StyleParseError::UnbalancedCloseCurlyBracketInDeclarationValueBlock.into()),
Token::Function(ref name) => { Token::Function(ref name) => {
if name.eq_ignore_ascii_case("var") { if name.eq_ignore_ascii_case("var") {
let position = input.position(); 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)) // If the var function is valid, return Ok((custom_property_name, fallback))
fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>,
references: &mut Option<HashSet<Name>>) references: &mut Option<HashSet<Name>>)
-> Result<(), ()> { -> Result<(), ParseError<'i>> {
let name = try!(input.expect_ident()); 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() { if input.try(|input| input.expect_comma()).is_ok() {
// Exclude `!` and `;` at the top level // Exclude `!` and `;` at the top level
// https://drafts.csswg.org/css-syntax/#typedef-declaration-value // 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 computed_value = if specified_value.references.map(|set| set.is_empty()) == Some(false) {
let mut partial_computed_value = ComputedValue::empty(); 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 mut position = (input.position(), specified_value.first_token_type);
let result = substitute_block( let result = substitute_block(
&mut input, &mut position, &mut partial_computed_value, &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. /// Return `Err(())` if `input` is invalid at computed-value time.
/// or `Ok(last_token_type that was pushed to partial_computed_value)` otherwise. /// or `Ok(last_token_type that was pushed to partial_computed_value)` otherwise.
fn substitute_block<F>(input: &mut Parser, fn substitute_block<'i, 't, F>(input: &mut Parser<'i, 't>,
position: &mut (SourcePosition, TokenSerializationType), position: &mut (SourcePosition, TokenSerializationType),
partial_computed_value: &mut ComputedValue, partial_computed_value: &mut ComputedValue,
substitute_one: &mut F) substitute_one: &mut F)
-> Result<TokenSerializationType, ()> -> Result<TokenSerializationType, ParseError<'i>>
where F: FnMut(&Name, &mut ComputedValue) -> Result<TokenSerializationType, ()> { where F: FnMut(&Name, &mut ComputedValue) -> Result<TokenSerializationType, ()> {
let mut last_token_type = TokenSerializationType::nothing(); let mut last_token_type = TokenSerializationType::nothing();
let mut set_position_at_next_iteration = false; let mut set_position_at_next_iteration = false;
@ -539,7 +550,7 @@ fn substitute_block<F>(input: &mut Parser,
if set_position_at_next_iteration { if set_position_at_next_iteration {
*position = (before_this_token, match next { *position = (before_this_token, match next {
Ok(ref token) => token.serialization_type(), Ok(ref token) => token.serialization_type(),
Err(()) => TokenSerializationType::nothing(), Err(_) => TokenSerializationType::nothing(),
}); });
set_position_at_next_iteration = false; set_position_at_next_iteration = false;
} }
@ -605,11 +616,12 @@ fn substitute_block<F>(input: &mut Parser,
/// Replace `var()` functions for a non-custom property. /// Replace `var()` functions for a non-custom property.
/// Return `Err(())` for invalid at computed time. /// Return `Err(())` for invalid at computed time.
pub fn substitute(input: &str, first_token_type: TokenSerializationType, pub fn substitute<'i>(input: &'i str, first_token_type: TokenSerializationType,
computed_values_map: &Option<Arc<HashMap<Name, ComputedValue>>>) computed_values_map: &Option<Arc<HashMap<Name, ComputedValue>>>)
-> Result<String, ()> { -> Result<String, ParseError<'i>> {
let mut substituted = ComputedValue::empty(); 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 mut position = (input.position(), first_token_type);
let last_token_type = try!(substitute_block( let last_token_type = try!(substitute_block(
&mut input, &mut position, &mut substituted, &mut |name, substituted| { &mut input, &mut position, &mut substituted, &mut |name, substituted| {

View file

@ -6,28 +6,30 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use cssparser::{Parser, SourcePosition}; use cssparser::{Parser, SourcePosition, BasicParseError, Token, NumericValue, PercentageValue};
use cssparser::ParseError as CssParseError;
use log; use log;
use style_traits::ParseError;
use stylesheets::UrlExtraData; use stylesheets::UrlExtraData;
/// Errors that can be encountered while parsing CSS. /// Errors that can be encountered while parsing CSS.
pub enum ParseError<'a> { pub enum ContextualParseError<'a> {
/// A property declaration was not recognized. /// A property declaration was not recognized.
UnsupportedPropertyDeclaration(&'a str), UnsupportedPropertyDeclaration(&'a str, ParseError<'a>),
/// A font face descriptor was not recognized. /// A font face descriptor was not recognized.
UnsupportedFontFaceDescriptor(&'a str), UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>),
/// A keyframe rule was not valid. /// A keyframe rule was not valid.
InvalidKeyframeRule(&'a str), InvalidKeyframeRule(&'a str, ParseError<'a>),
/// A keyframe property declaration was not recognized. /// A keyframe property declaration was not recognized.
UnsupportedKeyframePropertyDeclaration(&'a str), UnsupportedKeyframePropertyDeclaration(&'a str, ParseError<'a>),
/// A rule was invalid for some reason. /// A rule was invalid for some reason.
InvalidRule(&'a str), InvalidRule(&'a str, ParseError<'a>),
/// A rule was not recognized. /// A rule was not recognized.
UnsupportedRule(&'a str), UnsupportedRule(&'a str, ParseError<'a>),
/// A viewport descriptor declaration was not recognized. /// A viewport descriptor declaration was not recognized.
UnsupportedViewportDescriptorDeclaration(&'a str), UnsupportedViewportDescriptorDeclaration(&'a str, ParseError<'a>),
/// A counter style descriptor declaration was not recognized. /// A counter style descriptor declaration was not recognized.
UnsupportedCounterStyleDescriptorDeclaration(&'a str), UnsupportedCounterStyleDescriptorDeclaration(&'a str, ParseError<'a>),
/// A counter style rule had no symbols. /// A counter style rule had no symbols.
InvalidCounterStyleWithoutSymbols(String), InvalidCounterStyleWithoutSymbols(String),
/// A counter style rule had less than two symbols. /// A counter style rule had less than two symbols.
@ -40,35 +42,97 @@ pub enum ParseError<'a> {
InvalidCounterStyleExtendsWithAdditiveSymbols InvalidCounterStyleExtendsWithAdditiveSymbols
} }
impl<'a> ParseError<'a> { impl<'a> ContextualParseError<'a> {
/// Turn a parse error into a string representation. /// Turn a parse error into a string representation.
pub fn to_string(&self) -> String { 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::CDC => format!("CDC (-->)"),
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 { match *self {
ParseError::UnsupportedPropertyDeclaration(decl) => ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) =>
format!("Unsupported property declaration: '{}'", decl), format!("Unsupported property declaration: '{}', {}", decl,
ParseError::UnsupportedFontFaceDescriptor(decl) => parse_error_to_str(err)),
format!("Unsupported @font-face descriptor declaration: '{}'", decl), ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) =>
ParseError::InvalidKeyframeRule(rule) => format!("Unsupported @font-face descriptor declaration: '{}', {}", decl,
format!("Invalid keyframe rule: '{}'", rule), parse_error_to_str(err)),
ParseError::UnsupportedKeyframePropertyDeclaration(decl) => ContextualParseError::InvalidKeyframeRule(rule, ref err) =>
format!("Unsupported keyframe property declaration: '{}'", decl), format!("Invalid keyframe rule: '{}', {}", rule,
ParseError::InvalidRule(rule) => parse_error_to_str(err)),
format!("Invalid rule: '{}'", rule), ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) =>
ParseError::UnsupportedRule(rule) => format!("Unsupported keyframe property declaration: '{}', {}", decl,
format!("Unsupported rule: '{}'", rule), parse_error_to_str(err)),
ParseError::UnsupportedViewportDescriptorDeclaration(decl) => ContextualParseError::InvalidRule(rule, ref err) =>
format!("Unsupported @viewport descriptor declaration: '{}'", decl), format!("Invalid rule: '{}', {}", rule, parse_error_to_str(err)),
ParseError::UnsupportedCounterStyleDescriptorDeclaration(decl) => ContextualParseError::UnsupportedRule(rule, ref err) =>
format!("Unsupported @counter-style descriptor declaration: '{}'", decl), format!("Unsupported rule: '{}', {}", rule, parse_error_to_str(err)),
ParseError::InvalidCounterStyleWithoutSymbols(ref system) => 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), format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system),
ParseError::InvalidCounterStyleNotEnoughSymbols(ref system) => ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) =>
format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system), format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system),
ParseError::InvalidCounterStyleWithoutAdditiveSymbols => ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols =>
"Invalid @counter-style rule: 'system: additive' without 'additive-symbols'".into(), "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'".into(),
ParseError::InvalidCounterStyleExtendsWithSymbols => ContextualParseError::InvalidCounterStyleExtendsWithSymbols =>
"Invalid @counter-style rule: 'system: extends …' with 'symbols'".into(), "Invalid @counter-style rule: 'system: extends …' with 'symbols'".into(),
ParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols =>
"Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'".into(), "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'".into(),
} }
} }
@ -83,7 +147,7 @@ pub trait ParseErrorReporter : Sync {
fn report_error<'a>(&self, fn report_error<'a>(&self,
input: &mut Parser, input: &mut Parser,
position: SourcePosition, position: SourcePosition,
error: ParseError<'a>, error: ContextualParseError<'a>,
url: &UrlExtraData, url: &UrlExtraData,
line_number_offset: u64); line_number_offset: u64);
} }
@ -100,7 +164,7 @@ impl ParseErrorReporter for RustLogReporter {
fn report_error<'a>(&self, fn report_error<'a>(&self,
input: &mut Parser, input: &mut Parser,
position: SourcePosition, position: SourcePosition,
error: ParseError<'a>, error: ContextualParseError<'a>,
url: &UrlExtraData, url: &UrlExtraData,
line_number_offset: u64) { line_number_offset: u64) {
if log_enabled!(log::LogLevel::Info) { if log_enabled!(log::LogLevel::Info) {
@ -118,21 +182,14 @@ impl ParseErrorReporter for NullReporter {
fn report_error<'a>(&self, fn report_error<'a>(&self,
_: &mut Parser, _: &mut Parser,
_: SourcePosition, _: SourcePosition,
_: ParseError<'a>, _: ContextualParseError<'a>,
_: &UrlExtraData, _: &UrlExtraData,
_: u64) { _: u64) {
// do nothing // do nothing
} }
} }
/// Create an instance of the default error reporter for Servo. /// Create an instance of the default error reporter.
#[cfg(feature = "servo")]
pub fn create_error_reporter() -> RustLogReporter {
RustLogReporter
}
/// Create an instance of the default error reporter for Stylo.
#[cfg(feature = "gecko")]
pub fn create_error_reporter() -> RustLogReporter { pub fn create_error_reporter() -> RustLogReporter {
RustLogReporter RustLogReporter
} }

View file

@ -13,13 +13,15 @@ use computed_values::{font_feature_settings, font_stretch, font_style, font_weig
use computed_values::font_family::FamilyName; use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::SourceLocation; use cssparser::SourceLocation;
use error_reporting::ParseError; use error_reporting::ContextualParseError;
#[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors; #[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors;
#[cfg(feature = "gecko")] use cssparser::UnicodeRange; #[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse}; use parser::{ParserContext, log_css_error, Parse};
use selectors::parser::SelectorParseError;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::borrow::Cow;
use std::fmt; use std::fmt;
use style_traits::{ToCss, OneOrMoreCommaSeparated}; use style_traits::{ToCss, OneOrMoreCommaSeparated, ParseError, StyleParseError};
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
/// A source for a font-face rule. /// A source for a font-face rule.
@ -98,9 +100,10 @@ pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser, locati
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
if let Err(range) = declaration { if let Err(err) = declaration {
let pos = range.start; let pos = err.span.start;
let error = ParseError::UnsupportedFontFaceDescriptor(iter.input.slice(range)); let error = ContextualParseError::UnsupportedFontFaceDescriptor(
iter.input.slice(err.span), err.error);
log_css_error(iter.input, pos, error, context); log_css_error(iter.input, pos, error, context);
} }
} }
@ -154,13 +157,15 @@ struct FontFaceRuleParser<'a, 'b: 'a> {
} }
/// Default methods reject all at rules. /// 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 Prelude = ();
type AtRule = (); type AtRule = ();
type Error = SelectorParseError<'i, StyleParseError<'i>>;
} }
impl Parse for Source { impl Parse for Source {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Source, ParseError<'i>> {
if input.try(|input| input.expect_function_matching("local")).is_ok() { if input.try(|input| input.expect_function_matching("local")).is_ok() {
return input.parse_nested_block(|input| { return input.parse_nested_block(|input| {
FamilyName::parse(context, input) FamilyName::parse(context, input)
@ -247,11 +252,13 @@ macro_rules! font_face_descriptors_common {
} }
} }
impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> { impl<'a, 'b, 'i> DeclarationParser<'i> for FontFaceRuleParser<'a, 'b> {
type Declaration = (); 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>)
match_ignore_ascii_case! { name, -> Result<(), ParseError<'i>> {
match_ignore_ascii_case! { &*name,
$( $(
$name => { $name => {
// DeclarationParser also calls parse_entirely // DeclarationParser also calls parse_entirely
@ -262,7 +269,7 @@ macro_rules! font_face_descriptors_common {
self.rule.$ident = Some(value) self.rule.$ident = Some(value)
} }
)* )*
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
Ok(()) Ok(())
} }

View file

@ -6,7 +6,7 @@
use app_units::Au; use app_units::Au;
use context::QuirksMode; use context::QuirksMode;
use cssparser::{CssStringWriter, Parser, RGBA, Token}; use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseError};
use euclid::Size2D; use euclid::Size2D;
use font_metrics::get_metrics_provider_for_product; use font_metrics::get_metrics_provider_for_product;
use gecko::values::convert_nscolor_to_rgba; use gecko::values::convert_nscolor_to_rgba;
@ -19,11 +19,12 @@ use media_queries::MediaType;
use parser::ParserContext; use parser::ParserContext;
use properties::{ComputedValues, StyleBuilder}; use properties::{ComputedValues, StyleBuilder};
use properties::longhands::font_size; use properties::longhands::font_size;
use selectors::parser::SelectorParseError;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
use str::starts_with_ignore_ascii_case; use str::starts_with_ignore_ascii_case;
use string_cache::Atom; use string_cache::Atom;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use style_traits::viewport::ViewportConstraints; use style_traits::viewport::ViewportConstraints;
use stylearc::Arc; use stylearc::Arc;
use values::{CSSFloat, specified}; use values::{CSSFloat, specified};
@ -228,24 +229,25 @@ impl Resolution {
} }
} }
fn parse(input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let (value, unit) = match try!(input.next()) { let (value, unit) = match try!(input.next()) {
Token::Dimension(value, unit) => { Token::Dimension(value, unit) => {
(value.value, unit) (value, unit)
}, },
_ => return Err(()), t => return Err(BasicParseError::UnexpectedToken(t).into()),
}; };
if value <= 0. { let inner_value = value.value;
return Err(()) if inner_value <= 0. {
return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(match_ignore_ascii_case! { &unit, (match_ignore_ascii_case! { &unit,
"dpi" => Resolution::Dpi(value), "dpi" => Ok(Resolution::Dpi(inner_value)),
"dppx" => Resolution::Dppx(value), "dppx" => Ok(Resolution::Dppx(inner_value)),
"dpcm" => Resolution::Dpcm(value), "dpcm" => Ok(Resolution::Dpcm(inner_value)),
_ => return Err(()) _ => Err(())
}) }).map_err(|()| StyleParseError::UnexpectedDimension(unit).into())
} }
} }
@ -459,44 +461,51 @@ impl Expression {
/// ``` /// ```
/// (media-feature: media-value) /// (media-feature: media-value)
/// ``` /// ```
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
try!(input.expect_parenthesis_block()); try!(input.expect_parenthesis_block());
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
let ident = try!(input.expect_ident()); let ident = try!(input.expect_ident());
let mut flags = 0; 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. // TODO(emilio): this is under a pref in Gecko.
if starts_with_ignore_ascii_case(feature_name, "-webkit-") { if starts_with_ignore_ascii_case(feature_name, "-webkit-") {
feature_name = &feature_name[8..]; feature_name = &feature_name[8..];
flags |= nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8; flags |= nsMediaFeature_RequirementFlags::eHasWebkitPrefix as u8;
} }
let range = if starts_with_ignore_ascii_case(feature_name, "min-") { let range = if starts_with_ignore_ascii_case(feature_name, "min-") {
feature_name = &feature_name[4..]; feature_name = &feature_name[4..];
nsMediaExpression_Range::eMin nsMediaExpression_Range::eMin
} else if starts_with_ignore_ascii_case(feature_name, "max-") { } else if starts_with_ignore_ascii_case(feature_name, "max-") {
feature_name = &feature_name[4..]; feature_name = &feature_name[4..];
nsMediaExpression_Range::eMax nsMediaExpression_Range::eMax
} else { } else {
nsMediaExpression_Range::eEqual 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 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 { if (feature.mReqFlags & !flags) != 0 {
return Err(()); return Err(SelectorParseError::UnexpectedIdent(ident).into());
} }
if range != nsMediaExpression_Range::eEqual && if range != nsMediaExpression_Range::eEqual &&
feature.mRangeType != nsMediaFeature_RangeType::eMinMaxAllowed { 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 // If there's no colon, this is a media query of the form
@ -506,7 +515,7 @@ impl Expression {
// reject them here too. // reject them here too.
if input.try(|i| i.expect_colon()).is_err() { if input.try(|i| i.expect_colon()).is_err() {
if range != nsMediaExpression_Range::eEqual { if range != nsMediaExpression_Range::eEqual {
return Err(()) return Err(StyleParseError::RangedExpressionWithNoValue.into())
} }
return Ok(Expression::new(feature, None, range)); return Ok(Expression::new(feature, None, range));
} }
@ -519,14 +528,14 @@ impl Expression {
nsMediaFeature_ValueType::eInteger => { nsMediaFeature_ValueType::eInteger => {
let i = input.expect_integer()?; let i = input.expect_integer()?;
if i < 0 { if i < 0 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
MediaExpressionValue::Integer(i as u32) MediaExpressionValue::Integer(i as u32)
} }
nsMediaFeature_ValueType::eBoolInteger => { nsMediaFeature_ValueType::eBoolInteger => {
let i = input.expect_integer()?; let i = input.expect_integer()?;
if i < 0 || i > 1 { if i < 0 || i > 1 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
MediaExpressionValue::BoolInteger(i == 1) MediaExpressionValue::BoolInteger(i == 1)
} }
@ -536,14 +545,14 @@ impl Expression {
nsMediaFeature_ValueType::eIntRatio => { nsMediaFeature_ValueType::eIntRatio => {
let a = input.expect_integer()?; let a = input.expect_integer()?;
if a <= 0 { if a <= 0 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
input.expect_delim('/')?; input.expect_delim('/')?;
let b = input.expect_integer()?; let b = input.expect_integer()?;
if b <= 0 { if b <= 0 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
MediaExpressionValue::IntRatio(a as u32, b as u32) MediaExpressionValue::IntRatio(a as u32, b as u32)
} }
@ -566,7 +575,7 @@ impl Expression {
Some((_kw, value)) => { Some((_kw, value)) => {
value value
} }
None => return Err(()), None => return Err(StyleParseError::UnspecifiedError.into()),
}; };
MediaExpressionValue::Enumerated(value) MediaExpressionValue::Enumerated(value)

View file

@ -8,11 +8,12 @@ use cssparser::{Parser, ToCss};
use element_state::ElementState; use element_state::ElementState;
use gecko_bindings::structs::CSSPseudoClassType; use gecko_bindings::structs::CSSPseudoClassType;
use selector_parser::{SelectorParser, PseudoElementCascadeType}; use selector_parser::{SelectorParser, PseudoElementCascadeType};
use selectors::parser::{Selector, SelectorMethods}; use selectors::parser::{Selector, SelectorMethods, SelectorParseError};
use selectors::visitor::SelectorVisitor; use selectors::visitor::SelectorVisitor;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; 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::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT};
pub use gecko::snapshot::SnapshotMap; pub use gecko::snapshot::SnapshotMap;
@ -238,17 +239,20 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type NonTSPseudoClass = NonTSPseudoClass; type NonTSPseudoClass = NonTSPseudoClass;
} }
impl<'a> ::selectors::Parser for SelectorParser<'a> { impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
type Impl = SelectorImpl; type Impl = SelectorImpl;
type Error = StyleParseError<'i>;
fn parse_non_ts_pseudo_class(&self, name: Cow<str>) -> Result<NonTSPseudoClass, ()> { fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>)
-> Result<NonTSPseudoClass, ParseError<'i>> {
macro_rules! pseudo_class_parse { macro_rules! pseudo_class_parse {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (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),)*], 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),)*]) => { keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
$($css => NonTSPseudoClass::$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() { if !pseudo_class.is_internal() || self.in_user_agent_stylesheet() {
Ok(pseudo_class) Ok(pseudo_class)
} else { } else {
Err(()) Err(SelectorParseError::UnexpectedIdent(name).into())
} }
} }
fn parse_non_ts_functional_pseudo_class(&self, fn parse_non_ts_functional_pseudo_class<'t>(&self,
name: Cow<str>, name: Cow<'i, str>,
parser: &mut Parser) parser: &mut Parser<'i, 't>)
-> Result<NonTSPseudoClass, ()> { -> Result<NonTSPseudoClass, ParseError<'i>> {
macro_rules! pseudo_class_string_parse { macro_rules! pseudo_class_string_parse {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*], (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),)*], 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. // Selectors inside `:-moz-any` may not include combinators.
if selectors.iter().flat_map(|x| x.iter_raw()).any(|s| s.is_combinator()) { 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()) 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() { if !pseudo_class.is_internal() || self.in_user_agent_stylesheet() {
Ok(pseudo_class) Ok(pseudo_class)
} else { } else {
Err(()) Err(SelectorParseError::UnexpectedIdent(name).into())
} }
} }
fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> { fn parse_pseudo_element(&self, name: Cow<'i, str>) -> Result<PseudoElement, ParseError<'i>> {
PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) PseudoElement::from_slice(&name, self.in_user_agent_stylesheet())
.ok_or(()) .ok_or(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
fn default_namespace(&self) -> Option<Namespace> { fn default_namespace(&self) -> Option<Namespace> {

View file

@ -11,7 +11,7 @@ use gecko_bindings::sugar::refptr::RefPtr;
use parser::ParserContext; use parser::ParserContext;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::ToCss; use style_traits::{ToCss, ParseError};
use stylearc::Arc; use stylearc::Arc;
/// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls. /// 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. /// Returns `Err` in the case that extra_data is incomplete.
pub fn parse_from_string<'a>(url: Cow<'a, str>, pub fn parse_from_string<'a>(url: Cow<'a, str>,
context: &ParserContext) context: &ParserContext)
-> Result<Self, ()> { -> Result<Self, ParseError<'a>> {
Ok(SpecifiedUrl { Ok(SpecifiedUrl {
serialization: Arc::new(url.into_owned()), serialization: Arc::new(url.into_owned()),
extra_data: context.url_data.clone(), extra_data: context.url_data.clone(),

View file

@ -18,11 +18,14 @@ macro_rules! define_numbered_css_keyword_enum {
impl $crate::parser::Parse for $name { impl $crate::parser::Parse for $name {
#[allow(missing_docs)] #[allow(missing_docs)]
fn parse(_context: &$crate::parser::ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> { fn parse<'i, 't>(_context: &$crate::parser::ParserContext,
match_ignore_ascii_case! { &try!(input.expect_ident()), 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), )+ $( $css => Ok($name::$variant), )+
_ => Err(()) _ => Err(())
} }).map_err(|()| ::selectors::parser::SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
@ -49,9 +52,9 @@ macro_rules! add_impls_for_keyword_enum {
($name:ident) => { ($name:ident) => {
impl $crate::parser::Parse for $name { impl $crate::parser::Parse for $name {
#[inline] #[inline]
fn parse(_context: &$crate::parser::ParserContext, fn parse<'i, 't>(_context: &$crate::parser::ParserContext,
input: &mut ::cssparser::Parser) input: &mut ::cssparser::Parser<'i, 't>)
-> Result<Self, ()> { -> Result<Self, ::style_traits::ParseError<'i>> {
$name::parse(input) $name::parse(input)
} }
} }
@ -89,10 +92,10 @@ macro_rules! define_keyword_type {
} }
impl $crate::parser::Parse for $name { impl $crate::parser::Parse for $name {
fn parse(_context: &$crate::parser::ParserContext, fn parse<'i, 't>(_context: &$crate::parser::ParserContext,
input: &mut ::cssparser::Parser) input: &mut ::cssparser::Parser<'i, 't>)
-> Result<$name, ()> { -> Result<$name, ::style_traits::ParseError<'i>> {
input.expect_ident_matching($css).map(|_| $name) input.expect_ident_matching($css).map(|_| $name).map_err(|e| e.into())
} }
} }

View file

@ -8,12 +8,13 @@
use Atom; use Atom;
use context::QuirksMode; use context::QuirksMode;
use cssparser::{Delimiter, Parser, Token}; use cssparser::{Delimiter, Parser, Token, ParserInput};
use parser::ParserContext; use parser::ParserContext;
use selectors::parser::SelectorParseError;
use serialize_comma_separated_list; use serialize_comma_separated_list;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub use servo::media_queries::{Device, Expression}; pub use servo::media_queries::{Device, Expression};
@ -209,7 +210,8 @@ impl MediaQuery {
/// Parse a media query given css input. /// Parse a media query given css input.
/// ///
/// Returns an error if any of the expressions is unknown. /// Returns an error if any of the expressions is unknown.
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<MediaQuery, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<MediaQuery, ParseError<'i>> {
let mut expressions = vec![]; let mut expressions = vec![];
let qualifier = if input.try(|input| input.expect_ident_matching("only")).is_ok() { 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()) { let media_type = match input.try(|input| input.expect_ident()) {
Ok(ident) => try!(MediaQueryType::parse(&*ident)), Ok(ident) => {
Err(()) => { 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. // Media type is only optional if qualifier is not specified.
if qualifier.is_some() { if qualifier.is_some() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
// Without a media type, require at least one expression. // 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() { match input.next() {
Ok(Token::Comma) => {}, Ok(Token::Comma) => {},
Ok(_) => unreachable!(), Ok(_) => unreachable!(),
Err(()) => break, Err(_) => break,
} }
} }
@ -311,7 +317,8 @@ impl MediaList {
/// ///
/// Returns true if added, false if fail to parse the medium string. /// Returns true if added, false if fail to parse the medium string.
pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool { 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) { let new_query = match MediaQuery::parse(&context, &mut parser) {
Ok(query) => query, Ok(query) => query,
Err(_) => { return false; } Err(_) => { return false; }
@ -329,7 +336,8 @@ impl MediaList {
/// ///
/// Returns true if found and deleted, false otherwise. /// Returns true if found and deleted, false otherwise.
pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool { 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) { let old_query = match MediaQuery::parse(context, &mut parser) {
Ok(query) => query, Ok(query) => query,
Err(_) => { return false; } Err(_) => { return false; }

View file

@ -6,8 +6,8 @@
use context::QuirksMode; use context::QuirksMode;
use cssparser::{Parser, SourcePosition, UnicodeRange}; use cssparser::{Parser, SourcePosition, UnicodeRange};
use error_reporting::{ParseErrorReporter, ParseError}; use error_reporting::{ParseErrorReporter, ContextualParseError};
use style_traits::OneOrMoreCommaSeparated; use style_traits::{OneOrMoreCommaSeparated, ParseError};
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces}; use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};
bitflags! { bitflags! {
@ -166,7 +166,7 @@ impl<'a> ParserContext<'a> {
/// to log CSS parse errors to stderr. /// to log CSS parse errors to stderr.
pub fn log_css_error<'a>(input: &mut Parser, pub fn log_css_error<'a>(input: &mut Parser,
position: SourcePosition, position: SourcePosition,
error: ParseError<'a>, error: ContextualParseError<'a>,
parsercontext: &ParserContext) { parsercontext: &ParserContext) {
let url_data = parsercontext.url_data; let url_data = parsercontext.url_data;
let line_number_offset = parsercontext.line_number_offset; let line_number_offset = parsercontext.line_number_offset;
@ -183,19 +183,21 @@ pub trait Parse : Sized {
/// Parse a value of this type. /// Parse a value of this type.
/// ///
/// Returns an error on failure. /// Returns an error on failure.
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()>; fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>>;
} }
impl<T> Parse for Vec<T> where T: Parse + OneOrMoreCommaSeparated { impl<T> Parse for Vec<T> where T: Parse + OneOrMoreCommaSeparated {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
input.parse_comma_separated(|input| T::parse(context, input)) 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 /// Parse a non-empty space-separated or comma-separated list of objects parsed by parse_one
pub fn parse_space_or_comma_separated<F, T>(input: &mut Parser, mut parse_one: F) pub fn parse_space_or_comma_separated<'i, 't, F, T>(input: &mut Parser<'i, 't>, mut parse_one: F)
-> Result<Vec<T>, ()> -> Result<Vec<T>, ParseError<'i>>
where F: FnMut(&mut Parser) -> Result<T, ()> { where F: for<'ii, 'tt> FnMut(&mut Parser<'ii, 'tt>) -> Result<T, ParseError<'ii>> {
let first = parse_one(input)?; let first = parse_one(input)?;
let mut vec = vec![first]; let mut vec = vec![first];
loop { loop {
@ -209,7 +211,8 @@ pub fn parse_space_or_comma_separated<F, T>(input: &mut Parser, mut parse_one: F
Ok(vec) Ok(vec)
} }
impl Parse for UnicodeRange { impl Parse for UnicodeRange {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
UnicodeRange::parse(input) -> Result<Self, ParseError<'i>> {
UnicodeRange::parse(input).map_err(|e| e.into())
} }
} }

View file

@ -7,15 +7,16 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use context::QuirksMode; use context::QuirksMode;
use cssparser::{DeclarationListParser, parse_important}; use cssparser::{DeclarationListParser, parse_important, ParserInput};
use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter}; use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
use error_reporting::{ParseErrorReporter, ParseError}; use error_reporting::{ParseErrorReporter, ContextualParseError};
use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error}; use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error};
use properties::animated_properties::AnimationValue; use properties::animated_properties::AnimationValue;
use selectors::parser::SelectorParseError;
use shared_lock::Locked; use shared_lock::Locked;
use std::fmt; use std::fmt;
use std::slice::Iter; use std::slice::Iter;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use stylesheets::{CssRuleType, Origin, UrlExtraData}; use stylesheets::{CssRuleType, Origin, UrlExtraData};
use stylesheets::{MallocSizeOf, MallocSizeOfFn}; use stylesheets::{MallocSizeOf, MallocSizeOfFn};
use super::*; use super::*;
@ -875,7 +876,8 @@ pub fn parse_style_attribute(input: &str,
Some(CssRuleType::Style), Some(CssRuleType::Style),
PARSING_MODE_DEFAULT, PARSING_MODE_DEFAULT,
quirks_mode); 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 /// 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), Some(CssRuleType::Style),
parsing_mode, parsing_mode,
quirks_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) PropertyDeclaration::parse_into(declarations, id, &context, parser)
.map_err(|_| ()) .map_err(|e| e.into())
}) }).map_err(|_| ())
} }
/// A struct to parse property declarations. /// A struct to parse property declarations.
@ -910,23 +913,26 @@ struct PropertyDeclarationParser<'a, 'b: 'a> {
/// Default methods reject all at rules. /// 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 Prelude = ();
type AtRule = Importance; 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 Declaration = Importance;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Importance, ()> { fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>)
let id = try!(PropertyId::parse(name.into())); -> Result<Importance, ParseError<'i>> {
let id = try!(PropertyId::parse(name));
input.parse_until_before(Delimiter::Bang, |input| { input.parse_until_before(Delimiter::Bang, |input| {
PropertyDeclaration::parse_into(self.declarations, id, self.context, input) PropertyDeclaration::parse_into(self.declarations, id, self.context, input)
.map_err(|_| ()) .map_err(|e| e.into())
})?; })?;
let importance = match input.try(parse_important) { let importance = match input.try(parse_important) {
Ok(()) => Importance::Important, Ok(()) => Importance::Important,
Err(()) => Importance::Normal, Err(_) => Importance::Normal,
}; };
// In case there is still unparsed text in the declaration, we should roll back. // In case there is still unparsed text in the declaration, we should roll back.
input.expect_exhausted()?; input.expect_exhausted()?;
@ -952,10 +958,11 @@ pub fn parse_property_declaration_list(context: &ParserContext,
Ok(importance) => { Ok(importance) => {
block.extend(iter.parser.declarations.drain(), importance); block.extend(iter.parser.declarations.drain(), importance);
} }
Err(range) => { Err(err) => {
iter.parser.declarations.clear(); iter.parser.declarations.clear();
let pos = range.start; let pos = err.span.start;
let error = ParseError::UnsupportedPropertyDeclaration(iter.input.slice(range)); let error = ContextualParseError::UnsupportedPropertyDeclaration(
iter.input.slice(err.span), err.error);
log_css_error(iter.input, pos, error, &context); log_css_error(iter.input, pos, error, &context);
} }
} }

View file

@ -33,9 +33,9 @@
% endif % endif
#[allow(unused_variables)] #[allow(unused_variables)]
#[inline] #[inline]
pub fn parse(context: &ParserContext, pub fn parse<'i, 't>(context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
% if allow_quirks: % if allow_quirks:
specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes) specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes)
% elif needs_context: % elif needs_context:
@ -87,12 +87,16 @@
pub mod single_value { pub mod single_value {
#[allow(unused_imports)] #[allow(unused_imports)]
use cssparser::Parser; use cssparser::{Parser, BasicParseError};
#[allow(unused_imports)] #[allow(unused_imports)]
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
#[allow(unused_imports)] #[allow(unused_imports)]
use properties::ShorthandId; use properties::ShorthandId;
#[allow(unused_imports)] #[allow(unused_imports)]
use selectors::parser::SelectorParseError;
#[allow(unused_imports)]
use style_traits::{ParseError, StyleParseError};
#[allow(unused_imports)]
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
#[allow(unused_imports)] #[allow(unused_imports)]
use values::{computed, specified}; use values::{computed, specified};
@ -207,7 +211,8 @@
% endif % endif
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
#[allow(unused_imports)] #[allow(unused_imports)]
use parser::parse_space_or_comma_separated; use parser::parse_space_or_comma_separated;
@ -266,7 +271,7 @@
pub mod ${property.ident} { pub mod ${property.ident} {
% if not property.derived_from: % if not property.derived_from:
#[allow(unused_imports)] #[allow(unused_imports)]
use cssparser::Parser; use cssparser::{Parser, BasicParseError, Token};
#[allow(unused_imports)] #[allow(unused_imports)]
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
#[allow(unused_imports)] #[allow(unused_imports)]
@ -287,8 +292,12 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use properties::style_structs; use properties::style_structs;
#[allow(unused_imports)] #[allow(unused_imports)]
use selectors::parser::SelectorParseError;
#[allow(unused_imports)]
use stylearc::Arc; use stylearc::Arc;
#[allow(unused_imports)] #[allow(unused_imports)]
use style_traits::{ParseError, StyleParseError};
#[allow(unused_imports)]
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
#[allow(unused_imports)] #[allow(unused_imports)]
use values::{computed, generics, specified}; use values::{computed, generics, specified};
@ -423,12 +432,12 @@
% endif % endif
} }
% if not property.derived_from: % 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: % if property.boxed:
-> Result<Box<SpecifiedValue>, ()> { -> Result<Box<SpecifiedValue>, ParseError<'i>> {
parse(context, input).map(|result| Box::new(result)) parse(context, input).map(|result| Box::new(result))
% else: % else:
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
% if property.allow_quirks: % if property.allow_quirks:
parse_quirky(context, input, specified::AllowQuirks::Yes) parse_quirky(context, input, specified::AllowQuirks::Yes)
% else: % else:
@ -436,11 +445,11 @@
% endif % endif
% endif % endif
} }
pub fn parse_declared(context: &ParserContext, input: &mut Parser) pub fn parse_declared<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<PropertyDeclaration, ()> { -> Result<PropertyDeclaration, ParseError<'i>> {
match input.try(|i| CSSWideKeyword::parse(context, i)) { match input.try(|i| CSSWideKeyword::parse(context, i)) {
Ok(keyword) => Ok(PropertyDeclaration::CSSWideKeyword(LonghandId::${property.camel_case}, keyword)), Ok(keyword) => Ok(PropertyDeclaration::CSSWideKeyword(LonghandId::${property.camel_case}, keyword)),
Err(()) => { Err(_) => {
input.look_for_var_functions(); input.look_for_var_functions();
let start = input.position(); let start = input.position();
let specified = parse_specified(context, input); let specified = parse_specified(context, input);
@ -487,7 +496,7 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::ToCss; use style_traits::{ToCss, ParseError};
define_css_keyword_enum! { T: define_css_keyword_enum! { T:
% for value in keyword.values_for(product): % for value in keyword.values_for(product):
"${value}" => ${to_rust_ident(value)}, "${value}" => ${to_rust_ident(value)},
@ -495,7 +504,7 @@
} }
impl Parse for T { impl Parse for T {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
T::parse(input) T::parse(input)
} }
} }
@ -518,7 +527,7 @@
} }
} }
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<SpecifiedValue, ParseError<'i>> {
Ok(SpecifiedValue::Keyword(computed_value::T::parse(input)?)) Ok(SpecifiedValue::Keyword(computed_value::T::parse(input)?))
} }
@ -716,14 +725,14 @@
SpecifiedValue::${to_rust_ident(values.split()[0])} SpecifiedValue::${to_rust_ident(values.split()[0])}
} }
#[inline] #[inline]
pub fn parse(_context: &ParserContext, input: &mut Parser) pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(input) SpecifiedValue::parse(input)
} }
impl Parse for SpecifiedValue { impl Parse for SpecifiedValue {
#[inline] #[inline]
fn parse(_context: &ParserContext, input: &mut Parser) fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(input) SpecifiedValue::parse(input)
} }
} }
@ -764,9 +773,11 @@
use parser::ParserContext; use parser::ParserContext;
use properties::{PropertyDeclaration, SourcePropertyDeclaration, MaybeBoxed}; use properties::{PropertyDeclaration, SourcePropertyDeclaration, MaybeBoxed};
use properties::{ShorthandId, LonghandId, UnparsedValue, longhands}; use properties::{ShorthandId, LonghandId, UnparsedValue, longhands};
#[allow(unused_imports)]
use selectors::parser::SelectorParseError;
use std::fmt; use std::fmt;
use stylearc::Arc; use stylearc::Arc;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
pub struct Longhands { pub struct Longhands {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
@ -838,8 +849,8 @@
/// Parse the given shorthand and fill the result into the /// Parse the given shorthand and fill the result into the
/// `declarations` vector. /// `declarations` vector.
pub fn parse_into(declarations: &mut SourcePropertyDeclaration, pub fn parse_into<'i, 't>(declarations: &mut SourcePropertyDeclaration,
context: &ParserContext, input: &mut Parser) -> Result<(), ()> { context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> {
input.look_for_var_functions(); input.look_for_var_functions();
let start = input.position(); let start = input.position();
let value = input.parse_entirely(|input| parse_value(context, input)); let value = input.parse_entirely(|input| parse_value(context, input));
@ -872,7 +883,7 @@
% endfor % endfor
Ok(()) Ok(())
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -890,7 +901,8 @@
use values::generics::rect::Rect; use values::generics::rect::Rect;
use values::specified; use values::specified;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let rect = Rect::parse_with(context, input, |_c, i| { let rect = Rect::parse_with(context, input, |_c, i| {
% if allow_quirks: % if allow_quirks:
${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes) ${parser_function}_quirky(_c, i, specified::AllowQuirks::Yes)
@ -1114,7 +1126,8 @@
use values::computed::${length_type}; use values::computed::${length_type};
${length_type}::${initial_value} ${length_type}::${initial_value}
} }
fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
% if logical: % if logical:
let ret = ${length_type}::parse(context, input); let ret = ${length_type}::parse(context, input);
% else: % else:
@ -1123,7 +1136,7 @@
// Keyword values don't make sense in the block direction; don't parse them // Keyword values don't make sense in the block direction; don't parse them
% if "block" in name: % if "block" in name:
if let Ok(${length_type}::ExtremumLength(..)) = ret { if let Ok(${length_type}::ExtremumLength(..)) = ret {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
% endif % endif
ret.map(SpecifiedValue) ret.map(SpecifiedValue)

View file

@ -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::vertical_align::computed_value::T as VerticalAlign;
use properties::longhands::visibility::computed_value::T as Visibility; use properties::longhands::visibility::computed_value::T as Visibility;
#[cfg(feature = "gecko")] use properties::{PropertyDeclarationId, LonghandId}; #[cfg(feature = "gecko")] use properties::{PropertyDeclarationId, LonghandId};
use selectors::parser::SelectorParseError;
#[cfg(feature = "servo")] use servo_atoms::Atom; #[cfg(feature = "servo")] use servo_atoms::Atom;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::cmp; use std::cmp;
#[cfg(feature = "gecko")] use std::collections::HashMap; #[cfg(feature = "gecko")] use std::collections::HashMap;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError};
use super::ComputedValues; use super::ComputedValues;
use values::CSSFloat; use values::CSSFloat;
use values::{Auto, Either}; use values::{Auto, Either};
@ -99,9 +100,9 @@ impl TransitionProperty {
} }
/// Parse a transition-property value. /// Parse a transition-property value.
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let ident = try!(input.expect_ident()); let ident = try!(input.expect_ident());
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"all" => Ok(TransitionProperty::All), "all" => Ok(TransitionProperty::All),
% for prop in data.longhands: % for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
@ -118,7 +119,7 @@ impl TransitionProperty {
None => Ok(TransitionProperty::Unsupported((&*ident).into())) None => Ok(TransitionProperty::Unsupported((&*ident).into()))
} }
} }
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident.into()).into())
} }
/// Get a transition property from a property declaration. /// Get a transition property from a property declaration.

View file

@ -128,17 +128,20 @@ ${helpers.predefined_type("background-image", "ImageLayer",
} }
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"repeat-x" => Ok(SpecifiedValue::RepeatX), "repeat-x" => Ok(SpecifiedValue::RepeatX),
"repeat-y" => Ok(SpecifiedValue::RepeatY), "repeat-y" => Ok(SpecifiedValue::RepeatY),
_ => { _ => Err(()),
let horizontal = try!(RepeatKeyword::from_ident(&ident)); }).or_else(|()| {
let vertical = input.try(RepeatKeyword::parse).ok(); let horizontal: Result<_, ParseError> = RepeatKeyword::from_ident(&ident)
Ok(SpecifiedValue::Other(horizontal, vertical)) .map_err(|()| SelectorParseError::UnexpectedIdent(ident).into());
} let horizontal = try!(horizontal);
} let vertical = input.try(RepeatKeyword::parse).ok();
Ok(SpecifiedValue::Other(horizontal, vertical))
})
} }
</%helpers:vector_longhand> </%helpers:vector_longhand>

View file

@ -161,8 +161,8 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style',
} }
#[inline] #[inline]
pub fn parse(context: &ParserContext, input: &mut Parser) pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue::None) return Ok(SpecifiedValue::None)
} }
@ -175,7 +175,7 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style',
if !result.is_empty() { if !result.is_empty() {
Ok(SpecifiedValue::Colors(result)) Ok(SpecifiedValue::Colors(result))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -272,7 +272,8 @@ ${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
} }
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let first = try!(RepeatKeyword::parse(input)); let first = try!(RepeatKeyword::parse(input));
let second = input.try(RepeatKeyword::parse).ok(); let second = input.try(RepeatKeyword::parse).ok();

View file

@ -113,16 +113,17 @@
} }
/// Parse a display value. /// Parse a display value.
pub fn parse(_context: &ParserContext, input: &mut Parser) pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
match_ignore_ascii_case! { &try!(input.expect_ident()), let ident = try!(input.expect_ident());
(match_ignore_ascii_case! { &ident,
% for value in values: % for value in values:
"${value}" => { "${value}" => {
Ok(computed_value::T::${to_rust_ident(value)}) Ok(computed_value::T::${to_rust_ident(value)})
}, },
% endfor % endfor
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
impl ComputedValueAsSpecified for SpecifiedValue {} 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 /// baseline | sub | super | top | text-top | middle | bottom | text-bottom
/// | <percentage> | <length> /// | <percentage> | <length>
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
input.try(|i| specified::LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes)) input.try(|i| specified::LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes))
.map(SpecifiedValue::LengthOrPercentage) .map(SpecifiedValue::LengthOrPercentage)
.or_else(|_| { .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: % for keyword in vertical_align_keywords:
"${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}), "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
% endfor % endfor
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
}) })
} }
@ -500,17 +503,19 @@ ${helpers.predefined_type("transition-delay",
} }
impl Parse for SpecifiedValue { impl Parse for SpecifiedValue {
fn parse(context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut ::cssparser::Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if let Ok(name) = input.try(|input| KeyframesName::parse(context, input)) { if let Ok(name) = input.try(|input| KeyframesName::parse(context, input)) {
Ok(SpecifiedValue(Some(name))) Ok(SpecifiedValue(Some(name)))
} else { } 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); no_viewport_percentage!(SpecifiedValue);
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
SpecifiedValue::parse(context, input) SpecifiedValue::parse(context, input)
} }
@ -560,14 +565,15 @@ ${helpers.predefined_type("animation-timing-function",
} }
impl Parse for SpecifiedValue { impl Parse for SpecifiedValue {
fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut ::cssparser::Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("infinite")).is_ok() { if input.try(|input| input.expect_ident_matching("infinite")).is_ok() {
return Ok(SpecifiedValue::Infinite) return Ok(SpecifiedValue::Infinite)
} }
let number = try!(input.expect_number()); let number = try!(input.expect_number());
if number < 0.0 { if number < 0.0 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(SpecifiedValue::Number(number)) Ok(SpecifiedValue::Number(number))
@ -587,7 +593,8 @@ ${helpers.predefined_type("animation-timing-function",
} }
#[inline] #[inline]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(context, input) 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 // Allow unitless zero angle for rotate() and skew() to align with gecko
fn parse_internal(context: &ParserContext, input: &mut Parser, prefixed: bool) fn parse_internal<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>, prefixed: bool)
-> Result<SpecifiedValue,()> { -> Result<SpecifiedValue,ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new())) return Ok(SpecifiedValue(Vec::new()))
} }
@ -960,7 +967,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
Ok(name) => name, Ok(name) => name,
Err(_) => break, Err(_) => break,
}; };
match_ignore_ascii_case! { let valid_fn = match_ignore_ascii_case! {
&name, &name,
"matrix" => { "matrix" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
@ -970,7 +977,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
specified::parse_number(context, input) specified::parse_number(context, input)
})); }));
if values.len() != 6 { if values.len() != 6 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
result.push(SpecifiedOperation::Matrix { result.push(SpecifiedOperation::Matrix {
@ -981,7 +988,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
e: values[4], e: values[4],
f: values[5], f: values[5],
}); });
return Ok(()); return Ok(true);
} }
// Non-standard prefixed matrix parsing. // Non-standard prefixed matrix parsing.
@ -1014,7 +1021,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
e: lengths[0].clone(), e: lengths[0].clone(),
f: lengths[1].clone(), f: lengths[1].clone(),
}); });
Ok(()) Ok(true)
})) }))
}, },
"matrix3d" => { "matrix3d" => {
@ -1023,7 +1030,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
if !prefixed { if !prefixed {
let values = try!(input.parse_comma_separated(|i| specified::parse_number(context, i))); let values = try!(input.parse_comma_separated(|i| specified::parse_number(context, i)));
if values.len() != 16 { if values.len() != 16 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
result.push(SpecifiedOperation::Matrix3D { 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], m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11],
m41: values[12], m42: values[13], m43: values[14], m44: values[15] m41: values[12], m42: values[13], m43: values[14], m44: values[15]
}); });
return Ok(()); return Ok(true);
} }
// Non-standard prefixed matrix3d parsing. // 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(), m41: lops[0].clone(), m42: lops[1].clone(), m43: length_or_number.unwrap(),
m44: values[12] m44: values[12]
}); });
Ok(()) Ok(true)
})) }))
}, },
"translate" => { "translate" => {
@ -1081,28 +1088,28 @@ ${helpers.predefined_type("scroll-snap-coordinate",
} else { } else {
result.push(SpecifiedOperation::Translate(sx, None)); result.push(SpecifiedOperation::Translate(sx, None));
} }
Ok(()) Ok(true)
})) }))
}, },
"translatex" => { "translatex" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let tx = try!(specified::LengthOrPercentage::parse(context, input)); let tx = try!(specified::LengthOrPercentage::parse(context, input));
result.push(SpecifiedOperation::TranslateX(tx)); result.push(SpecifiedOperation::TranslateX(tx));
Ok(()) Ok(true)
})) }))
}, },
"translatey" => { "translatey" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let ty = try!(specified::LengthOrPercentage::parse(context, input)); let ty = try!(specified::LengthOrPercentage::parse(context, input));
result.push(SpecifiedOperation::TranslateY(ty)); result.push(SpecifiedOperation::TranslateY(ty));
Ok(()) Ok(true)
})) }))
}, },
"translatez" => { "translatez" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let tz = try!(specified::Length::parse(context, input)); let tz = try!(specified::Length::parse(context, input));
result.push(SpecifiedOperation::TranslateZ(tz)); result.push(SpecifiedOperation::TranslateZ(tz));
Ok(()) Ok(true)
})) }))
}, },
"translate3d" => { "translate3d" => {
@ -1113,7 +1120,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
try!(input.expect_comma()); try!(input.expect_comma());
let tz = try!(specified::Length::parse(context, input)); let tz = try!(specified::Length::parse(context, input));
result.push(SpecifiedOperation::Translate3D(tx, ty, tz)); result.push(SpecifiedOperation::Translate3D(tx, ty, tz));
Ok(()) Ok(true)
})) }))
}, },
"scale" => { "scale" => {
@ -1125,28 +1132,28 @@ ${helpers.predefined_type("scroll-snap-coordinate",
} else { } else {
result.push(SpecifiedOperation::Scale(sx, None)); result.push(SpecifiedOperation::Scale(sx, None));
} }
Ok(()) Ok(true)
})) }))
}, },
"scalex" => { "scalex" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let sx = try!(specified::parse_number(context, input)); let sx = try!(specified::parse_number(context, input));
result.push(SpecifiedOperation::ScaleX(sx)); result.push(SpecifiedOperation::ScaleX(sx));
Ok(()) Ok(true)
})) }))
}, },
"scaley" => { "scaley" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let sy = try!(specified::parse_number(context, input)); let sy = try!(specified::parse_number(context, input));
result.push(SpecifiedOperation::ScaleY(sy)); result.push(SpecifiedOperation::ScaleY(sy));
Ok(()) Ok(true)
})) }))
}, },
"scalez" => { "scalez" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let sz = try!(specified::parse_number(context, input)); let sz = try!(specified::parse_number(context, input));
result.push(SpecifiedOperation::ScaleZ(sz)); result.push(SpecifiedOperation::ScaleZ(sz));
Ok(()) Ok(true)
})) }))
}, },
"scale3d" => { "scale3d" => {
@ -1157,35 +1164,35 @@ ${helpers.predefined_type("scroll-snap-coordinate",
try!(input.expect_comma()); try!(input.expect_comma());
let sz = try!(specified::parse_number(context, input)); let sz = try!(specified::parse_number(context, input));
result.push(SpecifiedOperation::Scale3D(sx, sy, sz)); result.push(SpecifiedOperation::Scale3D(sx, sy, sz));
Ok(()) Ok(true)
})) }))
}, },
"rotate" => { "rotate" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let theta = try!(specified::Angle::parse_with_unitless(context, input)); let theta = try!(specified::Angle::parse_with_unitless(context, input));
result.push(SpecifiedOperation::Rotate(theta)); result.push(SpecifiedOperation::Rotate(theta));
Ok(()) Ok(true)
})) }))
}, },
"rotatex" => { "rotatex" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let theta = try!(specified::Angle::parse_with_unitless(context, input)); let theta = try!(specified::Angle::parse_with_unitless(context, input));
result.push(SpecifiedOperation::RotateX(theta)); result.push(SpecifiedOperation::RotateX(theta));
Ok(()) Ok(true)
})) }))
}, },
"rotatey" => { "rotatey" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let theta = try!(specified::Angle::parse_with_unitless(context, input)); let theta = try!(specified::Angle::parse_with_unitless(context, input));
result.push(SpecifiedOperation::RotateY(theta)); result.push(SpecifiedOperation::RotateY(theta));
Ok(()) Ok(true)
})) }))
}, },
"rotatez" => { "rotatez" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let theta = try!(specified::Angle::parse_with_unitless(context, input)); let theta = try!(specified::Angle::parse_with_unitless(context, input));
result.push(SpecifiedOperation::RotateZ(theta)); result.push(SpecifiedOperation::RotateZ(theta));
Ok(()) Ok(true)
})) }))
}, },
"rotate3d" => { "rotate3d" => {
@ -1199,7 +1206,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
let theta = try!(specified::Angle::parse_with_unitless(context, input)); let theta = try!(specified::Angle::parse_with_unitless(context, input));
// TODO(gw): Check the axis can be normalized!! // TODO(gw): Check the axis can be normalized!!
result.push(SpecifiedOperation::Rotate3D(ax, ay, az, theta)); result.push(SpecifiedOperation::Rotate3D(ax, ay, az, theta));
Ok(()) Ok(true)
})) }))
}, },
"skew" => { "skew" => {
@ -1211,51 +1218,56 @@ ${helpers.predefined_type("scroll-snap-coordinate",
} else { } else {
result.push(SpecifiedOperation::Skew(theta_x, None)); result.push(SpecifiedOperation::Skew(theta_x, None));
} }
Ok(()) Ok(true)
})) }))
}, },
"skewx" => { "skewx" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let theta_x = try!(specified::Angle::parse_with_unitless(context, input)); let theta_x = try!(specified::Angle::parse_with_unitless(context, input));
result.push(SpecifiedOperation::SkewX(theta_x)); result.push(SpecifiedOperation::SkewX(theta_x));
Ok(()) Ok(true)
})) }))
}, },
"skewy" => { "skewy" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let theta_y = try!(specified::Angle::parse_with_unitless(context, input)); let theta_y = try!(specified::Angle::parse_with_unitless(context, input));
result.push(SpecifiedOperation::SkewY(theta_y)); result.push(SpecifiedOperation::SkewY(theta_y));
Ok(()) Ok(true)
})) }))
}, },
"perspective" => { "perspective" => {
try!(input.parse_nested_block(|input| { try!(input.parse_nested_block(|input| {
let d = try!(specified::Length::parse_non_negative(context, input)); let d = try!(specified::Length::parse_non_negative(context, input));
result.push(SpecifiedOperation::Perspective(d)); result.push(SpecifiedOperation::Perspective(d));
Ok(()) Ok(true)
})) }))
}, },
_ => return Err(()) _ => false
};
if !valid_fn {
return Err(StyleParseError::UnexpectedFunction(name).into());
} }
} }
if !result.is_empty() { if !result.is_empty() {
Ok(SpecifiedValue(result)) Ok(SpecifiedValue(result))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
/// Parses `transform` property. /// Parses `transform` property.
#[inline] #[inline]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
parse_internal(context, input, false) parse_internal(context, input, false)
} }
/// Parses `-moz-transform` property. This prefixed property also accepts LengthOrPercentage /// Parses `-moz-transform` property. This prefixed property also accepts LengthOrPercentage
/// in the nondiagonal homogeneous components of matrix and matrix3d. /// in the nondiagonal homogeneous components of matrix and matrix3d.
#[inline] #[inline]
pub fn parse_prefixed(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse_prefixed<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
parse_internal(context, input, true) parse_internal(context, input, true)
} }
@ -1771,7 +1783,8 @@ ${helpers.predefined_type("transform-origin",
} }
/// none | strict | content | [ size || layout || style || paint ] /// none | strict | content | [ size || layout || style || paint ]
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = SpecifiedValue::empty(); let mut result = SpecifiedValue::empty();
if input.try(|input| input.expect_ident_matching("none")).is_ok() { 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()) { while let Ok(name) = input.try(|input| input.expect_ident()) {
let flag = match_ignore_ascii_case! { &name, let flag = match_ignore_ascii_case! { &name,
"layout" => LAYOUT, "layout" => Some(LAYOUT),
"style" => STYLE, "style" => Some(STYLE),
"paint" => PAINT, "paint" => Some(PAINT),
_ => return Err(()) _ => 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); result.insert(flag);
} }
if !result.is_empty() { if !result.is_empty() {
Ok(result) Ok(result)
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -1900,18 +1914,23 @@ ${helpers.single_keyword("-moz-orient",
} }
/// auto | <animateable-feature># /// auto | <animateable-feature>#
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() { if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
Ok(computed_value::T::Auto) Ok(computed_value::T::Auto)
} else { } else {
input.parse_comma_separated(|i| { input.parse_comma_separated(|i| {
let ident = i.expect_ident()?; let ident = i.expect_ident()?;
match_ignore_ascii_case! { &ident, let bad_keyword = match_ignore_ascii_case! { &ident,
"will-change" | "none" | "all" | "auto" | "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) }).map(SpecifiedValue::AnimateableFeatures)
} }
} }
@ -1976,9 +1995,10 @@ ${helpers.predefined_type("shape-outside", "basic_shape::FloatAreaShape",
TOUCH_ACTION_AUTO TOUCH_ACTION_AUTO
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"auto" => Ok(TOUCH_ACTION_AUTO), "auto" => Ok(TOUCH_ACTION_AUTO),
"none" => Ok(TOUCH_ACTION_NONE), "none" => Ok(TOUCH_ACTION_NONE),
"manipulation" => Ok(TOUCH_ACTION_MANIPULATION), "manipulation" => Ok(TOUCH_ACTION_MANIPULATION),
@ -1997,6 +2017,6 @@ ${helpers.predefined_type("shape-outside", "basic_shape::FloatAreaShape",
} }
}, },
_ => Err(()), _ => Err(()),
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
</%helpers:longhand> </%helpers:longhand>

View file

@ -43,7 +43,8 @@
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
RGBA::new(0, 0, 0, 255) // black RGBA::new(0, 0, 0, 255) // black
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
Color::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue) Color::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue)
} }
@ -118,7 +119,7 @@
} }
impl SystemColor { impl SystemColor {
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
static PARSE_ARRAY: &'static [(&'static str, SystemColor); ${len(system_colors)}] = &[ static PARSE_ARRAY: &'static [(&'static str, SystemColor); ${len(system_colors)}] = &[
@ -133,7 +134,7 @@
return Ok(color) return Ok(color)
} }
} }
Err(()) Err(SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
% endif % endif

View file

@ -8,7 +8,6 @@
<%helpers:longhand name="content" boxed="True" animation_value_type="none" <%helpers:longhand name="content" boxed="True" animation_value_type="none"
spec="https://drafts.csswg.org/css-content/#propdef-content"> spec="https://drafts.csswg.org/css-content/#propdef-content">
use cssparser::Token;
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone; use values::generics::CounterStyleOrNone;
@ -157,8 +156,8 @@
// normal | none | [ <string> | <counter> | open-quote | close-quote | no-open-quote | // normal | none | [ <string> | <counter> | open-quote | close-quote | no-open-quote |
// no-close-quote ]+ // no-close-quote ]+
// TODO: <uri>, attr(<identifier>) // TODO: <uri>, attr(<identifier>)
pub fn parse(context: &ParserContext, input: &mut Parser) pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("normal")).is_ok() { if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
return Ok(SpecifiedValue::Normal) return Ok(SpecifiedValue::Normal)
} }
@ -185,43 +184,50 @@
content.push(ContentItem::String(value.into_owned())) content.push(ContentItem::String(value.into_owned()))
} }
Ok(Token::Function(name)) => { Ok(Token::Function(name)) => {
content.push(try!(match_ignore_ascii_case! { &name, let result = match_ignore_ascii_case! { &name,
"counter" => input.parse_nested_block(|input| { "counter" => Some(input.parse_nested_block(|input| {
let name = try!(input.expect_ident()).into_owned(); let name = try!(input.expect_ident()).into_owned();
let style = parse_counter_style(context, input); let style = parse_counter_style(context, input);
Ok(ContentItem::Counter(name, style)) 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(); let name = try!(input.expect_ident()).into_owned();
try!(input.expect_comma()); try!(input.expect_comma());
let separator = try!(input.expect_string()).into_owned(); let separator = try!(input.expect_string()).into_owned();
let style = parse_counter_style(context, input); let style = parse_counter_style(context, input);
Ok(ContentItem::Counters(name, separator, style)) Ok(ContentItem::Counters(name, separator, style))
}), })),
% if product == "gecko": % if product == "gecko":
"attr" => input.parse_nested_block(|input| { "attr" => Some(input.parse_nested_block(|input| {
Ok(ContentItem::Attr(Attr::parse_function(context, input)?)) Ok(ContentItem::Attr(Attr::parse_function(context, input)?))
}), })),
% endif % endif
_ => return Err(()) _ => None
})); };
match result {
Some(result) => content.push(try!(result)),
None => return Err(StyleParseError::UnexpectedFunction(name).into())
}
} }
Ok(Token::Ident(ident)) => { Ok(Token::Ident(ident)) => {
match_ignore_ascii_case! { &ident, let valid = match_ignore_ascii_case! { &ident,
"open-quote" => content.push(ContentItem::OpenQuote), "open-quote" => { content.push(ContentItem::OpenQuote); true },
"close-quote" => content.push(ContentItem::CloseQuote), "close-quote" => { content.push(ContentItem::CloseQuote); true },
"no-open-quote" => content.push(ContentItem::NoOpenQuote), "no-open-quote" => { content.push(ContentItem::NoOpenQuote); true },
"no-close-quote" => content.push(ContentItem::NoCloseQuote), "no-close-quote" => { content.push(ContentItem::NoCloseQuote); true },
_ => return Err(()) _ => false,
};
if !valid {
return Err(SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
Err(_) => break, Err(_) => break,
_ => return Err(()) Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into())
} }
} }
if content.is_empty() { if content.is_empty() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(SpecifiedValue::Items(content)) Ok(SpecifiedValue::Items(content))
} }
@ -233,8 +239,6 @@
use style_traits::ToCss; use style_traits::ToCss;
use values::CustomIdent; use values::CustomIdent;
use cssparser::Token;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct SpecifiedValue(pub Vec<(CustomIdent, specified::Integer)>); pub struct SpecifiedValue(pub Vec<(CustomIdent, specified::Integer)>);
@ -315,11 +319,13 @@
} }
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
parse_common(context, 1, input) parse_common(context, 1, input)
} }
pub fn parse_common(context: &ParserContext, default_value: i32, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse_common<'i, 't>(context: &ParserContext, default_value: i32, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new())) return Ok(SpecifiedValue(Vec::new()))
} }
@ -328,7 +334,7 @@
loop { loop {
let counter_name = match input.next() { let counter_name = match input.next() {
Ok(Token::Ident(ident)) => CustomIdent::from_ident(ident, &["none"])?, Ok(Token::Ident(ident)) => CustomIdent::from_ident(ident, &["none"])?,
Ok(_) => return Err(()), Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()),
Err(_) => break, Err(_) => break,
}; };
let counter_delta = input.try(|input| specified::parse_integer(context, input)) let counter_delta = input.try(|input| specified::parse_integer(context, input))
@ -339,7 +345,7 @@
if !counters.is_empty() { if !counters.is_empty() {
Ok(SpecifiedValue(counters)) Ok(SpecifiedValue(counters))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -349,7 +355,8 @@
pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value}; pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value};
use super::counter_increment::parse_common; use super::counter_increment::parse_common;
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
parse_common(context, 0, input) parse_common(context, 0, input)
} }
</%helpers:longhand> </%helpers:longhand>

View file

@ -27,7 +27,8 @@ ${helpers.predefined_type("opacity",
pub type T = Shadow; pub type T = Shadow;
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<specified::Shadow, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<specified::Shadow, ParseError<'i>> {
specified::Shadow::parse(context, input, false) specified::Shadow::parse(context, input, false)
} }
</%helpers:vector_longhand> </%helpers:vector_longhand>
@ -263,7 +264,8 @@ ${helpers.predefined_type("clip",
computed_value::T::new(Vec::new()) computed_value::T::new(Vec::new())
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut filters = Vec::new(); let mut filters = Vec::new();
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(filters)) return Ok(SpecifiedValue(filters))
@ -290,23 +292,24 @@ ${helpers.predefined_type("clip",
"drop-shadow" => specified::Shadow::parse(context, input, true) "drop-shadow" => specified::Shadow::parse(context, input, true)
.map(SpecifiedFilter::DropShadow), .map(SpecifiedFilter::DropShadow),
% endif % endif
_ => Err(()) _ => Err(StyleParseError::UnexpectedFunction(function_name.clone()).into())
} }
}))); })));
} else if filters.is_empty() { } else if filters.is_empty() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} else { } else {
return Ok(SpecifiedValue(filters)) 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; use cssparser::Token;
match input.next() { match input.next() {
Ok(Token::Number(value)) if value.value.is_sign_positive() => Ok(value.value), 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), 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())
} }
} }

View file

@ -75,7 +75,7 @@
use cssparser::{CssStringWriter, Parser, serialize_identifier}; use cssparser::{CssStringWriter, Parser, serialize_identifier};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use Atom; use Atom;
use style_traits::ToCss; use style_traits::{ToCss, ParseError};
pub use self::FontFamily as SingleComputedValue; pub use self::FontFamily as SingleComputedValue;
#[derive(Debug, PartialEq, Eq, Clone, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Hash)]
@ -137,7 +137,7 @@
} }
/// Parse a font-family value /// Parse a font-family value
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(value) = input.try(|input| input.expect_string()) { if let Ok(value) = input.try(|input| input.expect_string()) {
return Ok(FontFamily::FamilyName(FamilyName { return Ok(FontFamily::FamilyName(FamilyName {
name: Atom::from(&*value), name: Atom::from(&*value),
@ -277,7 +277,8 @@
/// <family-name># /// <family-name>#
/// <family-name> = <string> | [ <ident>+ ] /// <family-name> = <string> | [ <ident>+ ]
/// TODO: <generic-family> /// TODO: <generic-family>
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(input) SpecifiedValue::parse(input)
} }
@ -331,7 +332,7 @@
} }
} }
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue::Values) input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue::Values)
} }
} }
@ -357,11 +358,11 @@
/// `FamilyName::parse` is based on `FontFamily::parse` and not the other way around /// `FamilyName::parse` is based on `FontFamily::parse` and not the other way around
/// because we want the former to exclude generic family keywords. /// because we want the former to exclude generic family keywords.
impl Parse for FamilyName { impl Parse for FamilyName {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match FontFamily::parse(input) { match FontFamily::parse(input) {
Ok(FontFamily::FamilyName(name)) => Ok(name), Ok(FontFamily::FamilyName(name)) => Ok(name),
Ok(FontFamily::Generic(_)) | Ok(FontFamily::Generic(_)) => Err(StyleParseError::UnspecifiedError.into()),
Err(()) => Err(()) Err(e) => Err(e)
} }
} }
} }
@ -427,17 +428,21 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
/// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
input.try(|input| { -> Result<SpecifiedValue, ParseError<'i>> {
match_ignore_ascii_case! { &try!(input.expect_ident()), let result: Result<_, ParseError> = input.try(|input| {
let ident = try!(input.expect_ident());
(match_ignore_ascii_case! { &ident,
"normal" => Ok(SpecifiedValue::Normal), "normal" => Ok(SpecifiedValue::Normal),
"bold" => Ok(SpecifiedValue::Bold), "bold" => Ok(SpecifiedValue::Bold),
"bolder" => Ok(SpecifiedValue::Bolder), "bolder" => Ok(SpecifiedValue::Bolder),
"lighter" => Ok(SpecifiedValue::Lighter), "lighter" => Ok(SpecifiedValue::Lighter),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
}).or_else(|()| { });
result.or_else(|_| {
SpecifiedValue::from_int(input.expect_integer()?) SpecifiedValue::from_int(input.expect_integer()?)
.map_err(|()| StyleParseError::UnspecifiedError.into())
}) })
} }
@ -472,7 +477,7 @@ ${helpers.single_keyword_system("font-variant-caps",
/// Used in @font-face, where relative keywords are not allowed. /// Used in @font-face, where relative keywords are not allowed.
impl Parse for computed_value::T { impl Parse for computed_value::T {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match parse(context, input)? { match parse(context, input)? {
% for weight in range(100, 901, 100): % for weight in range(100, 901, 100):
SpecifiedValue::Weight${weight} => Ok(computed_value::T::Weight${weight}), SpecifiedValue::Weight${weight} => Ok(computed_value::T::Weight${weight}),
@ -480,7 +485,7 @@ ${helpers.single_keyword_system("font-variant-caps",
SpecifiedValue::Normal => Ok(computed_value::T::Weight400), SpecifiedValue::Normal => Ok(computed_value::T::Weight400),
SpecifiedValue::Bold => Ok(computed_value::T::Weight700), SpecifiedValue::Bold => Ok(computed_value::T::Weight700),
SpecifiedValue::Bolder | SpecifiedValue::Bolder |
SpecifiedValue::Lighter => Err(()), SpecifiedValue::Lighter => Err(StyleParseError::UnspecifiedError.into()),
SpecifiedValue::System(..) => unreachable!(), SpecifiedValue::System(..) => unreachable!(),
} }
} }
@ -666,17 +671,18 @@ ${helpers.single_keyword_system("font-variant-caps",
pub use self::KeywordSize::*; pub use self::KeywordSize::*;
impl KeywordSize { impl KeywordSize {
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Ok(match_ignore_ascii_case! {&*input.expect_ident()?, let ident = input.expect_ident()?;
"xx-small" => XXSmall, (match_ignore_ascii_case! {&*ident,
"x-small" => XSmall, "xx-small" => Ok(XXSmall),
"small" => Small, "x-small" => Ok(XSmall),
"medium" => Medium, "small" => Ok(Small),
"large" => Large, "medium" => Ok(Medium),
"x-large" => XLarge, "large" => Ok(Large),
"xx-large" => XXLarge, "x-large" => Ok(XLarge),
_ => return Err(()) "xx-large" => Ok(XXLarge),
}) _ => Err(())
}).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
@ -889,15 +895,16 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
/// <length> | <percentage> | <absolute-size> | <relative-size> /// <length> | <percentage> | <absolute-size> | <relative-size>
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
parse_quirky(context, input, AllowQuirks::No) parse_quirky(context, input, AllowQuirks::No)
} }
/// Parses a font-size, with quirks. /// Parses a font-size, with quirks.
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ParseError<'i>> {
use self::specified::LengthOrPercentage; use self::specified::LengthOrPercentage;
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) { if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) {
return Ok(SpecifiedValue::Length(lop)) return Ok(SpecifiedValue::Length(lop))
@ -907,11 +914,12 @@ ${helpers.single_keyword_system("font-variant-caps",
return Ok(SpecifiedValue::Keyword(kw, 1.)) 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), "smaller" => Ok(SpecifiedValue::Smaller),
"larger" => Ok(SpecifiedValue::Larger), "larger" => Ok(SpecifiedValue::Larger),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
impl SpecifiedValue { impl SpecifiedValue {
@ -1133,7 +1141,8 @@ ${helpers.single_keyword_system("font-variant-caps",
} }
/// none | <number> /// none | <number>
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
use values::specified::Number; use values::specified::Number;
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
@ -1183,9 +1192,11 @@ ${helpers.single_keyword_system("font-variant-caps",
SpecifiedValue { weight: true, style: true } SpecifiedValue { weight: true, style: true }
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = SpecifiedValue { weight: false, style: false }; 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), "none" => Ok(result),
"weight" => { "weight" => {
result.weight = true; result.weight = true;
@ -1202,7 +1213,7 @@ ${helpers.single_keyword_system("font-variant-caps",
Ok(result) Ok(result)
}, },
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
</%helpers:longhand> </%helpers:longhand>
@ -1319,7 +1330,8 @@ ${helpers.single_keyword_system("font-kerning",
/// swash(<feature-value-name>) || /// swash(<feature-value-name>) ||
/// ornaments(<feature-value-name>) || /// ornaments(<feature-value-name>) ||
/// annotation(<feature-value-name>) ] /// annotation(<feature-value-name>) ]
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = VariantAlternates::empty(); let mut result = VariantAlternates::empty();
if input.try(|input| input.expect_ident_matching("normal")).is_ok() { if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
@ -1328,25 +1340,26 @@ ${helpers.single_keyword_system("font-kerning",
while let Ok(ident) = input.try(|input| input.expect_ident()) { while let Ok(ident) = input.try(|input| input.expect_ident()) {
let flag = match_ignore_ascii_case! { &ident, let flag = match_ignore_ascii_case! { &ident,
"stylistic" => STYLISTIC, "stylistic" => Some(STYLISTIC),
"historical-forms" => HISTORICAL_FORMS, "historical-forms" => Some(HISTORICAL_FORMS),
"styleset" => STYLESET, "styleset" => Some(STYLESET),
"character-variant" => CHARACTER_VARIANT, "character-variant" => Some(CHARACTER_VARIANT),
"swash" => SWASH, "swash" => Some(SWASH),
"ornaments" => ORNAMENTS, "ornaments" => Some(ORNAMENTS),
"annotation" => ANNOTATION, "annotation" => Some(ANNOTATION),
_ => return Err(()), _ => 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); result.insert(flag);
} }
if !result.is_empty() { if !result.is_empty() {
Ok(SpecifiedValue::Value(result)) Ok(SpecifiedValue::Value(result))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -1355,9 +1368,9 @@ ${helpers.single_keyword_system("font-kerning",
macro_rules! exclusive_value { macro_rules! exclusive_value {
(($value:ident, $set:expr) => $ident:ident) => { (($value:ident, $set:expr) => $ident:ident) => {
if $value.intersects($set) { if $value.intersects($set) {
return Err(()) None
} else { } else {
$ident Some($ident)
} }
} }
} }
@ -1462,7 +1475,8 @@ macro_rules! exclusive_value {
/// <east-asian-width-values> = [ full-width | proportional-width ] /// <east-asian-width-values> = [ full-width | proportional-width ]
<% east_asian_variant_values = "JIS78 | JIS83 | JIS90 | JIS04 | SIMPLIFIED | TRADITIONAL" %> <% east_asian_variant_values = "JIS78 | JIS83 | JIS90 | JIS04 | SIMPLIFIED | TRADITIONAL" %>
<% east_asian_width_values = "FULL_WIDTH | PROPORTIONAL_WIDTH" %> <% east_asian_width_values = "FULL_WIDTH | PROPORTIONAL_WIDTH" %>
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = VariantEastAsian::empty(); let mut result = VariantEastAsian::empty();
if input.try(|input| input.expect_ident_matching("normal")).is_ok() { if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
@ -1489,7 +1503,11 @@ macro_rules! exclusive_value {
exclusive_value!((result, ${east_asian_width_values}) => PROPORTIONAL_WIDTH), exclusive_value!((result, ${east_asian_width_values}) => PROPORTIONAL_WIDTH),
"ruby" => "ruby" =>
exclusive_value!((result, RUBY) => 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); result.insert(flag);
} }
@ -1497,7 +1515,7 @@ macro_rules! exclusive_value {
if !result.is_empty() { if !result.is_empty() {
Ok(SpecifiedValue::Value(result)) Ok(SpecifiedValue::Value(result))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -1611,7 +1629,8 @@ macro_rules! exclusive_value {
<% discretionary_lig_values = "DISCRETIONARY_LIGATURES | NO_DISCRETIONARY_LIGATURES" %> <% discretionary_lig_values = "DISCRETIONARY_LIGATURES | NO_DISCRETIONARY_LIGATURES" %>
<% historical_lig_values = "HISTORICAL_LIGATURES | NO_HISTORICAL_LIGATURES" %> <% historical_lig_values = "HISTORICAL_LIGATURES | NO_HISTORICAL_LIGATURES" %>
<% contextual_alt_values = "CONTEXTUAL | NO_CONTEXTUAL" %> <% contextual_alt_values = "CONTEXTUAL | NO_CONTEXTUAL" %>
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = VariantLigatures::empty(); let mut result = VariantLigatures::empty();
if input.try(|input| input.expect_ident_matching("normal")).is_ok() { if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
@ -1639,7 +1658,11 @@ macro_rules! exclusive_value {
exclusive_value!((result, ${contextual_alt_values}) => CONTEXTUAL), exclusive_value!((result, ${contextual_alt_values}) => CONTEXTUAL),
"no-contextual" => "no-contextual" =>
exclusive_value!((result, ${contextual_alt_values}) => 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); result.insert(flag);
} }
@ -1647,7 +1670,7 @@ macro_rules! exclusive_value {
if !result.is_empty() { if !result.is_empty() {
Ok(SpecifiedValue::Value(result)) Ok(SpecifiedValue::Value(result))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -1757,7 +1780,8 @@ macro_rules! exclusive_value {
<% numeric_figure_values = "LINING_NUMS | OLDSTYLE_NUMS" %> <% numeric_figure_values = "LINING_NUMS | OLDSTYLE_NUMS" %>
<% numeric_spacing_values = "PROPORTIONAL_NUMS | TABULAR_NUMS" %> <% numeric_spacing_values = "PROPORTIONAL_NUMS | TABULAR_NUMS" %>
<% numeric_fraction_values = "DIAGONAL_FRACTIONS | STACKED_FRACTIONS" %> <% numeric_fraction_values = "DIAGONAL_FRACTIONS | STACKED_FRACTIONS" %>
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = VariantNumeric::empty(); let mut result = VariantNumeric::empty();
if input.try(|input| input.expect_ident_matching("normal")).is_ok() { if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
@ -1773,16 +1797,20 @@ macro_rules! exclusive_value {
"lining-nums" => "lining-nums" =>
exclusive_value!((result, ${numeric_figure_values}) => LINING_NUMS ), exclusive_value!((result, ${numeric_figure_values}) => LINING_NUMS ),
"oldstyle-nums" => "oldstyle-nums" =>
exclusive_value!((result, ${numeric_figure_values}) => OLDSTYLE_NUMS ), exclusive_value!((result, ${numeric_figure_values}) => OLDSTYLE_NUMS),
"proportional-nums" => "proportional-nums" =>
exclusive_value!((result, ${numeric_spacing_values}) => PROPORTIONAL_NUMS ), exclusive_value!((result, ${numeric_spacing_values}) => PROPORTIONAL_NUMS),
"tabular-nums" => "tabular-nums" =>
exclusive_value!((result, ${numeric_spacing_values}) => TABULAR_NUMS ), exclusive_value!((result, ${numeric_spacing_values}) => TABULAR_NUMS),
"diagonal-fractions" => "diagonal-fractions" =>
exclusive_value!((result, ${numeric_fraction_values}) => DIAGONAL_FRACTIONS ), exclusive_value!((result, ${numeric_fraction_values}) => DIAGONAL_FRACTIONS),
"stacked-fractions" => "stacked-fractions" =>
exclusive_value!((result, ${numeric_fraction_values}) => STACKED_FRACTIONS ), exclusive_value!((result, ${numeric_fraction_values}) => STACKED_FRACTIONS),
_ => return Err(()), _ => None,
};
let flag = match flag {
Some(flag) => flag,
None => return Err(SelectorParseError::UnexpectedIdent(ident).into()),
}; };
result.insert(flag); result.insert(flag);
} }
@ -1790,7 +1818,7 @@ macro_rules! exclusive_value {
if !result.is_empty() { if !result.is_empty() {
Ok(SpecifiedValue::Value(result)) Ok(SpecifiedValue::Value(result))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -1836,7 +1864,8 @@ ${helpers.single_keyword_system("font-variant-position",
} }
/// normal | <feature-tag-value># /// normal | <feature-tag-value>#
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
computed_value::T::parse(context, input).map(SpecifiedValue::Value) computed_value::T::parse(context, input).map(SpecifiedValue::Value)
} }
</%helpers:longhand> </%helpers:longhand>
@ -1870,7 +1899,8 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-
} }
/// normal | <feature-tag-value># /// normal | <feature-tag-value>#
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
computed_value::T::parse(context, input) computed_value::T::parse(context, input)
} }
</%helpers:longhand> </%helpers:longhand>
@ -2000,13 +2030,14 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-
} }
/// normal | <string> /// normal | <string>
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("normal")).is_ok() { if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
Ok(SpecifiedValue::Normal) Ok(SpecifiedValue::Normal)
} else { } else {
input.expect_string().map(|cow| { input.expect_string().map(|cow| {
SpecifiedValue::Override(cow.into_owned()) SpecifiedValue::Override(cow.into_owned())
}) }).map_err(|e| e.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -2040,9 +2071,10 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-
computed_value::T(atom!("")) computed_value::T(atom!(""))
} }
pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
debug_assert!(false, "Should be set directly by presentation attributes only."); debug_assert!(false, "Should be set directly by presentation attributes only.");
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
</%helpers:longhand> </%helpers:longhand>
@ -2065,9 +2097,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 ::gecko_bindings::structs::NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER as f32
} }
pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
debug_assert!(false, "Should be set directly by presentation attributes only."); debug_assert!(false, "Should be set directly by presentation attributes only.");
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
</%helpers:longhand> </%helpers:longhand>
@ -2138,7 +2171,8 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-
} }
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if let Ok(i) = input.try(|i| i.expect_integer()) { if let Ok(i) = input.try(|i| i.expect_integer()) {
return Ok(SpecifiedValue::Relative(i)) return Ok(SpecifiedValue::Relative(i))
} }
@ -2213,9 +2247,10 @@ ${helpers.single_keyword("-moz-math-variant",
Au((NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT as f32 * AU_PER_PT) as i32) Au((NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT as f32 * AU_PER_PT) as i32)
} }
pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, _input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
debug_assert!(false, "Should be set directly by presentation attributes only."); debug_assert!(false, "Should be set directly by presentation attributes only.");
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
</%helpers:longhand> </%helpers:longhand>
@ -2240,7 +2275,9 @@ ${helpers.single_keyword("-moz-math-variant",
use app_units::Au; use app_units::Au;
use cssparser::Parser; use cssparser::Parser;
use properties::longhands; use properties::longhands;
use selectors::parser::SelectorParseError;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use style_traits::ParseError;
use values::computed::{ToComputedValue, Context}; use values::computed::{ToComputedValue, Context};
<% <%
system_fonts = """caption icon menu message-box small-caption status-bar system_fonts = """caption icon menu message-box small-caption status-bar
@ -2359,13 +2396,14 @@ ${helpers.single_keyword("-moz-math-variant",
} }
impl SystemFont { impl SystemFont {
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Ok(match_ignore_ascii_case! { &*input.expect_ident()?, let ident = input.expect_ident()?;
(match_ignore_ascii_case! { &*ident,
% for font in system_fonts: % for font in system_fonts:
"${font}" => SystemFont::${to_camel_case(font)}, "${font}" => Ok(SystemFont::${to_camel_case(font)}),
% endfor % endfor
_ => return Err(()) _ => Err(())
}) }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
} }

View file

@ -174,7 +174,8 @@ ${helpers.single_keyword("image-rendering",
} }
// from-image | <angle> | [<angle>? flip] // from-image | <angle> | [<angle>? flip]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("from-image")).is_ok() { if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
// Handle from-image // Handle from-image
Ok(SpecifiedValue { angle: None, flipped: false }) Ok(SpecifiedValue { angle: None, flipped: false })
@ -185,7 +186,7 @@ ${helpers.single_keyword("image-rendering",
// Handle <angle> | <angle> flip // Handle <angle> | <angle> flip
let angle = input.try(|input| Angle::parse(context, input)).ok(); let angle = input.try(|input| Angle::parse(context, input)).ok();
if angle.is_none() { if angle.is_none() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok(); let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();

View file

@ -183,7 +183,8 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
} }
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) { if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
Ok(SpecifiedValue(0)) Ok(SpecifiedValue(0))
} else { } else {
@ -195,33 +196,34 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
loop { loop {
let result = input.try(|i| { let result: Result<_, ParseError> = input.try(|i| {
match_ignore_ascii_case! { &i.expect_ident()?, let ident = i.expect_ident()?;
(match_ignore_ascii_case! { &ident,
"fill" => Ok(FILL), "fill" => Ok(FILL),
"stroke" => Ok(STROKE), "stroke" => Ok(STROKE),
"markers" => Ok(MARKERS), "markers" => Ok(MARKERS),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident.into()).into())
}); });
match result { match result {
Ok(val) => { Ok(val) => {
if (seen & (1 << val)) != 0 { if (seen & (1 << val)) != 0 {
// don't parse the same ident twice // don't parse the same ident twice
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} else { } else {
value |= val << (pos * SHIFT); value |= val << (pos * SHIFT);
seen |= 1 << val; seen |= 1 << val;
pos += 1; pos += 1;
} }
} }
Err(()) => break, Err(_) => break,
} }
} }
if value == 0 { if value == 0 {
// couldn't find any keyword // couldn't find any keyword
Err(()) Err(StyleParseError::UnspecifiedError.into())
} else { } else {
// fill in rest // fill in rest
for i in pos..COUNT { 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<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let i = input.expect_ident()?; let i = input.expect_ident()?;
CustomIdent::from_ident(i, &["all", "none", "auto"]) CustomIdent::from_ident(i, &["all", "none", "auto"])
} }

View file

@ -113,11 +113,12 @@ ${helpers.single_keyword("caption-side", "top bottom",
} }
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
let mut first = None; let mut first = None;
let mut second = None; let mut second = None;
match Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes) { match Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes) {
Err(()) => (), Err(_) => (),
Ok(length) => { Ok(length) => {
first = Some(length); first = Some(length);
if let Ok(len) = input.try(|i| Length::parse_non_negative_quirky(context, i, AllowQuirks::Yes)) { 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) { match (first, second) {
(None, None) => Err(()), (None, None) => Err(StyleParseError::UnspecifiedError.into()),
(Some(length), None) => { (Some(length), None) => {
Ok(SpecifiedValue { Ok(SpecifiedValue {
horizontal: length, horizontal: length,

View file

@ -176,7 +176,8 @@ ${helpers.single_keyword("text-align-last",
MatchParent, MatchParent,
MozCenterOrInherit, MozCenterOrInherit,
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
// MozCenterOrInherit cannot be parsed, only set directly on th elements // MozCenterOrInherit cannot be parsed, only set directly on th elements
if let Ok(key) = input.try(computed_value::T::parse) { if let Ok(key) = input.try(computed_value::T::parse) {
Ok(SpecifiedValue::Keyword(key)) Ok(SpecifiedValue::Keyword(key))
@ -252,7 +253,8 @@ ${helpers.single_keyword("text-align-last",
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
impl ComputedValueAsSpecified for SpecifiedValue {} impl ComputedValueAsSpecified for SpecifiedValue {}
pub use self::computed_value::T as SpecifiedValue; pub use self::computed_value::T as SpecifiedValue;
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
computed_value::T::parse(input) computed_value::T::parse(input)
} }
% endif % endif
@ -411,7 +413,8 @@ ${helpers.predefined_type("word-spacing",
pub type T = Shadow; pub type T = Shadow;
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<specified::Shadow, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<specified::Shadow, ParseError<'i>> {
specified::Shadow::parse(context, input, true) specified::Shadow::parse(context, input, true)
} }
</%helpers:vector_longhand> </%helpers:vector_longhand>
@ -573,7 +576,8 @@ ${helpers.predefined_type("word-spacing",
} }
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue::None); return Ok(SpecifiedValue::None);
} }
@ -599,7 +603,7 @@ ${helpers.predefined_type("word-spacing",
(Some(fill), Ok(shape)) => KeywordValue::FillAndShape(fill,shape), (Some(fill), Ok(shape)) => KeywordValue::FillAndShape(fill,shape),
(Some(fill), Err(_)) => KeywordValue::Fill(fill), (Some(fill), Err(_)) => KeywordValue::Fill(fill),
(None, Ok(shape)) => KeywordValue::Shape(shape), (None, Ok(shape)) => KeywordValue::Shape(shape),
_ => return Err(()), _ => return Err(StyleParseError::UnspecifiedError.into()),
}; };
Ok(SpecifiedValue::Keyword(keyword_value)) Ok(SpecifiedValue::Keyword(keyword_value))
} }
@ -632,7 +636,8 @@ ${helpers.predefined_type("word-spacing",
SpecifiedValue(HorizontalWritingModeValue::Over, VerticalWritingModeValue::Right) SpecifiedValue(HorizontalWritingModeValue::Over, VerticalWritingModeValue::Right)
} }
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if let Ok(horizontal) = input.try(|input| HorizontalWritingModeValue::parse(input)) { if let Ok(horizontal) = input.try(|input| HorizontalWritingModeValue::parse(input)) {
let vertical = try!(VerticalWritingModeValue::parse(input)); let vertical = try!(VerticalWritingModeValue::parse(input));
Ok(SpecifiedValue(horizontal, vertical)) Ok(SpecifiedValue(horizontal, vertical))

View file

@ -89,7 +89,8 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu
SpecifiedValue::CounterStyle(CounterStyleOrNone::disc()) SpecifiedValue::CounterStyle(CounterStyleOrNone::disc())
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
Ok(if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) { Ok(if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) {
SpecifiedValue::CounterStyle(style) SpecifiedValue::CounterStyle(style)
} else { } else {
@ -126,7 +127,8 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu
pub fn get_initial_specified_value() -> SpecifiedValue { pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(Either::Second(None_)) SpecifiedValue(Either::Second(None_))
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
% if product == "gecko": % if product == "gecko":
let mut value = input.try(|input| UrlOrNone::parse(context, input))?; let mut value = input.try(|input| UrlOrNone::parse(context, input))?;
if let Either::First(ref mut url) = value { 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" <%helpers:longhand name="quotes" animation_value_type="none"
spec="https://drafts.csswg.org/css-content/#propdef-quotes"> spec="https://drafts.csswg.org/css-content/#propdef-quotes">
use cssparser::Token;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use style_traits::ToCss; 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<SpecifiedValue,()> { pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new())) return Ok(SpecifiedValue(Vec::new()))
} }
@ -196,19 +198,20 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu
loop { loop {
let first = match input.next() { let first = match input.next() {
Ok(Token::QuotedString(value)) => value.into_owned(), Ok(Token::QuotedString(value)) => value.into_owned(),
Ok(_) => return Err(()), Ok(t) => return Err(BasicParseError::UnexpectedToken(t).into()),
Err(()) => break, Err(_) => break,
}; };
let second = match input.next() { let second = match input.next() {
Ok(Token::QuotedString(value)) => value.into_owned(), 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)) quotes.push((first, second))
} }
if !quotes.is_empty() { if !quotes.is_empty() {
Ok(SpecifiedValue(quotes)) Ok(SpecifiedValue(quotes))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>

View file

@ -46,14 +46,15 @@ ${helpers.predefined_type("outline-color", "Color", "computed_value::T::currentc
pub type T = super::SpecifiedValue; pub type T = super::SpecifiedValue;
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(context, input) SpecifiedValue::parse(context, input)
.and_then(|result| { .and_then(|result| {
if let Either::Second(BorderStyle::hidden) = result { if let Either::Second(BorderStyle::hidden) = result {
// The outline-style property accepts the same values as // The outline-style property accepts the same values as
// border-style, except that 'hidden' is not a legal outline // border-style, except that 'hidden' is not a legal outline
// style. // style.
Err(()) Err(SelectorParseError::UnexpectedIdent("hidden".into()).into())
} else { } else {
Ok(result) Ok(result)
} }

View file

@ -91,37 +91,43 @@
} }
impl Parse for computed_value::Keyword { impl Parse for computed_value::Keyword {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<computed_value::Keyword, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<computed_value::Keyword, ParseError<'i>> {
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use style_traits::cursor::Cursor; use style_traits::cursor::Cursor;
let ident = try!(input.expect_ident()); let ident = try!(input.expect_ident());
if ident.eq_ignore_ascii_case("auto") { if ident.eq_ignore_ascii_case("auto") {
Ok(computed_value::Keyword::Auto) Ok(computed_value::Keyword::Auto)
} else { } 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")] #[cfg(feature = "gecko")]
fn parse_image(context: &ParserContext, input: &mut Parser) -> Result<computed_value::Image, ()> { fn parse_image<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<computed_value::Image, ParseError<'i>> {
Ok(computed_value::Image { Ok(computed_value::Image {
url: try!(SpecifiedUrl::parse(context, input)), url: try!(SpecifiedUrl::parse(context, input)),
hotspot: match input.try(|input| input.expect_number()) { hotspot: match input.try(|input| input.expect_number()) {
Ok(number) => Some((number, try!(input.expect_number()))), Ok(number) => Some((number, try!(input.expect_number()))),
Err(()) => None, Err(_) => None,
}, },
}) })
} }
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
computed_value::Keyword::parse(context, input) computed_value::Keyword::parse(context, input)
} }
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...] /// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut images = vec![]; let mut images = vec![];
loop { loop {
match input.try(|input| parse_image(context, input)) { match input.try(|input| parse_image(context, input)) {
@ -129,7 +135,7 @@
image.url.build_image_value(); image.url.build_image_value();
images.push(image) images.push(image)
} }
Err(()) => break, Err(_) => break,
} }
try!(input.expect_comma()); try!(input.expect_comma());
} }

View file

@ -313,27 +313,32 @@ ${helpers.predefined_type("object-position",
} }
/// [ row | column ] || dense /// [ row | column ] || dense
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
use self::computed_value::AutoFlow; use self::computed_value::AutoFlow;
let mut value = None; let mut value = None;
let mut dense = false; let mut dense = false;
while !input.is_exhausted() { 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() => { "row" if value.is_none() => {
value = Some(AutoFlow::Row); value = Some(AutoFlow::Row);
continue true
}, },
"column" if value.is_none() => { "column" if value.is_none() => {
value = Some(AutoFlow::Column); value = Some(AutoFlow::Column);
continue true
}, },
"dense" if !dense => { "dense" if !dense => {
dense = true; dense = true;
continue true
}, },
_ => return Err(()) _ => false
};
if !success {
return Err(SelectorParseError::UnexpectedIdent(ident).into());
} }
} }
@ -343,7 +348,7 @@ ${helpers.predefined_type("object-position",
dense: dense, dense: dense,
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
</%helpers:longhand> </%helpers:longhand>
@ -372,7 +377,8 @@ ${helpers.predefined_type("object-position",
Either::Second(None_) Either::Second(None_)
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(context, input) SpecifiedValue::parse(context, input)
} }
@ -394,13 +400,15 @@ ${helpers.predefined_type("object-position",
impl ComputedValueAsSpecified for TemplateAreas {} impl ComputedValueAsSpecified for TemplateAreas {}
impl Parse for TemplateAreas { impl Parse for TemplateAreas {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
let mut strings = vec![]; let mut strings = vec![];
while let Ok(string) = input.try(Parser::expect_string) { while let Ok(string) = input.try(Parser::expect_string) {
strings.push(string.into_owned().into_boxed_str()); strings.push(string.into_owned().into_boxed_str());
} }
TemplateAreas::from_vec(strings) TemplateAreas::from_vec(strings)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
} }

View file

@ -129,7 +129,8 @@ ${helpers.single_keyword("mask-origin",
background_size::get_initial_value() background_size::get_initial_value()
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue,ParseError<'i>> {
background_size::parse(context, input) background_size::parse(context, input)
} }
</%helpers:longhand> </%helpers:longhand>

View file

@ -40,7 +40,8 @@ ${helpers.single_keyword("table-layout", "auto fixed",
} }
// never parse it, only set via presentation attribute // never parse it, only set via presentation attribute
fn parse(_: &ParserContext, _: &mut Parser) -> Result<SpecifiedValue, ()> { fn parse<'i, 't>(_: &ParserContext, _: &mut Parser<'i, 't>)
Err(()) -> Result<SpecifiedValue, ParseError<'i>> {
Err(StyleParseError::UnspecifiedError.into())
} }
</%helpers:longhand> </%helpers:longhand>

View file

@ -104,7 +104,8 @@
sides_are_logical: true, sides_are_logical: true,
} }
} }
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let first = try!(Side::parse(context, input)); let first = try!(Side::parse(context, input));
let second = input.try(|input| Side::parse(context, input)).ok(); let second = input.try(|input| Side::parse(context, input)).ok();
Ok(SpecifiedValue { Ok(SpecifiedValue {
@ -113,13 +114,14 @@
}) })
} }
impl Parse for Side { impl Parse for Side {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Side, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Side, ParseError<'i>> {
if let Ok(ident) = input.try(|input| input.expect_ident()) { if let Ok(ident) = input.try(|input| input.expect_ident()) {
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"clip" => Ok(Side::Clip), "clip" => Ok(Side::Clip),
"ellipsis" => Ok(Side::Ellipsis), "ellipsis" => Ok(Side::Ellipsis),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} else { } else {
Ok(Side::String(try!(input.expect_string()).into_owned().into_boxed_str())) Ok(Side::String(try!(input.expect_string()).into_owned().into_boxed_str()))
} }
@ -217,34 +219,39 @@ ${helpers.single_keyword("unicode-bidi",
SpecifiedValue::empty() SpecifiedValue::empty()
} }
/// none | [ underline || overline || line-through || blink ] /// none | [ underline || overline || line-through || blink ]
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
let mut result = SpecifiedValue::empty(); let mut result = SpecifiedValue::empty();
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(result) return Ok(result)
} }
let mut empty = true; let mut empty = true;
while input.try(|input| { loop {
if let Ok(ident) = input.expect_ident() { let result: Result<_, ParseError> = input.try(|input| {
match_ignore_ascii_case! { &ident, match input.expect_ident() {
"underline" => if result.contains(UNDERLINE) { return Err(()) } Ok(ident) => {
else { empty = false; result.insert(UNDERLINE) }, (match_ignore_ascii_case! { &ident,
"overline" => if result.contains(OVERLINE) { return Err(()) } "underline" => if result.contains(UNDERLINE) { Err(()) }
else { empty = false; result.insert(OVERLINE) }, else { empty = false; result.insert(UNDERLINE); Ok(()) },
"line-through" => if result.contains(LINE_THROUGH) { return Err(()) } "overline" => if result.contains(OVERLINE) { Err(()) }
else { empty = false; result.insert(LINE_THROUGH) }, else { empty = false; result.insert(OVERLINE); Ok(()) },
"blink" => if result.contains(BLINK) { return Err(()) } "line-through" => if result.contains(LINE_THROUGH) { Err(()) }
else { empty = false; result.insert(BLINK) }, else { empty = false; result.insert(LINE_THROUGH); Ok(()) },
_ => return Err(()) "blink" => if result.contains(BLINK) { Err(()) }
else { empty = false; result.insert(BLINK); Ok(()) },
_ => Err(())
}).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} else { Err(e) => return Err(e.into())
return Err(());
} }
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": % if product == "servo":

View file

@ -76,11 +76,12 @@ ${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet"
impl ComputedValueAsSpecified for SpecifiedValue {} impl ComputedValueAsSpecified for SpecifiedValue {}
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
match try!(input.expect_integer()) { match try!(input.expect_integer()) {
0 => Ok(computed_value::T(false)), 0 => Ok(computed_value::T(false)),
1 => Ok(computed_value::T(true)), 1 => Ok(computed_value::T(true)),
_ => Err(()), _ => Err(StyleParseError::UnspecifiedError.into()),
} }
} }
</%helpers:longhand> </%helpers:longhand>

View file

@ -20,6 +20,7 @@ use stylearc::{Arc, UniqueArc};
use app_units::Au; use app_units::Au;
#[cfg(feature = "servo")] use cssparser::RGBA; #[cfg(feature = "servo")] use cssparser::RGBA;
use cssparser::{Parser, TokenSerializationType, serialize_identifier}; use cssparser::{Parser, TokenSerializationType, serialize_identifier};
use cssparser::ParserInput;
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
#[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D; #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
use computed_values; use computed_values;
@ -33,9 +34,10 @@ use media_queries::Device;
use parser::{PARSING_MODE_DEFAULT, Parse, ParserContext}; use parser::{PARSING_MODE_DEFAULT, Parse, ParserContext};
use properties::animated_properties::TransitionProperty; use properties::animated_properties::TransitionProperty;
#[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont; #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont;
use selectors::parser::SelectorParseError;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS; #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use shared_lock::StylesheetGuards; use shared_lock::StylesheetGuards;
use style_traits::{HasViewportPercentage, ToCss}; use style_traits::{HasViewportPercentage, ToCss, ParseError, PropertyDeclarationParseError};
use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData}; use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData};
#[cfg(feature = "servo")] use values::Either; #[cfg(feature = "servo")] use values::Either;
use values::generics::text::LineHeight; use values::generics::text::LineHeight;
@ -168,6 +170,7 @@ macro_rules! unwrap_or_initial {
pub mod shorthands { pub mod shorthands {
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseError};
use values::specified; use values::specified;
<%include file="/shorthand/serialize.mako.rs" /> <%include file="/shorthand/serialize.mako.rs" />
@ -196,9 +199,11 @@ pub mod shorthands {
use parser::ParserContext; use parser::ParserContext;
use properties::{SourcePropertyDeclaration, AllShorthand, ShorthandId, UnparsedValue}; use properties::{SourcePropertyDeclaration, AllShorthand, ShorthandId, UnparsedValue};
use stylearc::Arc; use stylearc::Arc;
use style_traits::{ParseError, StyleParseError};
pub fn parse_into(declarations: &mut SourcePropertyDeclaration, pub fn parse_into<'i, 't>(declarations: &mut SourcePropertyDeclaration,
context: &ParserContext, input: &mut Parser) -> Result<(), ()> { context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<(), ParseError<'i>> {
// This function is like the parse() that is generated by // This function is like the parse() that is generated by
// helpers:shorthand, but since the only values for the 'all' // helpers:shorthand, but since the only values for the 'all'
// shorthand when not just a single CSS-wide keyword is one // shorthand when not just a single CSS-wide keyword is one
@ -222,7 +227,7 @@ pub mod shorthands {
})); }));
Ok(()) Ok(())
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
} }
@ -397,6 +402,7 @@ impl PropertyDeclarationIdSet {
{ {
f(& f(&
::custom_properties::substitute(css, first_token_type, custom_properties) ::custom_properties::substitute(css, first_token_type, custom_properties)
.ok()
.and_then(|css| { .and_then(|css| {
// As of this writing, only the base URL is used for property values: // As of this writing, only the base URL is used for property values:
// //
@ -408,7 +414,8 @@ impl PropertyDeclarationIdSet {
None, None,
PARSING_MODE_DEFAULT, PARSING_MODE_DEFAULT,
quirks_mode); quirks_mode);
Parser::new(&css).parse_entirely(|input| { let mut input = ParserInput::new(&css);
Parser::new(&mut input).parse_entirely(|input| {
match from_shorthand { match from_shorthand {
None => { None => {
longhands::${property.ident} longhands::${property.ident}
@ -417,7 +424,7 @@ impl PropertyDeclarationIdSet {
Some(ShorthandId::All) => { Some(ShorthandId::All) => {
// No need to parse the 'all' shorthand as anything other than a CSS-wide // No need to parse the 'all' shorthand as anything other than a CSS-wide
// keyword, after variable substitution. // keyword, after variable substitution.
Err(()) Err(SelectorParseError::UnexpectedIdent("all".into()).into())
} }
% for shorthand in data.shorthands_except_all(): % for shorthand in data.shorthands_except_all():
% if property in shorthand.sub_properties: % if property in shorthand.sub_properties:
@ -431,7 +438,7 @@ impl PropertyDeclarationIdSet {
% endfor % endfor
_ => unreachable!() _ => unreachable!()
} }
}) }).ok()
}) })
.unwrap_or( .unwrap_or(
// Invalid at computed-value time. // Invalid at computed-value time.
@ -483,10 +490,11 @@ impl CSSWideKeyword {
} }
impl Parse for CSSWideKeyword { impl Parse for CSSWideKeyword {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
input.expect_exhausted()?; input.expect_exhausted()?;
CSSWideKeyword::from_ident(&ident).ok_or(()) CSSWideKeyword::from_ident(&ident)
.ok_or(SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
@ -929,7 +937,7 @@ impl PropertyId {
/// Returns a given property from the string `s`. /// Returns a given property from the string `s`.
/// ///
/// Returns Err(()) for unknown non-custom properties /// Returns Err(()) for unknown non-custom properties
pub fn parse(property_name: Cow<str>) -> Result<Self, ()> { pub fn parse<'i>(property_name: Cow<'i, str>) -> Result<Self, ParseError<'i>> {
if let Ok(name) = ::custom_properties::parse_name(&property_name) { if let Ok(name) = ::custom_properties::parse_name(&property_name) {
return Ok(PropertyId::Custom(::custom_properties::Name::from(name))) return Ok(PropertyId::Custom(::custom_properties::Name::from(name)))
} }
@ -954,7 +962,7 @@ impl PropertyId {
match static_id(&property_name) { match static_id(&property_name) {
Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)), Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)),
Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)), Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)),
None => Err(()), None => Err(SelectorParseError::UnexpectedIdent(property_name).into()),
} }
} }
@ -1078,24 +1086,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 { impl fmt::Debug for PropertyDeclaration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(self.id().to_css(f)); try!(self.id().to_css(f));
@ -1390,9 +1380,9 @@ impl PropertyDeclaration {
PropertyId::Custom(name) => { PropertyId::Custom(name) => {
let value = match input.try(|i| CSSWideKeyword::parse(context, i)) { let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword), 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), Ok(value) => DeclaredValueOwned::Value(value),
Err(()) => return Err(PropertyDeclarationParseError::InvalidValue), Err(_) => return Err(PropertyDeclarationParseError::InvalidValue),
} }
}; };
declarations.push(PropertyDeclaration::Custom(name, value)); declarations.push(PropertyDeclaration::Custom(name, value));
@ -1425,7 +1415,7 @@ impl PropertyDeclaration {
declarations.push(value); declarations.push(value);
Ok(()) Ok(())
}, },
Err(()) => Err(PropertyDeclarationParseError::InvalidValue), Err(_) => Err(PropertyDeclarationParseError::InvalidValue),
} }
% else: % else:
Err(PropertyDeclarationParseError::UnknownProperty) Err(PropertyDeclarationParseError::UnknownProperty)
@ -1468,9 +1458,9 @@ impl PropertyDeclaration {
% endif % endif
Ok(()) Ok(())
}, },
Err(()) => { Err(_) => {
shorthands::${shorthand.ident}::parse_into(declarations, context, input) shorthands::${shorthand.ident}::parse_into(declarations, context, input)
.map_err(|()| PropertyDeclarationParseError::InvalidValue) .map_err(|_| PropertyDeclarationParseError::InvalidValue)
} }
} }
} }

View file

@ -32,7 +32,8 @@
} }
} }
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut background_color = None; let mut background_color = None;
% for name in "image position_x position_y repeat size attachment origin clip".split(): % 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 // background-color can only be in the last element, so if it
// is parsed anywhere before, the value is invalid. // is parsed anywhere before, the value is invalid.
if background_color.is_some() { if background_color.is_some() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
% for name in "image position repeat size attachment origin clip".split(): % for name in "image position repeat size attachment origin clip".split():
@ -107,7 +108,7 @@
% endfor % endfor
Ok(()) Ok(())
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
})); }));
@ -194,7 +195,8 @@
use values::specified::AllowQuirks; use values::specified::AllowQuirks;
use values::specified::position::Position; use values::specified::position::Position;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut position_x = background_position_x::SpecifiedValue(Vec::new()); let mut position_x = background_position_x::SpecifiedValue(Vec::new());
let mut position_y = background_position_y::SpecifiedValue(Vec::new()); let mut position_y = background_position_y::SpecifiedValue(Vec::new());
let mut any = false; let mut any = false;
@ -207,7 +209,7 @@
Ok(()) Ok(())
})?; })?;
if !any { if !any {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(expanded! { Ok(expanded! {

View file

@ -20,7 +20,8 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
use values::generics::rect::Rect; use values::generics::rect::Rect;
use values::specified::{AllowQuirks, BorderSideWidth}; use values::specified::{AllowQuirks, BorderSideWidth};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let rect = Rect::parse_with(context, input, |_, i| { let rect = Rect::parse_with(context, input, |_, i| {
BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes) BorderSideWidth::parse_quirky(context, i, AllowQuirks::Yes)
})?; })?;
@ -43,10 +44,10 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
</%helpers:shorthand> </%helpers:shorthand>
pub fn parse_border(context: &ParserContext, input: &mut Parser) pub fn parse_border<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<(specified::Color, -> Result<(specified::Color,
specified::BorderStyle, specified::BorderStyle,
specified::BorderSideWidth), ()> { specified::BorderSideWidth), ParseError<'i>> {
use values::specified::{Color, BorderStyle, BorderSideWidth}; use values::specified::{Color, BorderStyle, BorderSideWidth};
let _unused = context; let _unused = context;
let mut color = None; let mut color = None;
@ -82,7 +83,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
style.unwrap_or(BorderStyle::none), style.unwrap_or(BorderStyle::none),
width.unwrap_or(BorderSideWidth::Medium))) width.unwrap_or(BorderSideWidth::Medium)))
} else { } 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')}" alias="${maybe_moz_logical_alias(product, (side, logical), '-moz-border-%s')}"
spec="${spec}"> spec="${spec}">
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let (color, style, width) = try!(super::parse_border(context, input)); let (color, style, width) = try!(super::parse_border(context, input));
Ok(expanded! { Ok(expanded! {
border_${to_rust_ident(side)}_color: color, 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}; _moz_border_bottom_colors, _moz_border_left_colors};
% endif % endif
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice}; use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
use properties::longhands::{border_image_source, border_image_width}; 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 values::specified::border::BorderRadius;
use parser::Parse; use parser::Parse;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let radii = try!(BorderRadius::parse(context, input)); let radii = try!(BorderRadius::parse(context, input));
Ok(expanded! { Ok(expanded! {
border_top_left_radius: radii.top_left, 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_outset, border_image_repeat, border_image_slice};
use properties::longhands::{border_image_source, border_image_width}; use properties::longhands::{border_image_source, border_image_width};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
% for name in "outset repeat slice source width".split(): % for name in "outset repeat slice source width".split():
let mut border_image_${name} = border_image_${name}::get_initial_specified_value(); let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
% endfor % endfor
try!(input.try(|input| { let result: Result<_, ParseError> = input.try(|input| {
% for name in "outset repeat slice source width".split(): % for name in "outset repeat slice source width".split():
let mut ${name} = None; let mut ${name} = None;
% endfor % 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)) { if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
slice = Some(value); slice = Some(value);
// Parse border image width and outset, if applicable. // 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('/')); try!(input.expect_delim('/'));
// Parse border image width, if applicable. // 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) border_image_outset::parse(context, input)
}).ok(); }).ok();
if w.is_none() && o.is_none() { if w.is_none() && o.is_none() {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
else { else {
Ok((w, o)) Ok((w, o))
@ -305,9 +310,10 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
% endfor % endfor
Ok(()) Ok(())
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
})); });
try!(result);
Ok(expanded! { Ok(expanded! {
% for name in "outset repeat slice source width".split(): % for name in "outset repeat slice source width".split():

View file

@ -11,29 +11,33 @@
use properties::longhands::overflow_x::SpecifiedValue; use properties::longhands::overflow_x::SpecifiedValue;
% endif % endif
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
% if product == "gecko": % if product == "gecko":
let moz_kw_found = input.try(|i| match_ignore_ascii_case! { let moz_kw_found = input.try(|i| {
&i.expect_ident()?, let ident = i.expect_ident()?;
"-moz-scrollbars-horizontal" => { (match_ignore_ascii_case! {
Ok(expanded! { &ident,
overflow_x: SpecifiedValue::scroll, "-moz-scrollbars-horizontal" => {
overflow_y: SpecifiedValue::hidden, Ok(expanded! {
}) overflow_x: SpecifiedValue::scroll,
} overflow_y: SpecifiedValue::hidden,
"-moz-scrollbars-vertical" => { })
Ok(expanded! { }
overflow_x: SpecifiedValue::hidden, "-moz-scrollbars-vertical" => {
overflow_y: SpecifiedValue::scroll, Ok(expanded! {
}) overflow_x: SpecifiedValue::hidden,
} overflow_y: SpecifiedValue::scroll,
"-moz-scrollbars-none" => { })
Ok(expanded! { }
overflow_x: SpecifiedValue::hidden, "-moz-scrollbars-none" => {
overflow_y: SpecifiedValue::hidden, Ok(expanded! {
}) overflow_x: SpecifiedValue::hidden,
} overflow_y: SpecifiedValue::hidden,
_ => Err(()) })
}
_ => Err(())
}).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
}); });
if moz_kw_found.is_ok() { if moz_kw_found.is_ok() {
return moz_kw_found return moz_kw_found
@ -88,14 +92,16 @@ macro_rules! try_parse_one {
use properties::longhands::transition_${prop}; use properties::longhands::transition_${prop};
% endfor % endfor
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
struct SingleTransition { struct SingleTransition {
% for prop in "property duration timing_function delay".split(): % for prop in "property duration timing_function delay".split():
transition_${prop}: transition_${prop}::SingleSpecifiedValue, transition_${prop}: transition_${prop}::SingleSpecifiedValue,
% endfor % endfor
} }
fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result<SingleTransition,()> { fn parse_one_transition<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SingleTransition,ParseError<'i>> {
% for prop in "property duration timing_function delay".split(): % for prop in "property duration timing_function delay".split():
let mut ${prop} = None; let mut ${prop} = None;
% endfor % endfor
@ -123,7 +129,7 @@ macro_rules! try_parse_one {
% endfor % endfor
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -202,14 +208,16 @@ macro_rules! try_parse_one {
use properties::longhands::animation_${prop}; use properties::longhands::animation_${prop};
% endfor % endfor
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
struct SingleAnimation { struct SingleAnimation {
% for prop in props: % for prop in props:
animation_${prop}: animation_${prop}::SingleSpecifiedValue, animation_${prop}: animation_${prop}::SingleSpecifiedValue,
% endfor % endfor
} }
fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> { fn parse_one_animation<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SingleAnimation,ParseError<'i>> {
% for prop in props: % for prop in props:
let mut ${prop} = None; let mut ${prop} = None;
% endfor % endfor
@ -237,7 +245,7 @@ macro_rules! try_parse_one {
// If nothing is parsed, this is an invalid entry. // If nothing is parsed, this is an invalid entry.
if parsed == 0 { if parsed == 0 {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} else { } else {
Ok(SingleAnimation { Ok(SingleAnimation {
% for prop in props: % 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"> spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
use properties::longhands::scroll_snap_type_x; use properties::longhands::scroll_snap_type_x;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let result = try!(scroll_snap_type_x::parse(context, input)); let result = try!(scroll_snap_type_x::parse(context, input));
Ok(expanded! { Ok(expanded! {
scroll_snap_type_x: result, 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"> spec="Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/transform">
use properties::longhands::transform; use properties::longhands::transform;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
Ok(expanded! { Ok(expanded! {
transform: transform::parse_prefixed(context, input)?, transform: transform::parse_prefixed(context, input)?,
}) })

View file

@ -8,7 +8,8 @@
extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns"> extra_prefixes="moz" spec="https://drafts.csswg.org/css-multicol/#propdef-columns">
use properties::longhands::{column_count, column_width}; use properties::longhands::{column_count, column_width};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut column_count = None; let mut column_count = None;
let mut column_width = None; let mut column_width = None;
@ -40,7 +41,7 @@
let values = autos + column_count.iter().len() + column_width.iter().len(); let values = autos + column_count.iter().len() + column_width.iter().len();
if values == 0 || values > 2 { if values == 0 || values > 2 {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} else { } else {
Ok(expanded! { Ok(expanded! {
column_count: unwrap_or_initial!(column_count), 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_width, column_rule_style};
use properties::longhands::column_rule_color; use properties::longhands::column_rule_color;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
% for name in "width style color".split(): % for name in "width style color".split():
let mut column_rule_${name} = None; let mut column_rule_${name} = None;
% endfor % endfor
@ -92,7 +94,7 @@
column_rule_color: unwrap_or_initial!(column_rule_color), column_rule_color: unwrap_or_initial!(column_rule_color),
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }

View file

@ -38,7 +38,8 @@
% endif % endif
use self::font_family::SpecifiedValue as FontFamily; use self::font_family::SpecifiedValue as FontFamily;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut nb_normals = 0; let mut nb_normals = 0;
let mut style = None; let mut style = None;
let mut variant_caps = None; let mut variant_caps = None;
@ -97,7 +98,7 @@
} }
if size.is_none() || if size.is_none() ||
(count(&style) + count(&weight) + count(&variant_caps) + count(&stretch) + nb_normals) > 4 { (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() { let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
Some(try!(LineHeight::parse(context, input))) Some(try!(LineHeight::parse(context, input)))
@ -239,7 +240,8 @@
% endfor % endfor
% endif % endif
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut nb_normals = 0; let mut nb_normals = 0;
let mut caps = None; let mut caps = None;
loop { loop {
@ -264,7 +266,7 @@
} }
let count = count(&caps) + nb_normals; let count = count(&caps) + nb_normals;
if count == 0 || count > 1 { if count == 0 || count > 1 {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(expanded! { Ok(expanded! {
font_variant_caps: unwrap_or_initial!(font_variant_caps, caps), font_variant_caps: unwrap_or_initial!(font_variant_caps, caps),

View file

@ -9,7 +9,8 @@
spec="https://www.w3.org/TR/SVG2/painting.html#MarkerShorthand"> spec="https://www.w3.org/TR/SVG2/painting.html#MarkerShorthand">
use values::specified::UrlOrNone; use values::specified::UrlOrNone;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
use parser::Parse; use parser::Parse;
let url = UrlOrNone::parse(context, input)?; let url = UrlOrNone::parse(context, input)?;

View file

@ -9,7 +9,8 @@
spec="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-property"> spec="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-property">
use properties::longhands::{text_emphasis_color, text_emphasis_style}; use properties::longhands::{text_emphasis_color, text_emphasis_style};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut color = None; let mut color = None;
let mut style = None; let mut style = None;
@ -34,7 +35,7 @@
text_emphasis_style: unwrap_or_initial!(text_emphasis_style, style), text_emphasis_style: unwrap_or_initial!(text_emphasis_style, style),
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -56,7 +57,8 @@
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke"> spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke">
use properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width}; use properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut color = None; let mut color = None;
let mut width = None; let mut width = None;
loop { loop {
@ -82,7 +84,7 @@
_webkit_text_stroke_width: unwrap_or_initial!(_webkit_text_stroke_width, width), _webkit_text_stroke_width: unwrap_or_initial!(_webkit_text_stroke_width, width),
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }

View file

@ -10,7 +10,8 @@
use properties::longhands::{list_style_image, list_style_position, list_style_type}; use properties::longhands::{list_style_image, list_style_position, list_style_type};
use values::{Either, None_}; use values::{Either, None_};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
// `none` is ambiguous until we've finished parsing the shorthands, so we count the number // `none` is ambiguous until we've finished parsing the shorthands, so we count the number
// of times we see it. // of times we see it.
let mut nones = 0u8; let mut nones = 0u8;
@ -19,7 +20,7 @@
if input.try(|input| input.expect_ident_matching("none")).is_ok() { if input.try(|input| input.expect_ident_matching("none")).is_ok() {
nones = nones + 1; nones = nones + 1;
if nones > 2 { if nones > 2 {
return Err(()) return Err(SelectorParseError::UnexpectedIdent("none".into()).into())
} }
any = true; any = true;
continue continue
@ -104,7 +105,7 @@
list_style_type: unwrap_or_initial!(list_style_type), list_style_type: unwrap_or_initial!(list_style_type),
}) })
} }
_ => Err(()), _ => Err(StyleParseError::UnspecifiedError.into()),
} }
} }

View file

@ -35,7 +35,8 @@
} }
} }
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
% for name in "image mode position_x position_y size repeat origin clip composite".split(): % for name in "image mode position_x position_y size repeat origin clip composite".split():
let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new()); let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new());
% endfor % endfor
@ -103,7 +104,7 @@
% endfor % endfor
Ok(()) Ok(())
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
})); }));
@ -180,7 +181,8 @@
use values::specified::position::Position; use values::specified::position::Position;
use parser::Parse; use parser::Parse;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut position_x = mask_position_x::SpecifiedValue(Vec::new()); let mut position_x = mask_position_x::SpecifiedValue(Vec::new());
let mut position_y = mask_position_y::SpecifiedValue(Vec::new()); let mut position_y = mask_position_y::SpecifiedValue(Vec::new());
let mut any = false; let mut any = false;
@ -193,7 +195,7 @@
Ok(()) Ok(())
})?; })?;
if any == false { if any == false {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(expanded! { Ok(expanded! {

View file

@ -10,7 +10,8 @@
use values::specified; use values::specified;
use parser::Parse; use parser::Parse;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let _unused = context; let _unused = context;
let mut color = None; let mut color = None;
let mut style = None; let mut style = None;
@ -47,7 +48,7 @@
outline_width: unwrap_or_initial!(outline_width, width), outline_width: unwrap_or_initial!(outline_width, width),
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -71,7 +72,8 @@
use values::specified::border::BorderRadius; use values::specified::border::BorderRadius;
use parser::Parse; use parser::Parse;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let radii = try!(BorderRadius::parse(context, input)); let radii = try!(BorderRadius::parse(context, input));
Ok(expanded! { Ok(expanded! {
_moz_outline_radius_topleft: radii.top_left, _moz_outline_radius_topleft: radii.top_left,

View file

@ -8,7 +8,8 @@
spec="https://drafts.csswg.org/css-flexbox/#flex-flow-property"> spec="https://drafts.csswg.org/css-flexbox/#flex-flow-property">
use properties::longhands::{flex_direction, flex_wrap}; use properties::longhands::{flex_direction, flex_wrap};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut direction = None; let mut direction = None;
let mut wrap = None; let mut wrap = None;
loop { loop {
@ -28,7 +29,7 @@
} }
if direction.is_none() && wrap.is_none() { if direction.is_none() && wrap.is_none() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(expanded! { Ok(expanded! {
flex_direction: unwrap_or_initial!(flex_direction, direction), flex_direction: unwrap_or_initial!(flex_direction, direction),
@ -50,14 +51,15 @@
spec="https://drafts.csswg.org/css-flexbox/#flex-property"> spec="https://drafts.csswg.org/css-flexbox/#flex-property">
use values::specified::Number; use values::specified::Number;
fn parse_flexibility(context: &ParserContext, input: &mut Parser) fn parse_flexibility<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<(Number, Option<Number>),()> { -> Result<(Number, Option<Number>),ParseError<'i>> {
let grow = try!(Number::parse_non_negative(context, input)); let grow = try!(Number::parse_non_negative(context, input));
let shrink = input.try(|i| Number::parse_non_negative(context, i)).ok(); let shrink = input.try(|i| Number::parse_non_negative(context, i)).ok();
Ok((grow, shrink)) Ok((grow, shrink))
} }
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut grow = None; let mut grow = None;
let mut shrink = None; let mut shrink = None;
let mut basis = None; let mut basis = None;
@ -87,7 +89,7 @@
} }
if grow.is_none() && basis.is_none() { if grow.is_none() && basis.is_none() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(expanded! { Ok(expanded! {
flex_grow: grow.unwrap_or(Number::new(1.0)), flex_grow: grow.unwrap_or(Number::new(1.0)),
@ -118,7 +120,8 @@
products="gecko"> products="gecko">
use properties::longhands::{grid_row_gap, grid_column_gap}; use properties::longhands::{grid_row_gap, grid_column_gap};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let row_gap = grid_row_gap::parse(context, input)?; 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()); 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 // 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 // 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. // to limit the amount of code generated.
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let start = input.try(|i| GridLine::parse(context, i))?; let start = input.try(|i| GridLine::parse(context, i))?;
let end = if input.try(|i| i.expect_delim('/')).is_ok() { let end = if input.try(|i| i.expect_delim('/')).is_ok() {
GridLine::parse(context, input)? GridLine::parse(context, input)?
@ -189,7 +193,8 @@
use parser::Parse; use parser::Parse;
// The code is the same as `grid-{row,column}` except that this can have four values at most. // 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<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
fn line_with_ident_from(other: &GridLine) -> GridLine { fn line_with_ident_from(other: &GridLine) -> GridLine {
let mut this = GridLine::default(); let mut this = GridLine::default();
if other.line_num.is_none() && !other.is_span { if other.line_num.is_none() && !other.is_span {
@ -259,8 +264,9 @@
use values::specified::grid::parse_line_names; use values::specified::grid::parse_line_names;
/// Parsing for `<grid-template>` shorthand (also used by `grid` shorthand). /// Parsing for `<grid-template>` shorthand (also used by `grid` shorthand).
pub fn parse_grid_template(context: &ParserContext, input: &mut Parser) pub fn parse_grid_template<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<(TrackListOrNone, TrackListOrNone, Either<TemplateAreas, None_>), ()> { -> Result<(TrackListOrNone, TrackListOrNone, Either<TemplateAreas, None_>),
ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() { if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok((Either::Second(None_), Either::Second(None_), Either::Second(None_))) 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 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 { let template_rows = TrackList {
list_type: TrackListType::Normal, list_type: TrackListType::Normal,
values: values, values: values,
@ -306,7 +313,7 @@
let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() { let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() {
let track_list = TrackList::parse(context, input)?; let track_list = TrackList::parse(context, input)?;
if track_list.list_type != TrackListType::Explicit { if track_list.list_type != TrackListType::Explicit {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Either::First(track_list) Either::First(track_list)
@ -326,7 +333,8 @@
} }
#[inline] #[inline]
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let (rows, columns, areas) = parse_grid_template(context, input)?; let (rows, columns, areas) = parse_grid_template(context, input)?;
Ok(expanded! { Ok(expanded! {
grid_template_rows: rows, grid_template_rows: rows,
@ -410,7 +418,8 @@
use values::{Either, None_}; use values::{Either, None_};
use values::specified::{LengthOrPercentage, TrackSize}; use values::specified::{LengthOrPercentage, TrackSize};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let mut temp_rows = Either::Second(None_); let mut temp_rows = Either::Second(None_);
let mut temp_cols = Either::Second(None_); let mut temp_cols = Either::Second(None_);
let mut temp_areas = Either::Second(None_); let mut temp_areas = Either::Second(None_);
@ -418,7 +427,8 @@
let mut auto_cols = TrackSize::default(); let mut auto_cols = TrackSize::default();
let mut flow = grid_auto_flow::get_initial_value(); let mut flow = grid_auto_flow::get_initial_value();
fn parse_auto_flow(input: &mut Parser, is_row: bool) -> Result<SpecifiedAutoFlow, ()> { fn parse_auto_flow<'i, 't>(input: &mut Parser<'i, 't>, is_row: bool)
-> Result<SpecifiedAutoFlow, ParseError<'i>> {
let mut auto_flow = None; let mut auto_flow = None;
let mut dense = false; let mut dense = false;
for _ in 0..2 { for _ in 0..2 {
@ -440,7 +450,7 @@
autoflow: flow, autoflow: flow,
dense: dense, 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)) { 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::align_content;
use properties::longhands::justify_content; use properties::longhands::justify_content;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let align = align_content::parse(context, input)?; let align = align_content::parse(context, input)?;
if align.has_extra_flags() { if align.has_extra_flags() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
let justify = input.try(|input| justify_content::parse(context, input)) let justify = input.try(|input| justify_content::parse(context, input))
.unwrap_or(justify_content::SpecifiedValue::from(align)); .unwrap_or(justify_content::SpecifiedValue::from(align));
if justify.has_extra_flags() { if justify.has_extra_flags() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(expanded! { Ok(expanded! {
@ -541,14 +552,15 @@
use values::specified::align::AlignJustifySelf; use values::specified::align::AlignJustifySelf;
use parser::Parse; use parser::Parse;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let align = AlignJustifySelf::parse(context, input)?; let align = AlignJustifySelf::parse(context, input)?;
if align.has_extra_flags() { 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()); let justify = input.try(|input| AlignJustifySelf::parse(context, input)).unwrap_or(align.clone());
if justify.has_extra_flags() { if justify.has_extra_flags() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(expanded! { Ok(expanded! {
@ -582,15 +594,16 @@
} }
} }
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
let align = AlignItems::parse(context, input)?; let align = AlignItems::parse(context, input)?;
if align.has_extra_flags() { if align.has_extra_flags() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
let justify = input.try(|input| JustifyItems::parse(context, input)) let justify = input.try(|input| JustifyItems::parse(context, input))
.unwrap_or(JustifyItems::from(align)); .unwrap_or(JustifyItems::from(align));
if justify.has_extra_flags() { if justify.has_extra_flags() {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(expanded! { Ok(expanded! {

View file

@ -16,7 +16,8 @@
use properties::longhands::text_decoration_line; use properties::longhands::text_decoration_line;
% endif % endif
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Longhands, ParseError<'i>> {
% if product == "gecko" or data.testing: % if product == "gecko" or data.testing:
let (mut line, mut style, mut color, mut any) = (None, None, None, false); let (mut line, mut style, mut color, mut any) = (None, None, None, false);
% else: % else:
@ -47,7 +48,7 @@
} }
if !any { if !any {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(expanded! { Ok(expanded! {

View file

@ -6,10 +6,11 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use cssparser::Parser as CssParser; use cssparser::{Parser as CssParser, ParserInput};
use selectors::Element; use selectors::Element;
use selectors::parser::SelectorList; use selectors::parser::SelectorList;
use std::fmt::Debug; use std::fmt::Debug;
use style_traits::ParseError;
use stylesheets::{Origin, Namespaces}; use stylesheets::{Origin, Namespaces};
/// A convenient alias for the type that represents an attribute value used for /// 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`. /// This is used for some DOM APIs like `querySelector`.
pub fn parse_author_origin_no_namespace(input: &str) pub fn parse_author_origin_no_namespace(input: &str)
-> Result<SelectorList<SelectorImpl>, ()> { -> Result<SelectorList<SelectorImpl>, ParseError> {
let namespaces = Namespaces::default(); let namespaces = Namespaces::default();
let parser = SelectorParser { let parser = SelectorParser {
stylesheet_origin: Origin::Author, stylesheet_origin: Origin::Author,
namespaces: &namespaces, 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. /// Whether we're parsing selectors in a user-agent stylesheet.

View file

@ -13,9 +13,10 @@ use media_queries::MediaType;
use parser::ParserContext; use parser::ParserContext;
use properties::{ComputedValues, StyleBuilder}; use properties::{ComputedValues, StyleBuilder};
use properties::longhands::font_size; use properties::longhands::font_size;
use selectors::parser::SelectorParseError;
use std::fmt; use std::fmt;
use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
use style_traits::{CSSPixel, ToCss}; use style_traits::{CSSPixel, ToCss, ParseError};
use style_traits::viewport::ViewportConstraints; use style_traits::viewport::ViewportConstraints;
use values::computed::{self, ToComputedValue}; use values::computed::{self, ToComputedValue};
use values::specified; use values::specified;
@ -151,7 +152,8 @@ impl Expression {
/// ``` /// ```
/// ///
/// Only supports width and width ranges for now. /// Only supports width and width ranges for now.
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
try!(input.expect_parenthesis_block()); try!(input.expect_parenthesis_block());
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
let name = try!(input.expect_ident()); let name = try!(input.expect_ident());
@ -167,7 +169,7 @@ impl Expression {
"width" => { "width" => {
ExpressionKind::Width(Range::Eq(try!(specified::Length::parse_non_negative(context, input)))) ExpressionKind::Width(Range::Eq(try!(specified::Length::parse_non_negative(context, input))))
}, },
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
})) }))
}) })
} }

View file

@ -16,7 +16,7 @@ use restyle_hints::ElementSnapshot;
use selector_parser::{AttrValue as SelectorAttrValue, ElementExt, PseudoElementCascadeType, SelectorParser}; use selector_parser::{AttrValue as SelectorAttrValue, ElementExt, PseudoElementCascadeType, SelectorParser};
use selectors::Element; use selectors::Element;
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
use selectors::parser::SelectorMethods; use selectors::parser::{SelectorMethods, SelectorParseError};
use selectors::visitor::SelectorVisitor; use selectors::visitor::SelectorVisitor;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
@ -24,6 +24,7 @@ use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use style_traits::{ParseError, StyleParseError};
/// A pseudo-element, both public and private. /// A pseudo-element, both public and private.
/// ///
@ -300,10 +301,12 @@ impl ::selectors::SelectorImpl for SelectorImpl {
type BorrowedNamespaceUrl = Namespace; type BorrowedNamespaceUrl = Namespace;
} }
impl<'a> ::selectors::Parser for SelectorParser<'a> { impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
type Impl = SelectorImpl; type Impl = SelectorImpl;
type Error = StyleParseError<'i>;
fn parse_non_ts_pseudo_class(&self, name: Cow<str>) -> Result<NonTSPseudoClass, ()> { fn parse_non_ts_pseudo_class(&self, name: Cow<'i, str>)
-> Result<NonTSPseudoClass, ParseError<'i>> {
use self::NonTSPseudoClass::*; use self::NonTSPseudoClass::*;
let pseudo_class = match_ignore_ascii_case! { &name, let pseudo_class = match_ignore_ascii_case! { &name,
"active" => Active, "active" => Active,
@ -323,20 +326,21 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
"visited" => Visited, "visited" => Visited,
"-servo-nonzero-border" => { "-servo-nonzero-border" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()); return Err(SelectorParseError::UnexpectedIdent(
"-servo-nonzero-border".into()).into());
} }
ServoNonZeroBorder ServoNonZeroBorder
}, },
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into()),
}; };
Ok(pseudo_class) Ok(pseudo_class)
} }
fn parse_non_ts_functional_pseudo_class(&self, fn parse_non_ts_functional_pseudo_class<'t>(&self,
name: Cow<str>, name: Cow<'i, str>,
parser: &mut CssParser) parser: &mut CssParser<'i, 't>)
-> Result<NonTSPseudoClass, ()> { -> Result<NonTSPseudoClass, ParseError<'i>> {
use self::NonTSPseudoClass::*; use self::NonTSPseudoClass::*;
let pseudo_class = match_ignore_ascii_case!{ &name, let pseudo_class = match_ignore_ascii_case!{ &name,
"lang" => { "lang" => {
@ -344,18 +348,17 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
} }
"-servo-case-sensitive-type-attr" => { "-servo-case-sensitive-type-attr" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()); return Err(SelectorParseError::UnexpectedIdent(name.clone()).into());
} }
ServoCaseSensitiveTypeAttr(Atom::from(parser.expect_ident()?)) ServoCaseSensitiveTypeAttr(Atom::from(parser.expect_ident()?))
} }
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
}; };
Ok(pseudo_class) Ok(pseudo_class)
} }
fn parse_pseudo_element(&self, name: Cow<str>) fn parse_pseudo_element(&self, name: Cow<'i, str>) -> Result<PseudoElement, ParseError<'i>> {
-> Result<PseudoElement, ()> {
use self::PseudoElement::*; use self::PseudoElement::*;
let pseudo_element = match_ignore_ascii_case! { &name, let pseudo_element = match_ignore_ascii_case! { &name,
"before" => Before, "before" => Before,
@ -363,77 +366,78 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
"selection" => Selection, "selection" => Selection,
"-servo-details-summary" => { "-servo-details-summary" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
DetailsSummary DetailsSummary
}, },
"-servo-details-content" => { "-servo-details-content" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
DetailsContent DetailsContent
}, },
"-servo-text" => { "-servo-text" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoText ServoText
}, },
"-servo-input-text" => { "-servo-input-text" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoInputText ServoInputText
}, },
"-servo-table-wrapper" => { "-servo-table-wrapper" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoTableWrapper ServoTableWrapper
}, },
"-servo-anonymous-table-wrapper" => { "-servo-anonymous-table-wrapper" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoAnonymousTableWrapper ServoAnonymousTableWrapper
}, },
"-servo-anonymous-table" => { "-servo-anonymous-table" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoAnonymousTable ServoAnonymousTable
}, },
"-servo-anonymous-table-row" => { "-servo-anonymous-table-row" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoAnonymousTableRow ServoAnonymousTableRow
}, },
"-servo-anonymous-table-cell" => { "-servo-anonymous-table-cell" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoAnonymousTableCell ServoAnonymousTableCell
}, },
"-servo-anonymous-block" => { "-servo-anonymous-block" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoAnonymousBlock ServoAnonymousBlock
}, },
"-servo-inline-block-wrapper" => { "-servo-inline-block-wrapper" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoInlineBlockWrapper ServoInlineBlockWrapper
}, },
"-servo-input-absolute" => { "-servo-input-absolute" => {
if !self.in_user_agent_stylesheet() { if !self.in_user_agent_stylesheet() {
return Err(()) return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
} }
ServoInlineAbsolute ServoInlineAbsolute
}, },
_ => return Err(()) _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
}; };
Ok(pseudo_element) Ok(pseudo_element)

View file

@ -13,7 +13,7 @@ use std::fmt::{self, Write};
// nonzero optimization is important in keeping the size of SpecifiedUrl below // nonzero optimization is important in keeping the size of SpecifiedUrl below
// the threshold. // the threshold.
use std::sync::Arc; use std::sync::Arc;
use style_traits::ToCss; use style_traits::{ToCss, ParseError};
/// A specified url() value for servo. /// A specified url() value for servo.
/// ///
@ -43,7 +43,7 @@ impl SpecifiedUrl {
/// gecko version. /// gecko version.
pub fn parse_from_string<'a>(url: Cow<'a, str>, pub fn parse_from_string<'a>(url: Cow<'a, str>,
context: &ParserContext) context: &ParserContext)
-> Result<Self, ()> { -> Result<Self, ParseError<'a>> {
let serialization = Arc::new(url.into_owned()); let serialization = Arc::new(url.into_owned());
let resolved = context.url_data.join(&serialization).ok(); let resolved = context.url_data.join(&serialization).ok();
Ok(SpecifiedUrl { Ok(SpecifiedUrl {

View file

@ -6,12 +6,12 @@
//! initially in CSS Conditional Rules Module Level 3, @document has been postponed to the level 4. //! initially in CSS Conditional Rules Module Level 3, @document has been postponed to the level 4.
//! We implement the prefixed `@-moz-document`. //! We implement the prefixed `@-moz-document`.
use cssparser::{Parser, Token, SourceLocation}; use cssparser::{Parser, Token, SourceLocation, BasicParseError};
use media_queries::Device; use media_queries::Device;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use stylearc::Arc; use stylearc::Arc;
use stylesheets::CssRules; use stylesheets::CssRules;
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
@ -90,9 +90,10 @@ macro_rules! parse_quoted_or_unquoted_string {
match input.next() { match input.next() {
Ok(Token::QuotedString(value)) => Ok(Token::QuotedString(value)) =>
Ok($url_matching_function(value.into_owned())), 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() {} while let Ok(_) = input.next() {}
Ok($url_matching_function(input.slice_from(start).to_string())) Ok($url_matching_function(input.slice_from(start).to_string()))
}) })
@ -102,8 +103,8 @@ macro_rules! parse_quoted_or_unquoted_string {
impl UrlMatchingFunction { impl UrlMatchingFunction {
/// Parse a URL matching function for a`@document` rule's condition. /// Parse a URL matching function for a`@document` rule's condition.
pub fn parse(context: &ParserContext, input: &mut Parser) pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<UrlMatchingFunction, ()> { -> Result<UrlMatchingFunction, ParseError<'i>> {
if input.try(|input| input.expect_function_matching("url-prefix")).is_ok() { if input.try(|input| input.expect_function_matching("url-prefix")).is_ok() {
parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix) parse_quoted_or_unquoted_string!(input, UrlMatchingFunction::UrlPrefix)
} else if input.try(|input| input.expect_function_matching("domain")).is_ok() { } 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)) { } else if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
Ok(UrlMatchingFunction::Url(url)) Ok(UrlMatchingFunction::Url(url))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -189,8 +190,8 @@ pub struct DocumentCondition(Vec<UrlMatchingFunction>);
impl DocumentCondition { impl DocumentCondition {
/// Parse a document condition. /// Parse a document condition.
pub fn parse(context: &ParserContext, input: &mut Parser) pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
input.parse_comma_separated(|input| UrlMatchingFunction::parse(context, input)) input.parse_comma_separated(|input| UrlMatchingFunction::parse(context, input))
.map(DocumentCondition) .map(DocumentCondition)
} }

View file

@ -4,18 +4,20 @@
//! Keyframes: https://drafts.csswg.org/css-animations/#keyframes //! 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 cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation};
use error_reporting::{NullReporter, ParseError}; use error_reporting::{NullReporter, ContextualParseError};
use parser::{PARSING_MODE_DEFAULT, ParserContext, log_css_error}; use parser::{PARSING_MODE_DEFAULT, ParserContext, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, SourcePropertyDeclaration}; use properties::{PropertyDeclarationId, LonghandId, SourcePropertyDeclaration};
use properties::LonghandIdSet; use properties::LonghandIdSet;
use properties::animated_properties::TransitionProperty; use properties::animated_properties::TransitionProperty;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use selectors::parser::SelectorParseError;
use shared_lock::{DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard}; use shared_lock::{DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard};
use std::borrow::Cow;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use stylearc::Arc; use stylearc::Arc;
use stylesheets::{CssRuleType, Stylesheet}; use stylesheets::{CssRuleType, Stylesheet};
use stylesheets::rule_parser::VendorPrefix; use stylesheets::rule_parser::VendorPrefix;
@ -61,7 +63,8 @@ impl KeyframesRule {
/// Related spec: /// Related spec:
/// https://drafts.csswg.org/css-animations-1/#interface-csskeyframesrule-findrule /// https://drafts.csswg.org/css-animations-1/#interface-csskeyframesrule-findrule
pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> { pub fn find_rule(&self, guard: &SharedRwLockReadGuard, selector: &str) -> Option<usize> {
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() { for (i, keyframe) in self.keyframes.iter().enumerate().rev() {
if keyframe.read_with(guard).selector == selector { if keyframe.read_with(guard).selector == selector {
return Some(i); return Some(i);
@ -120,7 +123,7 @@ impl KeyframePercentage {
KeyframePercentage(value) KeyframePercentage(value)
} }
fn parse(input: &mut Parser) -> Result<KeyframePercentage, ()> { fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<KeyframePercentage, ParseError<'i>> {
let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() { let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
KeyframePercentage::new(0.) KeyframePercentage::new(0.)
} else if input.try(|input| input.expect_ident_matching("to")).is_ok() { } else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
@ -130,7 +133,7 @@ impl KeyframePercentage {
if percentage >= 0. && percentage <= 1. { if percentage >= 0. && percentage <= 1. {
KeyframePercentage::new(percentage) KeyframePercentage::new(percentage)
} else { } else {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
}; };
@ -168,7 +171,7 @@ impl KeyframeSelector {
} }
/// Parse a keyframe selector from CSS input. /// Parse a keyframe selector from CSS input.
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.parse_comma_separated(KeyframePercentage::parse) input.parse_comma_separated(KeyframePercentage::parse)
.map(KeyframeSelector) .map(KeyframeSelector)
} }
@ -200,8 +203,8 @@ impl ToCssWithGuard for Keyframe {
impl Keyframe { impl Keyframe {
/// Parse a CSS keyframe. /// Parse a CSS keyframe.
pub fn parse(css: &str, parent_stylesheet: &Stylesheet) pub fn parse<'i>(css: &'i str, parent_stylesheet: &Stylesheet)
-> Result<Arc<Locked<Self>>, ()> { -> Result<Arc<Locked<Self>>, ParseError<'i>> {
let error_reporter = NullReporter; let error_reporter = NullReporter;
let context = ParserContext::new(parent_stylesheet.origin, let context = ParserContext::new(parent_stylesheet.origin,
&parent_stylesheet.url_data, &parent_stylesheet.url_data,
@ -209,7 +212,8 @@ impl Keyframe {
Some(CssRuleType::Keyframe), Some(CssRuleType::Keyframe),
PARSING_MODE_DEFAULT, PARSING_MODE_DEFAULT,
parent_stylesheet.quirks_mode); 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 declarations = SourcePropertyDeclaration::new();
let mut rule_parser = KeyframeListParser { let mut rule_parser = KeyframeListParser {
@ -445,29 +449,31 @@ pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser, shared_l
} }
enum Void {} enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> { impl<'a, 'i> AtRuleParser<'i> for KeyframeListParser<'a> {
type Prelude = Void; type Prelude = Void;
type AtRule = Arc<Locked<Keyframe>>; type AtRule = Arc<Locked<Keyframe>>;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
} }
impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> {
type Prelude = KeyframeSelector; type Prelude = KeyframeSelector;
type QualifiedRule = Arc<Locked<Keyframe>>; type QualifiedRule = Arc<Locked<Keyframe>>;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> { fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>) -> Result<Self::Prelude, ParseError<'i>> {
let start = input.position(); let start = input.position();
match KeyframeSelector::parse(input) { match KeyframeSelector::parse(input) {
Ok(sel) => Ok(sel), Ok(sel) => Ok(sel),
Err(()) => { Err(e) => {
let error = ParseError::InvalidKeyframeRule(input.slice_from(start)); let error = ContextualParseError::InvalidKeyframeRule(input.slice_from(start), e.clone());
log_css_error(input, start, error, self.context); log_css_error(input, start, error, self.context);
Err(()) Err(e)
} }
} }
} }
fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser) fn parse_block<'t>(&mut self, prelude: Self::Prelude, input: &mut Parser<'i, 't>)
-> Result<Self::QualifiedRule, ()> { -> Result<Self::QualifiedRule, ParseError<'i>> {
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Keyframe)); let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Keyframe));
let parser = KeyframeDeclarationParser { let parser = KeyframeDeclarationParser {
context: &context, context: &context,
@ -480,10 +486,11 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
Ok(()) => { Ok(()) => {
block.extend(iter.parser.declarations.drain(), Importance::Normal); block.extend(iter.parser.declarations.drain(), Importance::Normal);
} }
Err(range) => { Err(err) => {
iter.parser.declarations.clear(); iter.parser.declarations.clear();
let pos = range.start; let pos = err.span.start;
let error = ParseError::UnsupportedKeyframePropertyDeclaration(iter.input.slice(range)); let error = ContextualParseError::UnsupportedKeyframePropertyDeclaration(
iter.input.slice(err.span), err.error);
log_css_error(iter.input, pos, error, &context); log_css_error(iter.input, pos, error, &context);
} }
} }
@ -502,22 +509,25 @@ struct KeyframeDeclarationParser<'a, 'b: 'a> {
} }
/// Default methods reject all at rules. /// 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 Prelude = ();
type AtRule = (); 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 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())); let id = try!(PropertyId::parse(name.into()));
match PropertyDeclaration::parse_into(self.declarations, id, self.context, input) { match PropertyDeclaration::parse_into(self.declarations, id, self.context, input) {
Ok(()) => { Ok(()) => {
// In case there is still unparsed text in the declaration, we should roll back. // 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())
} }
} }
} }

View file

@ -22,7 +22,7 @@ mod stylesheet;
pub mod supports_rule; pub mod supports_rule;
pub mod viewport_rule; pub mod viewport_rule;
use cssparser::{parse_one_rule, Parser}; use cssparser::{parse_one_rule, Parser, ParserInput};
use error_reporting::NullReporter; use error_reporting::NullReporter;
use parser::{ParserContext, PARSING_MODE_DEFAULT}; use parser::{ParserContext, PARSING_MODE_DEFAULT};
use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
@ -234,7 +234,8 @@ impl CssRule {
parent_stylesheet.quirks_mode 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(); let mut guard = parent_stylesheet.namespaces.write();

View file

@ -7,7 +7,7 @@
use {Namespace, Prefix}; use {Namespace, Prefix};
use counter_style::{parse_counter_style_body, parse_counter_style_name}; use counter_style::{parse_counter_style_body, parse_counter_style_name};
use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser, SourceLocation}; use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser, SourceLocation};
use error_reporting::ParseError; use error_reporting::ContextualParseError;
use font_face::parse_font_face_block; use font_face::parse_font_face_block;
use media_queries::{parse_media_query_list, MediaList}; use media_queries::{parse_media_query_list, MediaList};
use parking_lot::RwLock; use parking_lot::RwLock;
@ -15,9 +15,12 @@ use parser::{Parse, ParserContext, log_css_error};
use properties::parse_property_declaration_list; use properties::parse_property_declaration_list;
use selector_parser::{SelectorImpl, SelectorParser}; use selector_parser::{SelectorImpl, SelectorParser};
use selectors::SelectorList; use selectors::SelectorList;
use selectors::parser::SelectorParseError;
use shared_lock::{Locked, SharedRwLock}; use shared_lock::{Locked, SharedRwLock};
use std::borrow::Cow;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use str::starts_with_ignore_ascii_case; use str::starts_with_ignore_ascii_case;
use style_traits::{StyleParseError, ParseError};
use stylearc::Arc; use stylearc::Arc;
use stylesheets::{CssRule, CssRules, CssRuleType, Origin, StylesheetLoader}; use stylesheets::{CssRule, CssRules, CssRuleType, Origin, StylesheetLoader};
use stylesheets::{DocumentRule, ImportRule, KeyframesRule, MediaRule, NamespaceRule, PageRule}; use stylesheets::{DocumentRule, ImportRule, KeyframesRule, MediaRule, NamespaceRule, PageRule};
@ -133,22 +136,24 @@ fn register_namespace(_: &Namespace) -> Result<(), ()> {
Ok(()) // servo doesn't use namespace ids 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 Prelude = AtRulePrelude;
type AtRule = CssRule; type AtRule = CssRule;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
fn parse_prelude( fn parse_prelude<'t>(
&mut self, &mut self,
name: &str, name: Cow<'i, str>,
input: &mut Parser input: &mut Parser<'i, 't>
) -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> { ) -> Result<AtRuleType<AtRulePrelude, CssRule>, ParseError<'i>> {
let location = get_location_with_offset(input.current_source_location(), let location = get_location_with_offset(input.current_source_location(),
self.context.line_number_offset); self.context.line_number_offset);
match_ignore_ascii_case! { name, match_ignore_ascii_case! { &*name,
"import" => { "import" => {
if self.state > State::Imports { if self.state > State::Imports {
self.state = State::Invalid; 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; self.state = State::Imports;
@ -191,14 +196,16 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
"namespace" => { "namespace" => {
if self.state > State::Namespaces { if self.state > State::Namespaces {
self.state = State::Invalid; 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; self.state = State::Namespaces;
let prefix_result = input.try(|input| input.expect_ident()); let prefix_result = input.try(|input| input.expect_ident());
let url = Namespace::from(try!(input.expect_url_or_string())); 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(); let mut namespaces = self.namespaces.as_mut().unwrap();
@ -223,13 +230,13 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
}, },
// @charset is removed by rust-cssparser if its the first rule in the stylesheet // @charset is removed by rust-cssparser if its the first rule in the stylesheet
// anything left is invalid. // 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 // Don't allow starting with an invalid state
if self.state > State::Body { if self.state > State::Body {
self.state = State::Invalid; self.state = State::Invalid;
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
self.state = State::Body; self.state = State::Body;
@ -243,18 +250,21 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
} }
#[inline] #[inline]
fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> { fn parse_block<'t>(&mut self, prelude: AtRulePrelude, input: &mut Parser<'i, 't>)
-> Result<CssRule, ParseError<'i>> {
AtRuleParser::parse_block(&mut self.nested(), prelude, input) 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<SelectorImpl>; type Prelude = SelectorList<SelectorImpl>;
type QualifiedRule = CssRule; type QualifiedRule = CssRule;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
#[inline] #[inline]
fn parse_prelude(&mut self, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> { fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>)
-> Result<SelectorList<SelectorImpl>, ParseError<'i>> {
self.state = State::Body; self.state = State::Body;
// "Freeze" the namespace map (no more namespace rules can be parsed // "Freeze" the namespace map (no more namespace rules can be parsed
@ -268,11 +278,11 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
} }
#[inline] #[inline]
fn parse_block( fn parse_block<'t>(
&mut self, &mut self,
prelude: SelectorList<SelectorImpl>, prelude: SelectorList<SelectorImpl>,
input: &mut Parser input: &mut Parser<'i, 't>
) -> Result<CssRule, ()> { ) -> Result<CssRule, ParseError<'i>> {
QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input) QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input)
} }
} }
@ -303,9 +313,10 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> {
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
match result { match result {
Ok(rule) => rules.push(rule), Ok(rule) => rules.push(rule),
Err(range) => { Err(err) => {
let pos = range.start; let pos = err.span.start;
let error = ParseError::UnsupportedRule(iter.input.slice(range)); let error = ContextualParseError::UnsupportedRule(
iter.input.slice(err.span), err.error);
log_css_error(iter.input, pos, error, self.context); log_css_error(iter.input, pos, error, self.context);
} }
} }
@ -325,22 +336,23 @@ fn is_viewport_enabled() -> bool {
false // Gecko doesn't support @viewport. 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 Prelude = AtRulePrelude;
type AtRule = CssRule; type AtRule = CssRule;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
fn parse_prelude( fn parse_prelude<'t>(
&mut self, &mut self,
name: &str, name: Cow<'i, str>,
input: &mut Parser input: &mut Parser<'i, 't>
) -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> { ) -> Result<AtRuleType<AtRulePrelude, CssRule>, ParseError<'i>> {
let location = let location =
get_location_with_offset( get_location_with_offset(
input.current_source_location(), input.current_source_location(),
self.context.line_number_offset self.context.line_number_offset
); );
match_ignore_ascii_case! { name, match_ignore_ascii_case! { &*name,
"media" => { "media" => {
let media_queries = parse_media_query_list(self.context, input); let media_queries = parse_media_query_list(self.context, input);
let arc = Arc::new(self.shared_lock.wrap(media_queries)); let arc = Arc::new(self.shared_lock.wrap(media_queries));
@ -356,14 +368,14 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
"counter-style" => { "counter-style" => {
if !cfg!(feature = "gecko") { if !cfg!(feature = "gecko") {
// Support for this rule is not fully implemented in Servo yet. // 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)?; let name = parse_counter_style_name(input)?;
// ASCII-case-insensitive matches for "decimal" are already // ASCII-case-insensitive matches for "decimal" are already
// lower-cased by `parse_counter_style_name`, so we can use == // lower-cased by `parse_counter_style_name`, so we can use ==
// here. // here.
if name.0 == atom!("decimal") { if name.0 == atom!("decimal") {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(AtRuleType::WithBlock(AtRulePrelude::CounterStyle(name))) Ok(AtRuleType::WithBlock(AtRulePrelude::CounterStyle(name)))
}, },
@ -371,13 +383,13 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
if is_viewport_enabled() { if is_viewport_enabled() {
Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport)) Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport))
} else { } else {
Err(()) Err(StyleParseError::UnsupportedAtRule(name.clone()).into())
} }
}, },
"keyframes" | "-webkit-keyframes" | "-moz-keyframes" => { "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) Some(VendorPrefix::WebKit)
} else if starts_with_ignore_ascii_case(name, "-moz-") { } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
Some(VendorPrefix::Moz) Some(VendorPrefix::Moz)
} else { } else {
None None
@ -385,7 +397,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
if cfg!(feature = "servo") && if cfg!(feature = "servo") &&
prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) { prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) {
// Servo should not support @-moz-keyframes. // Servo should not support @-moz-keyframes.
return Err(()) return Err(StyleParseError::UnsupportedAtRule(name.clone()).into())
} }
let name = KeyframesName::parse(self.context, input)?; let name = KeyframesName::parse(self.context, input)?;
@ -395,7 +407,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
if cfg!(feature = "gecko") { if cfg!(feature = "gecko") {
Ok(AtRuleType::WithBlock(AtRulePrelude::Page(location))) Ok(AtRuleType::WithBlock(AtRulePrelude::Page(location)))
} else { } else {
Err(()) Err(StyleParseError::UnsupportedAtRule(name.clone()).into())
} }
}, },
"-moz-document" => { "-moz-document" => {
@ -403,18 +415,18 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
let cond = DocumentCondition::parse(self.context, input)?; let cond = DocumentCondition::parse(self.context, input)?;
Ok(AtRuleType::WithBlock(AtRulePrelude::Document(cond, location))) Ok(AtRuleType::WithBlock(AtRulePrelude::Document(cond, location)))
} else { } else {
Err(()) Err(StyleParseError::UnsupportedAtRule(name.clone()).into())
} }
}, },
_ => Err(()) _ => Err(StyleParseError::UnsupportedAtRule(name.clone()).into())
} }
} }
fn parse_block( fn parse_block<'t>(
&mut self, &mut self,
prelude: AtRulePrelude, prelude: AtRulePrelude,
input: &mut Parser input: &mut Parser<'i, 't>
) -> Result<CssRule, ()> { ) -> Result<CssRule, ParseError<'i>> {
match prelude { match prelude {
AtRulePrelude::FontFace(location) => { AtRulePrelude::FontFace(location) => {
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::FontFace)); let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::FontFace));
@ -479,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<SelectorImpl>; type Prelude = SelectorList<SelectorImpl>;
type QualifiedRule = CssRule; type QualifiedRule = CssRule;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
fn parse_prelude(&mut self, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> { fn parse_prelude<'t>(&mut self, input: &mut Parser<'i, 't>)
-> Result<SelectorList<SelectorImpl>, ParseError<'i>> {
let selector_parser = SelectorParser { let selector_parser = SelectorParser {
stylesheet_origin: self.stylesheet_origin, stylesheet_origin: self.stylesheet_origin,
namespaces: self.context.namespaces.unwrap(), namespaces: self.context.namespaces.unwrap(),
@ -492,11 +506,11 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
SelectorList::parse(&selector_parser, input) SelectorList::parse(&selector_parser, input)
} }
fn parse_block( fn parse_block<'t>(
&mut self, &mut self,
prelude: SelectorList<SelectorImpl>, prelude: SelectorList<SelectorImpl>,
input: &mut Parser input: &mut Parser<'i, 't>
) -> Result<CssRule, ()> { ) -> Result<CssRule, ParseError<'i>> {
let location = get_location_with_offset(input.current_source_location(), let location = get_location_with_offset(input.current_source_location(),
self.context.line_number_offset); self.context.line_number_offset);
let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Style)); let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Style));

View file

@ -4,8 +4,8 @@
use {Prefix, Namespace}; use {Prefix, Namespace};
use context::QuirksMode; use context::QuirksMode;
use cssparser::{Parser, RuleListParser}; use cssparser::{Parser, RuleListParser, ParserInput};
use error_reporting::{ParseErrorReporter, ParseError}; use error_reporting::{ParseErrorReporter, ContextualParseError};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use media_queries::{MediaList, Device}; use media_queries::{MediaList, Device};
use parking_lot::RwLock; use parking_lot::RwLock;
@ -110,7 +110,8 @@ impl Stylesheet {
line_number_offset: u64 line_number_offset: u64
) -> (Vec<CssRule>, bool) { ) -> (Vec<CssRule>, bool) {
let mut rules = Vec::new(); 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 = let context =
ParserContext::new_with_line_number_offset( ParserContext::new_with_line_number_offset(
@ -140,9 +141,10 @@ impl Stylesheet {
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
match result { match result {
Ok(rule) => rules.push(rule), Ok(rule) => rules.push(rule),
Err(range) => { Err(err) => {
let pos = range.start; let pos = err.span.start;
let error = ParseError::InvalidRule(iter.input.slice(range)); let error = ContextualParseError::InvalidRule(
iter.input.slice(err.span), err.error);
log_css_error(iter.input, pos, error, iter.parser.context()); log_css_error(iter.input, pos, error, iter.parser.context());
} }
} }

View file

@ -4,12 +4,14 @@
//! [@supports rules](https://drafts.csswg.org/css-conditional-3/#at-supports) //! [@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 cssparser::{Delimiter, parse_important, Parser, SourceLocation, Token};
use parser::ParserContext; use parser::ParserContext;
use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration}; use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
use selectors::parser::SelectorParseError;
use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use stylearc::Arc; use stylearc::Arc;
use stylesheets::{CssRuleType, CssRules}; use stylesheets::{CssRuleType, CssRules};
@ -81,7 +83,7 @@ impl SupportsCondition {
/// Parse a condition /// Parse a condition
/// ///
/// https://drafts.csswg.org/css-conditional/#supports_condition /// https://drafts.csswg.org/css-conditional/#supports_condition
pub fn parse(input: &mut Parser) -> Result<SupportsCondition, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) { if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) {
let inner = SupportsCondition::parse_in_parens(input)?; let inner = SupportsCondition::parse_in_parens(input)?;
return Ok(SupportsCondition::Not(Box::new(inner))); return Ok(SupportsCondition::Not(Box::new(inner)));
@ -90,7 +92,7 @@ impl SupportsCondition {
let in_parens = SupportsCondition::parse_in_parens(input)?; let in_parens = SupportsCondition::parse_in_parens(input)?;
let (keyword, wrapper) = match input.next() { let (keyword, wrapper) = match input.next() {
Err(()) => { Err(_) => {
// End of input // End of input
return Ok(in_parens) return Ok(in_parens)
} }
@ -98,10 +100,10 @@ impl SupportsCondition {
match_ignore_ascii_case! { &ident, match_ignore_ascii_case! { &ident,
"and" => ("and", SupportsCondition::And as fn(_) -> _), "and" => ("and", SupportsCondition::And as fn(_) -> _),
"or" => ("or", SupportsCondition::Or 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); let mut conditions = Vec::with_capacity(2);
@ -118,7 +120,7 @@ impl SupportsCondition {
} }
/// https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens /// https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens
fn parse_in_parens(input: &mut Parser) -> Result<SupportsCondition, ()> { fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
// Whitespace is normally taken care of in `Parser::next`, // Whitespace is normally taken care of in `Parser::next`,
// but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases. // but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases.
while input.try(Parser::expect_whitespace).is_ok() {} while input.try(Parser::expect_whitespace).is_ok() {}
@ -127,17 +129,18 @@ impl SupportsCondition {
Token::ParenthesisBlock => { Token::ParenthesisBlock => {
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
// `input.try()` not needed here since the alternative uses `consume_all()`. // `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); consume_all(input);
Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned())) Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned()))
}) })
}) })
} }
Token::Function(_) => { 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())) 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 /// supports_condition | declaration
/// https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext /// https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext
pub fn parse_condition_or_declaration(input: &mut Parser) -> Result<SupportsCondition, ()> { pub fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>)
-> Result<SupportsCondition, ParseError<'i>> {
if let Ok(condition) = input.try(SupportsCondition::parse) { if let Ok(condition) = input.try(SupportsCondition::parse) {
Ok(SupportsCondition::Parenthesized(Box::new(condition))) Ok(SupportsCondition::Parenthesized(Box::new(condition)))
} else { } else {
@ -244,7 +248,7 @@ fn consume_all(input: &mut Parser) {
impl Declaration { impl Declaration {
/// Parse a declaration /// Parse a declaration
pub fn parse(input: &mut Parser) -> Result<Declaration, ()> { pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Declaration, ParseError<'i>> {
let prop = input.expect_ident()?.into_owned(); let prop = input.expect_ident()?.into_owned();
input.expect_colon()?; input.expect_colon()?;
let val = parse_anything(input); let val = parse_anything(input);
@ -260,12 +264,13 @@ impl Declaration {
} else { } else {
return false 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 context = ParserContext::new_with_rule_type(cx, Some(CssRuleType::Style));
let mut declarations = SourcePropertyDeclaration::new(); let mut declarations = SourcePropertyDeclaration::new();
let res = input.parse_until_before(Delimiter::Bang, |input| { let res = input.parse_until_before(Delimiter::Bang, |input| {
PropertyDeclaration::parse_into(&mut declarations, id, &context, input) PropertyDeclaration::parse_into(&mut declarations, id, &context, input)
.map_err(|_| ()) .map_err(|e| StyleParseError::PropertyDeclaration(e).into())
}); });
let _ = input.try(parse_important); let _ = input.try(parse_important);
res.is_ok() && input.is_exhausted() res.is_ok() && input.is_exhausted()

View file

@ -11,19 +11,20 @@ use app_units::Au;
use context::QuirksMode; use context::QuirksMode;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important}; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
use cssparser::ToCss as ParserToCss; use cssparser::ToCss as ParserToCss;
use error_reporting::ParseError; use error_reporting::ContextualParseError;
use euclid::size::TypedSize2D; use euclid::size::TypedSize2D;
use font_metrics::get_metrics_provider_for_product; use font_metrics::get_metrics_provider_for_product;
use media_queries::Device; use media_queries::Device;
use parser::{Parse, ParserContext, log_css_error}; use parser::{Parse, ParserContext, log_css_error};
use properties::StyleBuilder; use properties::StyleBuilder;
use selectors::parser::SelectorParseError;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::iter::Enumerate; use std::iter::Enumerate;
use std::str::Chars; 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 style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
use stylearc::Arc; use stylearc::Arc;
use stylesheets::{Stylesheet, Origin}; use stylesheets::{Stylesheet, Origin};
@ -168,7 +169,8 @@ impl FromMeta for ViewportLength {
} }
impl ViewportLength { impl ViewportLength {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
// we explicitly do not accept 'extend-to-zoom', since it is a UA // we explicitly do not accept 'extend-to-zoom', since it is a UA
// internal value for <META> viewport translation // internal value for <META> viewport translation
LengthOrPercentageOrAuto::parse_non_negative(context, input).map(ViewportLength::Specified) LengthOrPercentageOrAuto::parse_non_negative(context, input).map(ViewportLength::Specified)
@ -247,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)); let min = try!(ViewportLength::parse(context, input));
match input.try(|i| ViewportLength::parse(context, i)) { match input.try(|i| ViewportLength::parse(context, i)) {
Err(()) => Ok((min.clone(), min)), Err(_) => Ok((min.clone(), min)),
Ok(max) => Ok((min, max)) 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 Prelude = ();
type AtRule = Vec<ViewportDescriptorDeclaration>; type AtRule = Vec<ViewportDescriptorDeclaration>;
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<ViewportDescriptorDeclaration>; type Declaration = Vec<ViewportDescriptorDeclaration>;
type Error = SelectorParseError<'i, StyleParseError<'i>>;
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Vec<ViewportDescriptorDeclaration>, ()> { fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>)
-> Result<Vec<ViewportDescriptorDeclaration>, ParseError<'i>> {
macro_rules! declaration { macro_rules! declaration {
($declaration:ident($parse:expr)) => { ($declaration:ident($parse:expr)) => {
declaration!($declaration(value: try!($parse(input)), declaration!($declaration(value: try!($parse(input)),
@ -290,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))), "min-width" => ok!(MinWidth(|i| ViewportLength::parse(self.context, i))),
"max-width" => ok!(MaxWidth(|i| ViewportLength::parse(self.context, i))), "max-width" => ok!(MaxWidth(|i| ViewportLength::parse(self.context, i))),
"width" => ok!(shorthand -> [MinWidth, MaxWidth]), "width" => ok!(shorthand -> [MinWidth, MaxWidth]),
@ -302,7 +308,7 @@ impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> {
"max-zoom" => ok!(MaxZoom(Zoom::parse)), "max-zoom" => ok!(MaxZoom(Zoom::parse)),
"user-zoom" => ok!(UserZoom(UserZoom::parse)), "user-zoom" => ok!(UserZoom(UserZoom::parse)),
"orientation" => ok!(Orientation(Orientation::parse)), "orientation" => ok!(Orientation(Orientation::parse)),
_ => Err(()), _ => Err(SelectorParseError::UnexpectedIdent(name.clone()).into()),
} }
} }
} }
@ -329,7 +335,7 @@ fn is_whitespace_separator_or_equals(c: &char) -> bool {
} }
impl Parse for ViewportRule { impl Parse for ViewportRule {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let parser = ViewportRuleParser { context: context }; let parser = ViewportRuleParser { context: context };
let mut cascade = Cascade::new(); let mut cascade = Cascade::new();
@ -341,9 +347,10 @@ impl Parse for ViewportRule {
cascade.add(Cow::Owned(declarations)) cascade.add(Cow::Owned(declarations))
} }
} }
Err(range) => { Err(err) => {
let pos = range.start; let pos = err.span.start;
let error = ParseError::UnsupportedViewportDescriptorDeclaration(parser.input.slice(range)); let error = ContextualParseError::UnsupportedViewportDescriptorDeclaration(
parser.input.slice(err.span), err.error);
log_css_error(parser.input, pos, error, &context); log_css_error(parser.input, pos, error, &context);
} }
} }

View file

@ -7,8 +7,9 @@
use cssparser::{Parser, serialize_identifier}; use cssparser::{Parser, serialize_identifier};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use std::{fmt, mem, usize}; use std::{fmt, mem, usize};
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use values::{CSSFloat, CustomIdent}; use values::{CSSFloat, CustomIdent};
use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue}; use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::Integer; use values::specified::Integer;
@ -70,7 +71,7 @@ impl ToCss for GridLine {
} }
impl Parse for GridLine { impl Parse for GridLine {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let mut grid_line = Default::default(); let mut grid_line = Default::default();
if input.try(|i| i.expect_ident_matching("auto")).is_ok() { if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(grid_line) return Ok(grid_line)
@ -85,7 +86,7 @@ impl Parse for GridLine {
for _ in 0..3 { // Maximum possible entities for <grid-line> for _ in 0..3 { // Maximum possible entities for <grid-line>
if input.try(|i| i.expect_ident_matching("span")).is_ok() { if input.try(|i| i.expect_ident_matching("span")).is_ok() {
if grid_line.is_span { if grid_line.is_span {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
if grid_line.line_num.is_some() || grid_line.ident.is_some() { 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; grid_line.is_span = true;
} else if let Ok(i) = input.try(|i| Integer::parse(context, i)) { } 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() { 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); grid_line.line_num = Some(i);
} else if let Ok(name) = input.try(|i| i.expect_ident()) { } else if let Ok(name) = input.try(|i| i.expect_ident()) {
if val_before_span || grid_line.ident.is_some() || if val_before_span || grid_line.ident.is_some() ||
CustomIdent::from_ident((&*name).into(), &[]).is_err() { CustomIdent::from_ident((&*name).into(), &[]).is_err() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
grid_line.ident = Some(name.into_owned()); grid_line.ident = Some(name.into_owned());
@ -112,18 +113,18 @@ impl Parse for GridLine {
} }
if grid_line.is_auto() { if grid_line.is_auto() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
if grid_line.is_span { if grid_line.is_span {
if let Some(i) = grid_line.line_num { if let Some(i) = grid_line.line_num {
if i.value() <= 0 { // disallow negative integers for grid spans 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 } else if grid_line.ident.is_some() { // integer could be omitted
grid_line.line_num = Some(Integer::new(1)); grid_line.line_num = Some(Integer::new(1));
} else { } else {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -341,19 +342,20 @@ pub enum RepeatCount {
} }
impl Parse for RepeatCount { impl Parse for RepeatCount {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(i) = input.try(|i| Integer::parse(context, i)) { if let Ok(i) = input.try(|i| Integer::parse(context, i)) {
if i.value() > 0 { if i.value() > 0 {
Ok(RepeatCount::Number(i)) Ok(RepeatCount::Number(i))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} else { } else {
match_ignore_ascii_case! { &input.expect_ident()?, let ident = input.expect_ident()?;
(match_ignore_ascii_case! { &ident,
"auto-fill" => Ok(RepeatCount::AutoFill), "auto-fill" => Ok(RepeatCount::AutoFill),
"auto-fit" => Ok(RepeatCount::AutoFit), "auto-fit" => Ok(RepeatCount::AutoFit),
_ => Err(()), _ => Err(()),
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
} }

View file

@ -8,8 +8,9 @@
use counter_style::{Symbols, parse_counter_style_name}; use counter_style::{Symbols, parse_counter_style_name};
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use std::fmt; use std::fmt;
use style_traits::{OneOrMoreCommaSeparated, ToCss}; use style_traits::{OneOrMoreCommaSeparated, ToCss, ParseError, StyleParseError};
use super::CustomIdent; use super::CustomIdent;
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
@ -79,7 +80,7 @@ impl CounterStyleOrNone {
no_viewport_percentage!(CounterStyleOrNone); no_viewport_percentage!(CounterStyleOrNone);
impl Parse for CounterStyleOrNone { impl Parse for CounterStyleOrNone {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(name) = input.try(|i| parse_counter_style_name(i)) { if let Ok(name) = input.try(|i| parse_counter_style_name(i)) {
return Ok(CounterStyleOrNone::Name(name)); return Ok(CounterStyleOrNone::Name(name));
} }
@ -95,16 +96,16 @@ impl Parse for CounterStyleOrNone {
// numeric system. // numeric system.
if (symbols_type == SymbolsType::Alphabetic || if (symbols_type == SymbolsType::Alphabetic ||
symbols_type == SymbolsType::Numeric) && symbols.0.len() < 2 { symbols_type == SymbolsType::Numeric) && symbols.0.len() < 2 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
// Identifier is not allowed in symbols() function. // Identifier is not allowed in symbols() function.
if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) { if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(CounterStyleOrNone::Symbols(symbols_type, symbols)) Ok(CounterStyleOrNone::Symbols(symbols_type, symbols))
}); });
} }
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -159,7 +160,7 @@ impl<T: Parse> Parse for FontSettingTag<T> {
/// settings-control-the-font-variation-settings-property /// settings-control-the-font-variation-settings-property
/// <string> [ on | off | <integer> ] /// <string> [ on | off | <integer> ]
/// <string> <number> /// <string> <number>
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
use byteorder::{ReadBytesExt, BigEndian}; use byteorder::{ReadBytesExt, BigEndian};
use std::io::Cursor; use std::io::Cursor;
@ -169,7 +170,7 @@ impl<T: Parse> Parse for FontSettingTag<T> {
if tag.len() != 4 || if tag.len() != 4 ||
tag.chars().any(|c| c < ' ' || c > '~') tag.chars().any(|c| c < ' ' || c > '~')
{ {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
let mut raw = Cursor::new(tag.as_bytes()); let mut raw = Cursor::new(tag.as_bytes());
@ -192,7 +193,7 @@ pub enum FontSettings<T> {
impl<T: Parse> Parse for FontSettings<T> { impl<T: Parse> Parse for FontSettings<T> {
/// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("normal")).is_ok() { if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(FontSettings::Normal); return Ok(FontSettings::Normal);
} }
@ -227,13 +228,13 @@ impl ToCss for FontSettingTagInt {
} }
impl Parse for FontSettingTagInt { impl Parse for FontSettingTagInt {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(value) = input.try(|input| input.expect_integer()) { if let Ok(value) = input.try(|input| input.expect_integer()) {
// handle integer, throw if it is negative // handle integer, throw if it is negative
if value >= 0 { if value >= 0 {
Ok(FontSettingTagInt(value as u32)) Ok(FontSettingTagInt(value as u32))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) { } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) {
// on is an alias for '1' // on is an alias for '1'
@ -250,8 +251,8 @@ impl Parse for FontSettingTagInt {
impl Parse for FontSettingTagFloat { impl Parse for FontSettingTagFloat {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.expect_number().map(FontSettingTagFloat) input.expect_number().map(FontSettingTagFloat).map_err(|e| e.into())
} }
} }
@ -326,18 +327,19 @@ impl<ColorType> SVGPaint<ColorType> {
impl<ColorType> SVGPaintKind<ColorType> { impl<ColorType> SVGPaintKind<ColorType> {
/// Parse a keyword value only /// Parse a keyword value only
fn parse_ident(input: &mut Parser) -> Result<Self, ()> { fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Ok(match_ignore_ascii_case! { &input.expect_ident()?, let ident = input.expect_ident()?;
"none" => SVGPaintKind::None, (match_ignore_ascii_case! { &ident,
"context-fill" => SVGPaintKind::ContextFill, "none" => Ok(SVGPaintKind::None),
"context-stroke" => SVGPaintKind::ContextStroke, "context-fill" => Ok(SVGPaintKind::ContextFill),
_ => return Err(()) "context-stroke" => Ok(SVGPaintKind::ContextStroke),
}) _ => Err(())
}).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
impl<ColorType: Parse> Parse for SVGPaint<ColorType> { impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) { if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
let fallback = input.try(|i| ColorType::parse(context, i)); let fallback = input.try(|i| ColorType::parse(context, i));
Ok(SVGPaint { Ok(SVGPaint {
@ -363,7 +365,7 @@ impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
fallback: None, fallback: None,
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
} }

View file

@ -7,7 +7,7 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt; 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 /// 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`. /// serialize as few components as possible, like for example in `border-width`.
@ -26,12 +26,12 @@ impl<T> Rect<T>
where T: Clone where T: Clone
{ {
/// Parses a new `Rect<T>` value with the given parse function. /// Parses a new `Rect<T>` value with the given parse function.
pub fn parse_with<Parse>( pub fn parse_with<'i, 't, Parse>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
parse: Parse) parse: Parse)
-> Result<Self, ()> -> Result<Self, ParseError<'i>>
where Parse: Fn(&ParserContext, &mut Parser) -> Result<T, ()> where Parse: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>
{ {
let first = parse(context, input)?; let first = parse(context, input)?;
let second = if let Ok(second) = input.try(|i| parse(context, i)) { second } else { let second = if let Ok(second) = input.try(|i| parse(context, i)) { second } else {
@ -64,7 +64,7 @@ impl<T> Parse for Rect<T>
where T: Clone + Parse where T: Clone + Parse
{ {
#[inline] #[inline]
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_with(context, input, T::parse) Self::parse_with(context, input, T::parse)
} }
} }

View file

@ -9,7 +9,7 @@ use cssparser::Parser;
use parser::ParserContext; use parser::ParserContext;
use properties::animated_properties::Animatable; use properties::animated_properties::Animatable;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError};
/// A generic value for the `initial-letter` property. /// A generic value for the `initial-letter` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -71,12 +71,12 @@ impl<Value> Spacing<Value> {
/// Parses. /// Parses.
#[inline] #[inline]
pub fn parse_with<F>( pub fn parse_with<'i, 't, F>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
parse: F) parse: F)
-> Result<Self, ()> -> Result<Self, ParseError<'i>>
where F: FnOnce(&ParserContext, &mut Parser) -> Result<Value, ()> where F: FnOnce(&ParserContext, &mut Parser<'i, 't>) -> Result<Value, ParseError<'i>>
{ {
if input.try(|i| i.expect_ident_matching("normal")).is_ok() { if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(Spacing::Normal); return Ok(Spacing::Normal);

View file

@ -9,13 +9,14 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use Atom; use Atom;
pub use cssparser::{RGBA, Token, Parser, serialize_identifier}; pub use cssparser::{RGBA, Token, Parser, serialize_identifier, BasicParseError};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
use std::hash; use std::hash;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
pub mod computed; pub mod computed;
pub mod generics; pub mod generics;
@ -54,7 +55,8 @@ impl<A: Debug, B: Debug> Debug for Either<A, B> {
} }
impl<A: Parse, B: Parse> Parse for Either<A, B> { impl<A: Parse, B: Parse> Parse for Either<A, B> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Either<A, B>, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Either<A, B>, ParseError<'i>> {
if let Ok(v) = input.try(|i| A::parse(context, i)) { if let Ok(v) = input.try(|i| A::parse(context, i)) {
Ok(Either::First(v)) Ok(Either::First(v))
} else { } else {
@ -91,13 +93,16 @@ pub struct CustomIdent(pub Atom);
impl CustomIdent { impl CustomIdent {
/// Parse an already-tokenizer identifier /// Parse an already-tokenizer identifier
pub fn from_ident(ident: Cow<str>, excluding: &[&str]) -> Result<Self, ()> { pub fn from_ident<'i>(ident: Cow<'i, str>, excluding: &[&str]) -> Result<Self, ParseError<'i>> {
match_ignore_ascii_case! { &ident, let valid = match_ignore_ascii_case! { &ident,
"initial" | "inherit" | "unset" | "default" => return Err(()), "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)) { if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} else { } else {
Ok(CustomIdent(ident.into())) Ok(CustomIdent(ident.into()))
} }
@ -125,7 +130,7 @@ impl KeyframesName {
pub fn from_ident(value: String) -> Self { pub fn from_ident(value: String) -> Self {
match CustomIdent::from_ident((&*value).into(), &["none"]) { match CustomIdent::from_ident((&*value).into(), &["none"]) {
Ok(ident) => KeyframesName::Ident(ident), 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 { impl Parse for KeyframesName {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match input.next() { match input.next() {
Ok(Token::Ident(s)) => Ok(KeyframesName::Ident(CustomIdent::from_ident(s, &["none"])?)), Ok(Token::Ident(s)) => Ok(KeyframesName::Ident(CustomIdent::from_ident(s, &["none"])?)),
Ok(Token::QuotedString(s)) => Ok(KeyframesName::QuotedString(s.into())), Ok(Token::QuotedString(s)) => Ok(KeyframesName::QuotedString(s.into())),
_ => Err(()) Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()),
Err(e) => Err(e.into()),
} }
} }
} }

View file

@ -9,9 +9,10 @@
use cssparser::Parser; use cssparser::Parser;
use gecko_bindings::structs; use gecko_bindings::structs;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
bitflags! { bitflags! {
/// Constants shared by multiple CSS Box Alignment properties /// Constants shared by multiple CSS Box Alignment properties
@ -181,7 +182,7 @@ no_viewport_percentage!(AlignJustifyContent);
impl Parse for AlignJustifyContent { impl Parse for AlignJustifyContent {
// normal | <baseline-position> | // normal | <baseline-position> |
// [ <content-distribution> || [ <overflow-position>? && <content-position> ] ] // [ <content-distribution> || [ <overflow-position>? && <content-position> ] ]
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
// normal | <baseline-position> // normal | <baseline-position>
if let Ok(value) = input.try(|input| parse_normal_or_baseline(input)) { if let Ok(value) = input.try(|input| parse_normal_or_baseline(input)) {
return Ok(AlignJustifyContent::new(value)) return Ok(AlignJustifyContent::new(value))
@ -202,7 +203,7 @@ impl Parse for AlignJustifyContent {
} }
return Ok(AlignJustifyContent::new(fallback)) return Ok(AlignJustifyContent::new(fallback))
} }
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -231,7 +232,7 @@ no_viewport_percentage!(AlignJustifySelf);
impl Parse for AlignJustifySelf { impl Parse for AlignJustifySelf {
// auto | normal | stretch | <baseline-position> | // auto | normal | stretch | <baseline-position> |
// [ <overflow-position>? && <self-position> ] // [ <overflow-position>? && <self-position> ]
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
// auto | normal | stretch | <baseline-position> // auto | normal | stretch | <baseline-position>
if let Ok(value) = input.try(parse_auto_normal_stretch_baseline) { if let Ok(value) = input.try(parse_auto_normal_stretch_baseline) {
return Ok(AlignJustifySelf(value)) return Ok(AlignJustifySelf(value))
@ -240,7 +241,7 @@ impl Parse for AlignJustifySelf {
if let Ok(value) = input.try(parse_overflow_self_position) { if let Ok(value) = input.try(parse_overflow_self_position) {
return Ok(AlignJustifySelf(value)) return Ok(AlignJustifySelf(value))
} }
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -269,7 +270,7 @@ no_viewport_percentage!(AlignItems);
impl Parse for AlignItems { impl Parse for AlignItems {
// normal | stretch | <baseline-position> | // normal | stretch | <baseline-position> |
// [ <overflow-position>? && <self-position> ] // [ <overflow-position>? && <self-position> ]
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
// normal | stretch | <baseline-position> // normal | stretch | <baseline-position>
if let Ok(value) = input.try(parse_normal_stretch_baseline) { if let Ok(value) = input.try(parse_normal_stretch_baseline) {
return Ok(AlignItems(value)) return Ok(AlignItems(value))
@ -278,7 +279,7 @@ impl Parse for AlignItems {
if let Ok(value) = input.try(parse_overflow_self_position) { if let Ok(value) = input.try(parse_overflow_self_position) {
return Ok(AlignItems(value)) return Ok(AlignItems(value))
} }
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -308,7 +309,7 @@ impl Parse for JustifyItems {
// auto | normal | stretch | <baseline-position> | // auto | normal | stretch | <baseline-position> |
// [ <overflow-position>? && <self-position> ] // [ <overflow-position>? && <self-position> ]
// [ legacy && [ left | right | center ] ] // [ legacy && [ left | right | center ] ]
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
// auto | normal | stretch | <baseline-position> // auto | normal | stretch | <baseline-position>
if let Ok(value) = input.try(parse_auto_normal_stretch_baseline) { if let Ok(value) = input.try(parse_auto_normal_stretch_baseline) {
return Ok(JustifyItems(value)) return Ok(JustifyItems(value))
@ -321,77 +322,78 @@ impl Parse for JustifyItems {
if let Ok(value) = parse_overflow_self_position(input) { if let Ok(value) = parse_overflow_self_position(input) {
return Ok(JustifyItems(value)) return Ok(JustifyItems(value))
} }
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
// auto | normal | stretch | <baseline-position> // auto | normal | stretch | <baseline-position>
fn parse_auto_normal_stretch_baseline(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_auto_normal_stretch_baseline<'i, 't>(input: &mut Parser<'i, 't>)
-> Result<AlignFlags, ParseError<'i>> {
if let Ok(baseline) = input.try(parse_baseline) { if let Ok(baseline) = input.try(parse_baseline) {
return Ok(baseline); return Ok(baseline);
} }
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"auto" => Ok(ALIGN_AUTO), "auto" => Ok(ALIGN_AUTO),
"normal" => Ok(ALIGN_NORMAL), "normal" => Ok(ALIGN_NORMAL),
"stretch" => Ok(ALIGN_STRETCH), "stretch" => Ok(ALIGN_STRETCH),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// normal | stretch | <baseline-position> // normal | stretch | <baseline-position>
fn parse_normal_stretch_baseline(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_normal_stretch_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
if let Ok(baseline) = input.try(parse_baseline) { if let Ok(baseline) = input.try(parse_baseline) {
return Ok(baseline); return Ok(baseline);
} }
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"normal" => Ok(ALIGN_NORMAL), "normal" => Ok(ALIGN_NORMAL),
"stretch" => Ok(ALIGN_STRETCH), "stretch" => Ok(ALIGN_STRETCH),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// normal | <baseline-position> // normal | <baseline-position>
fn parse_normal_or_baseline(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_normal_or_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
if let Ok(baseline) = input.try(parse_baseline) { if let Ok(baseline) = input.try(parse_baseline) {
return Ok(baseline); return Ok(baseline);
} }
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"normal" => Ok(ALIGN_NORMAL), "normal" => Ok(ALIGN_NORMAL),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// <baseline-position> // <baseline-position>
fn parse_baseline(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"baseline" => Ok(ALIGN_BASELINE), "baseline" => Ok(ALIGN_BASELINE),
"first" => input.expect_ident_matching("baseline").map(|_| ALIGN_BASELINE), "first" => return input.expect_ident_matching("baseline").map(|_| ALIGN_BASELINE).map_err(|e| e.into()),
"last" => input.expect_ident_matching("baseline").map(|_| ALIGN_LAST_BASELINE), "last" => return input.expect_ident_matching("baseline").map(|_| ALIGN_LAST_BASELINE).map_err(|e| e.into()),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// <content-distribution> // <content-distribution>
fn parse_content_distribution(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_content_distribution<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"stretch" => Ok(ALIGN_STRETCH), "stretch" => Ok(ALIGN_STRETCH),
"space-between" => Ok(ALIGN_SPACE_BETWEEN), "space-between" => Ok(ALIGN_SPACE_BETWEEN),
"space-around" => Ok(ALIGN_SPACE_AROUND), "space-around" => Ok(ALIGN_SPACE_AROUND),
"space-evenly" => Ok(ALIGN_SPACE_EVENLY), "space-evenly" => Ok(ALIGN_SPACE_EVENLY),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// [ <overflow-position>? && <content-position> ] // [ <overflow-position>? && <content-position> ]
fn parse_overflow_content_position(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_overflow_content_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
// <content-position> followed by optional <overflow-position> // <content-position> followed by optional <overflow-position>
if let Ok(mut content) = input.try(parse_content_position) { if let Ok(mut content) = input.try(parse_content_position) {
if let Ok(overflow) = input.try(parse_overflow_position) { if let Ok(overflow) = input.try(parse_overflow_position) {
@ -405,13 +407,13 @@ fn parse_overflow_content_position(input: &mut Parser) -> Result<AlignFlags, ()>
return Ok(overflow | content) return Ok(overflow | content)
} }
} }
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
// <content-position> // <content-position>
fn parse_content_position(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_content_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"start" => Ok(ALIGN_START), "start" => Ok(ALIGN_START),
"end" => Ok(ALIGN_END), "end" => Ok(ALIGN_END),
"flex-start" => Ok(ALIGN_FLEX_START), "flex-start" => Ok(ALIGN_FLEX_START),
@ -420,21 +422,21 @@ fn parse_content_position(input: &mut Parser) -> Result<AlignFlags, ()> {
"left" => Ok(ALIGN_LEFT), "left" => Ok(ALIGN_LEFT),
"right" => Ok(ALIGN_RIGHT), "right" => Ok(ALIGN_RIGHT),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// <overflow-position> // <overflow-position>
fn parse_overflow_position(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_overflow_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"safe" => Ok(ALIGN_SAFE), "safe" => Ok(ALIGN_SAFE),
"unsafe" => Ok(ALIGN_UNSAFE), "unsafe" => Ok(ALIGN_UNSAFE),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// [ <overflow-position>? && <self-position> ] // [ <overflow-position>? && <self-position> ]
fn parse_overflow_self_position(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_overflow_self_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
// <self-position> followed by optional <overflow-position> // <self-position> followed by optional <overflow-position>
if let Ok(mut self_position) = input.try(parse_self_position) { if let Ok(mut self_position) = input.try(parse_self_position) {
if let Ok(overflow) = input.try(parse_overflow_position) { if let Ok(overflow) = input.try(parse_overflow_position) {
@ -448,13 +450,13 @@ fn parse_overflow_self_position(input: &mut Parser) -> Result<AlignFlags, ()> {
return Ok(overflow | self_position) return Ok(overflow | self_position)
} }
} }
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
// <self-position> // <self-position>
fn parse_self_position(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_self_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident, (match_ignore_ascii_case! { &ident,
"start" => Ok(ALIGN_START), "start" => Ok(ALIGN_START),
"end" => Ok(ALIGN_END), "end" => Ok(ALIGN_END),
"flex-start" => Ok(ALIGN_FLEX_START), "flex-start" => Ok(ALIGN_FLEX_START),
@ -465,28 +467,28 @@ fn parse_self_position(input: &mut Parser) -> Result<AlignFlags, ()> {
"self-start" => Ok(ALIGN_SELF_START), "self-start" => Ok(ALIGN_SELF_START),
"self-end" => Ok(ALIGN_SELF_END), "self-end" => Ok(ALIGN_SELF_END),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
// [ legacy && [ left | right | center ] ] // [ legacy && [ left | right | center ] ]
fn parse_legacy(input: &mut Parser) -> Result<AlignFlags, ()> { fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
let a = input.expect_ident()?; let a = input.expect_ident()?;
let b = input.expect_ident()?; let b = input.expect_ident()?;
if a.eq_ignore_ascii_case("legacy") { if a.eq_ignore_ascii_case("legacy") {
match_ignore_ascii_case! { &b, (match_ignore_ascii_case! { &b,
"left" => Ok(ALIGN_LEGACY | ALIGN_LEFT), "left" => Ok(ALIGN_LEGACY | ALIGN_LEFT),
"right" => Ok(ALIGN_LEGACY | ALIGN_RIGHT), "right" => Ok(ALIGN_LEGACY | ALIGN_RIGHT),
"center" => Ok(ALIGN_LEGACY | ALIGN_CENTER), "center" => Ok(ALIGN_LEGACY | ALIGN_CENTER),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(b).into())
} else if b.eq_ignore_ascii_case("legacy") { } else if b.eq_ignore_ascii_case("legacy") {
match_ignore_ascii_case! { &a, (match_ignore_ascii_case! { &a,
"left" => Ok(ALIGN_LEGACY | ALIGN_LEFT), "left" => Ok(ALIGN_LEGACY | ALIGN_LEFT),
"right" => Ok(ALIGN_LEGACY | ALIGN_RIGHT), "right" => Ok(ALIGN_LEGACY | ALIGN_RIGHT),
"center" => Ok(ALIGN_LEGACY | ALIGN_CENTER), "center" => Ok(ALIGN_LEGACY | ALIGN_CENTER),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(a).into())
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }

View file

@ -6,6 +6,8 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use style_traits::ParseError;
use values::generics::background::BackgroundSize as GenericBackgroundSize; use values::generics::background::BackgroundSize as GenericBackgroundSize;
use values::specified::length::LengthOrPercentageOrAuto; use values::specified::length::LengthOrPercentageOrAuto;
@ -13,17 +15,18 @@ use values::specified::length::LengthOrPercentageOrAuto;
pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>; pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
impl Parse for BackgroundSize { impl Parse for BackgroundSize {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(width) = input.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) { if let Ok(width) = input.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) {
let height = input let height = input
.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) .try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i))
.unwrap_or(LengthOrPercentageOrAuto::Auto); .unwrap_or(LengthOrPercentageOrAuto::Auto);
return Ok(GenericBackgroundSize::Explicit { width: width, height: height }); 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), "cover" => Ok(GenericBackgroundSize::Cover),
"contain" => Ok(GenericBackgroundSize::Contain), "contain" => Ok(GenericBackgroundSize::Contain),
_ => Err(()), _ => Err(()),
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }

View file

@ -9,9 +9,10 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; 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::{Circle as GenericCircle};
use values::generics::basic_shape::{ClippingShape as GenericClippingShape, Ellipse as GenericEllipse}; use values::generics::basic_shape::{ClippingShape as GenericClippingShape, Ellipse as GenericEllipse};
use values::generics::basic_shape::{FillRule, BasicShape as GenericBasicShape}; use values::generics::basic_shape::{FillRule, BasicShape as GenericBasicShape};
@ -49,7 +50,7 @@ pub type ShapeRadius = GenericShapeRadius<LengthOrPercentage>;
pub type Polygon = GenericPolygon<LengthOrPercentage>; pub type Polygon = GenericPolygon<LengthOrPercentage>;
impl<ReferenceBox: Parse> Parse for ShapeSource<BasicShape, ReferenceBox> { impl<ReferenceBox: Parse> Parse for ShapeSource<BasicShape, ReferenceBox> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() { if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(ShapeSource::None) return Ok(ShapeSource::None)
} }
@ -80,42 +81,43 @@ impl<ReferenceBox: Parse> Parse for ShapeSource<BasicShape, ReferenceBox> {
return Ok(ShapeSource::Shape(shp, ref_box)) 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 { impl Parse for GeometryBox {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(shape_box) = input.try(|i| ShapeBox::parse(i)) { if let Ok(shape_box) = input.try(|i| ShapeBox::parse(i)) {
return Ok(GeometryBox::ShapeBox(shape_box)) 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), "fill-box" => Ok(GeometryBox::FillBox),
"stroke-box" => Ok(GeometryBox::StrokeBox), "stroke-box" => Ok(GeometryBox::StrokeBox),
"view-box" => Ok(GeometryBox::ViewBox), "view-box" => Ok(GeometryBox::ViewBox),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
impl Parse for BasicShape { impl Parse for BasicShape {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let function = input.expect_function()?; let function = input.expect_function()?;
input.parse_nested_block(|i| { input.parse_nested_block(move |i| {
match_ignore_ascii_case! { &function, (match_ignore_ascii_case! { &function,
"inset" => InsetRect::parse_function_arguments(context, i).map(GenericBasicShape::Inset), "inset" => return InsetRect::parse_function_arguments(context, i).map(GenericBasicShape::Inset),
"circle" => Circle::parse_function_arguments(context, i).map(GenericBasicShape::Circle), "circle" => return Circle::parse_function_arguments(context, i).map(GenericBasicShape::Circle),
"ellipse" => Ellipse::parse_function_arguments(context, i).map(GenericBasicShape::Ellipse), "ellipse" => return Ellipse::parse_function_arguments(context, i).map(GenericBasicShape::Ellipse),
"polygon" => Polygon::parse_function_arguments(context, i).map(GenericBasicShape::Polygon), "polygon" => return Polygon::parse_function_arguments(context, i).map(GenericBasicShape::Polygon),
_ => Err(()) _ => Err(())
} }).map_err(|()| StyleParseError::UnexpectedFunction(function).into())
}) })
} }
} }
impl Parse for InsetRect { impl Parse for InsetRect {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.expect_function_matching("inset")?; input.expect_function_matching("inset")?;
input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) input.parse_nested_block(|i| Self::parse_function_arguments(context, i))
} }
@ -123,7 +125,8 @@ impl Parse for InsetRect {
impl InsetRect { impl InsetRect {
/// Parse the inner function arguments of `inset()` /// Parse the inner function arguments of `inset()`
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
let rect = Rect::parse_with(context, input, LengthOrPercentage::parse)?; let rect = Rect::parse_with(context, input, LengthOrPercentage::parse)?;
let round = if input.try(|i| i.expect_ident_matching("round")).is_ok() { let round = if input.try(|i| i.expect_ident_matching("round")).is_ok() {
Some(BorderRadius::parse(context, input)?) Some(BorderRadius::parse(context, input)?)
@ -138,7 +141,8 @@ impl InsetRect {
} }
impl Parse for Circle { impl Parse for Circle {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
input.expect_function_matching("circle")?; input.expect_function_matching("circle")?;
input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) input.parse_nested_block(|i| Self::parse_function_arguments(context, i))
} }
@ -146,7 +150,8 @@ impl Parse for Circle {
impl Circle { impl Circle {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
let radius = input.try(|i| ShapeRadius::parse(context, i)).ok().unwrap_or_default(); 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() { let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() {
Position::parse(context, input)? Position::parse(context, input)?
@ -176,7 +181,7 @@ impl ToCss for Circle {
} }
impl Parse for Ellipse { impl Parse for Ellipse {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.expect_function_matching("ellipse")?; input.expect_function_matching("ellipse")?;
input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) input.parse_nested_block(|i| Self::parse_function_arguments(context, i))
} }
@ -184,8 +189,9 @@ impl Parse for Ellipse {
impl Ellipse { impl Ellipse {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
let (a, b) = input.try(|i| -> Result<_, ()> { -> Result<Self, ParseError<'i>> {
let (a, b) = input.try(|i| -> Result<_, ParseError> {
Ok((ShapeRadius::parse(context, i)?, ShapeRadius::parse(context, i)?)) Ok((ShapeRadius::parse(context, i)?, ShapeRadius::parse(context, i)?))
}).ok().unwrap_or_default(); }).ok().unwrap_or_default();
let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() { 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 { impl Parse for ShapeRadius {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(GenericShapeRadius::Length(lop)) 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), "closest-side" => Ok(GenericShapeRadius::ClosestSide),
"farthest-side" => Ok(GenericShapeRadius::FarthestSide), "farthest-side" => Ok(GenericShapeRadius::FarthestSide),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
@ -300,7 +308,7 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W) -> fmt::R
} }
impl Parse for Polygon { impl Parse for Polygon {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.expect_function_matching("polygon")?; input.expect_function_matching("polygon")?;
input.parse_nested_block(|i| Self::parse_function_arguments(context, i)) input.parse_nested_block(|i| Self::parse_function_arguments(context, i))
} }
@ -308,8 +316,9 @@ impl Parse for Polygon {
impl Polygon { impl Polygon {
/// Parse the inner arguments of a `polygon` function. /// Parse the inner arguments of a `polygon` function.
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_function_arguments<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
let fill = input.try(|i| -> Result<_, ()> { -> Result<Self, ParseError<'i>> {
let fill = input.try(|i| -> Result<_, ParseError> {
let fill = FillRule::parse(i)?; let fill = FillRule::parse(i)?;
i.expect_comma()?; // only eat the comma if there is something before it i.expect_comma()?; // only eat the comma if there is something before it
Ok(fill) Ok(fill)

View file

@ -7,6 +7,8 @@
use app_units::Au; use app_units::Au;
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use style_traits::ParseError;
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
@ -47,26 +49,27 @@ pub type BorderCornerRadius = GenericBorderCornerRadius<LengthOrPercentage>;
impl BorderSideWidth { impl BorderSideWidth {
/// Parses, with quirks. /// Parses, with quirks.
pub fn parse_quirky( pub fn parse_quirky<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> -> Result<Self, ParseError<'i>>
{ {
if let Ok(length) = input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) { if let Ok(length) = input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) {
return Ok(BorderSideWidth::Length(length)); 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), "thin" => Ok(BorderSideWidth::Thin),
"medium" => Ok(BorderSideWidth::Medium), "medium" => Ok(BorderSideWidth::Medium),
"thick" => Ok(BorderSideWidth::Thick), "thick" => Ok(BorderSideWidth::Thick),
_ => Err(()) _ => Err(())
} }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
} }
} }
impl Parse for BorderSideWidth { impl Parse for BorderSideWidth {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
@ -102,7 +105,7 @@ impl BorderImageSideWidth {
} }
impl Parse for BorderImageSideWidth { impl Parse for BorderImageSideWidth {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("auto")).is_ok() { if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
return Ok(GenericBorderImageSideWidth::Auto); return Ok(GenericBorderImageSideWidth::Auto);
} }
@ -117,7 +120,7 @@ impl Parse for BorderImageSideWidth {
} }
impl Parse for BorderImageSlice { impl Parse for BorderImageSlice {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?; let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?;
if !fill { if !fill {
@ -131,7 +134,7 @@ impl Parse for BorderImageSlice {
} }
impl Parse for BorderRadius { impl Parse for BorderRadius {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?; let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?;
let heights = if input.try(|i| i.expect_delim('/')).is_ok() { let heights = if input.try(|i| i.expect_delim('/')).is_ok() {
Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)? Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?
@ -149,11 +152,11 @@ impl Parse for BorderRadius {
} }
impl Parse for BorderCornerRadius { impl Parse for BorderCornerRadius {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let first = LengthOrPercentage::parse_non_negative(context, input)?; let first = LengthOrPercentage::parse_non_negative(context, input)?;
let second = input let second = input
.try(|i| LengthOrPercentage::parse_non_negative(context, i)) .try(|i| LengthOrPercentage::parse_non_negative(context, i))
.unwrap_or_else(|()| first.clone()); .unwrap_or_else(|_| first.clone());
Ok(Self::new(first, second)) Ok(Self::new(first, second))
} }
} }

View file

@ -7,11 +7,11 @@
//! [calc]: https://drafts.csswg.org/css-values/#calc-notation //! [calc]: https://drafts.csswg.org/css-values/#calc-notation
use app_units::Au; use app_units::Au;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token, BasicParseError};
use parser::ParserContext; use parser::ParserContext;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::fmt; use std::fmt;
use style_traits::{HasViewportPercentage, ToCss}; use style_traits::{HasViewportPercentage, ToCss, ParseError, StyleParseError};
use style_traits::values::specified::AllowedLengthType; use style_traits::values::specified::AllowedLengthType;
use values::{CSSInteger, CSSFloat}; use values::{CSSInteger, CSSFloat};
use values::specified::{Angle, Time}; use values::specified::{Angle, Time};
@ -142,11 +142,11 @@ impl CalcNode {
/// ///
/// May return a "complex" `CalcNode`, in the presence of a parenthesized /// May return a "complex" `CalcNode`, in the presence of a parenthesized
/// expression, for example. /// expression, for example.
fn parse_one( fn parse_one<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
expected_unit: CalcUnit) expected_unit: CalcUnit)
-> Result<Self, ()> -> Result<Self, ParseError<'i>>
{ {
match (try!(input.next()), expected_unit) { match (try!(input.next()), expected_unit) {
(Token::Number(ref value), _) => Ok(CalcNode::Number(value.value)), (Token::Number(ref value), _) => Ok(CalcNode::Number(value.value)),
@ -154,18 +154,21 @@ impl CalcNode {
(Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => { (Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => {
NoCalcLength::parse_dimension(context, value.value, unit) NoCalcLength::parse_dimension(context, value.value, unit)
.map(CalcNode::Length) .map(CalcNode::Length)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
(Token::Dimension(ref value, ref unit), CalcUnit::Angle) => { (Token::Dimension(ref value, ref unit), CalcUnit::Angle) => {
Angle::parse_dimension(value.value, Angle::parse_dimension(value.value,
unit, unit,
/* from_calc = */ true) /* from_calc = */ true)
.map(CalcNode::Angle) .map(CalcNode::Angle)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
(Token::Dimension(ref value, ref unit), CalcUnit::Time) => { (Token::Dimension(ref value, ref unit), CalcUnit::Time) => {
Time::parse_dimension(value.value, Time::parse_dimension(value.value,
unit, unit,
/* from_calc = */ true) /* from_calc = */ true)
.map(CalcNode::Time) .map(CalcNode::Time)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
(Token::Percentage(ref value), CalcUnit::LengthOrPercentage) => { (Token::Percentage(ref value), CalcUnit::LengthOrPercentage) => {
Ok(CalcNode::Percentage(value.unit_value)) Ok(CalcNode::Percentage(value.unit_value))
@ -180,18 +183,18 @@ impl CalcNode {
CalcNode::parse(context, i, expected_unit) CalcNode::parse(context, i, expected_unit)
}) })
} }
_ => Err(()) (t, _) => Err(BasicParseError::UnexpectedToken(t).into())
} }
} }
/// Parse a top-level `calc` expression, with all nested sub-expressions. /// Parse a top-level `calc` expression, with all nested sub-expressions.
/// ///
/// This is in charge of parsing, for example, `2 + 3 * 100%`. /// This is in charge of parsing, for example, `2 + 3 * 100%`.
fn parse( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
expected_unit: CalcUnit) expected_unit: CalcUnit)
-> Result<Self, ()> -> Result<Self, ParseError<'i>>
{ {
let mut root = Self::parse_product(context, input, expected_unit)?; let mut root = Self::parse_product(context, input, expected_unit)?;
@ -217,7 +220,7 @@ impl CalcNode {
CalcNode::Sub(Box::new(root), Box::new(rhs)); CalcNode::Sub(Box::new(root), Box::new(rhs));
root = new_root; root = new_root;
} }
_ => return Err(()), t => return Err(BasicParseError::UnexpectedToken(t).into()),
} }
} }
_ => { _ => {
@ -239,11 +242,11 @@ impl CalcNode {
/// * `2 * 2` /// * `2 * 2`
/// * `2 * 2 + 2` (but will leave the `+ 2` unparsed). /// * `2 * 2 + 2` (but will leave the `+ 2` unparsed).
/// ///
fn parse_product( fn parse_product<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
expected_unit: CalcUnit) expected_unit: CalcUnit)
-> Result<Self, ()> -> Result<Self, ParseError<'i>>
{ {
let mut root = Self::parse_one(context, input, expected_unit)?; let mut root = Self::parse_one(context, input, expected_unit)?;
@ -491,65 +494,71 @@ impl CalcNode {
} }
/// Convenience parsing function for integers. /// Convenience parsing function for integers.
pub fn parse_integer( pub fn parse_integer<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<CSSInteger, ()> -> Result<CSSInteger, ParseError<'i>>
{ {
Self::parse(context, input, CalcUnit::Integer)? Self::parse(context, input, CalcUnit::Integer)?
.to_number() .to_number()
.map(|n| n as CSSInteger) .map(|n| n as CSSInteger)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
/// Convenience parsing function for `<length> | <percentage>`. /// Convenience parsing function for `<length> | <percentage>`.
pub fn parse_length_or_percentage( pub fn parse_length_or_percentage<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
clamping_mode: AllowedLengthType) clamping_mode: AllowedLengthType)
-> Result<CalcLengthOrPercentage, ()> -> Result<CalcLengthOrPercentage, ParseError<'i>>
{ {
Self::parse(context, input, CalcUnit::LengthOrPercentage)? Self::parse(context, input, CalcUnit::LengthOrPercentage)?
.to_length_or_percentage(clamping_mode) .to_length_or_percentage(clamping_mode)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
/// Convenience parsing function for `<length>`. /// Convenience parsing function for `<length>`.
pub fn parse_length( pub fn parse_length<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
clamping_mode: AllowedLengthType) clamping_mode: AllowedLengthType)
-> Result<CalcLengthOrPercentage, ()> -> Result<CalcLengthOrPercentage, ParseError<'i>>
{ {
Self::parse(context, input, CalcUnit::Length)? Self::parse(context, input, CalcUnit::Length)?
.to_length_or_percentage(clamping_mode) .to_length_or_percentage(clamping_mode)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
/// Convenience parsing function for `<number>`. /// Convenience parsing function for `<number>`.
pub fn parse_number( pub fn parse_number<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<CSSFloat, ()> -> Result<CSSFloat, ParseError<'i>>
{ {
Self::parse(context, input, CalcUnit::Number)? Self::parse(context, input, CalcUnit::Number)?
.to_number() .to_number()
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
/// Convenience parsing function for `<angle>`. /// Convenience parsing function for `<angle>`.
pub fn parse_angle( pub fn parse_angle<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<Angle, ()> -> Result<Angle, ParseError<'i>>
{ {
Self::parse(context, input, CalcUnit::Angle)? Self::parse(context, input, CalcUnit::Angle)?
.to_angle() .to_angle()
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
/// Convenience parsing function for `<time>`. /// Convenience parsing function for `<time>`.
pub fn parse_time( pub fn parse_time<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<Time, ()> -> Result<Time, ParseError<'i>>
{ {
Self::parse(context, input, CalcUnit::Time)? Self::parse(context, input, CalcUnit::Time)?
.to_time() .to_time()
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
} }

View file

@ -4,7 +4,7 @@
//! Specified color values. //! Specified color values.
use cssparser::{Color as CSSParserColor, Parser, RGBA, Token}; use cssparser::{Color as CSSParserColor, Parser, RGBA, Token, BasicParseError};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use gecko_bindings::structs::nscolor; use gecko_bindings::structs::nscolor;
use itoa; use itoa;
@ -13,7 +13,7 @@ use parser::{ParserContext, Parse};
use properties::longhands::color::SystemColor; use properties::longhands::color::SystemColor;
use std::fmt; use std::fmt;
use std::io::Write; use std::io::Write;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use super::AllowQuirks; use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue}; use values::computed::{Color as ComputedColor, Context, ToComputedValue};
@ -66,7 +66,7 @@ impl From<RGBA> for Color {
} }
impl Parse for Color { impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
// Currently we only store authored value for color keywords, // Currently we only store authored value for color keywords,
// because all browsers serialize those values as keywords for // because all browsers serialize those values as keywords for
// specified value. // specified value.
@ -93,7 +93,7 @@ impl Parse for Color {
} }
} }
#[cfg(not(feature = "gecko"))] { #[cfg(not(feature = "gecko"))] {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
} }
@ -157,13 +157,13 @@ impl Color {
/// Parse a color, with quirks. /// Parse a color, with quirks.
/// ///
/// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
input.try(|i| Self::parse(context, i)).or_else(|_| { input.try(|i| Self::parse(context, i)).or_else(|_| {
if !allow_quirks.allowed(context.quirks_mode) { if !allow_quirks.allowed(context.quirks_mode) {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba)) Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba))
}) })
@ -172,7 +172,7 @@ impl Color {
/// Parse a <quirky-color> value. /// Parse a <quirky-color> value.
/// ///
/// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
fn parse_quirky_color(input: &mut Parser) -> Result<RGBA, ()> { fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<RGBA, ParseError<'i>> {
let (number, dimension) = match input.next()? { let (number, dimension) = match input.next()? {
Token::Number(number) => { Token::Number(number) => {
(number, None) (number, None)
@ -182,17 +182,18 @@ impl Color {
}, },
Token::Ident(ident) => { Token::Ident(ident) => {
if ident.len() != 3 && ident.len() != 6 { if ident.len() != 3 && ident.len() != 6 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
return parse_hash_color(ident.as_bytes()); return parse_hash_color(ident.as_bytes())
.map_err(|()| StyleParseError::UnspecifiedError.into());
} }
_ => { t => {
return Err(()); return Err(BasicParseError::UnexpectedToken(t).into());
}, },
}; };
let value = number.int_value.ok_or(())?; let value = number.int_value.ok_or(StyleParseError::UnspecifiedError)?;
if value < 0 { if value < 0 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
let length = if value <= 9 { let length = if value <= 9 {
1 1
@ -207,11 +208,11 @@ impl Color {
} else if value <= 999999 { } else if value <= 999999 {
6 6
} else { } else {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
}; };
let total = length + dimension.as_ref().map_or(0, |d| d.len()); let total = length + dimension.as_ref().map_or(0, |d| d.len());
if total > 6 { if total > 6 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
let mut serialization = [b'0'; 6]; let mut serialization = [b'0'; 6];
let space_padding = 6 - total; let space_padding = 6 - total;
@ -221,7 +222,7 @@ impl Color {
written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap(); written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap();
} }
debug_assert!(written == 6); debug_assert!(written == 6);
parse_hash_color(&serialization) parse_hash_color(&serialization).map_err(|()| StyleParseError::UnspecifiedError.into())
} }
/// Returns false if the color is completely transparent, and /// Returns false if the color is completely transparent, and
@ -306,7 +307,7 @@ pub struct RGBAColor(pub Color);
no_viewport_percentage!(RGBAColor); no_viewport_percentage!(RGBAColor);
impl Parse for RGBAColor { impl Parse for RGBAColor {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Color::parse(context, input).map(RGBAColor) Color::parse(context, input).map(RGBAColor)
} }
} }

View file

@ -6,6 +6,7 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::ParseError;
use values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint; use values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint;
use values::specified::length::LengthOrPercentage; use values::specified::length::LengthOrPercentage;
@ -13,7 +14,7 @@ use values::specified::length::LengthOrPercentage;
pub type ScrollSnapPoint = GenericScrollSnapPoint<LengthOrPercentage>; pub type ScrollSnapPoint = GenericScrollSnapPoint<LengthOrPercentage>;
impl Parse for ScrollSnapPoint { impl Parse for ScrollSnapPoint {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() { if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(GenericScrollSnapPoint::None); return Ok(GenericScrollSnapPoint::None);
} }

View file

@ -5,11 +5,11 @@
//! CSS handling for the computed value of //! CSS handling for the computed value of
//! [grids](https://drafts.csswg.org/css-grid/) //! [grids](https://drafts.csswg.org/css-grid/)
use cssparser::{Parser, Token}; use cssparser::{Parser, Token, BasicParseError};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::{mem, usize}; use std::{mem, usize};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use style_traits::HasViewportPercentage; use style_traits::{HasViewportPercentage, ParseError, StyleParseError};
use values::{CSSFloat, CustomIdent, Either}; use values::{CSSFloat, CustomIdent, Either};
use values::computed::{self, Context, ToComputedValue}; use values::computed::{self, Context, ToComputedValue};
use values::generics::grid::{RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat}; use values::generics::grid::{RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
@ -17,16 +17,16 @@ use values::generics::grid::{TrackSize, TrackList, TrackListType};
use values::specified::LengthOrPercentage; use values::specified::LengthOrPercentage;
/// Parse a single flexible length. /// Parse a single flexible length.
pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> { pub fn parse_flex<'i, 't>(input: &mut Parser<'i, 't>) -> Result<CSSFloat, ParseError<'i>> {
match input.next()? { match input.next()? {
Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive() Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive()
=> Ok(value.value), => Ok(value.value),
_ => Err(()), t => Err(BasicParseError::UnexpectedToken(t).into()),
} }
} }
impl Parse for TrackBreadth<LengthOrPercentage> { impl Parse for TrackBreadth<LengthOrPercentage> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(TrackBreadth::Breadth(lop)) return Ok(TrackBreadth::Breadth(lop))
} }
@ -51,7 +51,7 @@ impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
} }
impl Parse for TrackSize<LengthOrPercentage> { impl Parse for TrackSize<LengthOrPercentage> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) { if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
return Ok(TrackSize::Breadth(b)) return Ok(TrackSize::Breadth(b))
} }
@ -81,13 +81,13 @@ impl Parse for TrackSize<LengthOrPercentage> {
/// Parse the grid line names into a vector of owned strings. /// Parse the grid line names into a vector of owned strings.
/// ///
/// https://drafts.csswg.org/css-grid/#typedef-line-names /// https://drafts.csswg.org/css-grid/#typedef-line-names
pub fn parse_line_names(input: &mut Parser) -> Result<Vec<String>, ()> { pub fn parse_line_names<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Vec<String>, ParseError<'i>> {
input.expect_square_bracket_block()?; input.expect_square_bracket_block()?;
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
let mut values = vec![]; let mut values = vec![];
while let Ok(ident) = input.try(|i| i.expect_ident()) { while let Ok(ident) = input.try(|i| i.expect_ident()) {
if CustomIdent::from_ident((&*ident).into(), &["span"]).is_err() { if CustomIdent::from_ident((&*ident).into(), &["span"]).is_err() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
values.push(ident.into_owned()); values.push(ident.into_owned());
@ -112,9 +112,10 @@ enum RepeatType {
} }
impl TrackRepeat<LengthOrPercentage> { impl TrackRepeat<LengthOrPercentage> {
fn parse_with_repeat_type(context: &ParserContext, input: &mut Parser) fn parse_with_repeat_type<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<(TrackRepeat<LengthOrPercentage>, RepeatType), ()> { -> Result<(TrackRepeat<LengthOrPercentage>, RepeatType),
input.try(|i| i.expect_function_matching("repeat")).and_then(|_| { ParseError<'i>> {
input.try(|i| i.expect_function_matching("repeat").map_err(|e| e.into())).and_then(|_| {
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
let count = RepeatCount::parse(context, input)?; let count = RepeatCount::parse(context, input)?;
input.expect_comma()?; input.expect_comma()?;
@ -135,7 +136,8 @@ impl TrackRepeat<LengthOrPercentage> {
if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) { if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
if !track_size.is_fixed() { if !track_size.is_fixed() {
if is_auto { if is_auto {
return Err(()) // should be <fixed-size> for <auto-repeat> // should be <fixed-size> for <auto-repeat>
return Err(StyleParseError::UnspecifiedError.into())
} }
if repeat_type == RepeatType::Fixed { if repeat_type == RepeatType::Fixed {
@ -147,7 +149,8 @@ impl TrackRepeat<LengthOrPercentage> {
names.push(current_names); names.push(current_names);
} else { } else {
if values.is_empty() { if values.is_empty() {
return Err(()) // expecting at least one <track-size> // expecting at least one <track-size>
return Err(StyleParseError::UnspecifiedError.into())
} }
names.push(current_names); // final `<line-names>` names.push(current_names); // final `<line-names>`
@ -181,7 +184,7 @@ impl HasViewportPercentage for TrackRepeat<LengthOrPercentage> {
pub type TrackSizeOrRepeat = Either<TrackSize<LengthOrPercentage>, TrackRepeat<LengthOrPercentage>>; pub type TrackSizeOrRepeat = Either<TrackSize<LengthOrPercentage>, TrackRepeat<LengthOrPercentage>>;
impl Parse for TrackList<TrackSizeOrRepeat> { impl Parse for TrackList<TrackSizeOrRepeat> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let mut current_names; let mut current_names;
let mut names = vec![]; let mut names = vec![];
let mut values = vec![]; let mut values = vec![];
@ -198,7 +201,8 @@ impl Parse for TrackList<TrackSizeOrRepeat> {
if !track_size.is_fixed() { if !track_size.is_fixed() {
atleast_one_not_fixed = true; atleast_one_not_fixed = true;
if is_auto { if is_auto {
return Err(()) // <auto-track-list> only accepts <fixed-size> and <fixed-repeat> // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
return Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -213,13 +217,13 @@ impl Parse for TrackList<TrackSizeOrRepeat> {
RepeatType::Normal => { RepeatType::Normal => {
atleast_one_not_fixed = true; atleast_one_not_fixed = true;
if is_auto { // only <fixed-repeat> if is_auto { // only <fixed-repeat>
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
}, },
RepeatType::Auto => { RepeatType::Auto => {
if is_auto || atleast_one_not_fixed { if is_auto || atleast_one_not_fixed {
// We've either seen <auto-repeat> earlier, or there's at least one non-fixed value // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
is_auto = true; is_auto = true;
@ -232,7 +236,7 @@ impl Parse for TrackList<TrackSizeOrRepeat> {
values.push(Either::Second(repeat)); values.push(Either::Second(repeat));
} else { } else {
if values.is_empty() { if values.is_empty() {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
names.push(current_names); names.push(current_names);

View file

@ -8,14 +8,15 @@
//! [image]: https://drafts.csswg.org/css-images/#image-values //! [image]: https://drafts.csswg.org/css-images/#image-values
use Atom; use Atom;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token, BasicParseError};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::f32::consts::PI; use std::f32::consts::PI;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use values::{Either, None_}; use values::{Either, None_};
use values::generics::image::{Circle, CompatMode, Ellipse, ColorStop as GenericColorStop}; use values::generics::image::{Circle, CompatMode, Ellipse, ColorStop as GenericColorStop};
use values::generics::image::{EndingShape as GenericEndingShape, Gradient as GenericGradient}; use values::generics::image::{EndingShape as GenericEndingShape, Gradient as GenericGradient};
@ -82,7 +83,7 @@ pub type ColorStop = GenericColorStop<RGBAColor, LengthOrPercentage>;
pub type ImageRect = GenericImageRect<NumberOrPercentage>; pub type ImageRect = GenericImageRect<NumberOrPercentage>;
impl Parse for Image { impl Parse for Image {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Image, ParseError<'i>> {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
{ {
if let Ok(mut url) = input.try(|input| SpecifiedUrl::parse(context, input)) { if let Ok(mut url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
@ -132,53 +133,59 @@ impl Image {
} }
/// Parses a `-moz-element(# <element-id>)`. /// Parses a `-moz-element(# <element-id>)`.
fn parse_element(input: &mut Parser) -> Result<Atom, ()> { fn parse_element<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Atom, ParseError<'i>> {
input.try(|i| i.expect_function_matching("-moz-element"))?; input.try(|i| i.expect_function_matching("-moz-element"))?;
input.parse_nested_block(|i| { input.parse_nested_block(|i| {
match i.next()? { match i.next()? {
Token::IDHash(id) => Ok(Atom::from(id)), Token::IDHash(id) => Ok(Atom::from(id)),
_ => Err(()), t => Err(BasicParseError::UnexpectedToken(t).into()),
} }
}) })
} }
} }
impl Parse for Gradient { impl Parse for Gradient {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
enum Shape { enum Shape {
Linear, Linear,
Radial, Radial,
} }
let (shape, repeating, compat_mode) = match_ignore_ascii_case! { &try!(input.expect_function()), let func = try!(input.expect_function());
let result = match_ignore_ascii_case! { &func,
"linear-gradient" => { "linear-gradient" => {
(Shape::Linear, false, CompatMode::Modern) Some((Shape::Linear, false, CompatMode::Modern))
}, },
"-webkit-linear-gradient" => { "-webkit-linear-gradient" => {
(Shape::Linear, false, CompatMode::WebKit) Some((Shape::Linear, false, CompatMode::WebKit))
}, },
"repeating-linear-gradient" => { "repeating-linear-gradient" => {
(Shape::Linear, true, CompatMode::Modern) Some((Shape::Linear, true, CompatMode::Modern))
}, },
"-webkit-repeating-linear-gradient" => { "-webkit-repeating-linear-gradient" => {
(Shape::Linear, true, CompatMode::WebKit) Some((Shape::Linear, true, CompatMode::WebKit))
}, },
"radial-gradient" => { "radial-gradient" => {
(Shape::Radial, false, CompatMode::Modern) Some((Shape::Radial, false, CompatMode::Modern))
}, },
"-webkit-radial-gradient" => { "-webkit-radial-gradient" => {
(Shape::Radial, false, CompatMode::WebKit) Some((Shape::Radial, false, CompatMode::WebKit))
}, },
"repeating-radial-gradient" => { "repeating-radial-gradient" => {
(Shape::Radial, true, CompatMode::Modern) Some((Shape::Radial, true, CompatMode::Modern))
}, },
"-webkit-repeating-radial-gradient" => { "-webkit-repeating-radial-gradient" => {
(Shape::Radial, true, CompatMode::WebKit) Some((Shape::Radial, true, CompatMode::WebKit))
}, },
"-webkit-gradient" => { "-webkit-gradient" => {
return input.parse_nested_block(|i| Self::parse_webkit_gradient_argument(context, i)); return input.parse_nested_block(|i| Self::parse_webkit_gradient_argument(context, i));
}, },
_ => { return Err(()); } _ => None,
};
let (shape, repeating, compat_mode) = match result {
Some(result) => result,
None => return Err(StyleParseError::UnexpectedFunction(func).into()),
}; };
let (kind, items) = input.parse_nested_block(|i| { let (kind, items) = input.parse_nested_block(|i| {
@ -191,7 +198,7 @@ impl Parse for Gradient {
})?; })?;
if items.len() < 2 { if items.len() < 2 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(Gradient { Ok(Gradient {
@ -204,7 +211,8 @@ impl Parse for Gradient {
} }
impl Gradient { impl Gradient {
fn parse_webkit_gradient_argument(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse_webkit_gradient_argument<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
type Point = GenericPosition<Component<X>, Component<Y>>; type Point = GenericPosition<Component<X>, Component<Y>>;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -259,7 +267,8 @@ impl Gradient {
} }
impl Parse for Point { impl Parse for Point {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
input.try(|i| { input.try(|i| {
let x = Component::parse(context, i)?; let x = Component::parse(context, i)?;
let y = Component::parse(context, i)?; let y = Component::parse(context, i)?;
@ -318,7 +327,8 @@ impl Gradient {
} }
impl<S: Parse> Parse for Component<S> { impl<S: Parse> Parse for Component<S> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if let Ok(side) = input.try(|i| S::parse(context, i)) { if let Ok(side) = input.try(|i| S::parse(context, i)) {
return Ok(Component::Side(side)); return Ok(Component::Side(side));
} }
@ -365,7 +375,7 @@ impl Gradient {
(kind, reverse_stops) (kind, reverse_stops)
}, },
_ => return Err(()), _ => return Err(SelectorParseError::UnexpectedIdent(ident.clone()).into()),
}; };
let mut items = input.try(|i| { let mut items = input.try(|i| {
@ -384,11 +394,11 @@ impl Gradient {
}, },
"from" => 0., "from" => 0.,
"to" => 1., "to" => 1.,
_ => return Err(()), _ => return Err(StyleParseError::UnexpectedFunction(function.clone()).into()),
}; };
let color = Color::parse(context, i)?; let color = Color::parse(context, i)?;
if color == Color::CurrentColor { if color == Color::CurrentColor {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok((color.into(), p)) Ok((color.into(), p))
})?; })?;
@ -450,10 +460,10 @@ impl Gradient {
} }
impl GradientKind { impl GradientKind {
fn parse_linear(context: &ParserContext, fn parse_linear<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
compat_mode: CompatMode) compat_mode: CompatMode)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode)) { let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode)) {
input.expect_comma()?; input.expect_comma()?;
d d
@ -463,10 +473,10 @@ impl GradientKind {
Ok(GenericGradientKind::Linear(direction)) Ok(GenericGradientKind::Linear(direction))
} }
fn parse_radial(context: &ParserContext, fn parse_radial<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
compat_mode: CompatMode) compat_mode: CompatMode)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
let (shape, position) = if compat_mode == CompatMode::Modern { let (shape, position) = if compat_mode == CompatMode::Modern {
let shape = input.try(|i| EndingShape::parse(context, i, compat_mode)); let shape = input.try(|i| EndingShape::parse(context, i, compat_mode));
let position = input.try(|i| { let position = input.try(|i| {
@ -538,10 +548,10 @@ impl GenericsLineDirection for LineDirection {
} }
impl LineDirection { impl LineDirection {
fn parse(context: &ParserContext, fn parse<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
compat_mode: CompatMode) compat_mode: CompatMode)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) { if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) {
return Ok(LineDirection::Angle(angle)); return Ok(LineDirection::Angle(angle));
} }
@ -565,10 +575,10 @@ impl LineDirection {
} }
impl EndingShape { impl EndingShape {
fn parse(context: &ParserContext, fn parse<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
compat_mode: CompatMode) compat_mode: CompatMode)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) { if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
if input.try(|i| i.expect_ident_matching("circle")).is_ok() { if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
return Ok(GenericEndingShape::Circle(Circle::Extent(extent))); return Ok(GenericEndingShape::Circle(Circle::Extent(extent)));
@ -592,7 +602,7 @@ impl EndingShape {
return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(extent))); return Ok(GenericEndingShape::Ellipse(Ellipse::Extent(extent)));
} }
if compat_mode == CompatMode::Modern { if compat_mode == CompatMode::Modern {
let pair: Result<_, ()> = input.try(|i| { let pair: Result<_, ParseError> = input.try(|i| {
let x = LengthOrPercentage::parse(context, i)?; let x = LengthOrPercentage::parse(context, i)?;
let y = LengthOrPercentage::parse(context, i)?; let y = LengthOrPercentage::parse(context, i)?;
Ok((x, y)) Ok((x, y))
@ -641,18 +651,20 @@ impl EndingShape {
} }
impl ShapeExtent { impl ShapeExtent {
fn parse_with_compat_mode(input: &mut Parser, fn parse_with_compat_mode<'i, 't>(input: &mut Parser<'i, 't>,
compat_mode: CompatMode) compat_mode: CompatMode)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
match try!(Self::parse(input)) { match try!(Self::parse(input)) {
ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern => Err(()), ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern =>
Err(StyleParseError::UnspecifiedError.into()),
keyword => Ok(keyword), keyword => Ok(keyword),
} }
} }
} }
impl GradientItem { impl GradientItem {
fn parse_comma_separated(context: &ParserContext, input: &mut Parser) -> Result<Vec<Self>, ()> { fn parse_comma_separated<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Vec<Self>, ParseError<'i>> {
let mut seen_stop = false; let mut seen_stop = false;
let items = try!(input.parse_comma_separated(|input| { let items = try!(input.parse_comma_separated(|input| {
if seen_stop { if seen_stop {
@ -665,14 +677,15 @@ impl GradientItem {
ColorStop::parse(context, input).map(GenericGradientItem::ColorStop) ColorStop::parse(context, input).map(GenericGradientItem::ColorStop)
})); }));
if !seen_stop || items.len() < 2 { if !seen_stop || items.len() < 2 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
Ok(items) Ok(items)
} }
} }
impl Parse for ColorStop { impl Parse for ColorStop {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
Ok(ColorStop { Ok(ColorStop {
color: try!(RGBAColor::parse(context, input)), color: try!(RGBAColor::parse(context, input)),
position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(), position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
@ -681,7 +694,7 @@ impl Parse for ColorStop {
} }
impl Parse for PaintWorklet { impl Parse for PaintWorklet {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.expect_function_matching("paint")?; input.expect_function_matching("paint")?;
input.parse_nested_block(|i| { input.parse_nested_block(|i| {
let name = i.expect_ident()?; let name = i.expect_ident()?;
@ -693,7 +706,7 @@ impl Parse for PaintWorklet {
} }
impl Parse for ImageRect { impl Parse for ImageRect {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.try(|i| i.expect_function_matching("-moz-image-rect"))?; input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
input.parse_nested_block(|i| { input.parse_nested_block(|i| {
let string = i.expect_url_or_string()?; let string = i.expect_url_or_string()?;

View file

@ -7,14 +7,14 @@
//! [length]: https://drafts.csswg.org/css-values/#lengths //! [length]: https://drafts.csswg.org/css-values/#lengths
use app_units::Au; use app_units::Au;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token, BasicParseError};
use euclid::size::Size2D; use euclid::size::Size2D;
use font_metrics::FontMetricsQueryResult; use font_metrics::FontMetricsQueryResult;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::{cmp, fmt, mem}; use std::{cmp, fmt, mem};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::ops::Mul; use std::ops::Mul;
use style_traits::{HasViewportPercentage, ToCss}; use style_traits::{HasViewportPercentage, ToCss, ParseError, StyleParseError};
use style_traits::values::specified::{AllowedLengthType, AllowedNumericType}; use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
use stylesheets::CssRuleType; use stylesheets::CssRuleType;
use super::{AllowQuirks, Number, ToComputedValue}; use super::{AllowQuirks, Number, ToComputedValue};
@ -451,7 +451,8 @@ impl Mul<CSSFloat> for NoCalcLength {
impl NoCalcLength { impl NoCalcLength {
/// Parse a given absolute or relative dimension. /// Parse a given absolute or relative dimension.
pub fn parse_dimension(context: &ParserContext, value: CSSFloat, unit: &str) -> Result<NoCalcLength, ()> { pub fn parse_dimension(context: &ParserContext, value: CSSFloat, unit: &str)
-> Result<NoCalcLength, ()> {
let in_page_rule = context.rule_type.map_or(false, |rule_type| rule_type == CssRuleType::Page); let in_page_rule = context.rule_type.map_or(false, |rule_type| rule_type == CssRuleType::Page);
match_ignore_ascii_case! { unit, match_ignore_ascii_case! { unit,
"px" => Ok(NoCalcLength::Absolute(AbsoluteLength::Px(value))), "px" => Ok(NoCalcLength::Absolute(AbsoluteLength::Px(value))),
@ -597,47 +598,50 @@ impl Length {
} }
/// Parse a given absolute or relative dimension. /// Parse a given absolute or relative dimension.
pub fn parse_dimension(context: &ParserContext, value: CSSFloat, unit: &str) -> Result<Length, ()> { pub fn parse_dimension(context: &ParserContext, value: CSSFloat, unit: &str)
-> Result<Length, ()> {
NoCalcLength::parse_dimension(context, value, unit).map(Length::NoCalc) NoCalcLength::parse_dimension(context, value, unit).map(Length::NoCalc)
} }
#[inline] #[inline]
fn parse_internal(context: &ParserContext, fn parse_internal<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
num_context: AllowedLengthType, num_context: AllowedLengthType,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Length, ()> { -> Result<Length, ParseError<'i>> {
match try!(input.next()) { let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
Length::parse_dimension(context, value.value, unit), Length::parse_dimension(context, value.value, unit),
Token::Number(ref value) if num_context.is_ok(value.value) => { Token::Number(ref value) if num_context.is_ok(value.value) => {
if value.value != 0. && if value.value != 0. &&
!context.parsing_mode.allows_unitless_lengths() && !context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) { !allow_quirks.allowed(context.quirks_mode) {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(value.value)))) Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(value.value))))
}, },
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
input.parse_nested_block(|input| { return input.parse_nested_block(|input| {
CalcNode::parse_length(context, input, num_context).map(|calc| Length::Calc(Box::new(calc))) CalcNode::parse_length(context, input, num_context).map(|calc| Length::Calc(Box::new(calc)))
}), }),
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
/// Parse a non-negative length /// Parse a non-negative length
#[inline] #[inline]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Length, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Length, ParseError<'i>> {
Self::parse_non_negative_quirky(context, input, AllowQuirks::No) Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
} }
/// Parse a non-negative length, allowing quirks. /// Parse a non-negative length, allowing quirks.
#[inline] #[inline]
pub fn parse_non_negative_quirky(context: &ParserContext, pub fn parse_non_negative_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Length, ()> { -> Result<Length, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
} }
@ -657,17 +661,17 @@ impl Length {
} }
impl Parse for Length { impl Parse for Length {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
impl Length { impl Length {
/// Parses a length, with quirks. /// Parses a length, with quirks.
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
} }
} }
@ -675,7 +679,8 @@ impl Length {
impl<T: Parse> Either<Length, T> { impl<T: Parse> Either<Length, T> {
/// Parse a non-negative length /// Parse a non-negative length
#[inline] #[inline]
pub fn parse_non_negative_length(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative_length<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if let Ok(v) = input.try(|input| T::parse(context, input)) { if let Ok(v) = input.try(|input| T::parse(context, input)) {
return Ok(Either::Second(v)); return Ok(Either::Second(v));
} }
@ -710,19 +715,19 @@ impl ToCss for Percentage {
impl Percentage { impl Percentage {
/// Parse a specific kind of percentage. /// Parse a specific kind of percentage.
pub fn parse_with_clamping_mode(input: &mut Parser, pub fn parse_with_clamping_mode<'i, 't>(input: &mut Parser<'i, 't>,
context: AllowedNumericType) context: AllowedNumericType)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
match try!(input.next()) { match try!(input.next()) {
Token::Percentage(ref value) if context.is_ok(value.unit_value) => { Token::Percentage(ref value) if context.is_ok(value.unit_value) => {
Ok(Percentage(value.unit_value)) Ok(Percentage(value.unit_value))
} }
_ => Err(()) t => Err(BasicParseError::UnexpectedToken(t).into())
} }
} }
/// Parses a percentage token, but rejects it if it's negative. /// Parses a percentage token, but rejects it if it's negative.
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(input, AllowedNumericType::NonNegative) Self::parse_with_clamping_mode(input, AllowedNumericType::NonNegative)
} }
@ -741,7 +746,7 @@ impl Percentage {
impl Parse for Percentage { impl Parse for Percentage {
#[inline] #[inline]
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(input, AllowedNumericType::All) Self::parse_with_clamping_mode(input, AllowedNumericType::All)
} }
} }
@ -788,54 +793,58 @@ impl LengthOrPercentage {
LengthOrPercentage::Length(NoCalcLength::zero()) LengthOrPercentage::Length(NoCalcLength::zero())
} }
fn parse_internal(context: &ParserContext, fn parse_internal<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
num_context: AllowedLengthType, num_context: AllowedLengthType,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<LengthOrPercentage, ()> -> Result<LengthOrPercentage, ParseError<'i>>
{ {
match try!(input.next()) { let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length), NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length),
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))), return Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
Token::Number(value) if num_context.is_ok(value.value) => { Token::Number(value) if num_context.is_ok(value.value) => {
if value.value != 0. && if value.value != 0. &&
!context.parsing_mode.allows_unitless_lengths() && !context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) { !allow_quirks.allowed(context.quirks_mode) {
return Err(()) Err(())
} else {
return Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value)))
} }
Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value)))
} }
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| { let calc = try!(input.parse_nested_block(|i| {
CalcNode::parse_length_or_percentage(context, i, num_context) CalcNode::parse_length_or_percentage(context, i, num_context)
})); }));
Ok(LengthOrPercentage::Calc(Box::new(calc))) return Ok(LengthOrPercentage::Calc(Box::new(calc)))
}, },
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
/// Parse a non-negative length. /// Parse a non-negative length.
#[inline] #[inline]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<LengthOrPercentage, ParseError<'i>> {
Self::parse_non_negative_quirky(context, input, AllowQuirks::No) Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
} }
/// Parse a non-negative length, with quirks. /// Parse a non-negative length, with quirks.
#[inline] #[inline]
pub fn parse_non_negative_quirky(context: &ParserContext, pub fn parse_non_negative_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<LengthOrPercentage, ()> { -> Result<LengthOrPercentage, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
} }
/// Parse a length, treating dimensionless numbers as pixels /// Parse a length, treating dimensionless numbers as pixels
/// ///
/// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value /// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value
pub fn parse_numbers_are_pixels(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { pub fn parse_numbers_are_pixels<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<LengthOrPercentage, ParseError<'i>> {
if let Ok(lop) = input.try(|i| Self::parse(context, i)) { if let Ok(lop) = input.try(|i| Self::parse(context, i)) {
return Ok(lop) return Ok(lop)
} }
@ -849,9 +858,9 @@ impl LengthOrPercentage {
/// Parse a non-negative length, treating dimensionless numbers as pixels /// Parse a non-negative length, treating dimensionless numbers as pixels
/// ///
/// This is nonstandard behavior used by Firefox for SVG /// This is nonstandard behavior used by Firefox for SVG
pub fn parse_numbers_are_pixels_non_negative(context: &ParserContext, pub fn parse_numbers_are_pixels_non_negative<'i, 't>(context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<LengthOrPercentage, ()> { -> Result<LengthOrPercentage, ParseError<'i>> {
if let Ok(lop) = input.try(|i| Self::parse_non_negative(context, i)) { if let Ok(lop) = input.try(|i| Self::parse_non_negative(context, i)) {
return Ok(lop) return Ok(lop)
} }
@ -862,7 +871,7 @@ impl LengthOrPercentage {
if num >= 0. { if num >= 0. {
Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(num)))) Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(num))))
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
@ -877,7 +886,7 @@ impl LengthOrPercentage {
impl Parse for LengthOrPercentage { impl Parse for LengthOrPercentage {
#[inline] #[inline]
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
@ -886,9 +895,9 @@ impl LengthOrPercentage {
/// Parses a length or a percentage, allowing the unitless length quirk. /// Parses a length or a percentage, allowing the unitless length quirk.
/// https://quirks.spec.whatwg.org/#the-unitless-length-quirk /// https://quirks.spec.whatwg.org/#the-unitless-length-quirk
#[inline] #[inline]
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Self, ()> { allow_quirks: AllowQuirks) -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
} }
} }
@ -919,12 +928,13 @@ impl From<Percentage> for LengthOrPercentageOrAuto {
} }
impl LengthOrPercentageOrAuto { impl LengthOrPercentageOrAuto {
fn parse_internal(context: &ParserContext, fn parse_internal<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
num_context: AllowedLengthType, num_context: AllowedLengthType,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
match try!(input.next()) { let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrAuto::Length), NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrAuto::Length),
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
@ -933,7 +943,7 @@ impl LengthOrPercentageOrAuto {
if value.value != 0. && if value.value != 0. &&
!context.parsing_mode.allows_unitless_lengths() && !context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) { !allow_quirks.allowed(context.quirks_mode) {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(LengthOrPercentageOrAuto::Length( Ok(LengthOrPercentageOrAuto::Length(
NoCalcLength::Absolute(AbsoluteLength::Px(value.value)) NoCalcLength::Absolute(AbsoluteLength::Px(value.value))
@ -948,21 +958,22 @@ impl LengthOrPercentageOrAuto {
Ok(LengthOrPercentageOrAuto::Calc(Box::new(calc))) Ok(LengthOrPercentageOrAuto::Calc(Box::new(calc)))
}, },
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
/// Parse a non-negative length, percentage, or auto. /// Parse a non-negative length, percentage, or auto.
#[inline] #[inline]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<LengthOrPercentageOrAuto, ParseError<'i>> {
Self::parse_non_negative_quirky(context, input, AllowQuirks::No) Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
} }
/// Parse a non-negative length, percentage, or auto. /// Parse a non-negative length, percentage, or auto.
#[inline] #[inline]
pub fn parse_non_negative_quirky(context: &ParserContext, pub fn parse_non_negative_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
} }
@ -984,7 +995,7 @@ impl LengthOrPercentageOrAuto {
impl Parse for LengthOrPercentageOrAuto { impl Parse for LengthOrPercentageOrAuto {
#[inline] #[inline]
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
@ -992,10 +1003,10 @@ impl Parse for LengthOrPercentageOrAuto {
impl LengthOrPercentageOrAuto { impl LengthOrPercentageOrAuto {
/// Parses, with quirks. /// Parses, with quirks.
#[inline] #[inline]
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
} }
} }
@ -1012,13 +1023,14 @@ pub enum LengthOrPercentageOrNone {
} }
impl LengthOrPercentageOrNone { impl LengthOrPercentageOrNone {
fn parse_internal(context: &ParserContext, fn parse_internal<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
num_context: AllowedLengthType, num_context: AllowedLengthType,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<LengthOrPercentageOrNone, ()> -> Result<LengthOrPercentageOrNone, ParseError<'i>>
{ {
match try!(input.next()) { let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrNone::Length), NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrNone::Length),
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
@ -1026,7 +1038,7 @@ impl LengthOrPercentageOrNone {
Token::Number(value) if num_context.is_ok(value.value) => { Token::Number(value) if num_context.is_ok(value.value) => {
if value.value != 0. && !context.parsing_mode.allows_unitless_lengths() && if value.value != 0. && !context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) { !allow_quirks.allowed(context.quirks_mode) {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
Ok(LengthOrPercentageOrNone::Length( Ok(LengthOrPercentageOrNone::Length(
NoCalcLength::Absolute(AbsoluteLength::Px(value.value)) NoCalcLength::Absolute(AbsoluteLength::Px(value.value))
@ -1041,28 +1053,29 @@ impl LengthOrPercentageOrNone {
Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
Ok(LengthOrPercentageOrNone::None), Ok(LengthOrPercentageOrNone::None),
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
/// Parse a non-negative LengthOrPercentageOrNone. /// Parse a non-negative LengthOrPercentageOrNone.
#[inline] #[inline]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
Self::parse_non_negative_quirky(context, input, AllowQuirks::No) Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
} }
/// Parse a non-negative LengthOrPercentageOrNone, with quirks. /// Parse a non-negative LengthOrPercentageOrNone, with quirks.
#[inline] #[inline]
pub fn parse_non_negative_quirky(context: &ParserContext, pub fn parse_non_negative_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
} }
} }
impl Parse for LengthOrPercentageOrNone { impl Parse for LengthOrPercentageOrNone {
#[inline] #[inline]
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedLengthType::All, AllowQuirks::No) Self::parse_internal(context, input, AllowedLengthType::All, AllowQuirks::No)
} }
} }
@ -1095,9 +1108,11 @@ pub enum LengthOrPercentageOrAutoOrContent {
impl LengthOrPercentageOrAutoOrContent { impl LengthOrPercentageOrAutoOrContent {
/// Parse a non-negative LengthOrPercentageOrAutoOrContent. /// Parse a non-negative LengthOrPercentageOrAutoOrContent.
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
let num_context = AllowedLengthType::NonNegative; let num_context = AllowedLengthType::NonNegative;
match try!(input.next()) { let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
NoCalcLength::parse_dimension(context, value.value, unit) NoCalcLength::parse_dimension(context, value.value, unit)
.map(LengthOrPercentageOrAutoOrContent::Length), .map(LengthOrPercentageOrAutoOrContent::Length),
@ -1116,7 +1131,7 @@ impl LengthOrPercentageOrAutoOrContent {
Ok(LengthOrPercentageOrAutoOrContent::Calc(Box::new(calc))) Ok(LengthOrPercentageOrAutoOrContent::Calc(Box::new(calc)))
}, },
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
/// Returns the `auto` value. /// Returns the `auto` value.
@ -1140,7 +1155,8 @@ pub type LengthOrNumber = Either<Length, Number>;
impl LengthOrNumber { impl LengthOrNumber {
/// Parse a non-negative LengthOrNumber. /// Parse a non-negative LengthOrNumber.
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
// We try to parse as a Number first because, for cases like // We try to parse as a Number first because, for cases like
// LengthOrNumber, we want "0" to be parsed as a plain Number rather // LengthOrNumber, we want "0" to be parsed as a plain Number rather
// than a Length (0px); this matches the behaviour of all major browsers // than a Length (0px); this matches the behaviour of all major browsers
@ -1170,18 +1186,18 @@ pub enum MozLength {
} }
impl Parse for MozLength { impl Parse for MozLength {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
MozLength::parse_quirky(context, input, AllowQuirks::No) MozLength::parse_quirky(context, input, AllowQuirks::No)
} }
} }
impl MozLength { impl MozLength {
/// Parses, with quirks. /// Parses, with quirks.
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Self, ()> { allow_quirks: AllowQuirks) -> Result<Self, ParseError<'i>> {
input.try(ExtremumLength::parse).map(MozLength::ExtremumLength) input.try(ExtremumLength::parse).map(MozLength::ExtremumLength)
.or_else(|()| input.try(|i| LengthOrPercentageOrAuto::parse_non_negative_quirky(context, i, allow_quirks)) .or_else(|_| input.try(|i| LengthOrPercentageOrAuto::parse_non_negative_quirky(context, i, allow_quirks))
.map(MozLength::LengthOrPercentageOrAuto)) .map(MozLength::LengthOrPercentageOrAuto))
} }
} }
@ -1196,18 +1212,18 @@ pub enum MaxLength {
} }
impl Parse for MaxLength { impl Parse for MaxLength {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
MaxLength::parse_quirky(context, input, AllowQuirks::No) MaxLength::parse_quirky(context, input, AllowQuirks::No)
} }
} }
impl MaxLength { impl MaxLength {
/// Parses, with quirks. /// Parses, with quirks.
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Self, ()> { allow_quirks: AllowQuirks) -> Result<Self, ParseError<'i>> {
input.try(ExtremumLength::parse).map(MaxLength::ExtremumLength) input.try(ExtremumLength::parse).map(MaxLength::ExtremumLength)
.or_else(|()| input.try(|i| LengthOrPercentageOrNone::parse_non_negative_quirky(context, i, allow_quirks)) .or_else(|_| input.try(|i| LengthOrPercentageOrNone::parse_non_negative_quirky(context, i, allow_quirks))
.map(MaxLength::LengthOrPercentageOrNone)) .map(MaxLength::LengthOrPercentageOrNone))
} }
} }

View file

@ -8,14 +8,14 @@
use Namespace; use Namespace;
use context::QuirksMode; use context::QuirksMode;
use cssparser::{Parser, Token, serialize_identifier}; use cssparser::{Parser, Token, serialize_identifier, BasicParseError};
use parser::{ParserContext, Parse}; use parser::{ParserContext, Parse};
use self::grid::TrackSizeOrRepeat; use self::grid::TrackSizeOrRepeat;
use self::url::SpecifiedUrl; use self::url::SpecifiedUrl;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::f32; use std::f32;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::{ToCss, ParseError, StyleParseError};
use style_traits::values::specified::AllowedNumericType; use style_traits::values::specified::AllowedNumericType;
use super::{Auto, CSSFloat, CSSInteger, Either, None_}; use super::{Auto, CSSFloat, CSSInteger, Either, None_};
use super::computed::{self, Context}; use super::computed::{self, Context};
@ -68,6 +68,7 @@ pub mod transform;
pub mod url { pub mod url {
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use style_traits::ParseError;
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
@ -76,7 +77,7 @@ pub use ::servo::url::*;
pub use ::gecko::url::*; pub use ::gecko::url::*;
impl Parse for SpecifiedUrl { impl Parse for SpecifiedUrl {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let url = try!(input.expect_url()); let url = try!(input.expect_url());
Self::parse_from_string(url, context) Self::parse_from_string(url, context)
} }
@ -91,9 +92,10 @@ no_viewport_percentage!(SpecifiedUrl);
} }
/// Parse an `<integer>` value, handling `calc()` correctly. /// Parse an `<integer>` value, handling `calc()` correctly.
pub fn parse_integer(context: &ParserContext, input: &mut Parser) -> Result<Integer, ()> { pub fn parse_integer<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Integer, ParseError<'i>> {
match try!(input.next()) { match try!(input.next()) {
Token::Number(ref value) => value.int_value.ok_or(()).map(Integer::new), Token::Number(ref value) => value.int_value.ok_or(StyleParseError::UnspecifiedError.into()).map(Integer::new),
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let result = try!(input.parse_nested_block(|i| { let result = try!(input.parse_nested_block(|i| {
CalcNode::parse_integer(context, i) CalcNode::parse_integer(context, i)
@ -101,21 +103,22 @@ pub fn parse_integer(context: &ParserContext, input: &mut Parser) -> Result<Inte
Ok(Integer::from_calc(result)) Ok(Integer::from_calc(result))
} }
_ => Err(()) t => Err(BasicParseError::UnexpectedToken(t).into())
} }
} }
/// Parse a `<number>` value, handling `calc()` correctly, and without length /// Parse a `<number>` value, handling `calc()` correctly, and without length
/// limitations. /// limitations.
pub fn parse_number(context: &ParserContext, input: &mut Parser) -> Result<Number, ()> { pub fn parse_number<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Number, ParseError<'i>> {
parse_number_with_clamping_mode(context, input, AllowedNumericType::All) parse_number_with_clamping_mode(context, input, AllowedNumericType::All)
} }
/// Parse a `<number>` value, with a given clamping mode. /// Parse a `<number>` value, with a given clamping mode.
pub fn parse_number_with_clamping_mode(context: &ParserContext, pub fn parse_number_with_clamping_mode<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
clamping_mode: AllowedNumericType) clamping_mode: AllowedNumericType)
-> Result<Number, ()> { -> Result<Number, ParseError<'i>> {
match try!(input.next()) { match try!(input.next()) {
Token::Number(ref value) if clamping_mode.is_ok(value.value) => { Token::Number(ref value) if clamping_mode.is_ok(value.value) => {
Ok(Number { Ok(Number {
@ -133,7 +136,7 @@ pub fn parse_number_with_clamping_mode(context: &ParserContext,
calc_clamping_mode: Some(clamping_mode), calc_clamping_mode: Some(clamping_mode),
}) })
} }
_ => Err(()) t => Err(BasicParseError::UnexpectedToken(t).into())
} }
} }
@ -220,18 +223,19 @@ impl Angle {
impl Parse for Angle { impl Parse for Angle {
/// Parses an angle according to CSS-VALUES § 6.1. /// Parses an angle according to CSS-VALUES § 6.1.
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
match try!(input.next()) { let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) => { Token::Dimension(ref value, ref unit) => {
Angle::parse_dimension(value.value, Angle::parse_dimension(value.value,
unit, unit,
/* from_calc = */ false) /* from_calc = */ false)
} }
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
input.parse_nested_block(|i| CalcNode::parse_angle(context, i)) return input.parse_nested_block(|i| CalcNode::parse_angle(context, i))
} }
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
} }
@ -260,8 +264,10 @@ impl Angle {
/// ///
/// We can remove this and get back to the unified version Angle::parse once /// We can remove this and get back to the unified version Angle::parse once
/// https://github.com/w3c/csswg-drafts/issues/1162 is resolved. /// https://github.com/w3c/csswg-drafts/issues/1162 is resolved.
pub fn parse_with_unitless(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_with_unitless<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
match try!(input.next()) { -> Result<Self, ParseError<'i>> {
let token = try!(input.next());
match token {
Token::Dimension(ref value, ref unit) => { Token::Dimension(ref value, ref unit) => {
Angle::parse_dimension(value.value, Angle::parse_dimension(value.value,
unit, unit,
@ -269,10 +275,10 @@ impl Angle {
} }
Token::Number(ref value) if value.value == 0. => Ok(Angle::zero()), Token::Number(ref value) if value.value == 0. => Ok(Angle::zero()),
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
input.parse_nested_block(|i| CalcNode::parse_angle(context, i)) return input.parse_nested_block(|i| CalcNode::parse_angle(context, i))
} }
_ => Err(()) _ => Err(())
} }.map_err(|()| BasicParseError::UnexpectedToken(token).into())
} }
} }
@ -337,7 +343,7 @@ impl Time {
let seconds = match_ignore_ascii_case! { unit, let seconds = match_ignore_ascii_case! { unit,
"s" => value, "s" => value,
"ms" => value / 1000.0, "ms" => value / 1000.0,
_ => return Err(()), _ => return Err(())
}; };
Ok(Time { Ok(Time {
@ -354,25 +360,29 @@ impl Time {
} }
} }
fn parse_with_clamping_mode(context: &ParserContext, fn parse_with_clamping_mode<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
clamping_mode: AllowedNumericType) -> Result<Self, ()> { clamping_mode: AllowedNumericType)
-> Result<Self, ParseError<'i>> {
match input.next() { match input.next() {
Ok(Token::Dimension(ref value, ref unit)) if clamping_mode.is_ok(value.value) => { Ok(Token::Dimension(ref value, ref unit)) if clamping_mode.is_ok(value.value) => {
Time::parse_dimension(value.value, &unit, /* from_calc = */ false) Time::parse_dimension(value.value, &unit, /* from_calc = */ false)
.map_err(|()| StyleParseError::UnspecifiedError.into())
} }
Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => { Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => {
match input.parse_nested_block(|i| CalcNode::parse_time(context, i)) { match input.parse_nested_block(|i| CalcNode::parse_time(context, i)) {
Ok(time) if clamping_mode.is_ok(time.seconds) => Ok(time), Ok(time) if clamping_mode.is_ok(time.seconds) => Ok(time),
_ => Err(()), _ => Err(StyleParseError::UnspecifiedError.into()),
} }
} }
_ => Err(()) Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()),
Err(e) => Err(e.into())
} }
} }
/// Parse <time> that values are non-negative. /// Parse <time> that values are non-negative.
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative) Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
} }
} }
@ -393,7 +403,7 @@ impl ToComputedValue for Time {
} }
impl Parse for Time { impl Parse for Time {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::All) Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
} }
} }
@ -425,7 +435,7 @@ pub struct Number {
no_viewport_percentage!(Number); no_viewport_percentage!(Number);
impl Parse for Number { impl Parse for Number {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
parse_number(context, input) parse_number(context, input)
} }
} }
@ -445,7 +455,8 @@ impl Number {
} }
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Number, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Number, ParseError<'i>> {
if context.parsing_mode.allows_all_numeric_values() { if context.parsing_mode.allows_all_numeric_values() {
parse_number(context, input) parse_number(context, input)
} else { } else {
@ -454,7 +465,8 @@ impl Number {
} }
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_at_least_one(context: &ParserContext, input: &mut Parser) -> Result<Number, ()> { pub fn parse_at_least_one<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Number, ParseError<'i>> {
if context.parsing_mode.allows_all_numeric_values() { if context.parsing_mode.allows_all_numeric_values() {
parse_number(context, input) parse_number(context, input)
} else { } else {
@ -506,10 +518,10 @@ pub enum NumberOrPercentage {
no_viewport_percentage!(NumberOrPercentage); no_viewport_percentage!(NumberOrPercentage);
impl NumberOrPercentage { impl NumberOrPercentage {
fn parse_with_clamping_mode(context: &ParserContext, fn parse_with_clamping_mode<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
type_: AllowedNumericType) type_: AllowedNumericType)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
if let Ok(per) = input.try(|i| Percentage::parse_with_clamping_mode(i, type_)) { if let Ok(per) = input.try(|i| Percentage::parse_with_clamping_mode(i, type_)) {
return Ok(NumberOrPercentage::Percentage(per)); return Ok(NumberOrPercentage::Percentage(per));
} }
@ -518,13 +530,14 @@ impl NumberOrPercentage {
} }
/// Parse a non-negative number or percentage. /// Parse a non-negative number or percentage.
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative) Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
} }
} }
impl Parse for NumberOrPercentage { impl Parse for NumberOrPercentage {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::All) Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
} }
} }
@ -537,7 +550,7 @@ pub struct Opacity(Number);
no_viewport_percentage!(Opacity); no_viewport_percentage!(Opacity);
impl Parse for Opacity { impl Parse for Opacity {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
parse_number(context, input).map(Opacity) parse_number(context, input).map(Opacity)
} }
} }
@ -590,27 +603,31 @@ impl Integer {
no_viewport_percentage!(Integer); no_viewport_percentage!(Integer);
impl Parse for Integer { impl Parse for Integer {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
parse_integer(context, input) parse_integer(context, input)
} }
} }
impl Integer { impl Integer {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_with_minimum(context: &ParserContext, input: &mut Parser, min: i32) -> Result<Integer, ()> { pub fn parse_with_minimum<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>, min: i32)
-> Result<Integer, ParseError<'i>> {
match parse_integer(context, input) { match parse_integer(context, input) {
Ok(value) if value.value() >= min => Ok(value), Ok(value) if value.value() >= min => Ok(value),
_ => Err(()), Ok(_value) => Err(StyleParseError::UnspecifiedError.into()),
Err(e) => Err(e),
} }
} }
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Integer, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Integer, ParseError<'i>> {
Integer::parse_with_minimum(context, input, 0) Integer::parse_with_minimum(context, input, 0)
} }
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_positive(context: &ParserContext, input: &mut Parser) -> Result<Integer, ()> { pub fn parse_positive<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Integer, ParseError<'i>> {
Integer::parse_with_minimum(context, input, 1) Integer::parse_with_minimum(context, input, 1)
} }
} }
@ -647,11 +664,11 @@ pub type IntegerOrAuto = Either<Integer, Auto>;
impl IntegerOrAuto { impl IntegerOrAuto {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse_positive(context: &ParserContext, pub fn parse_positive<'i, 't>(context: &ParserContext,
input: &mut Parser) input: &mut Parser<'i, 't>)
-> Result<IntegerOrAuto, ()> { -> Result<IntegerOrAuto, ParseError<'i>> {
match IntegerOrAuto::parse(context, input) { match IntegerOrAuto::parse(context, input) {
Ok(Either::First(integer)) if integer.value() <= 0 => Err(()), Ok(Either::First(integer)) if integer.value() <= 0 => Err(StyleParseError::UnspecifiedError.into()),
result => result, result => result,
} }
} }
@ -739,7 +756,10 @@ impl ToCss for Shadow {
impl Shadow { impl Shadow {
// disable_spread_and_inset is for filter: drop-shadow(...) // disable_spread_and_inset is for filter: drop-shadow(...)
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn parse(context: &ParserContext, input: &mut Parser, disable_spread_and_inset: bool) -> Result<Shadow, ()> { pub fn parse<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>,
disable_spread_and_inset: bool)
-> Result<Shadow, ParseError<'i>> {
let mut lengths = [Length::zero(), Length::zero(), Length::zero(), Length::zero()]; let mut lengths = [Length::zero(), Length::zero(), Length::zero(), Length::zero()];
let mut lengths_parsed = false; let mut lengths_parsed = false;
let mut color = None; let mut color = None;
@ -779,7 +799,7 @@ impl Shadow {
// Lengths must be specified. // Lengths must be specified.
if !lengths_parsed { if !lengths_parsed {
return Err(()) return Err(StyleParseError::UnspecifiedError.into())
} }
debug_assert!(!disable_spread_and_inset || lengths[3] == Length::zero()); debug_assert!(!disable_spread_and_inset || lengths[3] == Length::zero());
@ -841,7 +861,8 @@ pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
impl LengthOrPercentageOrNumber { impl LengthOrPercentageOrNumber {
/// parse a <length-percentage> | <number> enforcing that the contents aren't negative /// parse a <length-percentage> | <number> enforcing that the contents aren't negative
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
// NB: Parse numbers before Lengths so we are consistent about how to // NB: Parse numbers before Lengths so we are consistent about how to
// recognize and serialize "0". // recognize and serialize "0".
if let Ok(num) = input.try(|i| Number::parse_non_negative(context, i)) { if let Ok(num) = input.try(|i| Number::parse_non_negative(context, i)) {
@ -928,19 +949,19 @@ impl ToComputedValue for ClipRect {
} }
impl Parse for ClipRect { impl Parse for ClipRect {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
impl ClipRect { impl ClipRect {
/// Parses a rect(<top>, <left>, <bottom>, <right>), allowing quirks. /// Parses a rect(<top>, <left>, <bottom>, <right>), allowing quirks.
pub fn parse_quirky(context: &ParserContext, input: &mut Parser, pub fn parse_quirky<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Self, ()> { allow_quirks: AllowQuirks) -> Result<Self, ParseError<'i>> {
use values::specified::Length; use values::specified::Length;
fn parse_argument(context: &ParserContext, input: &mut Parser, fn parse_argument<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Option<Length>, ()> { allow_quirks: AllowQuirks) -> Result<Option<Length>, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("auto")).is_ok() { if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
Ok(None) Ok(None)
} else { } else {
@ -948,8 +969,9 @@ impl ClipRect {
} }
} }
if !try!(input.expect_function()).eq_ignore_ascii_case("rect") { let func = try!(input.expect_function());
return Err(()) if !func.eq_ignore_ascii_case("rect") {
return Err(StyleParseError::UnexpectedFunction(func).into())
} }
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
@ -984,8 +1006,8 @@ pub type ClipRectOrAuto = Either<ClipRect, Auto>;
impl ClipRectOrAuto { impl ClipRectOrAuto {
/// Parses a ClipRect or Auto, allowing quirks. /// Parses a ClipRect or Auto, allowing quirks.
pub fn parse_quirky(context: &ParserContext, input: &mut Parser, pub fn parse_quirky<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) -> Result<Self, ()> { allow_quirks: AllowQuirks) -> Result<Self, ParseError<'i>> {
if let Ok(v) = input.try(|i| ClipRect::parse_quirky(context, i, allow_quirks)) { if let Ok(v) = input.try(|i| ClipRect::parse_quirky(context, i, allow_quirks)) {
Ok(Either::First(v)) Ok(Either::First(v))
} else { } else {
@ -1035,7 +1057,7 @@ pub struct Attr {
} }
impl Parse for Attr { impl Parse for Attr {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Attr, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Attr, ParseError<'i>> {
input.expect_function_matching("attr")?; input.expect_function_matching("attr")?;
input.parse_nested_block(|i| Attr::parse_function(context, i)) input.parse_nested_block(|i| Attr::parse_function(context, i))
} }
@ -1068,25 +1090,28 @@ fn get_id_for_namespace(_: &Namespace, _: &ParserContext) -> Result<NamespaceId,
impl Attr { impl Attr {
/// Parse contents of attr() assuming we have already parsed `attr` and are /// Parse contents of attr() assuming we have already parsed `attr` and are
/// within a parse_nested_block() /// within a parse_nested_block()
pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Attr, ()> { pub fn parse_function<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Attr, ParseError<'i>> {
// Syntax is `[namespace? `|`]? ident` // Syntax is `[namespace? `|`]? ident`
// no spaces allowed // no spaces allowed
let first = input.try(|i| i.expect_ident()).ok(); let first = input.try(|i| i.expect_ident()).ok();
if let Ok(token) = input.try(|i| i.next_including_whitespace()) { if let Ok(token) = input.try(|i| i.next_including_whitespace()) {
match token { match token {
Token::Delim('|') => {} Token::Delim('|') => {}
_ => return Err(()), t => return Err(BasicParseError::UnexpectedToken(t).into()),
} }
// must be followed by an ident // must be followed by an ident
let second_token = match input.next_including_whitespace()? { let second_token = match input.next_including_whitespace()? {
Token::Ident(second) => second, Token::Ident(second) => second,
_ => return Err(()), t => return Err(BasicParseError::UnexpectedToken(t).into()),
}; };
let ns_with_id = if let Some(ns) = first { let ns_with_id = if let Some(ns) = first {
let ns: Namespace = ns.into(); let ns: Namespace = ns.into();
let id = get_id_for_namespace(&ns, context)?; let id: Result<_, ParseError> =
Some((ns, id)) get_id_for_namespace(&ns, context)
.map_err(|()| StyleParseError::UnspecifiedError.into());
Some((ns, id?))
} else { } else {
None None
}; };
@ -1102,7 +1127,7 @@ impl Attr {
attribute: first.into_owned(), attribute: first.into_owned(),
}) })
} else { } else {
Err(()) Err(StyleParseError::UnspecifiedError.into())
} }
} }
} }

View file

@ -10,7 +10,7 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt; use std::fmt;
use style_traits::{HasViewportPercentage, ToCss}; use style_traits::{HasViewportPercentage, ToCss, ParseError};
use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage}; use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage};
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
use values::generics::position::Position as GenericPosition; use values::generics::position::Position as GenericPosition;
@ -50,17 +50,17 @@ define_css_keyword_enum! { Y:
add_impls_for_keyword_enum!(Y); add_impls_for_keyword_enum!(Y);
impl Parse for Position { impl Parse for Position {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
impl Position { impl Position {
/// Parses a `<position>`, with quirks. /// Parses a `<position>`, with quirks.
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
match input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { match input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
Ok(x_pos @ PositionComponent::Center) => { Ok(x_pos @ PositionComponent::Center) => {
if let Ok(y_pos) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { if let Ok(y_pos) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
@ -104,7 +104,7 @@ impl Position {
Err(_) => {}, Err(_) => {},
} }
let y_keyword = Y::parse(input)?; let y_keyword = Y::parse(input)?;
let lop_and_x_pos: Result<_, ()> = input.try(|i| { let lop_and_x_pos: Result<_, ParseError> = input.try(|i| {
let y_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok(); let y_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok();
if let Ok(x_keyword) = i.try(X::parse) { if let Ok(x_keyword) = i.try(X::parse) {
let x_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok(); let x_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok();
@ -167,17 +167,17 @@ impl<S> HasViewportPercentage for PositionComponent<S> {
} }
impl<S: Parse> Parse for PositionComponent<S> { impl<S: Parse> Parse for PositionComponent<S> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No) Self::parse_quirky(context, input, AllowQuirks::No)
} }
} }
impl<S: Parse> PositionComponent<S> { impl<S: Parse> PositionComponent<S> {
/// Parses a component of a CSS position, with quirks. /// Parses a component of a CSS position, with quirks.
pub fn parse_quirky(context: &ParserContext, pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser, input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks) allow_quirks: AllowQuirks)
-> Result<Self, ()> { -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("center")).is_ok() { if input.try(|i| i.expect_ident_matching("center")).is_ok() {
return Ok(PositionComponent::Center); return Ok(PositionComponent::Center);
} }

View file

@ -6,6 +6,7 @@
use cssparser::Parser; use cssparser::Parser;
use parser::ParserContext; use parser::ParserContext;
use style_traits::ParseError;
use values::generics::rect::Rect; use values::generics::rect::Rect;
use values::specified::length::LengthOrNumber; use values::specified::length::LengthOrNumber;
@ -15,7 +16,8 @@ pub type LengthOrNumberRect = Rect<LengthOrNumber>;
impl LengthOrNumberRect { impl LengthOrNumberRect {
/// Parses a `LengthOrNumberRect`, rejecting negative values. /// Parses a `LengthOrNumberRect`, rejecting negative values.
#[inline] #[inline]
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
Rect::parse_with(context, input, LengthOrNumber::parse_non_negative) Rect::parse_with(context, input, LengthOrNumber::parse_non_negative)
} }
} }

View file

@ -6,7 +6,9 @@
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use style_traits::ParseError;
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
use values::computed::text::LineHeight as ComputedLineHeight; use values::computed::text::LineHeight as ComputedLineHeight;
use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::InitialLetter as GenericInitialLetter;
@ -28,7 +30,7 @@ pub type WordSpacing = Spacing<LengthOrPercentage>;
pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>; pub type LineHeight = GenericLineHeight<Number, LengthOrPercentage>;
impl Parse for InitialLetter { impl Parse for InitialLetter {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("normal")).is_ok() { if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(GenericInitialLetter::Normal); return Ok(GenericInitialLetter::Normal);
} }
@ -39,7 +41,7 @@ impl Parse for InitialLetter {
} }
impl Parse for LetterSpacing { impl Parse for LetterSpacing {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Spacing::parse_with(context, input, |c, i| { Spacing::parse_with(context, input, |c, i| {
Length::parse_quirky(c, i, AllowQuirks::Yes) Length::parse_quirky(c, i, AllowQuirks::Yes)
}) })
@ -47,7 +49,7 @@ impl Parse for LetterSpacing {
} }
impl Parse for WordSpacing { impl Parse for WordSpacing {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Spacing::parse_with(context, input, |c, i| { Spacing::parse_with(context, input, |c, i| {
LengthOrPercentage::parse_quirky(c, i, AllowQuirks::Yes) LengthOrPercentage::parse_quirky(c, i, AllowQuirks::Yes)
}) })
@ -55,22 +57,23 @@ impl Parse for WordSpacing {
} }
impl Parse for LineHeight { impl Parse for LineHeight {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(number) = input.try(|i| Number::parse_non_negative(context, i)) { if let Ok(number) = input.try(|i| Number::parse_non_negative(context, i)) {
return Ok(GenericLineHeight::Number(number)) return Ok(GenericLineHeight::Number(number))
} }
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(GenericLineHeight::Length(lop)) return Ok(GenericLineHeight::Length(lop))
} }
match &input.expect_ident()? { let ident = input.expect_ident()?;
ident if ident.eq_ignore_ascii_case("normal") => { match ident {
ref ident if ident.eq_ignore_ascii_case("normal") => {
Ok(GenericLineHeight::Normal) Ok(GenericLineHeight::Normal)
}, },
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
ident if ident.eq_ignore_ascii_case("-moz-block-height") => { ref ident if ident.eq_ignore_ascii_case("-moz-block-height") => {
Ok(GenericLineHeight::MozBlockHeight) Ok(GenericLineHeight::MozBlockHeight)
}, },
_ => Err(()), ident => Err(SelectorParseError::UnexpectedIdent(ident).into()),
} }
} }
} }

View file

@ -7,6 +7,8 @@
use cssparser::Parser; use cssparser::Parser;
use euclid::Point2D; use euclid::Point2D;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use style_traits::{ParseError, StyleParseError};
use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, Context, ToComputedValue}; use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, Context, ToComputedValue};
use values::computed::transform::TimingFunction as ComputedTimingFunction; use values::computed::transform::TimingFunction as ComputedTimingFunction;
use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction}; use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction};
@ -34,7 +36,7 @@ pub enum OriginComponent<S> {
pub type TimingFunction = GenericTimingFunction<Integer, Number>; pub type TimingFunction = GenericTimingFunction<Integer, Number>;
impl Parse for TransformOrigin { impl Parse for TransformOrigin {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
let parse_depth = |input: &mut Parser| { let parse_depth = |input: &mut Parser| {
input.try(|i| Length::parse(context, i)).unwrap_or(Length::from_px(0.)) input.try(|i| Length::parse(context, i)).unwrap_or(Length::from_px(0.))
}; };
@ -85,7 +87,7 @@ impl Parse for TransformOrigin {
impl<S> Parse for OriginComponent<S> impl<S> Parse for OriginComponent<S>
where S: Parse, where S: Parse,
{ {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("center")).is_ok() { if input.try(|i| i.expect_ident_matching("center")).is_ok() {
return Ok(OriginComponent::Center); return Ok(OriginComponent::Center);
} }
@ -123,7 +125,7 @@ impl<S> ToComputedValue for OriginComponent<S>
} }
impl Parse for TimingFunction { impl Parse for TimingFunction {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(keyword) = input.try(TimingKeyword::parse) { if let Ok(keyword) = input.try(TimingKeyword::parse) {
return Ok(GenericTimingFunction::Keyword(keyword)); return Ok(GenericTimingFunction::Keyword(keyword));
} }
@ -131,13 +133,13 @@ impl Parse for TimingFunction {
let position = match_ignore_ascii_case! { &ident, let position = match_ignore_ascii_case! { &ident,
"step-start" => StepPosition::Start, "step-start" => StepPosition::Start,
"step-end" => StepPosition::End, "step-end" => StepPosition::End,
_ => return Err(()), _ => return Err(SelectorParseError::UnexpectedIdent(ident.clone()).into()),
}; };
return Ok(GenericTimingFunction::Steps(Integer::new(1), position)); return Ok(GenericTimingFunction::Steps(Integer::new(1), position));
} }
let function = input.expect_function()?; let function = input.expect_function()?;
input.parse_nested_block(|i| { input.parse_nested_block(move |i| {
match_ignore_ascii_case! { &function, (match_ignore_ascii_case! { &function,
"cubic-bezier" => { "cubic-bezier" => {
let p1x = Number::parse(context, i)?; let p1x = Number::parse(context, i)?;
i.expect_comma()?; i.expect_comma()?;
@ -148,7 +150,7 @@ impl Parse for TimingFunction {
let p2y = Number::parse(context, i)?; let p2y = Number::parse(context, i)?;
if p1x.get() < 0.0 || p1x.get() > 1.0 || p2x.get() < 0.0 || p2x.get() > 1.0 { if p1x.get() < 0.0 || p1x.get() > 1.0 || p2x.get() < 0.0 || p2x.get() > 1.0 {
return Err(()); return Err(StyleParseError::UnspecifiedError.into());
} }
let (p1, p2) = (Point2D::new(p1x, p1y), Point2D::new(p2x, p2y)); let (p1, p2) = (Point2D::new(p1x, p1y), Point2D::new(p2x, p2y));
@ -167,7 +169,7 @@ impl Parse for TimingFunction {
Ok(GenericTimingFunction::Frames(frames)) Ok(GenericTimingFunction::Frames(frames))
}, },
_ => Err(()), _ => Err(()),
} }).map_err(|()| StyleParseError::UnexpectedFunction(function).into())
}) })
} }
} }

View file

@ -16,9 +16,10 @@ gecko = []
[dependencies] [dependencies]
app_units = "0.4.1" app_units = "0.4.1"
cssparser = "0.13.7" cssparser = "0.14.0"
euclid = "0.13" euclid = "0.13"
heapsize = {version = "0.4", optional = true} heapsize = {version = "0.4", optional = true}
heapsize_derive = {version = "0.1", optional = true} heapsize_derive = {version = "0.1", optional = true}
selectors = { path = "../selectors" }
serde = {version = "0.9", optional = true} serde = {version = "0.9", optional = true}
serde_derive = {version = "0.9", optional = true} serde_derive = {version = "0.9", optional = true}

View file

@ -18,8 +18,12 @@ extern crate app_units;
extern crate euclid; extern crate euclid;
#[cfg(feature = "servo")] extern crate heapsize; #[cfg(feature = "servo")] extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive; #[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
extern crate selectors;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive; #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
use selectors::parser::SelectorParseError;
use std::borrow::Cow;
/// Opaque type stored in type-unsafe work queues for parallel layout. /// Opaque type stored in type-unsafe work queues for parallel layout.
/// Must be transmutable to and from `TNode`. /// Must be transmutable to and from `TNode`.
pub type UnsafeNode = (usize, usize); pub type UnsafeNode = (usize, usize);
@ -68,3 +72,71 @@ pub mod viewport;
pub use values::{ToCss, OneOrMoreCommaSeparated}; pub use values::{ToCss, OneOrMoreCommaSeparated};
pub use viewport::HasViewportPercentage; pub use viewport::HasViewportPercentage;
/// The error type for all CSS parsing routines.
pub type ParseError<'i> = cssparser::ParseError<'i, SelectorParseError<'i, StyleParseError<'i>>>;
#[derive(Clone, Debug, PartialEq)]
/// Errors that can be encountered while parsing CSS values.
pub enum StyleParseError<'i> {
/// A bad URL token in a DVB.
BadUrlInDeclarationValueBlock,
/// A bad string token in a DVB.
BadStringInDeclarationValueBlock,
/// Unexpected closing parenthesis in a DVB.
UnbalancedCloseParenthesisInDeclarationValueBlock,
/// Unexpected closing bracket in a DVB.
UnbalancedCloseSquareBracketInDeclarationValueBlock,
/// Unexpected closing curly bracket in a DVB.
UnbalancedCloseCurlyBracketInDeclarationValueBlock,
/// A property declaration parsing error.
PropertyDeclaration(PropertyDeclarationParseError),
/// A property declaration value had input remaining after successfully parsing.
PropertyDeclarationValueNotExhausted,
/// An unexpected dimension token was encountered.
UnexpectedDimension(Cow<'i, str>),
/// A media query using a ranged expression with no value was encountered.
RangedExpressionWithNoValue,
/// A function was encountered that was not expected.
UnexpectedFunction(Cow<'i, str>),
/// @namespace must be before any rule but @charset and @import
UnexpectedNamespaceRule,
/// @import must be before any rule but @charset
UnexpectedImportRule,
/// Unexpected @charset rule encountered.
UnexpectedCharsetRule,
/// Unsupported @ rule
UnsupportedAtRule(Cow<'i, str>),
/// A placeholder for many sources of errors that require more specific variants.
UnspecifiedError,
}
/// The result of parsing a property declaration.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
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<'a> From<StyleParseError<'a>> for ParseError<'a> {
fn from(this: StyleParseError<'a>) -> Self {
cssparser::ParseError::Custom(SelectorParseError::Custom(this))
}
}
impl<'a> From<PropertyDeclarationParseError> for ParseError<'a> {
fn from(this: PropertyDeclarationParseError) -> Self {
cssparser::ParseError::Custom(SelectorParseError::Custom(StyleParseError::PropertyDeclaration(this)))
}
}

View file

@ -171,9 +171,13 @@ macro_rules! __define_css_keyword_enum__actual {
impl $name { impl $name {
/// Parse this property from a CSS input stream. /// Parse this property from a CSS input stream.
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> { pub fn parse<'i, 't>(input: &mut ::cssparser::Parser<'i, 't>)
-> Result<$name, $crate::ParseError<'i>> {
let ident = input.expect_ident()?; let ident = input.expect_ident()?;
Self::from_ident(&ident) Self::from_ident(&ident)
.map_err(|()| ::cssparser::ParseError::Basic(
::cssparser::BasicParseError::UnexpectedToken(
::cssparser::Token::Ident(ident))))
} }
/// Parse this property from an already-tokenized identifier. /// Parse this property from an already-tokenized identifier.

Some files were not shown because too many files have changed in this diff Show more