servo: Merge #17265 - style: Reduce some code duplication and ugliness when parsing identifiers (from emilio:macros-on-top-of-macros); r=wafflespeanut
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sun, 11 Jun 2017 09:31:48 -0700
changeset 411518 dae49146c17ca29cf317249630e142dbcac84946
parent 411517 11e9775fd375003197c01c05ccd4091ba6dd0222
child 411519 77d1075b9f522cbf13b14f6e18db5ea53e06a9a0
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswafflespeanut
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #17265 - style: Reduce some code duplication and ugliness when parsing identifiers (from emilio:macros-on-top-of-macros); r=wafflespeanut Source-Repo: https://github.com/servo/servo Source-Revision: 197afeee2d7ac54f330408708673805095a1399a
servo/components/style/counter_style/mod.rs
servo/components/style/macros.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/properties/longhand/inherited_svg.mako.rs
servo/components/style/properties/longhand/text.mako.rs
servo/components/style/properties/shorthand/box.mako.rs
servo/components/style/values/generics/grid.rs
servo/components/style/values/generics/mod.rs
servo/components/style/values/specified/align.rs
servo/components/style/values/specified/basic_shape.rs
servo/components/style/values/specified/border.rs
--- a/servo/components/style/counter_style/mod.rs
+++ b/servo/components/style/counter_style/mod.rs
@@ -290,33 +290,31 @@ pub enum System {
         first_symbol_value: Option<i32>
     },
     /// 'extends <counter-style-name>'
     Extends(CustomIdent),
 }
 
 impl Parse for System {
     fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "cyclic" => Ok(System::Cyclic),
             "numeric" => Ok(System::Numeric),
             "alphabetic" => Ok(System::Alphabetic),
             "symbolic" => Ok(System::Symbolic),
             "additive" => Ok(System::Additive),
             "fixed" => {
                 let first_symbol_value = input.try(|i| i.expect_integer()).ok();
                 Ok(System::Fixed { first_symbol_value: first_symbol_value })
             }
             "extends" => {
                 let other = parse_counter_style_name(input)?;
                 Ok(System::Extends(other))
             }
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 }
 
 impl ToCss for System {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         match *self {
             System::Cyclic => dest.write_str("cyclic"),
             System::Numeric => dest.write_str("numeric"),
@@ -612,29 +610,29 @@ pub enum SpeakAs {
     // SpellOut,
     /// <counter-style-name>
     Other(CustomIdent),
 }
 
 impl Parse for SpeakAs {
     fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
         let mut is_spell_out = false;
-        let result: Result<_, ParseError> = input.try(|input| {
-            let ident = input.expect_ident()?;
-            (match_ignore_ascii_case! { &ident,
+        let result = input.try(|input| {
+            let ident = input.expect_ident().map_err(|_| ())?;
+            match_ignore_ascii_case! { &*ident,
                 "auto" => Ok(SpeakAs::Auto),
                 "bullets" => Ok(SpeakAs::Bullets),
                 "numbers" => Ok(SpeakAs::Numbers),
                 "words" => Ok(SpeakAs::Words),
                 "spell-out" => {
                     is_spell_out = true;
                     Err(())
                 }
-                _ => Err(())
-            }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+                _ => Err(()),
+            }
         });
         if is_spell_out {
             // spell-out is not supported, but don’t parse it as a <counter-style-name>.
             // See bug 1024178.
             return Err(StyleParseError::UnspecifiedError.into())
         }
         result.or_else(|_| {
             Ok(SpeakAs::Other(parse_counter_style_name(input)?))
--- a/servo/components/style/macros.rs
+++ b/servo/components/style/macros.rs
@@ -1,14 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 //! Various macro helpers.
 
+/// A macro to parse an identifier, or return an `UnexpectedIndent` error
+/// otherwise.
+///
+/// FIXME(emilio): The fact that `UnexpectedIdent` is a `SelectorParseError`
+/// doesn't make a lot of sense to me.
+macro_rules! try_match_ident_ignore_ascii_case {
+    ($ident:expr, $( $match_body:tt )*) => {
+        let __ident = $ident;
+        (match_ignore_ascii_case! { &*__ident,
+            $( $match_body )*
+            _ => Err(()),
+        })
+        .map_err(|()| {
+            ::selectors::parser::SelectorParseError::UnexpectedIdent(__ident).into()
+        })
+    }
+}
+
 macro_rules! define_numbered_css_keyword_enum {
     ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => {
         define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+);
     };
     ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => {
         #[allow(non_camel_case_types, missing_docs)]
         #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
@@ -16,21 +34,19 @@ macro_rules! define_numbered_css_keyword
             $( $variant = $value ),+
         }
 
         impl $crate::parser::Parse for $name {
             #[allow(missing_docs)]
             fn parse<'i, 't>(_context: &$crate::parser::ParserContext,
                              input: &mut ::cssparser::Parser<'i, 't>)
                              -> Result<$name, ::style_traits::ParseError<'i>> {
-                let ident = try!(input.expect_ident());
-                (match_ignore_ascii_case! { &ident,
+                try_match_ident_ignore_ascii_case! { input.expect_ident()?,
                     $( $css => Ok($name::$variant), )+
-                    _ => Err(())
-                }).map_err(|()| ::selectors::parser::SelectorParseError::UnexpectedIdent(ident).into())
+                }
             }
         }
 
         impl ::style_traits::values::ToCss for $name {
             fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
                 where W: ::std::fmt::Write,
             {
                 match *self {
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -110,25 +110,23 @@
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T::${to_rust_ident(values[0])}
     }
 
     /// Parse a display value.
     pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                          -> Result<SpecifiedValue, ParseError<'i>> {
-        let ident = try!(input.expect_ident());
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             % for value in values:
                 "${value}" => {
                     Ok(computed_value::T::${to_rust_ident(value)})
                 },
             % endfor
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
 
     % if product == "servo":
         fn cascade_property_custom(_declaration: &PropertyDeclaration,
                                    _inherited_style: &ComputedValues,
                                    context: &mut computed::Context,
@@ -290,27 +288,25 @@
                 SpecifiedValue::LengthOrPercentage(ref value) => value.to_css(dest),
             }
         }
     }
     /// baseline | sub | super | top | text-top | middle | bottom | text-bottom
     /// | <percentage> | <length>
     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))
-        .map(SpecifiedValue::LengthOrPercentage)
-        .or_else(|_| {
-            let ident = try!(input.expect_ident());
-            (match_ignore_ascii_case! { &ident,
-                % for keyword in vertical_align_keywords:
-                    "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
-                % endfor
-                _ => Err(())
-            }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
-        })
+        if let Ok(lop) = input.try(|i| specified::LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes)) {
+            return Ok(SpecifiedValue::LengthOrPercentage(lop));
+        }
+
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
+            % for keyword in vertical_align_keywords:
+                "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
+            % endfor
+        }
     }
 
     /// The computed value for `vertical-align`.
     pub mod computed_value {
         use std::fmt;
         use style_traits::ToCss;
         use values::computed;
 
@@ -1992,18 +1988,17 @@
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         TOUCH_ACTION_AUTO
     }
 
     pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                          -> Result<SpecifiedValue, ParseError<'i>> {
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "auto" => Ok(TOUCH_ACTION_AUTO),
             "none" => Ok(TOUCH_ACTION_NONE),
             "manipulation" => Ok(TOUCH_ACTION_MANIPULATION),
             "pan-x" => {
                 if input.try(|i| i.expect_ident_matching("pan-y")).is_ok() {
                     Ok(TOUCH_ACTION_PAN_X | TOUCH_ACTION_PAN_Y)
                 } else {
                     Ok(TOUCH_ACTION_PAN_X)
@@ -2011,15 +2006,14 @@
             },
             "pan-y" => {
                 if input.try(|i| i.expect_ident_matching("pan-x")).is_ok() {
                     Ok(TOUCH_ACTION_PAN_X | TOUCH_ACTION_PAN_Y)
                 } else {
                     Ok(TOUCH_ACTION_PAN_Y)
                 }
             },
-            _ => Err(()),
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 
     #[cfg(feature = "gecko")]
     impl_bitflags_conversions!(SpecifiedValue);
 </%helpers:longhand>
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 <% from data import Method, to_camel_case, to_rust_ident, to_camel_case_lower, SYSTEM_FONT_LONGHANDS %>
 
-<% data.new_style_struct("Font",
-                         inherited=True) %>
+<% data.new_style_struct("Font", inherited=True) %>
 
 <%def name="nongecko_unreachable()">
     %if product == "gecko":
         ${caller.body()}
     %else:
         unreachable!()
     %endif
 </%def>
@@ -442,25 +441,25 @@ macro_rules! impl_gecko_keyword_from_tra
                 SpecifiedValue::System(_) => Ok(())
             }
         }
     }
 
     /// normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
     pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                          -> Result<SpecifiedValue, ParseError<'i>> {
-        let result: Result<_, ParseError> = input.try(|input| {
-            let ident = try!(input.expect_ident());
-            (match_ignore_ascii_case! { &ident,
+        let result = input.try(|input| {
+            let ident = input.expect_ident().map_err(|_| ())?;
+            match_ignore_ascii_case! { &ident,
                 "normal" => Ok(SpecifiedValue::Normal),
                 "bold" => Ok(SpecifiedValue::Bold),
                 "bolder" => Ok(SpecifiedValue::Bolder),
                 "lighter" => Ok(SpecifiedValue::Lighter),
                 _ => Err(())
-            }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+            }
         });
         result.or_else(|_| {
             SpecifiedValue::from_int(input.expect_integer()?)
                 .map_err(|()| StyleParseError::UnspecifiedError.into())
         })
     }
 
     impl SpecifiedValue {
@@ -684,27 +683,25 @@ macro_rules! impl_gecko_keyword_from_tra
         // HTML font-size 7 corresponds to this value
         XXXLarge = 7,
     }
 
     pub use self::KeywordSize::*;
 
     impl KeywordSize {
         pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-            let ident = input.expect_ident()?;
-            (match_ignore_ascii_case! {&*ident,
+            try_match_ident_ignore_ascii_case! { input.expect_ident()?,
                 "xx-small" => Ok(XXSmall),
                 "x-small" => Ok(XSmall),
                 "small" => Ok(Small),
                 "medium" => Ok(Medium),
                 "large" => Ok(Large),
                 "x-large" => Ok(XLarge),
                 "xx-large" => Ok(XXLarge),
-                _ => Err(())
-            }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+            }
         }
     }
 
     impl Default for KeywordSize {
         fn default() -> Self {
             Medium
         }
     }
@@ -926,22 +923,20 @@ macro_rules! impl_gecko_keyword_from_tra
         if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) {
             return Ok(SpecifiedValue::Length(lop))
         }
 
         if let Ok(kw) = input.try(KeywordSize::parse) {
             return Ok(SpecifiedValue::Keyword(kw, 1.))
         }
 
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! {&*ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "smaller" => Ok(SpecifiedValue::Smaller),
             "larger" => Ok(SpecifiedValue::Larger),
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 
     impl SpecifiedValue {
         pub fn system_font(f: SystemFont) -> Self {
             SpecifiedValue::System(f)
         }
         pub fn get_system(&self) -> Option<SystemFont> {
             if let SpecifiedValue::System(s) = *self {
@@ -1207,35 +1202,33 @@ macro_rules! impl_gecko_keyword_from_tra
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         SpecifiedValue { weight: true, style: true }
     }
 
     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 ident = try!(input.expect_ident());
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "none" => Ok(result),
             "weight" => {
                 result.weight = true;
                 if input.try(|input| input.expect_ident_matching("style")).is_ok() {
                     result.style = true;
                 }
                 Ok(result)
             },
             "style" => {
                 result.style = true;
                 if input.try(|input| input.expect_ident_matching("weight")).is_ok() {
                     result.weight = true;
                 }
                 Ok(result)
             },
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 
     #[cfg(feature = "gecko")]
     impl From<u8> for SpecifiedValue {
         fn from(bits: u8) -> SpecifiedValue {
             use gecko_bindings::structs;
 
             SpecifiedValue {
@@ -2338,17 +2331,16 @@ https://drafts.csswg.org/css-fonts-4/#lo
         //! the specified system font. When the cascade function (in helpers)
         //! detects that a value has a system font, it will resolve it, and
         //! cache it on the ComputedValues. After this, it can be just fetched
         //! whenever a font longhand on the same element needs the system font.
 
         use app_units::Au;
         use cssparser::Parser;
         use properties::longhands;
-        use selectors::parser::SelectorParseError;
         use std::hash::{Hash, Hasher};
         use style_traits::ParseError;
         use values::computed::{ToComputedValue, Context};
         <%
             system_fonts = """caption icon menu message-box small-caption status-bar
                               -moz-window -moz-document -moz-workspace -moz-desktop
                               -moz-info -moz-dialog -moz-button -moz-pull-down-menu
                               -moz-list -moz-field""".split()
@@ -2460,23 +2452,21 @@ https://drafts.csswg.org/css-fonts-4/#lo
             % for name in SYSTEM_FONT_LONGHANDS:
                 pub ${name}: longhands::${name}::computed_value::T,
             % endfor
             pub system_font: SystemFont,
         }
 
         impl SystemFont {
             pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-                let ident = input.expect_ident()?;
-                (match_ignore_ascii_case! { &*ident,
+                try_match_ident_ignore_ascii_case! { input.expect_ident()?,
                     % for font in system_fonts:
                         "${font}" => Ok(SystemFont::${to_camel_case(font)}),
                     % endfor
-                    _ => Err(())
-                }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+                }
             }
         }
     }
 % else:
     pub mod system_font {
         use cssparser::Parser;
 
         // We don't parse system fonts, but in the interest of not littering
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -190,25 +190,22 @@
         } else {
             let mut value = 0;
             // bitfield representing what we've seen so far
             // bit 1 is fill, bit 2 is stroke, bit 3 is markers
             let mut seen = 0;
             let mut pos = 0;
 
             loop {
-
                 let result: Result<_, ParseError> = input.try(|i| {
-                    let ident = i.expect_ident()?;
-                    (match_ignore_ascii_case! { &ident,
+                    try_match_ident_ignore_ascii_case! { i.expect_ident()?,
                         "fill" => Ok(FILL),
                         "stroke" => Ok(STROKE),
                         "markers" => Ok(MARKERS),
-                        _ => Err(())
-                    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident.into()).into())
+                    }
                 });
 
                 match result {
                     Ok(val) => {
                         if (seen & (1 << val)) != 0 {
                             // don't parse the same ident twice
                             return Err(StyleParseError::UnspecifiedError.into())
                         } else {
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -101,34 +101,37 @@
         computed_value::T {
             first: Side::Clip,
             second: Side::Clip,
             sides_are_logical: true,
         }
     }
     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 = Side::parse(context, input)?;
         let second = input.try(|input| Side::parse(context, input)).ok();
         Ok(SpecifiedValue {
             first: first,
             second: second,
         })
     }
     impl Parse for 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()) {
-                (match_ignore_ascii_case! { &ident,
-                    "clip" => Ok(Side::Clip),
-                    "ellipsis" => Ok(Side::Ellipsis),
-                    _ => Err(())
-                }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
-            } else {
-                Ok(Side::String(try!(input.expect_string()).into_owned().into_boxed_str()))
+            match input.next()? {
+                Token::Ident(ident) => {
+                    try_match_ident_ignore_ascii_case! { ident,
+                        "clip" => Ok(Side::Clip),
+                        "ellipsis" => Ok(Side::Ellipsis),
+                    }
+                }
+                Token::QuotedString(v) => {
+                    Ok(Side::String(v.into_owned().into_boxed_str()))
+                }
+                other => Err(BasicParseError::UnexpectedToken(other).into()),
             }
         }
     }
 
     impl ToCss for SpecifiedValue {
         fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             try!(self.first.to_css(dest));
             if let Some(ref second) = self.second {
--- a/servo/components/style/properties/shorthand/box.mako.rs
+++ b/servo/components/style/properties/shorthand/box.mako.rs
@@ -10,19 +10,17 @@
     % if product == "gecko":
         use properties::longhands::overflow_x::SpecifiedValue;
     % endif
 
     pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                -> Result<Longhands, ParseError<'i>> {
         % if product == "gecko":
             let moz_kw_found = input.try(|i| {
-                let ident = i.expect_ident()?;
-                (match_ignore_ascii_case! {
-                    &ident,
+                try_match_ident_ignore_ascii_case! { i.expect_ident()?,
                     "-moz-scrollbars-horizontal" => {
                         Ok(expanded! {
                             overflow_x: SpecifiedValue::scroll,
                             overflow_y: SpecifiedValue::hidden,
                         })
                     }
                     "-moz-scrollbars-vertical" => {
                         Ok(expanded! {
@@ -31,24 +29,23 @@
                         })
                     }
                     "-moz-scrollbars-none" => {
                         Ok(expanded! {
                             overflow_x: SpecifiedValue::hidden,
                             overflow_y: SpecifiedValue::hidden,
                         })
                     }
-                    _ => Err(())
-                }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+                }
             });
             if moz_kw_found.is_ok() {
                 return moz_kw_found
             }
         % endif
-        let overflow = try!(parse_overflow(context, input));
+        let overflow = parse_overflow(context, input)?;
         Ok(expanded! {
             overflow_x: overflow,
             overflow_y: overflow,
         })
     }
 
     impl<'a> ToCss for LonghandsToSerialize<'a>  {
         fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
--- a/servo/components/style/values/generics/grid.rs
+++ b/servo/components/style/values/generics/grid.rs
@@ -2,17 +2,16 @@
  * 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/. */
 
 //! Generic types for the handling of
 //! [grids](https://drafts.csswg.org/css-grid/).
 
 use cssparser::{Parser, serialize_identifier};
 use parser::{Parse, ParserContext};
-use selectors::parser::SelectorParseError;
 use std::{fmt, mem, usize};
 use style_traits::{ToCss, ParseError, StyleParseError};
 use values::{CSSFloat, CustomIdent};
 use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
 use values::specified::Integer;
 
 #[derive(PartialEq, Clone, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -345,22 +344,20 @@ impl Parse for RepeatCount {
     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 i.value() > 0 {
                 Ok(RepeatCount::Number(i))
             } else {
                 Err(StyleParseError::UnspecifiedError.into())
             }
         } else {
-            let ident = input.expect_ident()?;
-            (match_ignore_ascii_case! { &ident,
+            try_match_ident_ignore_ascii_case! { input.expect_ident()?,
                 "auto-fill" => Ok(RepeatCount::AutoFill),
                 "auto-fit" => Ok(RepeatCount::AutoFit),
-                _ => Err(()),
-            }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+            }
         }
     }
 }
 
 impl ComputedValueAsSpecified for RepeatCount {}
 no_viewport_percentage!(RepeatCount);
 
 /// The structure containing `<line-names>` and `<track-size>` values.
--- a/servo/components/style/values/generics/mod.rs
+++ b/servo/components/style/values/generics/mod.rs
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Generic types that share their serialization implementations
 //! for both specified and computed values.
 
 use counter_style::{Symbols, parse_counter_style_name};
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
-use selectors::parser::SelectorParseError;
 use std::fmt;
 use style_traits::{OneOrMoreCommaSeparated, ToCss, ParseError, StyleParseError};
 use super::CustomIdent;
 use values::specified::url::SpecifiedUrl;
 
 pub mod background;
 pub mod basic_shape;
 pub mod border;
@@ -323,23 +322,21 @@ impl<ColorType> SVGPaint<ColorType> {
             fallback: self.fallback.as_ref().map(|color| f(color))
         }
     }
 }
 
 impl<ColorType> SVGPaintKind<ColorType> {
     /// Parse a keyword value only
     fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "none" => Ok(SVGPaintKind::None),
             "context-fill" => Ok(SVGPaintKind::ContextFill),
             "context-stroke" => Ok(SVGPaintKind::ContextStroke),
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 }
 
 impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
     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)) {
             let fallback = input.try(|i| ColorType::parse(context, i));
             Ok(SVGPaint {
--- a/servo/components/style/values/specified/align.rs
+++ b/servo/components/style/values/specified/align.rs
@@ -338,73 +338,68 @@ impl From<AlignJustifyContent> for u16 {
 
 // auto | normal | stretch | <baseline-position>
 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) {
         return Ok(baseline);
     }
 
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "auto" => Ok(ALIGN_AUTO),
         "normal" => Ok(ALIGN_NORMAL),
         "stretch" => Ok(ALIGN_STRETCH),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    }
 }
 
 // normal | stretch | <baseline-position>
 fn parse_normal_stretch_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
     if let Ok(baseline) = input.try(parse_baseline) {
         return Ok(baseline);
     }
 
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "normal" => Ok(ALIGN_NORMAL),
         "stretch" => Ok(ALIGN_STRETCH),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    }
 }
 
 // normal | <baseline-position>
 fn parse_normal_or_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
     if let Ok(baseline) = input.try(parse_baseline) {
         return Ok(baseline);
     }
 
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
-        "normal" => Ok(ALIGN_NORMAL),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    input.expect_ident_matching("normal")?;
+    Ok(ALIGN_NORMAL)
 }
 
 // <baseline-position>
 fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "baseline" => Ok(ALIGN_BASELINE),
-        "first" => return input.expect_ident_matching("baseline").map(|_| ALIGN_BASELINE).map_err(|e| e.into()),
-        "last" => return input.expect_ident_matching("baseline").map(|_| ALIGN_LAST_BASELINE).map_err(|e| e.into()),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        "first" => {
+            input.expect_ident_matching("baseline")?;
+            Ok(ALIGN_BASELINE)
+        }
+        "last" => {
+            input.expect_ident_matching("baseline")?;
+            Ok(ALIGN_LAST_BASELINE)
+        }
+    }
 }
 
 // <content-distribution>
 fn parse_content_distribution<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "stretch" => Ok(ALIGN_STRETCH),
         "space-between" => Ok(ALIGN_SPACE_BETWEEN),
         "space-around" => Ok(ALIGN_SPACE_AROUND),
         "space-evenly" => Ok(ALIGN_SPACE_EVENLY),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    }
 }
 
 // [ <overflow-position>? && <content-position> ]
 fn parse_overflow_content_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
     // <content-position> followed by optional <overflow-position>
     if let Ok(mut content) = input.try(parse_content_position) {
         if let Ok(overflow) = input.try(parse_overflow_position) {
             content |= overflow;
@@ -417,37 +412,33 @@ fn parse_overflow_content_position<'i, '
             return Ok(overflow | content)
         }
     }
     return Err(StyleParseError::UnspecifiedError.into())
 }
 
 // <content-position>
 fn parse_content_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "start" => Ok(ALIGN_START),
         "end" => Ok(ALIGN_END),
         "flex-start" => Ok(ALIGN_FLEX_START),
         "flex-end" => Ok(ALIGN_FLEX_END),
         "center" => Ok(ALIGN_CENTER),
         "left" => Ok(ALIGN_LEFT),
         "right" => Ok(ALIGN_RIGHT),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    }
 }
 
 // <overflow-position>
 fn parse_overflow_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "safe" => Ok(ALIGN_SAFE),
         "unsafe" => Ok(ALIGN_UNSAFE),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    }
 }
 
 // [ <overflow-position>? && <self-position> ]
 fn parse_overflow_self_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
     // <self-position> followed by optional <overflow-position>
     if let Ok(mut self_position) = input.try(parse_self_position) {
         if let Ok(overflow) = input.try(parse_overflow_position) {
             self_position |= overflow;
@@ -460,29 +451,27 @@ fn parse_overflow_self_position<'i, 't>(
             return Ok(overflow | self_position)
         }
     }
     return Err(StyleParseError::UnspecifiedError.into())
 }
 
 // <self-position>
 fn parse_self_position<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
-    let ident = input.expect_ident()?;
-    (match_ignore_ascii_case! { &ident,
+    try_match_ident_ignore_ascii_case! { input.expect_ident()?,
         "start" => Ok(ALIGN_START),
         "end" => Ok(ALIGN_END),
         "flex-start" => Ok(ALIGN_FLEX_START),
         "flex-end" => Ok(ALIGN_FLEX_END),
         "center" => Ok(ALIGN_CENTER),
         "left" => Ok(ALIGN_LEFT),
         "right" => Ok(ALIGN_RIGHT),
         "self-start" => Ok(ALIGN_SELF_START),
         "self-end" => Ok(ALIGN_SELF_END),
-        _ => Err(())
-    }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+    }
 }
 
 // [ legacy && [ left | right | center ] ]
 fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseError<'i>> {
     let a = input.expect_ident()?;
     let b = input.expect_ident()?;
     if a.eq_ignore_ascii_case("legacy") {
         (match_ignore_ascii_case! { &b,
--- a/servo/components/style/values/specified/basic_shape.rs
+++ b/servo/components/style/values/specified/basic_shape.rs
@@ -4,17 +4,16 @@
 
 //! CSS handling for the specified value of
 //! [`basic-shape`][basic-shape]s
 //!
 //! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
 
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
-use selectors::parser::SelectorParseError;
 use std::borrow::Cow;
 use std::fmt;
 use style_traits::{ToCss, ParseError, StyleParseError};
 use values::generics::basic_shape::{Circle as GenericCircle};
 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::{FloatAreaShape as GenericFloatAreaShape, InsetRect as GenericInsetRect};
 use values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
@@ -86,23 +85,21 @@ impl<ReferenceBox: Parse> Parse for Shap
 }
 
 impl Parse for GeometryBox {
     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)) {
             return Ok(GeometryBox::ShapeBox(shape_box))
         }
 
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "fill-box" => Ok(GeometryBox::FillBox),
             "stroke-box" => Ok(GeometryBox::StrokeBox),
             "view-box" => Ok(GeometryBox::ViewBox),
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 }
 
 impl Parse for BasicShape {
     fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
         let function = input.expect_function()?;
         input.parse_nested_block(move |i| {
             (match_ignore_ascii_case! { &function,
@@ -226,22 +223,20 @@ impl ToCss for Ellipse {
 
 impl Parse for ShapeRadius {
     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)) {
             return Ok(GenericShapeRadius::Length(lop))
         }
 
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "closest-side" => Ok(GenericShapeRadius::ClosestSide),
             "farthest-side" => Ok(GenericShapeRadius::FarthestSide),
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 }
 
 /// https://drafts.csswg.org/css-shapes/#basic-shape-serialization
 ///
 /// Positions get serialized differently with basic shapes. Keywords
 /// are converted to percentages where possible. Only the two or four
 /// value forms are used. In case of two keyword-percentage pairs,
--- a/servo/components/style/values/specified/border.rs
+++ b/servo/components/style/values/specified/border.rs
@@ -2,17 +2,16 @@
  * 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/. */
 
 //! Specified types for CSS values related to borders.
 
 use app_units::Au;
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
-use selectors::parser::SelectorParseError;
 use style_traits::ParseError;
 use values::computed::{Context, ToComputedValue};
 use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
 use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
 use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
 use values::generics::border::BorderRadius as GenericBorderRadius;
 use values::generics::rect::Rect;
 use values::specified::{AllowQuirks, Number, NumberOrPercentage};
@@ -53,23 +52,21 @@ impl BorderSideWidth {
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
         allow_quirks: AllowQuirks)
         -> Result<Self, ParseError<'i>>
     {
         if let Ok(length) = input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) {
             return Ok(BorderSideWidth::Length(length));
         }
-        let ident = input.expect_ident()?;
-        (match_ignore_ascii_case! { &ident,
+        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
             "thin" => Ok(BorderSideWidth::Thin),
             "medium" => Ok(BorderSideWidth::Medium),
             "thick" => Ok(BorderSideWidth::Thick),
-            _ => Err(())
-        }).map_err(|()| SelectorParseError::UnexpectedIdent(ident).into())
+        }
     }
 }
 
 impl Parse for BorderSideWidth {
     fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
         Self::parse_quirky(context, input, AllowQuirks::No)
     }
 }