Make PropertyDeclaration::parse return an enum rather than push to a Vec.

This commit is contained in:
Simon Sapin 2017-03-07 17:12:37 +01:00
parent 8160490272
commit 9d663ea7af
6 changed files with 83 additions and 113 deletions

View file

@ -250,14 +250,14 @@ impl CSSStyleDeclaration {
// Step 6 // Step 6
let window = self.owner.window(); let window = self.owner.window();
let declarations = let result =
parse_one_declaration(id, &value, &self.owner.base_url(), parse_one_declaration(id, &value, &self.owner.base_url(),
window.css_error_reporter(), window.css_error_reporter(),
ParserContextExtraData::default()); ParserContextExtraData::default());
// Step 7 // Step 7
let declarations = match declarations { let parsed = match result {
Ok(declarations) => declarations, Ok(parsed) => parsed,
Err(_) => { Err(_) => {
*changed = false; *changed = false;
return Ok(()); return Ok(());
@ -267,9 +267,9 @@ impl CSSStyleDeclaration {
// Step 8 // Step 8
// Step 9 // Step 9
*changed = false; *changed = false;
for declaration in declarations { parsed.expand(|declaration| {
*changed |= pdb.set_parsed_declaration(declaration.0, importance); *changed |= pdb.set_parsed_declaration(declaration, importance);
} });
Ok(()) Ok(())
}) })

View file

@ -11,7 +11,7 @@ use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock; use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error}; use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue}; use properties::{PropertyDeclarationId, LonghandId, DeclaredValue, ParsedDeclaration};
use properties::LonghandIdSet; use properties::LonghandIdSet;
use properties::animated_properties::TransitionProperty; use properties::animated_properties::TransitionProperty;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
@ -360,12 +360,12 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
-> Result<Self::QualifiedRule, ()> { -> Result<Self::QualifiedRule, ()> {
let parser = KeyframeDeclarationParser { let parser = KeyframeDeclarationParser {
context: self.context, context: self.context,
declarations: vec![],
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
let mut declarations = Vec::new();
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok(_) => (), Ok(parsed) => parsed.expand(|d| declarations.push((d, Importance::Normal))),
Err(range) => { Err(range) => {
let pos = range.start; let pos = range.start;
let message = format!("Unsupported keyframe property declaration: '{}'", let message = format!("Unsupported keyframe property declaration: '{}'",
@ -378,7 +378,7 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
Ok(Arc::new(RwLock::new(Keyframe { Ok(Arc::new(RwLock::new(Keyframe {
selector: prelude, selector: prelude,
block: Arc::new(RwLock::new(PropertyDeclarationBlock { block: Arc::new(RwLock::new(PropertyDeclarationBlock {
declarations: iter.parser.declarations, declarations: declarations,
important_count: 0, important_count: 0,
})), })),
}))) })))
@ -387,32 +387,30 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
struct KeyframeDeclarationParser<'a, 'b: 'a> { struct KeyframeDeclarationParser<'a, 'b: 'a> {
context: &'a ParserContext<'b>, context: &'a ParserContext<'b>,
declarations: Vec<(PropertyDeclaration, Importance)>
} }
/// Default methods reject all at rules. /// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> { impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> {
type Prelude = (); type Prelude = ();
type AtRule = (); type AtRule = ParsedDeclaration;
} }
impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> { impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
/// We parse rules directly into the declarations object /// We parse rules directly into the declarations object
type Declaration = (); type Declaration = ParsedDeclaration;
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<ParsedDeclaration, ()> {
let id = try!(PropertyId::parse(name.into())); let id = try!(PropertyId::parse(name.into()));
let old_len = self.declarations.len(); match PropertyDeclaration::parse(id, self.context, input, true) {
if PropertyDeclaration::parse(id, self.context, input, &mut self.declarations, true).is_err() { Ok(parsed) => {
self.declarations.truncate(old_len); // In case there is still unparsed text in the declaration, we should roll back.
return Err(()) if !input.is_exhausted() {
} Err(())
// In case there is still unparsed text in the declaration, we should roll back. } else {
if !input.is_exhausted() { Ok(parsed)
self.declarations.truncate(old_len); }
Err(()) }
} else { Err(_) => Err(())
Ok(())
} }
} }
} }

View file

@ -56,7 +56,7 @@ pub struct PropertyDeclarationBlock {
pub declarations: Vec<(PropertyDeclaration, Importance)>, pub declarations: Vec<(PropertyDeclaration, Importance)>,
/// The number of entries in `self.declaration` with `Importance::Important` /// The number of entries in `self.declaration` with `Importance::Important`
pub important_count: u32, pub important_count: usize,
} }
impl PropertyDeclarationBlock { impl PropertyDeclarationBlock {
@ -75,7 +75,7 @@ impl PropertyDeclarationBlock {
/// which should be maintained whenever `declarations` is changed. /// which should be maintained whenever `declarations` is changed.
// FIXME: make fields private and maintain it here in methods? // FIXME: make fields private and maintain it here in methods?
pub fn any_normal(&self) -> bool { pub fn any_normal(&self) -> bool {
self.declarations.len() > self.important_count as usize self.declarations.len() > self.important_count
} }
/// Get a declaration for a given property. /// Get a declaration for a given property.
@ -554,63 +554,46 @@ pub fn parse_one_declaration(id: PropertyId,
base_url: &ServoUrl, base_url: &ServoUrl,
error_reporter: StdBox<ParseErrorReporter + Send>, error_reporter: StdBox<ParseErrorReporter + Send>,
extra_data: ParserContextExtraData) extra_data: ParserContextExtraData)
-> Result<Vec<(PropertyDeclaration, Importance)>, ()> { -> Result<ParsedDeclaration, ()> {
let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data); let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
Parser::new(input).parse_entirely(|parser| { Parser::new(input).parse_entirely(|parser| {
let mut results = vec![]; PropertyDeclaration::parse(id, &context, parser, false)
match PropertyDeclaration::parse(id, &context, parser, &mut results, false) { .map_err(|_| ())
Ok(()) => Ok(results),
Err(_) => Err(())
}
}) })
} }
/// A struct to parse property declarations. /// A struct to parse property declarations.
struct PropertyDeclarationParser<'a, 'b: 'a> { struct PropertyDeclarationParser<'a, 'b: 'a> {
context: &'a ParserContext<'b>, context: &'a ParserContext<'b>,
declarations: Vec<(PropertyDeclaration, Importance)>
} }
/// Default methods reject all at rules. /// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> { impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
type Prelude = (); type Prelude = ();
type AtRule = (u32, Importance); type AtRule = (ParsedDeclaration, Importance);
} }
impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> { impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
/// Declarations are pushed to the internal vector. This will only type Declaration = (ParsedDeclaration, Importance);
/// let you know if the decl was !important and how many longhands
/// it expanded to
type Declaration = (u32, Importance);
fn parse_value(&mut self, name: &str, input: &mut Parser) fn parse_value(&mut self, name: &str, input: &mut Parser)
-> Result<(u32, Importance), ()> { -> Result<(ParsedDeclaration, Importance), ()> {
let id = try!(PropertyId::parse(name.into())); let id = try!(PropertyId::parse(name.into()));
let old_len = self.declarations.len(); let parsed = input.parse_until_before(Delimiter::Bang, |input| {
let parse_result = input.parse_until_before(Delimiter::Bang, |input| { PropertyDeclaration::parse(id, self.context, input, false)
PropertyDeclaration::parse(id, self.context, input, &mut self.declarations, false) .map_err(|_| ())
.map_err(|_| ()) })?;
});
if let Err(_) = parse_result {
// rollback
self.declarations.truncate(old_len);
return Err(())
}
let importance = match input.try(parse_important) { let importance = match input.try(parse_important) {
Ok(()) => Importance::Important, Ok(()) => Importance::Important,
Err(()) => Importance::Normal, Err(()) => Importance::Normal,
}; };
// In case there is still unparsed text in the declaration, we should roll back. // In case there is still unparsed text in the declaration, we should roll back.
if !input.is_exhausted() { if !input.is_exhausted() {
self.declarations.truncate(old_len);
return Err(()) return Err(())
} }
for decl in &mut self.declarations[old_len..] { Ok((parsed, importance))
decl.1 = importance
}
Ok(((self.declarations.len() - old_len) as u32, importance))
} }
} }
@ -620,17 +603,19 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
pub fn parse_property_declaration_list(context: &ParserContext, pub fn parse_property_declaration_list(context: &ParserContext,
input: &mut Parser) input: &mut Parser)
-> PropertyDeclarationBlock { -> PropertyDeclarationBlock {
let mut declarations = Vec::new();
let mut important_count = 0; let mut important_count = 0;
let parser = PropertyDeclarationParser { let parser = PropertyDeclarationParser {
context: context, context: context,
declarations: vec![],
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok((count, importance)) => { Ok((parsed, importance)) => {
let old_len = declarations.len();
parsed.expand(|d| declarations.push((d, importance)));
if importance.important() { if importance.important() {
important_count += count; important_count += declarations.len() - old_len;
} }
} }
Err(range) => { Err(range) => {
@ -642,7 +627,7 @@ pub fn parse_property_declaration_list(context: &ParserContext,
} }
} }
let mut block = PropertyDeclarationBlock { let mut block = PropertyDeclarationBlock {
declarations: iter.parser.declarations, declarations: declarations,
important_count: important_count, important_count: important_count,
}; };
block.deduplicate(); block.deduplicate();

View file

@ -800,11 +800,14 @@ pub enum ParsedDeclaration {
% for shorthand in data.shorthands: % for shorthand in data.shorthands:
/// ${shorthand.name} /// ${shorthand.name}
${shorthand.camel_case}(shorthands::${shorthand.ident}::Longhands), ${shorthand.camel_case}(shorthands::${shorthand.ident}::Longhands),
% endfor
% for shorthand in data.shorthands: /// ${shorthand.name} with a CSS-wide keyword
${shorthand.camel_case}CSSWideKeyword(CSSWideKeyword),
/// ${shorthand.name} with var() functions /// ${shorthand.name} with var() functions
${shorthand.camel_case}WithVariables(Arc<UnparsedValue>), ${shorthand.camel_case}WithVariables(Arc<UnparsedValue>),
% endfor % endfor
/// Not a shorthand /// Not a shorthand
LonghandOrCustom(PropertyDeclaration), LonghandOrCustom(PropertyDeclaration),
} }
@ -832,8 +835,13 @@ impl ParsedDeclaration {
)); ));
% endfor % endfor
} }
% endfor ParsedDeclaration::${shorthand.camel_case}CSSWideKeyword(keyword) => {
% for shorthand in data.shorthands: % for sub_property in shorthand.sub_properties:
f(PropertyDeclaration::${sub_property.camel_case}(
DeclaredValue::CSSWideKeyword(keyword)
));
% endfor
}
ParsedDeclaration::${shorthand.camel_case}WithVariables(value) => { ParsedDeclaration::${shorthand.camel_case}WithVariables(value) => {
debug_assert_eq!( debug_assert_eq!(
value.from_shorthand, value.from_shorthand,
@ -841,7 +849,8 @@ impl ParsedDeclaration {
); );
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
f(PropertyDeclaration::${sub_property.camel_case}( f(PropertyDeclaration::${sub_property.camel_case}(
DeclaredValue::WithVariables(value.clone()))); DeclaredValue::WithVariables(value.clone())
));
% endfor % endfor
} }
% endfor % endfor
@ -1053,9 +1062,8 @@ impl PropertyDeclaration {
/// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser, /// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,
/// we only set them here so that we don't have to reallocate /// we only set them here so that we don't have to reallocate
pub fn parse(id: PropertyId, context: &ParserContext, input: &mut Parser, pub fn parse(id: PropertyId, context: &ParserContext, input: &mut Parser,
result_list: &mut Vec<(PropertyDeclaration, Importance)>,
in_keyframe_block: bool) in_keyframe_block: bool)
-> Result<(), PropertyDeclarationParseError> { -> Result<ParsedDeclaration, PropertyDeclarationParseError> {
match id { match id {
PropertyId::Custom(name) => { PropertyId::Custom(name) => {
let value = match input.try(|i| CSSWideKeyword::parse(context, i)) { let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
@ -1065,9 +1073,7 @@ impl PropertyDeclaration {
Err(()) => return Err(PropertyDeclarationParseError::InvalidValue), Err(()) => return Err(PropertyDeclarationParseError::InvalidValue),
} }
}; };
result_list.push((PropertyDeclaration::Custom(name, value), Ok(ParsedDeclaration::LonghandOrCustom(PropertyDeclaration::Custom(name, value)))
Importance::Normal));
return Ok(());
} }
PropertyId::Longhand(id) => match id { PropertyId::Longhand(id) => match id {
% for property in data.longhands: % for property in data.longhands:
@ -1088,9 +1094,9 @@ impl PropertyDeclaration {
match longhands::${property.ident}::parse_declared(context, input) { match longhands::${property.ident}::parse_declared(context, input) {
Ok(value) => { Ok(value) => {
result_list.push((PropertyDeclaration::${property.camel_case}(value), Ok(ParsedDeclaration::LonghandOrCustom(
Importance::Normal)); PropertyDeclaration::${property.camel_case}(value)
Ok(()) ))
}, },
Err(()) => Err(PropertyDeclarationParseError::InvalidValue), Err(()) => Err(PropertyDeclarationParseError::InvalidValue),
} }
@ -1118,21 +1124,11 @@ impl PropertyDeclaration {
match input.try(|i| CSSWideKeyword::parse(context, i)) { match input.try(|i| CSSWideKeyword::parse(context, i)) {
Ok(keyword) => { Ok(keyword) => {
% for sub_property in shorthand.sub_properties: Ok(ParsedDeclaration::${shorthand.camel_case}CSSWideKeyword(keyword))
result_list.push((
PropertyDeclaration::${sub_property.camel_case}(
DeclaredValue::CSSWideKeyword(keyword)), Importance::Normal));
% endfor
Ok(())
}, },
Err(()) => match shorthands::${shorthand.ident}::parse(context, input) { Err(()) => {
Ok(parsed) => { shorthands::${shorthand.ident}::parse(context, input)
parsed.expand(|declaration| { .map_err(|()| PropertyDeclarationParseError::InvalidValue)
result_list.push((declaration, Importance::Normal))
});
Ok(())
}
Err(()) => Err(PropertyDeclarationParseError::InvalidValue),
} }
} }
} }

View file

@ -211,13 +211,8 @@ impl Declaration {
return false return false
}; };
let mut input = Parser::new(&self.val); let mut input = Parser::new(&self.val);
let mut list = Vec::new(); let res = PropertyDeclaration::parse(id, cx, &mut input, /* in_keyframe */ false);
let res = PropertyDeclaration::parse(id, cx, &mut input,
&mut list, /* in_keyframe */ false);
let _ = input.try(parse_important); let _ = input.try(parse_important);
if !input.is_exhausted() { res.is_ok() && input.is_exhausted()
return false;
}
res.is_ok()
} }
} }

View file

@ -713,18 +713,17 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const
Box::new(StdoutErrorReporter), Box::new(StdoutErrorReporter),
extra_data); extra_data);
let mut results = vec![]; match PropertyDeclaration::parse(id, &context, &mut Parser::new(value), false) {
let result = PropertyDeclaration::parse( Ok(parsed) => {
id, &context, &mut Parser::new(value), &mut results, false let mut declarations = Vec::new();
); parsed.expand(|d| declarations.push((d, Importance::Normal)));
if result.is_err() { Arc::new(RwLock::new(PropertyDeclarationBlock {
return RawServoDeclarationBlockStrong::null() declarations: declarations,
important_count: 0,
})).into_strong()
}
Err(_) => RawServoDeclarationBlockStrong::null()
} }
Arc::new(RwLock::new(PropertyDeclarationBlock {
declarations: results,
important_count: 0,
})).into_strong()
} }
#[no_mangle] #[no_mangle]
@ -834,14 +833,14 @@ fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: Pro
// FIXME Needs real URL and ParserContextExtraData. // FIXME Needs real URL and ParserContextExtraData.
let base_url = &*DUMMY_BASE_URL; let base_url = &*DUMMY_BASE_URL;
let extra_data = ParserContextExtraData::default(); let extra_data = ParserContextExtraData::default();
if let Ok(decls) = parse_one_declaration(property_id, value, &base_url, if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url,
Box::new(StdoutErrorReporter), extra_data) { Box::new(StdoutErrorReporter), extra_data) {
let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write(); let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write();
let importance = if is_important { Importance::Important } else { Importance::Normal }; let importance = if is_important { Importance::Important } else { Importance::Normal };
let mut changed = false; let mut changed = false;
for decl in decls.into_iter() { parsed.expand(|decl| {
changed |= declarations.set_parsed_declaration(decl.0, importance); changed |= declarations.set_parsed_declaration(decl, importance);
} });
changed changed
} else { } else {
false false
@ -1166,10 +1165,7 @@ pub extern "C" fn Servo_CSSSupports2(property: *const nsACString, value: *const
let base_url = &*DUMMY_BASE_URL; let base_url = &*DUMMY_BASE_URL;
let extra_data = ParserContextExtraData::default(); let extra_data = ParserContextExtraData::default();
match parse_one_declaration(id, &value, &base_url, Box::new(StdoutErrorReporter), extra_data) { parse_one_declaration(id, &value, &base_url, Box::new(StdoutErrorReporter), extra_data).is_ok()
Ok(decls) => !decls.is_empty(),
Err(()) => false,
}
} }
#[no_mangle] #[no_mangle]