1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Types used to report parsing errors. 6 7 #![deny(missing_docs)] 8 9 use crate::selector_parser::SelectorImpl; 10 use crate::stylesheets::UrlExtraData; 11 use cssparser::{BasicParseErrorKind, ParseErrorKind, SourceLocation, Token}; 12 use selectors::SelectorList; 13 use std::fmt; 14 use style_traits::ParseError; 15 16 /// Errors that can be encountered while parsing CSS. 17 #[derive(Debug)] 18 pub enum ContextualParseError<'a> { 19 /// A property declaration was not recognized. 20 UnsupportedPropertyDeclaration( 21 &'a str, 22 ParseError<'a>, 23 Option<&'a SelectorList<SelectorImpl>>, 24 ), 25 /// A font face descriptor was not recognized. 26 UnsupportedFontFaceDescriptor(&'a str, ParseError<'a>), 27 /// A font feature values descriptor was not recognized. 28 UnsupportedFontFeatureValuesDescriptor(&'a str, ParseError<'a>), 29 /// A keyframe rule was not valid. 30 InvalidKeyframeRule(&'a str, ParseError<'a>), 31 /// A font feature values rule was not valid. 32 InvalidFontFeatureValuesRule(&'a str, ParseError<'a>), 33 /// A keyframe property declaration was not recognized. 34 UnsupportedKeyframePropertyDeclaration(&'a str, ParseError<'a>), 35 /// A rule was invalid for some reason. 36 InvalidRule(&'a str, ParseError<'a>), 37 /// A rule was not recognized. 38 UnsupportedRule(&'a str, ParseError<'a>), 39 /// A viewport descriptor declaration was not recognized. 40 UnsupportedViewportDescriptorDeclaration(&'a str, ParseError<'a>), 41 /// A counter style descriptor declaration was not recognized. 42 UnsupportedCounterStyleDescriptorDeclaration(&'a str, ParseError<'a>), 43 /// A counter style rule had no symbols. 44 InvalidCounterStyleWithoutSymbols(String), 45 /// A counter style rule had less than two symbols. 46 InvalidCounterStyleNotEnoughSymbols(String), 47 /// A counter style rule did not have additive-symbols. 48 InvalidCounterStyleWithoutAdditiveSymbols, 49 /// A counter style rule had extends with symbols. 50 InvalidCounterStyleExtendsWithSymbols, 51 /// A counter style rule had extends with additive-symbols. 52 InvalidCounterStyleExtendsWithAdditiveSymbols, 53 /// A media rule was invalid for some reason. 54 InvalidMediaRule(&'a str, ParseError<'a>), 55 /// A value was not recognized. 56 UnsupportedValue(&'a str, ParseError<'a>), 57 } 58 59 impl<'a> fmt::Display for ContextualParseError<'a> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 61 fn token_to_str(t: &Token, f: &mut fmt::Formatter) -> fmt::Result { 62 match *t { 63 Token::Ident(ref i) => write!(f, "identifier {}", i), 64 Token::AtKeyword(ref kw) => write!(f, "keyword @{}", kw), 65 Token::Hash(ref h) => write!(f, "hash #{}", h), 66 Token::IDHash(ref h) => write!(f, "id selector #{}", h), 67 Token::QuotedString(ref s) => write!(f, "quoted string \"{}\"", s), 68 Token::UnquotedUrl(ref u) => write!(f, "url {}", u), 69 Token::Delim(ref d) => write!(f, "delimiter {}", d), 70 Token::Number { 71 int_value: Some(i), .. 72 } => write!(f, "number {}", i), 73 Token::Number { value, .. } => write!(f, "number {}", value), 74 Token::Percentage { 75 int_value: Some(i), .. 76 } => write!(f, "percentage {}", i), 77 Token::Percentage { unit_value, .. } => { 78 write!(f, "percentage {}", unit_value * 100.) 79 }, 80 Token::Dimension { 81 value, ref unit, .. 82 } => write!(f, "dimension {}{}", value, unit), 83 Token::WhiteSpace(_) => write!(f, "whitespace"), 84 Token::Comment(_) => write!(f, "comment"), 85 Token::Colon => write!(f, "colon (:)"), 86 Token::Semicolon => write!(f, "semicolon (;)"), 87 Token::Comma => write!(f, "comma (,)"), 88 Token::IncludeMatch => write!(f, "include match (~=)"), 89 Token::DashMatch => write!(f, "dash match (|=)"), 90 Token::PrefixMatch => write!(f, "prefix match (^=)"), 91 Token::SuffixMatch => write!(f, "suffix match ($=)"), 92 Token::SubstringMatch => write!(f, "substring match (*=)"), 93 Token::CDO => write!(f, "CDO (<!--)"), 94 Token::CDC => write!(f, "CDC (-->)"), 95 Token::Function(ref name) => write!(f, "function {}", name), 96 Token::ParenthesisBlock => write!(f, "parenthesis ("), 97 Token::SquareBracketBlock => write!(f, "square bracket ["), 98 Token::CurlyBracketBlock => write!(f, "curly bracket {{"), 99 Token::BadUrl(ref _u) => write!(f, "bad url parse error"), 100 Token::BadString(ref _s) => write!(f, "bad string parse error"), 101 Token::CloseParenthesis => write!(f, "unmatched close parenthesis"), 102 Token::CloseSquareBracket => write!(f, "unmatched close square bracket"), 103 Token::CloseCurlyBracket => write!(f, "unmatched close curly bracket"), 104 } 105 } 106 107 fn parse_error_to_str(err: &ParseError, f: &mut fmt::Formatter) -> fmt::Result { 108 match err.kind { 109 ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)) => { 110 write!(f, "found unexpected ")?; 111 token_to_str(t, f) 112 }, 113 ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) => { 114 write!(f, "unexpected end of input") 115 }, 116 ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(ref i)) => { 117 write!(f, "@ rule invalid: {}", i) 118 }, 119 ParseErrorKind::Basic(BasicParseErrorKind::AtRuleBodyInvalid) => { 120 write!(f, "@ rule invalid") 121 }, 122 ParseErrorKind::Basic(BasicParseErrorKind::QualifiedRuleInvalid) => { 123 write!(f, "qualified rule invalid") 124 }, 125 ParseErrorKind::Custom(ref err) => write!(f, "{:?}", err), 126 } 127 } 128 129 match *self { 130 ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err, _selectors) => { 131 write!(f, "Unsupported property declaration: '{}', ", decl)?; 132 parse_error_to_str(err, f) 133 }, 134 ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) => { 135 write!( 136 f, 137 "Unsupported @font-face descriptor declaration: '{}', ", 138 decl 139 )?; 140 parse_error_to_str(err, f) 141 }, 142 ContextualParseError::UnsupportedFontFeatureValuesDescriptor(decl, ref err) => { 143 write!( 144 f, 145 "Unsupported @font-feature-values descriptor declaration: '{}', ", 146 decl 147 )?; 148 parse_error_to_str(err, f) 149 }, 150 ContextualParseError::InvalidKeyframeRule(rule, ref err) => { 151 write!(f, "Invalid keyframe rule: '{}', ", rule)?; 152 parse_error_to_str(err, f) 153 }, 154 ContextualParseError::InvalidFontFeatureValuesRule(rule, ref err) => { 155 write!(f, "Invalid font feature value rule: '{}', ", rule)?; 156 parse_error_to_str(err, f) 157 }, 158 ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) => { 159 write!(f, "Unsupported keyframe property declaration: '{}', ", decl)?; 160 parse_error_to_str(err, f) 161 }, 162 ContextualParseError::InvalidRule(rule, ref err) => { 163 write!(f, "Invalid rule: '{}', ", rule)?; 164 parse_error_to_str(err, f) 165 }, 166 ContextualParseError::UnsupportedRule(rule, ref err) => { 167 write!(f, "Unsupported rule: '{}', ", rule)?; 168 parse_error_to_str(err, f) 169 }, 170 ContextualParseError::UnsupportedViewportDescriptorDeclaration(decl, ref err) => { 171 write!( 172 f, 173 "Unsupported @viewport descriptor declaration: '{}', ", 174 decl 175 )?; 176 parse_error_to_str(err, f) 177 }, 178 ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(decl, ref err) => { 179 write!( 180 f, 181 "Unsupported @counter-style descriptor declaration: '{}', ", 182 decl 183 )?; 184 parse_error_to_str(err, f) 185 }, 186 ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) => write!( 187 f, 188 "Invalid @counter-style rule: 'system: {}' without 'symbols'", 189 system 190 ), 191 ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) => write!( 192 f, 193 "Invalid @counter-style rule: 'system: {}' less than two 'symbols'", 194 system 195 ), 196 ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols => write!( 197 f, 198 "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'" 199 ), 200 ContextualParseError::InvalidCounterStyleExtendsWithSymbols => write!( 201 f, 202 "Invalid @counter-style rule: 'system: extends …' with 'symbols'" 203 ), 204 ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => write!( 205 f, 206 "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'" 207 ), 208 ContextualParseError::InvalidMediaRule(media_rule, ref err) => { 209 write!(f, "Invalid media rule: {}, ", media_rule)?; 210 parse_error_to_str(err, f) 211 }, 212 ContextualParseError::UnsupportedValue(_value, ref err) => parse_error_to_str(err, f), 213 } 214 } 215 } 216 217 /// A generic trait for an error reporter. 218 pub trait ParseErrorReporter { 219 /// Called when the style engine detects an error. 220 /// 221 /// Returns the current input being parsed, the source location it was 222 /// reported from, and a message. report_error( &self, url: &UrlExtraData, location: SourceLocation, error: ContextualParseError, )223 fn report_error( 224 &self, 225 url: &UrlExtraData, 226 location: SourceLocation, 227 error: ContextualParseError, 228 ); 229 } 230 231 /// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log) 232 /// at `info` level. 233 /// 234 /// This logging is silent by default, and can be enabled with a `RUST_LOG=style=info` 235 /// environment variable. 236 /// (See [`env_logger`](https://rust-lang-nursery.github.io/log/env_logger/).) 237 #[cfg(feature = "servo")] 238 pub struct RustLogReporter; 239 240 #[cfg(feature = "servo")] 241 impl ParseErrorReporter for RustLogReporter { report_error( &self, url: &UrlExtraData, location: SourceLocation, error: ContextualParseError, )242 fn report_error( 243 &self, 244 url: &UrlExtraData, 245 location: SourceLocation, 246 error: ContextualParseError, 247 ) { 248 if log_enabled!(log::Level::Info) { 249 info!( 250 "Url:\t{}\n{}:{} {}", 251 url.as_str(), 252 location.line, 253 location.column, 254 error 255 ) 256 } 257 } 258 } 259