Skip to content

Commit bec5cc6

Browse files
committed
Return more specific parse error data.
1 parent 1b1f703 commit bec5cc6

File tree

7 files changed

+292
-210
lines changed

7 files changed

+292
-210
lines changed

src/color.rs

+44-41
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,46 +141,47 @@ 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) => {
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) => {
147148
Color::parse_hash(value.as_bytes())
148149
},
149-
Token::Ident(value) => parse_color_keyword(&*value),
150-
Token::Function(name) => {
151-
input.parse_nested_block(|arguments| {
150+
Token::Ident(ref value) => parse_color_keyword(&*value),
151+
Token::Function(ref name) => {
152+
return input.parse_nested_block(|arguments| {
152153
parse_color_function(&*name, arguments)
153-
})
154+
});
154155
}
155156
_ => Err(())
156-
}
157+
}.map_err(|()| ParseError::UnexpectedToken(token))
157158
}
158159

159160
/// Parse a color hash, without the leading '#' character.
160161
#[inline]
161162
pub fn parse_hash(value: &[u8]) -> Result<Self, ()> {
162163
match value.len() {
163-
8 => rgba(
164+
8 => Ok(rgba(
164165
try!(from_hex(value[0])) * 16 + try!(from_hex(value[1])),
165166
try!(from_hex(value[2])) * 16 + try!(from_hex(value[3])),
166167
try!(from_hex(value[4])) * 16 + try!(from_hex(value[5])),
167-
try!(from_hex(value[6])) * 16 + try!(from_hex(value[7])),
168+
try!(from_hex(value[6])) * 16 + try!(from_hex(value[7]))),
168169
),
169-
6 => rgb(
170+
6 => Ok(rgb(
170171
try!(from_hex(value[0])) * 16 + try!(from_hex(value[1])),
171172
try!(from_hex(value[2])) * 16 + try!(from_hex(value[3])),
172-
try!(from_hex(value[4])) * 16 + try!(from_hex(value[5])),
173+
try!(from_hex(value[4])) * 16 + try!(from_hex(value[5]))),
173174
),
174-
4 => rgba(
175+
4 => Ok(rgba(
175176
try!(from_hex(value[0])) * 17,
176177
try!(from_hex(value[1])) * 17,
177178
try!(from_hex(value[2])) * 17,
178-
try!(from_hex(value[3])) * 17,
179+
try!(from_hex(value[3])) * 17),
179180
),
180-
3 => rgb(
181+
3 => Ok(rgb(
181182
try!(from_hex(value[0])) * 17,
182183
try!(from_hex(value[1])) * 17,
183-
try!(from_hex(value[2])) * 17,
184+
try!(from_hex(value[2])) * 17),
184185
),
185186
_ => Err(())
186187
}
@@ -190,13 +191,13 @@ impl Color {
190191

191192

192193
#[inline]
193-
fn rgb(red: u8, green: u8, blue: u8) -> Result<Color, ()> {
194+
fn rgb(red: u8, green: u8, blue: u8) -> Color {
194195
rgba(red, green, blue, 255)
195196
}
196197

197198
#[inline]
198-
fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Result<Color, ()> {
199-
Ok(Color::RGBA(RGBA::new(red, green, blue, alpha)))
199+
fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
200+
Color::RGBA(RGBA::new(red, green, blue, alpha))
200201
}
201202

202203

@@ -410,11 +411,11 @@ fn clamp_floor_256_f32(val: f32) -> u8 {
410411
}
411412

412413
#[inline]
413-
fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()> {
414+
fn parse_color_function<'i, 't>(name: &str, arguments: &mut Parser<'i, 't>) -> Result<Color, ParseError<'i>> {
414415
let (red, green, blue, uses_commas) = match_ignore_ascii_case! { name,
415416
"rgb" | "rgba" => parse_rgb_components_rgb(arguments)?,
416417
"hsl" | "hsla" => parse_rgb_components_hsl(arguments)?,
417-
_ => return Err(())
418+
_ => return Err(ParseError::UnexpectedToken(Token::Ident(name.to_owned().into()))),
418419
};
419420

420421
let alpha = if !arguments.is_exhausted() {
@@ -423,7 +424,7 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
423424
} else {
424425
match try!(arguments.next()) {
425426
Token::Delim('/') => {},
426-
_ => return Err(())
427+
t => return Err(ParseError::UnexpectedToken(t)),
427428
};
428429
};
429430
let token = try!(arguments.next());
@@ -434,21 +435,21 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
434435
Token::Percentage(ref v) => {
435436
clamp_unit_f32(v.unit_value)
436437
}
437-
_ => {
438-
return Err(())
438+
t => {
439+
return Err(ParseError::UnexpectedToken(t))
439440
}
440441
}
441442
} else {
442443
255
443444
};
444445

445446
try!(arguments.expect_exhausted());
446-
rgba(red, green, blue, alpha)
447+
Ok(rgba(red, green, blue, alpha))
447448
}
448449

449450

450451
#[inline]
451-
fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool), ()> {
452+
fn parse_rgb_components_rgb<'i, 't>(arguments: &mut Parser<'i, 't>) -> Result<(u8, u8, u8, bool), ParseError<'i>> {
452453
let red: u8;
453454
let green: u8;
454455
let blue: u8;
@@ -465,7 +466,7 @@ fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
465466
uses_commas = true;
466467
try!(arguments.expect_number())
467468
}
468-
_ => return Err(())
469+
t => return Err(ParseError::UnexpectedToken(t))
469470
});
470471
if uses_commas {
471472
try!(arguments.expect_comma());
@@ -480,36 +481,38 @@ fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
480481
uses_commas = true;
481482
try!(arguments.expect_percentage())
482483
}
483-
_ => return Err(())
484+
t => return Err(ParseError::UnexpectedToken(t))
484485
});
485486
if uses_commas {
486487
try!(arguments.expect_comma());
487488
}
488489
blue = clamp_unit_f32(try!(arguments.expect_percentage()));
489490
}
490-
_ => return Err(())
491+
t => return Err(ParseError::UnexpectedToken(t))
491492
};
492493
return Ok((red, green, blue, uses_commas));
493494
}
494495

495496
#[inline]
496-
fn parse_rgb_components_hsl(arguments: &mut Parser) -> Result<(u8, u8, u8, bool), ()> {
497+
fn parse_rgb_components_hsl<'i, 't>(arguments: &mut Parser<'i, 't>) -> Result<(u8, u8, u8, bool), ParseError<'i>> {
497498
let mut uses_commas = false;
498499
// Hue given as an angle
499500
// https://drafts.csswg.org/css-values/#angles
500-
let hue_degrees = match try!(arguments.next()) {
501-
Token::Number(NumericValue { value: v, .. }) => v,
502-
Token::Dimension(NumericValue { value: v, .. }, unit) => {
501+
let token = try!(arguments.next());
502+
let hue_degrees = match token {
503+
Token::Number(NumericValue { value: v, .. }) => Ok(v),
504+
Token::Dimension(NumericValue { value: v, .. }, ref unit) => {
503505
match_ignore_ascii_case! { &*unit,
504-
"deg" => v,
505-
"grad" => v * 360. / 400.,
506-
"rad" => v * 360. / (2. * PI),
507-
"turn" => v * 360.,
508-
_ => return Err(())
506+
"deg" => Ok(v),
507+
"grad" => Ok(v * 360. / 400.),
508+
"rad" => Ok(v * 360. / (2. * PI)),
509+
"turn" => Ok(v * 360.),
510+
_ => Err(()),
509511
}
510512
}
511-
_ => return Err(())
513+
t => return Err(ParseError::UnexpectedToken(t))
512514
};
515+
let hue_degrees = try!(hue_degrees.map_err(|()| ParseError::UnexpectedToken(token)));
513516
// Subtract an integer before rounding, to avoid some rounding errors:
514517
let hue_normalized_degrees = hue_degrees - 360. * (hue_degrees / 360.).floor();
515518
let hue = hue_normalized_degrees / 360.;
@@ -522,7 +525,7 @@ fn parse_rgb_components_hsl(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
522525
uses_commas = true;
523526
try!(arguments.expect_percentage())
524527
}
525-
_ => return Err(())
528+
t => return Err(ParseError::UnexpectedToken(t))
526529
};
527530
let saturation = saturation.max(0.).min(1.);
528531

src/lib.rs

+1-1
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

+55-33
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)