Skip to content

Commit f51e0dd

Browse files
committed
Return more specific parse error data.
1 parent af83617 commit f51e0dd

File tree

7 files changed

+293
-211
lines changed

7 files changed

+293
-211
lines changed

src/color.rs

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::fmt;
66
use std::f32::consts::PI;
77

8-
use super::{Token, Parser, ToCss};
8+
use super::{Token, Parser, ToCss, ParseError};
99
use tokenizer::NumericValue;
1010

1111
#[cfg(feature = "serde")]
@@ -141,29 +141,30 @@ impl Color {
141141
/// Parse a <color> value, per CSS Color Module Level 3.
142142
///
143143
/// FIXME(#2) Deprecated CSS2 System Colors are not supported yet.
144-
pub fn parse(input: &mut Parser) -> Result<Color, ()> {
145-
match try!(input.next()) {
146-
Token::Hash(value) | Token::IDHash(value) => parse_color_hash(&*value),
147-
Token::Ident(value) => parse_color_keyword(&*value),
148-
Token::Function(name) => {
149-
input.parse_nested_block(|arguments| {
144+
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Color, ParseError<'i>> {
145+
let token = try!(input.next());
146+
match token {
147+
Token::Hash(ref value) | Token::IDHash(ref value) => parse_color_hash(&*value),
148+
Token::Ident(ref value) => parse_color_keyword(&*value),
149+
Token::Function(ref name) => {
150+
return input.parse_nested_block(|arguments| {
150151
parse_color_function(&*name, arguments)
151-
})
152+
});
152153
}
153154
_ => Err(())
154-
}
155+
}.map_err(|()| ParseError::UnexpectedToken(token))
155156
}
156157
}
157158

158159

159160
#[inline]
160-
fn rgb(red: u8, green: u8, blue: u8) -> Result<Color, ()> {
161+
fn rgb(red: u8, green: u8, blue: u8) -> Color {
161162
rgba(red, green, blue, 255)
162163
}
163164

164165
#[inline]
165-
fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Result<Color, ()> {
166-
Ok(Color::RGBA(RGBA::new(red, green, blue, alpha)))
166+
fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
167+
Color::RGBA(RGBA::new(red, green, blue, alpha))
167168
}
168169

169170

@@ -359,29 +360,29 @@ fn from_hex(c: u8) -> Result<u8, ()> {
359360
fn parse_color_hash(value: &str) -> Result<Color, ()> {
360361
let value = value.as_bytes();
361362
match value.len() {
362-
8 => rgba(
363+
8 => Ok(rgba(
363364
try!(from_hex(value[0])) * 16 + try!(from_hex(value[1])),
364365
try!(from_hex(value[2])) * 16 + try!(from_hex(value[3])),
365366
try!(from_hex(value[4])) * 16 + try!(from_hex(value[5])),
366367
try!(from_hex(value[6])) * 16 + try!(from_hex(value[7])),
367-
),
368-
6 => rgb(
368+
)),
369+
6 => Ok(rgb(
369370
try!(from_hex(value[0])) * 16 + try!(from_hex(value[1])),
370371
try!(from_hex(value[2])) * 16 + try!(from_hex(value[3])),
371372
try!(from_hex(value[4])) * 16 + try!(from_hex(value[5])),
372-
),
373-
4 => rgba(
373+
)),
374+
4 => Ok(rgba(
374375
try!(from_hex(value[0])) * 17,
375376
try!(from_hex(value[1])) * 17,
376377
try!(from_hex(value[2])) * 17,
377378
try!(from_hex(value[3])) * 17,
378-
),
379-
3 => rgb(
379+
)),
380+
3 => Ok(rgb(
380381
try!(from_hex(value[0])) * 17,
381382
try!(from_hex(value[1])) * 17,
382383
try!(from_hex(value[2])) * 17,
383-
),
384-
_ => Err(())
384+
)),
385+
_ => Err(()),
385386
}
386387
}
387388

@@ -401,11 +402,11 @@ fn clamp_256_f32(val: f32) -> u8 {
401402
}
402403

403404
#[inline]
404-
fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()> {
405+
fn parse_color_function<'i, 't>(name: &str, arguments: &mut Parser<'i, 't>) -> Result<Color, ParseError<'i>> {
405406
let (red, green, blue, uses_commas) = match_ignore_ascii_case! { name,
406407
"rgb" | "rgba" => parse_rgb_components_rgb(arguments)?,
407408
"hsl" | "hsla" => parse_rgb_components_hsl(arguments)?,
408-
_ => return Err(())
409+
_ => return Err(ParseError::UnexpectedToken(Token::Ident(name.to_owned().into()))),
409410
};
410411

411412
let alpha = if !arguments.is_exhausted() {
@@ -414,7 +415,7 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
414415
} else {
415416
match try!(arguments.next()) {
416417
Token::Delim('/') => {},
417-
_ => return Err(())
418+
t => return Err(ParseError::UnexpectedToken(t)),
418419
};
419420
};
420421
let token = try!(arguments.next());
@@ -425,21 +426,21 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
425426
Token::Percentage(ref v) => {
426427
clamp_unit_f32(v.unit_value)
427428
}
428-
_ => {
429-
return Err(())
429+
t => {
430+
return Err(ParseError::UnexpectedToken(t))
430431
}
431432
}
432433
} else {
433434
255
434435
};
435436

436437
try!(arguments.expect_exhausted());
437-
rgba(red, green, blue, alpha)
438+
Ok(rgba(red, green, blue, alpha))
438439
}
439440

440441

441442
#[inline]
442-
fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool), ()> {
443+
fn parse_rgb_components_rgb<'i, 't>(arguments: &mut Parser<'i, 't>) -> Result<(u8, u8, u8, bool), ParseError<'i>> {
443444
let red: u8;
444445
let green: u8;
445446
let blue: u8;
@@ -456,7 +457,7 @@ fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
456457
uses_commas = true;
457458
try!(arguments.expect_number())
458459
}
459-
_ => return Err(())
460+
t => return Err(ParseError::UnexpectedToken(t))
460461
});
461462
if uses_commas {
462463
try!(arguments.expect_comma());
@@ -471,36 +472,38 @@ fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
471472
uses_commas = true;
472473
try!(arguments.expect_percentage())
473474
}
474-
_ => return Err(())
475+
t => return Err(ParseError::UnexpectedToken(t))
475476
});
476477
if uses_commas {
477478
try!(arguments.expect_comma());
478479
}
479480
blue = clamp_unit_f32(try!(arguments.expect_percentage()));
480481
}
481-
_ => return Err(())
482+
t => return Err(ParseError::UnexpectedToken(t))
482483
};
483484
return Ok((red, green, blue, uses_commas));
484485
}
485486

486487
#[inline]
487-
fn parse_rgb_components_hsl(arguments: &mut Parser) -> Result<(u8, u8, u8, bool), ()> {
488+
fn parse_rgb_components_hsl<'i, 't>(arguments: &mut Parser<'i, 't>) -> Result<(u8, u8, u8, bool), ParseError<'i>> {
488489
let mut uses_commas = false;
489490
// Hue given as an angle
490491
// https://drafts.csswg.org/css-values/#angles
491-
let hue_degrees = match try!(arguments.next()) {
492-
Token::Number(NumericValue { value: v, .. }) => v,
493-
Token::Dimension(NumericValue { value: v, .. }, unit) => {
492+
let token = try!(arguments.next());
493+
let hue_degrees = match token {
494+
Token::Number(NumericValue { value: v, .. }) => Ok(v),
495+
Token::Dimension(NumericValue { value: v, .. }, ref unit) => {
494496
match_ignore_ascii_case! { &*unit,
495-
"deg" => v,
496-
"grad" => v * 360. / 400.,
497-
"rad" => v * 360. / (2. * PI),
498-
"turn" => v * 360.,
499-
_ => return Err(())
497+
"deg" => Ok(v),
498+
"grad" => Ok(v * 360. / 400.),
499+
"rad" => Ok(v * 360. / (2. * PI)),
500+
"turn" => Ok(v * 360.),
501+
_ => Err(()),
500502
}
501503
}
502-
_ => return Err(())
504+
t => return Err(ParseError::UnexpectedToken(t))
503505
};
506+
let hue_degrees = try!(hue_degrees.map_err(|()| ParseError::UnexpectedToken(token)));
504507
// Subtract an integer before rounding, to avoid some rounding errors:
505508
let hue_normalized_degrees = hue_degrees - 360. * (hue_degrees / 360.).floor();
506509
let hue = hue_normalized_degrees / 360.;
@@ -513,7 +516,7 @@ fn parse_rgb_components_hsl(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
513516
uses_commas = true;
514517
try!(arguments.expect_percentage())
515518
}
516-
_ => return Err(())
519+
t => return Err(ParseError::UnexpectedToken(t))
517520
};
518521
let saturation = saturation.max(0.).min(1.);
519522

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub use from_bytes::{stylesheet_encoding, EncodingSupport};
8989
pub use color::{RGBA, Color, parse_color_keyword};
9090
pub use nth::parse_nth;
9191
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
92-
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
92+
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition, ParseError};
9393
pub use unicode_range::UnicodeRange;
9494

9595
// For macros

src/nth.rs

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,76 +4,98 @@
44

55
use std::ascii::AsciiExt;
66

7-
use super::{Token, Parser};
7+
use super::{Token, Parser, ParseError};
88

99

1010
/// Parse the *An+B* notation, as found in the `:nth-child()` selector.
1111
/// The input is typically the arguments of a function,
1212
/// in which case the caller needs to check if the arguments’ parser is exhausted.
1313
/// Return `Ok((A, B))`, or `Err(())` for a syntax error.
14-
pub fn parse_nth(input: &mut Parser) -> Result<(i32, i32), ()> {
15-
match try!(input.next()) {
16-
Token::Number(value) => Ok((0, try!(value.int_value.ok_or(())) as i32)),
17-
Token::Dimension(value, unit) => {
18-
let a = try!(value.int_value.ok_or(())) as i32;
19-
match_ignore_ascii_case! { &unit,
20-
"n" => parse_b(input, a),
21-
"n-" => parse_signless_b(input, a, -1),
22-
_ => Ok((a, try!(parse_n_dash_digits(&*unit))))
14+
pub fn parse_nth<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(i32, i32), ParseError<'i>> {
15+
let token = try!(input.next());
16+
match token {
17+
Token::Number(ref value) => {
18+
match value.int_value {
19+
Some(v) => Ok((0, v as i32)),
20+
None => Err(()),
2321
}
2422
}
25-
Token::Ident(value) => {
23+
Token::Dimension(value, ref unit) => {
24+
match value.int_value {
25+
Some(v) => {
26+
let a = v as i32;
27+
match_ignore_ascii_case! {
28+
&unit,
29+
"n" => Ok(try!(parse_b(input, a))),
30+
"n-" => Ok(try!(parse_signless_b(input, a, -1))),
31+
_ => {
32+
parse_n_dash_digits(&*unit).map(|val| (a, val))
33+
}
34+
}
35+
}
36+
None => Err(()),
37+
}
38+
}
39+
Token::Ident(ref value) => {
2640
match_ignore_ascii_case! { &value,
2741
"even" => Ok((2, 0)),
2842
"odd" => Ok((2, 1)),
29-
"n" => parse_b(input, 1),
30-
"-n" => parse_b(input, -1),
31-
"n-" => parse_signless_b(input, 1, -1),
32-
"-n-" => parse_signless_b(input, -1, -1),
43+
"n" => Ok(try!(parse_b(input, 1))),
44+
"-n" => Ok(try!(parse_b(input, -1))),
45+
"n-" => Ok(try!(parse_signless_b(input, 1, -1))),
46+
"-n-" => Ok(try!(parse_signless_b(input, -1, -1))),
3347
_ => if value.starts_with("-") {
34-
Ok((-1, try!(parse_n_dash_digits(&value[1..]))))
48+
parse_n_dash_digits(&value[1..]).map(|v| (-1, v))
3549
} else {
36-
Ok((1, try!(parse_n_dash_digits(&*value))))
50+
parse_n_dash_digits(&*value).map(|v| (1, v))
3751
}
3852
}
3953
}
4054
Token::Delim('+') => match try!(input.next_including_whitespace()) {
4155
Token::Ident(value) => {
4256
match_ignore_ascii_case! { &value,
43-
"n" => parse_b(input, 1),
44-
"n-" => parse_signless_b(input, 1, -1),
45-
_ => Ok((1, try!(parse_n_dash_digits(&*value))))
57+
"n" => Ok(try!(parse_b(input, 1))),
58+
"n-" => Ok(try!(parse_signless_b(input, 1, -1))),
59+
_ => parse_n_dash_digits(&*value).map(|v| (1, v))
4660
}
4761
}
48-
_ => Err(())
62+
t => return Err(ParseError::UnexpectedToken(t)),
4963
},
50-
_ => Err(())
51-
}
64+
_ => Err(()),
65+
}.map_err(|()| ParseError::UnexpectedToken(token))
5266
}
5367

5468

55-
fn parse_b(input: &mut Parser, a: i32) -> Result<(i32, i32), ()> {
69+
fn parse_b<'i, 't>(input: &mut Parser<'i, 't>, a: i32) -> Result<(i32, i32), ParseError<'i>> {
5670
let start_position = input.position();
57-
match input.next() {
58-
Ok(Token::Delim('+')) => parse_signless_b(input, a, 1),
59-
Ok(Token::Delim('-')) => parse_signless_b(input, a, -1),
71+
let token = input.next();
72+
match token {
73+
Ok(Token::Delim('+')) => Ok(try!(parse_signless_b(input, a, 1))),
74+
Ok(Token::Delim('-')) => Ok(try!(parse_signless_b(input, a, -1))),
6075
Ok(Token::Number(ref value)) if value.has_sign => {
61-
Ok((a, try!(value.int_value.ok_or(())) as i32))
76+
match value.int_value {
77+
Some(v) => Ok((a, v as i32)),
78+
None => Err(()),
79+
}
6280
}
6381
_ => {
6482
input.reset(start_position);
6583
Ok((a, 0))
6684
}
67-
}
85+
}.map_err(|()| ParseError::UnexpectedToken(token.unwrap()))
6886
}
6987

70-
fn parse_signless_b(input: &mut Parser, a: i32, b_sign: i32) -> Result<(i32, i32), ()> {
71-
match try!(input.next()) {
88+
fn parse_signless_b<'i, 't>(input: &mut Parser<'i, 't>, a: i32, b_sign: i32) -> Result<(i32, i32), ParseError<'i>> {
89+
let token = try!(input.next());
90+
match token {
7291
Token::Number(ref value) if !value.has_sign => {
73-
Ok((a, b_sign * (try!(value.int_value.ok_or(())) as i32)))
92+
match value.int_value {
93+
Some(v) => Ok((a, b_sign * v as i32)),
94+
None => Err(()),
95+
}
7496
}
7597
_ => Err(())
76-
}
98+
}.map_err(|()| ParseError::UnexpectedToken(token))
7799
}
78100

79101
fn parse_n_dash_digits(string: &str) -> Result<i32, ()> {

0 commit comments

Comments
 (0)