Skip to content

Commit

Permalink
Report CSS parse errors via enum instead of strings.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdm committed Jun 9, 2017
1 parent e46aa87 commit fd6e54d
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 65 deletions.
18 changes: 9 additions & 9 deletions components/script_layout_interface/reporter.rs
Expand Up @@ -9,7 +9,7 @@ use msg::constellation_msg::PipelineId;
use script_traits::ConstellationControlMsg;
use servo_url::ServoUrl;
use std::sync::{Mutex, Arc};
use style::error_reporting::ParseErrorReporter;
use style::error_reporting::{ParseErrorReporter, ParseError};

#[derive(HeapSizeOf, Clone)]
pub struct CSSErrorReporter {
Expand All @@ -22,20 +22,20 @@ pub struct CSSErrorReporter {
}

impl ParseErrorReporter for CSSErrorReporter {
fn report_error(&self,
input: &mut Parser,
position: SourcePosition,
message: &str,
url: &ServoUrl,
line_number_offset: u64) {
fn report_error<'a>(&self,
input: &mut Parser,
position: SourcePosition,
error: ParseError<'a>,
url: &ServoUrl,
line_number_offset: u64) {
let location = input.source_location(position);
let line_offset = location.line + line_number_offset as usize;
if log_enabled!(log::LogLevel::Info) {
info!("Url:\t{}\n{}:{} {}",
url.as_str(),
line_offset,
location.column,
message)
error.to_string())
}

//TODO: report a real filename
Expand All @@ -44,6 +44,6 @@ impl ParseErrorReporter for CSSErrorReporter {
"".to_owned(),
location.line,
location.column,
message.to_owned()));
error.to_string()));
}
}
24 changes: 10 additions & 14 deletions components/style/counter_style/mod.rs
Expand Up @@ -9,6 +9,7 @@
use Atom;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser};
use cssparser::{Parser, Token, serialize_identifier};
use error_reporting::ParseError;
#[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
use parser::{ParserContext, log_css_error, Parse};
Expand Down Expand Up @@ -61,9 +62,8 @@ pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, inpu
while let Some(declaration) = iter.next() {
if let Err(range) = declaration {
let pos = range.start;
let message = format!("Unsupported @counter-style descriptor declaration: '{}'",
iter.input.slice(range));
log_css_error(iter.input, pos, &*message, context);
let error = ParseError::UnsupportedViewportDescriptorDeclaration(iter.input.slice(range));
log_css_error(iter.input, pos, error, context);
}
}
}
Expand All @@ -75,31 +75,27 @@ pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, inpu
ref system @ System::Numeric
if rule.symbols.is_none() => {
let system = system.to_css_string();
Some(format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system))
Some(ParseError::InvalidCounterStyleWithoutSymbols(system))
}
ref system @ System::Alphabetic |
ref system @ System::Numeric
if rule.symbols().unwrap().0.len() < 2 => {
let system = system.to_css_string();
Some(format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'",
system))
Some(ParseError::InvalidCounterStyleNotEnoughSymbols(system))
}
System::Additive if rule.additive_symbols.is_none() => {
let s = "Invalid @counter-style rule: 'system: additive' without 'additive-symbols'";
Some(s.to_owned())
Some(ParseError::InvalidCounterStyleWithoutAdditiveSymbols)
}
System::Extends(_) if rule.symbols.is_some() => {
let s = "Invalid @counter-style rule: 'system: extends …' with 'symbols'";
Some(s.to_owned())
Some(ParseError::InvalidCounterStyleExtendsWithSymbols)
}
System::Extends(_) if rule.additive_symbols.is_some() => {
let s = "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'";
Some(s.to_owned())
Some(ParseError::InvalidCounterStyleExtendsWithAdditiveSymbols)
}
_ => None
};
if let Some(message) = error {
log_css_error(input, start, &message, context);
if let Some(error) = error {
log_css_error(input, start, error, context);
Err(())
} else {
Ok(rule)
Expand Down
94 changes: 79 additions & 15 deletions components/style/error_reporting.rs
Expand Up @@ -10,18 +10,82 @@ use cssparser::{Parser, SourcePosition};
use log;
use stylesheets::UrlExtraData;

/// Errors that can be encountered while parsing CSS.
pub enum ParseError<'a> {
/// A property declaration was not recognized.
UnsupportedPropertyDeclaration(&'a str),
/// A font face descriptor was not recognized.
UnsupportedFontFaceDescriptor(&'a str),
/// A keyframe rule was not valid.
InvalidKeyframeRule(&'a str),
/// A keyframe property declaration was not recognized.
UnsupportedKeyframePropertyDeclaration(&'a str),
/// A rule was invalid for some reason.
InvalidRule(&'a str),
/// A rule was not recognized.
UnsupportedRule(&'a str),
/// A viewport descriptor declaration was not recognized.
UnsupportedViewportDescriptorDeclaration(&'a str),
/// A counter style descriptor declaration was not recognized.
UnsupportedCounterStyleDescriptorDeclaration(&'a str),
/// A counter style rule had no symbols.
InvalidCounterStyleWithoutSymbols(String),
/// A counter style rule had less than two symbols.
InvalidCounterStyleNotEnoughSymbols(String),
/// A counter style rule did not have additive-symbols.
InvalidCounterStyleWithoutAdditiveSymbols,
/// A counter style rule had extends with symbols.
InvalidCounterStyleExtendsWithSymbols,
/// A counter style rule had extends with additive-symbols.
InvalidCounterStyleExtendsWithAdditiveSymbols
}

impl<'a> ParseError<'a> {
/// Turn a parse error into a string representation.
pub fn to_string(&self) -> String {
match *self {
ParseError::UnsupportedPropertyDeclaration(decl) =>
format!("Unsupported property declaration: '{}'", decl),
ParseError::UnsupportedFontFaceDescriptor(decl) =>
format!("Unsupported @font-face descriptor declaration: '{}'", decl),
ParseError::InvalidKeyframeRule(rule) =>
format!("Invalid keyframe rule: '{}'", rule),
ParseError::UnsupportedKeyframePropertyDeclaration(decl) =>
format!("Unsupported keyframe property declaration: '{}'", decl),
ParseError::InvalidRule(rule) =>
format!("Invalid rule: '{}'", rule),
ParseError::UnsupportedRule(rule) =>
format!("Unsupported rule: '{}'", rule),
ParseError::UnsupportedViewportDescriptorDeclaration(decl) =>
format!("Unsupported @viewport descriptor declaration: '{}'", decl),
ParseError::UnsupportedCounterStyleDescriptorDeclaration(decl) =>
format!("Unsupported @counter-style descriptor declaration: '{}'", decl),
ParseError::InvalidCounterStyleWithoutSymbols(ref system) =>
format!("Invalid @counter-style rule: 'system: {}' without 'symbols'", system),
ParseError::InvalidCounterStyleNotEnoughSymbols(ref system) =>
format!("Invalid @counter-style rule: 'system: {}' less than two 'symbols'", system),
ParseError::InvalidCounterStyleWithoutAdditiveSymbols =>
"Invalid @counter-style rule: 'system: additive' without 'additive-symbols'".into(),
ParseError::InvalidCounterStyleExtendsWithSymbols =>
"Invalid @counter-style rule: 'system: extends …' with 'symbols'".into(),
ParseError::InvalidCounterStyleExtendsWithAdditiveSymbols =>
"Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'".into(),
}
}
}

/// A generic trait for an error reporter.
pub trait ParseErrorReporter : Sync + Send {
/// Called when the style engine detects an error.
///
/// Returns the current input being parsed, the source position it was
/// reported from, and a message.
fn report_error(&self,
input: &mut Parser,
position: SourcePosition,
message: &str,
url: &UrlExtraData,
line_number_offset: u64);
fn report_error<'a>(&self,
input: &mut Parser,
position: SourcePosition,
error: ParseError<'a>,
url: &UrlExtraData,
line_number_offset: u64);
}

/// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log)
Expand All @@ -33,16 +97,16 @@ pub trait ParseErrorReporter : Sync + Send {
pub struct RustLogReporter;

impl ParseErrorReporter for RustLogReporter {
fn report_error(&self,
input: &mut Parser,
position: SourcePosition,
message: &str,
url: &UrlExtraData,
line_number_offset: u64) {
fn report_error<'a>(&self,
input: &mut Parser,
position: SourcePosition,
error: ParseError<'a>,
url: &UrlExtraData,
line_number_offset: u64) {
if log_enabled!(log::LogLevel::Info) {
let location = input.source_location(position);
let line_offset = location.line + line_number_offset as usize;
info!("Url:\t{}\n{}:{} {}", url.as_str(), line_offset, location.column, message)
info!("Url:\t{}\n{}:{} {}", url.as_str(), line_offset, location.column, error.to_string())
}
}
}
Expand All @@ -51,10 +115,10 @@ impl ParseErrorReporter for RustLogReporter {
pub struct NullReporter;

impl ParseErrorReporter for NullReporter {
fn report_error(&self,
fn report_error<'a>(&self,
_: &mut Parser,
_: SourcePosition,
_: &str,
_: ParseError<'a>,
_: &UrlExtraData,
_: u64) {
// do nothing
Expand Down
6 changes: 3 additions & 3 deletions components/style/font_face.rs
Expand Up @@ -13,6 +13,7 @@ use computed_values::{font_feature_settings, font_stretch, font_style, font_weig
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::SourceLocation;
use error_reporting::ParseError;
#[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors;
#[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse};
Expand Down Expand Up @@ -99,9 +100,8 @@ pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser, locati
while let Some(declaration) = iter.next() {
if let Err(range) = declaration {
let pos = range.start;
let message = format!("Unsupported @font-face descriptor declaration: '{}'",
iter.input.slice(range));
log_css_error(iter.input, pos, &*message, context);
let error = ParseError::UnsupportedFontFaceDescriptor(iter.input.slice(range));
log_css_error(iter.input, pos, error, context);
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions components/style/parser.rs
Expand Up @@ -6,7 +6,7 @@

use context::QuirksMode;
use cssparser::{Parser, SourcePosition, UnicodeRange};
use error_reporting::ParseErrorReporter;
use error_reporting::{ParseErrorReporter, ParseError};
use style_traits::OneOrMoreCommaSeparated;
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};

Expand Down Expand Up @@ -164,14 +164,14 @@ impl<'a> ParserContext<'a> {
/// Defaults to a no-op.
/// Set a `RUST_LOG=style::errors` environment variable
/// to log CSS parse errors to stderr.
pub fn log_css_error(input: &mut Parser,
position: SourcePosition,
message: &str,
parsercontext: &ParserContext) {
pub fn log_css_error<'a>(input: &mut Parser,
position: SourcePosition,
error: ParseError<'a>,
parsercontext: &ParserContext) {
let url_data = parsercontext.url_data;
let line_number_offset = parsercontext.line_number_offset;
parsercontext.error_reporter.report_error(input, position,
message, url_data,
error, url_data,
line_number_offset);
}

Expand Down
7 changes: 3 additions & 4 deletions components/style/properties/declaration_block.rs
Expand Up @@ -9,7 +9,7 @@
use context::QuirksMode;
use cssparser::{DeclarationListParser, parse_important};
use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
use error_reporting::ParseErrorReporter;
use error_reporting::{ParseErrorReporter, ParseError};
use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error};
use properties::animated_properties::AnimationValue;
use shared_lock::Locked;
Expand Down Expand Up @@ -955,9 +955,8 @@ pub fn parse_property_declaration_list(context: &ParserContext,
Err(range) => {
iter.parser.declarations.clear();
let pos = range.start;
let message = format!("Unsupported property declaration: '{}'",
iter.input.slice(range));
log_css_error(iter.input, pos, &*message, &context);
let error = ParseError::UnsupportedPropertyDeclaration(iter.input.slice(range));
log_css_error(iter.input, pos, error, &context);
}
}
}
Expand Down
11 changes: 5 additions & 6 deletions components/style/stylesheets/keyframes_rule.rs
Expand Up @@ -6,7 +6,7 @@

use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation};
use error_reporting::NullReporter;
use error_reporting::{NullReporter, ParseError};
use parser::{PARSING_MODE_DEFAULT, ParserContext, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, SourcePropertyDeclaration};
Expand Down Expand Up @@ -459,8 +459,8 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
match KeyframeSelector::parse(input) {
Ok(sel) => Ok(sel),
Err(()) => {
let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
log_css_error(input, start, &message, self.context);
let error = ParseError::InvalidKeyframeRule(input.slice_from(start));
log_css_error(input, start, error, self.context);
Err(())
}
}
Expand All @@ -483,9 +483,8 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
Err(range) => {
iter.parser.declarations.clear();
let pos = range.start;
let message = format!("Unsupported keyframe property declaration: '{}'",
iter.input.slice(range));
log_css_error(iter.input, pos, &*message, &context);
let error = ParseError::UnsupportedKeyframePropertyDeclaration(iter.input.slice(range));
log_css_error(iter.input, pos, error, &context);
}
}
// `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
Expand Down
5 changes: 3 additions & 2 deletions components/style/stylesheets/rule_parser.rs
Expand Up @@ -7,6 +7,7 @@
use {Namespace, Prefix};
use counter_style::{parse_counter_style_body, parse_counter_style_name};
use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser, SourceLocation};
use error_reporting::ParseError;
use font_face::parse_font_face_block;
use media_queries::{parse_media_query_list, MediaList};
use parking_lot::RwLock;
Expand Down Expand Up @@ -304,8 +305,8 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> {
Ok(rule) => rules.push(rule),
Err(range) => {
let pos = range.start;
let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
log_css_error(iter.input, pos, &*message, self.context);
let error = ParseError::UnsupportedRule(iter.input.slice(range));
log_css_error(iter.input, pos, error, self.context);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions components/style/stylesheets/stylesheet.rs
Expand Up @@ -5,7 +5,7 @@
use {Prefix, Namespace};
use context::QuirksMode;
use cssparser::{Parser, RuleListParser};
use error_reporting::ParseErrorReporter;
use error_reporting::{ParseErrorReporter, ParseError};
use fnv::FnvHashMap;
use media_queries::{MediaList, Device};
use parking_lot::RwLock;
Expand Down Expand Up @@ -142,8 +142,8 @@ impl Stylesheet {
Ok(rule) => rules.push(rule),
Err(range) => {
let pos = range.start;
let message = format!("Invalid rule: '{}'", iter.input.slice(range));
log_css_error(iter.input, pos, &*message, iter.parser.context());
let error = ParseError::InvalidRule(iter.input.slice(range));
log_css_error(iter.input, pos, error, iter.parser.context());
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions components/style/stylesheets/viewport_rule.rs
Expand Up @@ -11,6 +11,7 @@ use app_units::Au;
use context::QuirksMode;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
use cssparser::ToCss as ParserToCss;
use error_reporting::ParseError;
use euclid::size::TypedSize2D;
use font_metrics::get_metrics_provider_for_product;
use media_queries::Device;
Expand Down Expand Up @@ -342,9 +343,8 @@ impl Parse for ViewportRule {
}
Err(range) => {
let pos = range.start;
let message = format!("Unsupported @viewport descriptor declaration: '{}'",
parser.input.slice(range));
log_css_error(parser.input, pos, &*message, &context);
let error = ParseError::UnsupportedViewportDescriptorDeclaration(parser.input.slice(range));
log_css_error(parser.input, pos, error, &context);
}
}
}
Expand Down

0 comments on commit fd6e54d

Please sign in to comment.