Skip to content

Migrate next_* methods to return Option #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ impl Color {
///
/// FIXME(#2) Deprecated CSS2 System Colors are not supported yet.
pub fn parse(input: &mut Parser) -> Result<Color, ()> {
match try!(input.next()) {
Token::Hash(value) | Token::IDHash(value) => parse_color_hash(&*value),
Token::Ident(value) => parse_color_keyword(&*value),
Token::Function(name) => {
match input.next() {
Some(Token::Hash(value)) | Some(Token::IDHash(value)) => parse_color_hash(&*value),
Some(Token::Ident(value)) => parse_color_keyword(&*value),
Some(Token::Function(name)) => {
input.parse_nested_block(|arguments| {
parse_color_function(&*name, arguments)
})
Expand Down Expand Up @@ -307,15 +307,15 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
let blue: f32;
if is_rgb {
// Either integers or percentages, but all the same type.
match try!(arguments.next()) {
Token::Number(ref v) if v.int_value.is_some() => {
match arguments.next() {
Some(Token::Number(ref v)) if v.int_value.is_some() => {
red = (v.value / 255.) as f32;
try!(arguments.expect_comma());
green = try!(arguments.expect_integer()) as f32 / 255.;
try!(arguments.expect_comma());
blue = try!(arguments.expect_integer()) as f32 / 255.;
}
Token::Percentage(ref v) => {
Some(Token::Percentage(ref v)) => {
red = v.unit_value as f32;
try!(arguments.expect_comma());
green = try!(arguments.expect_percentage()) as f32;
Expand Down
22 changes: 11 additions & 11 deletions src/nth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ use super::{Token, Parser};
/// in which case the caller needs to check if the arguments’ parser is exhausted.
/// Return `Ok((A, B))`, or `Err(())` for a syntax error.
pub fn parse_nth(input: &mut Parser) -> Result<(i32, i32), ()> {
match try!(input.next()) {
Token::Number(value) => Ok((0, try!(value.int_value.ok_or(())) as i32)),
Token::Dimension(value, unit) => {
match input.next() {
Some(Token::Number(value)) => Ok((0, try!(value.int_value.ok_or(())) as i32)),
Some(Token::Dimension(value, unit)) => {
let a = try!(value.int_value.ok_or(())) as i32;
match_ignore_ascii_case! { unit,
"n" => parse_b(input, a),
"n-" => parse_signless_b(input, a, -1)
_ => Ok((a, try!(parse_n_dash_digits(&*unit))))
}
}
Token::Ident(value) => {
Some(Token::Ident(value)) => {
match_ignore_ascii_case! { value,
"even" => Ok((2, 0)),
"odd" => Ok((2, 1)),
Expand All @@ -37,8 +37,8 @@ pub fn parse_nth(input: &mut Parser) -> Result<(i32, i32), ()> {
}
}
}
Token::Delim('+') => match try!(input.next_including_whitespace()) {
Token::Ident(value) => {
Some(Token::Delim('+')) => match input.next_including_whitespace() {
Some(Token::Ident(value)) => {
match_ignore_ascii_case! { value,
"n" => parse_b(input, 1),
"n-" => parse_signless_b(input, 1, -1)
Expand All @@ -55,9 +55,9 @@ pub fn parse_nth(input: &mut Parser) -> Result<(i32, i32), ()> {
fn parse_b(input: &mut Parser, a: i32) -> Result<(i32, i32), ()> {
let start_position = input.position();
match input.next() {
Ok(Token::Delim('+')) => parse_signless_b(input, a, 1),
Ok(Token::Delim('-')) => parse_signless_b(input, a, -1),
Ok(Token::Number(ref value)) if value.signed => {
Some(Token::Delim('+')) => parse_signless_b(input, a, 1),
Some(Token::Delim('-')) => parse_signless_b(input, a, -1),
Some(Token::Number(ref value)) if value.signed => {
Ok((a, try!(value.int_value.ok_or(())) as i32))
}
_ => {
Expand All @@ -68,8 +68,8 @@ fn parse_b(input: &mut Parser, a: i32) -> Result<(i32, i32), ()> {
}

fn parse_signless_b(input: &mut Parser, a: i32, b_sign: i32) -> Result<(i32, i32), ()> {
match try!(input.next()) {
Token::Number(ref value) if !value.signed => {
match input.next() {
Some(Token::Number(ref value)) if !value.signed => {
Ok((a, b_sign * (try!(value.int_value.ok_or(())) as i32)))
}
_ => Err(())
Expand Down
111 changes: 56 additions & 55 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,8 @@ impl<'i, 't> Parser<'i, 't> {
pub fn expect_exhausted(&mut self) -> Result<(), ()> {
let start_position = self.position();
let result = match self.next() {
Err(()) => Ok(()),
Ok(_) => {
Err(())
}
None => Ok(()),
Some(_) => Err(()),
};
self.reset(start_position);
result
Expand Down Expand Up @@ -270,38 +268,41 @@ impl<'i, 't> Parser<'i, 't> {
/// See the `Parser::parse_nested_block` method to parse the content of functions or blocks.
///
/// This only returns a closing token when it is unmatched (and therefore an error).
pub fn next(&mut self) -> Result<Token<'i>, ()> {
pub fn next(&mut self) -> Option<Token<'i>> {
loop {
match self.next_including_whitespace_and_comments() {
Ok(Token::WhiteSpace(_)) | Ok(Token::Comment(_)) => {},
Some(Token::WhiteSpace(_)) | Some(Token::Comment(_)) => {},
result => return result
}
}
}

/// Same as `Parser::next`, but does not skip whitespace tokens.
pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
pub fn next_including_whitespace(&mut self) -> Option<Token<'i>> {
loop {
match self.next_including_whitespace_and_comments() {
Ok(Token::Comment(_)) => {},
Some(Token::Comment(_)) => {},
result => return result
}
}
}

/// Same as `Parser::next`, but does not skip whitespace or comment tokens.
pub fn next_including_whitespace_and_comments(&mut self) -> Result<Token<'i>, ()> {
pub fn next_including_whitespace_and_comments(&mut self) -> Option<Token<'i>> {
if let Some(block_type) = self.at_start_of.take() {
consume_until_end_of_block(block_type, &mut *self.tokenizer);
}
if self.stop_before.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
return Err(())
return None
}
let token = try!(self.tokenizer.next());
let token = match self.tokenizer.next() {
Some(t) => t,
None => return None,
};
if let Some(block_type) = BlockType::opening(&token) {
self.at_start_of = Some(block_type);
}
Ok(token)
Some(token)
}

/// Have the given closure parse something, then check the the input is exhausted.
Expand Down Expand Up @@ -333,9 +334,9 @@ impl<'i, 't> Parser<'i, 't> {
loop {
values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
match self.next() {
Err(()) => return Ok(values),
Ok(Token::Comma) => continue,
Ok(_) => unreachable!(),
None => return Ok(values),
Some(Token::Comma) => continue,
Some(_) => unreachable!(),
}
}
}
Expand Down Expand Up @@ -408,7 +409,7 @@ impl<'i, 't> Parser<'i, 't> {
if delimiters.contains(Delimiters::from_byte(self.tokenizer.next_byte())) {
break
}
if let Ok(token) = self.tokenizer.next() {
if let Some(token) = self.tokenizer.next() {
if let Some(block_type) = BlockType::opening(&token) {
consume_until_end_of_block(block_type, &mut *self.tokenizer);
}
Expand Down Expand Up @@ -440,73 +441,73 @@ impl<'i, 't> Parser<'i, 't> {
/// Parse a <ident-token> and return the unescaped value.
#[inline]
pub fn expect_ident(&mut self) -> Result<Cow<'i, str>, ()> {
match try!(self.next()) {
Token::Ident(value) => Ok(value),
match self.next() {
Some(Token::Ident(value)) => Ok(value),
_ => Err(())
}
}

/// Parse a <ident-token> whose unescaped value is an ASCII-insensitive match for the given value.
#[inline]
pub fn expect_ident_matching<'a>(&mut self, expected_value: &str) -> Result<(), ()> {
match try!(self.next()) {
Token::Ident(ref value) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
match self.next() {
Some(Token::Ident(ref value)) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
_ => Err(())
}
}

/// Parse a <string-token> and return the unescaped value.
#[inline]
pub fn expect_string(&mut self) -> Result<Cow<'i, str>, ()> {
match try!(self.next()) {
Token::QuotedString(value) => Ok(value),
match self.next() {
Some(Token::QuotedString(value)) => Ok(value),
_ => Err(())
}
}

/// Parse either a <ident-token> or a <string-token>, and return the unescaped value.
#[inline]
pub fn expect_ident_or_string(&mut self) -> Result<Cow<'i, str>, ()> {
match try!(self.next()) {
Token::Ident(value) => Ok(value),
Token::QuotedString(value) => Ok(value),
match self.next() {
Some(Token::Ident(value)) => Ok(value),
Some(Token::QuotedString(value)) => Ok(value),
_ => Err(())
}
}

/// Parse a <url-token> and return the unescaped value.
#[inline]
pub fn expect_url(&mut self) -> Result<Cow<'i, str>, ()> {
match try!(self.next()) {
Token::Url(value) => Ok(value),
match self.next() {
Some(Token::Url(value)) => Ok(value),
_ => Err(())
}
}

/// Parse either a <url-token> or a <string-token>, and return the unescaped value.
#[inline]
pub fn expect_url_or_string(&mut self) -> Result<Cow<'i, str>, ()> {
match try!(self.next()) {
Token::Url(value) => Ok(value),
Token::QuotedString(value) => Ok(value),
match self.next() {
Some(Token::Url(value)) => Ok(value),
Some(Token::QuotedString(value)) => Ok(value),
_ => Err(())
}
}

/// Parse a <number-token> and return the integer value.
#[inline]
pub fn expect_number(&mut self) -> Result<f64, ()> {
match try!(self.next()) {
Token::Number(NumericValue { value, .. }) => Ok(value),
match self.next() {
Some(Token::Number(NumericValue { value, .. })) => Ok(value),
_ => Err(())
}
}

/// Parse a <number-token> that does not have a fractional part, and return the integer value.
#[inline]
pub fn expect_integer(&mut self) -> Result<i64, ()> {
match try!(self.next()) {
Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
match self.next() {
Some(Token::Number(NumericValue { int_value, .. })) => int_value.ok_or(()),
_ => Err(())
}
}
Expand All @@ -515,44 +516,44 @@ impl<'i, 't> Parser<'i, 't> {
/// `0%` and `100%` map to `0.0` and `1.0` (not `100.0`), respectively.
#[inline]
pub fn expect_percentage(&mut self) -> Result<f64, ()> {
match try!(self.next()) {
Token::Percentage(PercentageValue { unit_value, .. }) => Ok(unit_value),
match self.next() {
Some(Token::Percentage(PercentageValue { unit_value, .. })) => Ok(unit_value),
_ => Err(())
}
}

/// Parse a `:` <colon-token>.
#[inline]
pub fn expect_colon(&mut self) -> Result<(), ()> {
match try!(self.next()) {
Token::Colon => Ok(()),
match self.next() {
Some(Token::Colon) => Ok(()),
_ => Err(())
}
}

/// Parse a `;` <semicolon-token>.
#[inline]
pub fn expect_semicolon(&mut self) -> Result<(), ()> {
match try!(self.next()) {
Token::Semicolon => Ok(()),
match self.next() {
Some(Token::Semicolon) => Ok(()),
_ => Err(())
}
}

/// Parse a `,` <comma-token>.
#[inline]
pub fn expect_comma(&mut self) -> Result<(), ()> {
match try!(self.next()) {
Token::Comma => Ok(()),
match self.next() {
Some(Token::Comma) => Ok(()),
_ => Err(())
}
}

/// Parse a <delim-token> with the given value.
#[inline]
pub fn expect_delim(&mut self, expected_value: char) -> Result<(), ()> {
match try!(self.next()) {
Token::Delim(value) if value == expected_value => Ok(()),
match self.next() {
Some(Token::Delim(value)) if value == expected_value => Ok(()),
_ => Err(())
}
}
Expand All @@ -562,8 +563,8 @@ impl<'i, 't> Parser<'i, 't> {
/// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
#[inline]
pub fn expect_curly_bracket_block(&mut self) -> Result<(), ()> {
match try!(self.next()) {
Token::CurlyBracketBlock => Ok(()),
match self.next() {
Some(Token::CurlyBracketBlock) => Ok(()),
_ => Err(())
}
}
Expand All @@ -573,8 +574,8 @@ impl<'i, 't> Parser<'i, 't> {
/// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
#[inline]
pub fn expect_square_bracket_block(&mut self) -> Result<(), ()> {
match try!(self.next()) {
Token::SquareBracketBlock => Ok(()),
match self.next() {
Some(Token::SquareBracketBlock) => Ok(()),
_ => Err(())
}
}
Expand All @@ -584,8 +585,8 @@ impl<'i, 't> Parser<'i, 't> {
/// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
#[inline]
pub fn expect_parenthesis_block(&mut self) -> Result<(), ()> {
match try!(self.next()) {
Token::ParenthesisBlock => Ok(()),
match self.next() {
Some(Token::ParenthesisBlock) => Ok(()),
_ => Err(())
}
}
Expand All @@ -595,8 +596,8 @@ impl<'i, 't> Parser<'i, 't> {
/// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
#[inline]
pub fn expect_function(&mut self) -> Result<Cow<'i, str>, ()> {
match try!(self.next()) {
Token::Function(name) => Ok(name),
match self.next() {
Some(Token::Function(name)) => Ok(name),
_ => Err(())
}
}
Expand All @@ -606,8 +607,8 @@ impl<'i, 't> Parser<'i, 't> {
/// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
#[inline]
pub fn expect_function_matching(&mut self, expected_name: &str) -> Result<(), ()> {
match try!(self.next()) {
Token::Function(ref name) if name.eq_ignore_ascii_case(expected_name) => Ok(()),
match self.next() {
Some(Token::Function(ref name)) if name.eq_ignore_ascii_case(expected_name) => Ok(()),
_ => Err(())
}
}
Expand All @@ -617,7 +618,7 @@ impl<'i, 't> Parser<'i, 't> {
/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) {
// FIXME: have a special-purpose tokenizer method for this that does less work.
while let Ok(ref token) = tokenizer.next() {
while let Some(ref token) = tokenizer.next() {
if BlockType::closing(token) == Some(block_type) {
return
}
Expand Down
Loading