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

View file

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