44
55// https://drafts.csswg.org/css-syntax/#parsing
66
7- use super :: { BasicParseError , BasicParseErrorKind , Delimiter } ;
8- use super :: { ParseError , Parser , Token } ;
7+ use super :: { BasicParseError , BasicParseErrorKind , Delimiter , Delimiters , ParseError , Parser , Token } ;
98use crate :: cow_rc_str:: CowRcStr ;
109use crate :: parser:: { parse_nested_block, parse_until_after, parse_until_before, ParserState } ;
1110
@@ -50,14 +49,9 @@ pub trait DeclarationParser<'i> {
5049 & mut self ,
5150 name : CowRcStr < ' i > ,
5251 input : & mut Parser < ' i , ' t > ,
53- ) -> Result < Self :: Declaration , ParseError < ' i , Self :: Error > > ;
54-
55- /// Whether to try to parse qualified rules along with declarations. See
56- /// <https://github.com/w3c/csswg-drafts/issues/7961> for the current state of the discussion.
57- /// This is a low effort opt-in to be able to experiment with it, but it's likely to be needed
58- /// when nesting is less experimental as well (e.g., you probably don't want to allow nesting
59- /// in a style attribute anyways).
60- fn enable_nesting ( & self ) -> bool { false }
52+ ) -> Result < Self :: Declaration , ParseError < ' i , Self :: Error > > {
53+ Err ( input. new_error ( BasicParseErrorKind :: UnexpectedToken ( Token :: Ident ( name) ) ) )
54+ }
6155}
6256
6357/// A trait to provide various parsing of at-rules.
@@ -99,8 +93,6 @@ pub trait AtRuleParser<'i> {
9993 name : CowRcStr < ' i > ,
10094 input : & mut Parser < ' i , ' t > ,
10195 ) -> Result < Self :: Prelude , ParseError < ' i , Self :: Error > > {
102- let _ = name;
103- let _ = input;
10496 Err ( input. new_error ( BasicParseErrorKind :: AtRuleInvalid ( name) ) )
10597 }
10698
@@ -140,7 +132,6 @@ pub trait AtRuleParser<'i> {
140132 ) -> Result < Self :: AtRule , ParseError < ' i , Self :: Error > > {
141133 let _ = prelude;
142134 let _ = start;
143- let _ = input;
144135 Err ( input. new_error ( BasicParseErrorKind :: AtRuleBodyInvalid ) )
145136 }
146137}
@@ -178,7 +169,6 @@ pub trait QualifiedRuleParser<'i> {
178169 & mut self ,
179170 input : & mut Parser < ' i , ' t > ,
180171 ) -> Result < Self :: Prelude , ParseError < ' i , Self :: Error > > {
181- let _ = input;
182172 Err ( input. new_error ( BasicParseErrorKind :: QualifiedRuleInvalid ) )
183173 }
184174
@@ -197,24 +187,35 @@ pub trait QualifiedRuleParser<'i> {
197187 ) -> Result < Self :: QualifiedRule , ParseError < ' i , Self :: Error > > {
198188 let _ = prelude;
199189 let _ = start;
200- let _ = input;
201190 Err ( input. new_error ( BasicParseErrorKind :: QualifiedRuleInvalid ) )
202191 }
203192}
204193
205- /// Provides an iterator for declaration list parsing .
206- pub struct DeclarationListParser < ' i , ' t , ' a , P > {
207- /// The input given to `DeclarationListParser::new`
194+ /// Provides an iterator for rule bodies and declaration lists .
195+ pub struct RuleBodyParser < ' i , ' t , ' a , P , I , E > {
196+ /// The input given to the parser.
208197 pub input : & ' a mut Parser < ' i , ' t > ,
209-
210198 /// The parser given to `DeclarationListParser::new`
211- pub parser : P ,
199+ pub parser : & ' a mut P ,
200+
201+ _phantom : std:: marker:: PhantomData < ( I , E ) > ,
212202}
213203
214- impl < ' i , ' t , ' a , I , P , E : ' i > DeclarationListParser < ' i , ' t , ' a , P >
215- where
216- P : DeclarationParser < ' i , Declaration = I , Error = E > + AtRuleParser < ' i , AtRule = I , Error = E > ,
204+ /// A parser for a rule body item.
205+ pub trait RuleBodyItemParser < ' i , DeclOrRule , Error : ' i > :
206+ DeclarationParser < ' i , Declaration = DeclOrRule , Error = Error >
207+ + QualifiedRuleParser < ' i , QualifiedRule = DeclOrRule , Error = Error >
208+ + AtRuleParser < ' i , AtRule = DeclOrRule , Error = Error >
217209{
210+ /// Whether we should attempt to parse declarations. If you know you won't, returning false
211+ /// here is slightly faster.
212+ fn parse_declarations ( & self ) -> bool ;
213+ /// Whether we should attempt to parse qualified rules. If you know you won't, returning false
214+ /// would be slightly faster.
215+ fn parse_qualified ( & self ) -> bool ;
216+ }
217+
218+ impl < ' i , ' t , ' a , P , I , E > RuleBodyParser < ' i , ' t , ' a , P , I , E > {
218219 /// Create a new `DeclarationListParser` for the given `input` and `parser`.
219220 ///
220221 /// Note that all CSS declaration lists can on principle contain at-rules.
@@ -229,55 +230,69 @@ where
229230 /// The return type for finished declarations and at-rules also needs to be the same,
230231 /// since `<DeclarationListParser as Iterator>::next` can return either.
231232 /// It could be a custom enum.
232- pub fn new ( input : & ' a mut Parser < ' i , ' t > , parser : P ) -> Self {
233- DeclarationListParser { input, parser }
233+ pub fn new ( input : & ' a mut Parser < ' i , ' t > , parser : & ' a mut P ) -> Self {
234+ Self {
235+ input,
236+ parser,
237+ _phantom : std:: marker:: PhantomData ,
238+ }
234239 }
235240}
236241
237242/// `DeclarationListParser` is an iterator that yields `Ok(_)` for a valid declaration or at-rule
238243/// or `Err(())` for an invalid one.
239- impl < ' i , ' t , ' a , I , P , E : ' i > Iterator for DeclarationListParser < ' i , ' t , ' a , P >
244+ impl < ' i , ' t , ' a , I , P , E : ' i > Iterator for RuleBodyParser < ' i , ' t , ' a , P , I , E >
240245where
241- P : DeclarationParser < ' i , Declaration = I , Error = E >
242- + AtRuleParser < ' i , AtRule = I , Error = E >
243- + QualifiedRuleParser < ' i , QualifiedRule = I , Error = E > ,
246+ P : RuleBodyItemParser < ' i , I , E > ,
244247{
245248 type Item = Result < I , ( ParseError < ' i , E > , & ' i str ) > ;
246249
247250 fn next ( & mut self ) -> Option < Self :: Item > {
248251 loop {
249252 let start = self . input . state ( ) ;
250- match self . input . next_including_whitespace_and_comments ( ) {
251- Ok ( & Token :: WhiteSpace ( _) ) | Ok ( & Token :: Comment ( _) ) | Ok ( & Token :: Semicolon ) => {
252- continue
253+ match self . input . next_including_whitespace_and_comments ( ) . ok ( ) ? {
254+ Token :: WhiteSpace ( _) | Token :: Comment ( _) | Token :: Semicolon => {
255+ continue ;
253256 }
254- Ok ( & Token :: Ident ( ref name) ) => {
257+ Token :: Ident ( ref name) if self . parser . parse_declarations ( ) => {
255258 let name = name. clone ( ) ;
259+ let parse_qualified = self . parser . parse_qualified ( ) ;
260+ let delimiters = if parse_qualified {
261+ Delimiter :: Semicolon | Delimiter :: CurlyBracketBlock
262+ } else {
263+ Delimiter :: Semicolon
264+ } ;
256265 let mut result = {
257266 let parser = & mut self . parser ;
258- parse_until_after ( self . input , Delimiter :: Semicolon , |input| {
267+ parse_until_after ( self . input , delimiters , |input| {
259268 input. expect_colon ( ) ?;
260269 parser. parse_value ( name, input)
261270 } )
262271 } ;
263272
264- if result. is_err ( ) && self . parser . enable_nesting ( ) {
273+ if result. is_err ( ) && parse_qualified {
265274 self . input . reset ( & start) ;
266- result = parse_qualified_rule ( & start, self . input , & mut self . parser ) ;
275+ result =
276+ parse_qualified_rule ( & start, self . input , & mut * self . parser , delimiters) ;
267277 }
268278
269279 return Some ( result. map_err ( |e| ( e, self . input . slice_from ( start. position ( ) ) ) ) ) ;
270280 }
271- Ok ( & Token :: AtKeyword ( ref name) ) => {
281+ Token :: AtKeyword ( ref name) => {
272282 let name = name. clone ( ) ;
273- return Some ( parse_at_rule ( & start, name, self . input , & mut self . parser ) ) ;
283+ return Some ( parse_at_rule ( & start, name, self . input , & mut * self . parser ) ) ;
274284 }
275- Ok ( token) => {
276- let result = if self . parser . enable_nesting ( ) {
285+ token => {
286+ let result = if self . parser . parse_qualified ( ) {
277287 self . input . reset ( & start) ;
278- // XXX do we need to, if we fail, consume only until the next semicolon,
279- // rather than until the next `{`?
280- parse_qualified_rule ( & start, self . input , & mut self . parser )
288+ // TODO(emilio, nesting): do we need to, if we fail, consume only until the
289+ // next semicolon, rather than until the next `{`?
290+ parse_qualified_rule (
291+ & start,
292+ self . input ,
293+ & mut * self . parser ,
294+ Delimiter :: CurlyBracketBlock ,
295+ )
281296 } else {
282297 let token = token. clone ( ) ;
283298 self . input . parse_until_after ( Delimiter :: Semicolon , |_| {
@@ -286,66 +301,44 @@ where
286301 } ;
287302 return Some ( result. map_err ( |e| ( e, self . input . slice_from ( start. position ( ) ) ) ) ) ;
288303 }
289- Err ( ..) => return None ,
290304 }
291305 }
292306 }
293307}
294308
295- /// Provides an iterator for rule list parsing.
296- pub struct RuleListParser < ' i , ' t , ' a , P > {
297- /// The input given to `RuleListParser::new`
309+ /// Provides an iterator for rule list parsing at the top-level of a stylesheet .
310+ pub struct StyleSheetParser < ' i , ' t , ' a , P > {
311+ /// The input given.
298312 pub input : & ' a mut Parser < ' i , ' t > ,
299313
300- /// The parser given to `RuleListParser::new`
301- pub parser : P ,
314+ /// The parser given.
315+ pub parser : & ' a mut P ,
302316
303- is_stylesheet : bool ,
304317 any_rule_so_far : bool ,
305318}
306319
307- impl < ' i , ' t , ' a , R , P , E : ' i > RuleListParser < ' i , ' t , ' a , P >
320+ impl < ' i , ' t , ' a , R , P , E : ' i > StyleSheetParser < ' i , ' t , ' a , P >
308321where
309322 P : QualifiedRuleParser < ' i , QualifiedRule = R , Error = E >
310323 + AtRuleParser < ' i , AtRule = R , Error = E > ,
311324{
312- /// Create a new `RuleListParser` for the given `input` at the top-level of a stylesheet
313- /// and the given `parser`.
314- ///
315325 /// The given `parser` needs to implement both `QualifiedRuleParser` and `AtRuleParser` traits.
316- /// However, either of them can be an empty `impl`
317- /// since the traits provide default implementations of their methods.
326+ /// However, either of them can be an empty `impl` since the traits provide default
327+ /// implementations of their methods.
318328 ///
319329 /// The return type for finished qualified rules and at-rules also needs to be the same,
320- /// since `<RuleListParser as Iterator>::next` can return either.
321- /// It could be a custom enum.
322- pub fn new_for_stylesheet ( input : & ' a mut Parser < ' i , ' t > , parser : P ) -> Self {
323- RuleListParser {
330+ /// since `<RuleListParser as Iterator>::next` can return either. It could be a custom enum.
331+ pub fn new ( input : & ' a mut Parser < ' i , ' t > , parser : & ' a mut P ) -> Self {
332+ Self {
324333 input,
325334 parser,
326- is_stylesheet : true ,
327- any_rule_so_far : false ,
328- }
329- }
330-
331- /// Same is `new_for_stylesheet`, but should be used for rule lists inside a block
332- /// such as the body of an `@media` rule.
333- ///
334- /// This differs in that `<!--` and `-->` tokens
335- /// should only be ignored at the stylesheet top-level.
336- /// (This is to deal with legacy workarounds for `<style>` HTML element parsing.)
337- pub fn new_for_nested_rule ( input : & ' a mut Parser < ' i , ' t > , parser : P ) -> Self {
338- RuleListParser {
339- input,
340- parser,
341- is_stylesheet : false ,
342335 any_rule_so_far : false ,
343336 }
344337 }
345338}
346339
347340/// `RuleListParser` is an iterator that yields `Ok(_)` for a rule or `Err(())` for an invalid one.
348- impl < ' i , ' t , ' a , R , P , E : ' i > Iterator for RuleListParser < ' i , ' t , ' a , P >
341+ impl < ' i , ' t , ' a , R , P , E : ' i > Iterator for StyleSheetParser < ' i , ' t , ' a , P >
349342where
350343 P : QualifiedRuleParser < ' i , QualifiedRule = R , Error = E >
351344 + AtRuleParser < ' i , AtRule = R , Error = E > ,
@@ -354,13 +347,8 @@ where
354347
355348 fn next ( & mut self ) -> Option < Self :: Item > {
356349 loop {
357- if self . is_stylesheet {
358- self . input . skip_cdc_and_cdo ( )
359- } else {
360- self . input . skip_whitespace ( )
361- }
350+ self . input . skip_cdc_and_cdo ( ) ;
362351 let start = self . input . state ( ) ;
363-
364352 let at_keyword = match self . input . next_byte ( ) ? {
365353 b'@' => match self . input . next_including_whitespace_and_comments ( ) {
366354 Ok ( & Token :: AtKeyword ( ref name) ) => Some ( name. clone ( ) ) ,
@@ -373,7 +361,7 @@ where
373361 } ;
374362
375363 if let Some ( name) = at_keyword {
376- let first_stylesheet_rule = self . is_stylesheet && !self . any_rule_so_far ;
364+ let first_stylesheet_rule = !self . any_rule_so_far ;
377365 self . any_rule_so_far = true ;
378366 if first_stylesheet_rule && name. eq_ignore_ascii_case ( "charset" ) {
379367 let delimiters = Delimiter :: Semicolon | Delimiter :: CurlyBracketBlock ;
@@ -384,12 +372,17 @@ where
384372 & start,
385373 name. clone ( ) ,
386374 self . input ,
387- & mut self . parser ,
375+ & mut * self . parser ,
388376 ) ) ;
389377 }
390378 } else {
391379 self . any_rule_so_far = true ;
392- let result = parse_qualified_rule ( & start, self . input , & mut self . parser ) ;
380+ let result = parse_qualified_rule (
381+ & start,
382+ self . input ,
383+ & mut * self . parser ,
384+ Delimiter :: CurlyBracketBlock ,
385+ ) ;
393386 return Some ( result. map_err ( |e| ( e, self . input . slice_from ( start. position ( ) ) ) ) ) ;
394387 }
395388 }
@@ -441,7 +434,7 @@ where
441434 if let Some ( name) = at_keyword {
442435 parse_at_rule ( & start, name, input, parser) . map_err ( |e| e. 0 )
443436 } else {
444- parse_qualified_rule ( & start, input, parser)
437+ parse_qualified_rule ( & start, input, parser, Delimiter :: CurlyBracketBlock )
445438 }
446439 } )
447440}
@@ -485,19 +478,14 @@ fn parse_qualified_rule<'i, 't, P, E>(
485478 start : & ParserState ,
486479 input : & mut Parser < ' i , ' t > ,
487480 parser : & mut P ,
481+ delimiters : Delimiters ,
488482) -> Result < <P as QualifiedRuleParser < ' i > >:: QualifiedRule , ParseError < ' i , E > >
489483where
490484 P : QualifiedRuleParser < ' i , Error = E > ,
491485{
492- let prelude = parse_until_before ( input, Delimiter :: CurlyBracketBlock , |input| {
493- parser. parse_prelude ( input)
494- } ) ;
495- match * input. next ( ) ? {
496- Token :: CurlyBracketBlock => {
497- // Do this here so that we consume the `{` even if the prelude is `Err`.
498- let prelude = prelude?;
499- parse_nested_block ( input, |input| parser. parse_block ( prelude, & start, input) )
500- }
501- _ => unreachable ! ( ) ,
502- }
486+ let prelude = parse_until_before ( input, delimiters, |input| parser. parse_prelude ( input) ) ;
487+ input. expect_curly_bracket_block ( ) ?;
488+ // Do this here so that we consume the `{` even if the prelude is `Err`.
489+ let prelude = prelude?;
490+ parse_nested_block ( input, |input| parser. parse_block ( prelude, & start, input) )
503491}
0 commit comments