4
4
5
5
// https://drafts.csswg.org/css-syntax/#parsing
6
6
7
- use super :: { BasicParseError , BasicParseErrorKind , Delimiter } ;
8
- use super :: { ParseError , Parser , Token } ;
7
+ use super :: { BasicParseError , BasicParseErrorKind , Delimiter , Delimiters , ParseError , Parser , Token } ;
9
8
use crate :: cow_rc_str:: CowRcStr ;
10
9
use crate :: parser:: { parse_nested_block, parse_until_after, parse_until_before, ParserState } ;
11
10
@@ -50,14 +49,9 @@ pub trait DeclarationParser<'i> {
50
49
& mut self ,
51
50
name : CowRcStr < ' i > ,
52
51
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
+ }
61
55
}
62
56
63
57
/// A trait to provide various parsing of at-rules.
@@ -99,8 +93,6 @@ pub trait AtRuleParser<'i> {
99
93
name : CowRcStr < ' i > ,
100
94
input : & mut Parser < ' i , ' t > ,
101
95
) -> Result < Self :: Prelude , ParseError < ' i , Self :: Error > > {
102
- let _ = name;
103
- let _ = input;
104
96
Err ( input. new_error ( BasicParseErrorKind :: AtRuleInvalid ( name) ) )
105
97
}
106
98
@@ -140,7 +132,6 @@ pub trait AtRuleParser<'i> {
140
132
) -> Result < Self :: AtRule , ParseError < ' i , Self :: Error > > {
141
133
let _ = prelude;
142
134
let _ = start;
143
- let _ = input;
144
135
Err ( input. new_error ( BasicParseErrorKind :: AtRuleBodyInvalid ) )
145
136
}
146
137
}
@@ -178,7 +169,6 @@ pub trait QualifiedRuleParser<'i> {
178
169
& mut self ,
179
170
input : & mut Parser < ' i , ' t > ,
180
171
) -> Result < Self :: Prelude , ParseError < ' i , Self :: Error > > {
181
- let _ = input;
182
172
Err ( input. new_error ( BasicParseErrorKind :: QualifiedRuleInvalid ) )
183
173
}
184
174
@@ -197,24 +187,35 @@ pub trait QualifiedRuleParser<'i> {
197
187
) -> Result < Self :: QualifiedRule , ParseError < ' i , Self :: Error > > {
198
188
let _ = prelude;
199
189
let _ = start;
200
- let _ = input;
201
190
Err ( input. new_error ( BasicParseErrorKind :: QualifiedRuleInvalid ) )
202
191
}
203
192
}
204
193
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.
208
197
pub input : & ' a mut Parser < ' i , ' t > ,
209
-
210
198
/// The parser given to `DeclarationListParser::new`
211
- pub parser : P ,
199
+ pub parser : & ' a mut P ,
200
+
201
+ _phantom : std:: marker:: PhantomData < ( I , E ) > ,
212
202
}
213
203
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 >
217
209
{
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 > {
218
219
/// Create a new `DeclarationListParser` for the given `input` and `parser`.
219
220
///
220
221
/// Note that all CSS declaration lists can on principle contain at-rules.
@@ -229,55 +230,69 @@ where
229
230
/// The return type for finished declarations and at-rules also needs to be the same,
230
231
/// since `<DeclarationListParser as Iterator>::next` can return either.
231
232
/// 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
+ }
234
239
}
235
240
}
236
241
237
242
/// `DeclarationListParser` is an iterator that yields `Ok(_)` for a valid declaration or at-rule
238
243
/// 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 >
240
245
where
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 > ,
244
247
{
245
248
type Item = Result < I , ( ParseError < ' i , E > , & ' i str ) > ;
246
249
247
250
fn next ( & mut self ) -> Option < Self :: Item > {
248
251
loop {
249
252
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 ;
253
256
}
254
- Ok ( & Token :: Ident ( ref name) ) => {
257
+ Token :: Ident ( ref name) if self . parser . parse_declarations ( ) => {
255
258
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
+ } ;
256
265
let mut result = {
257
266
let parser = & mut self . parser ;
258
- parse_until_after ( self . input , Delimiter :: Semicolon , |input| {
267
+ parse_until_after ( self . input , delimiters , |input| {
259
268
input. expect_colon ( ) ?;
260
269
parser. parse_value ( name, input)
261
270
} )
262
271
} ;
263
272
264
- if result. is_err ( ) && self . parser . enable_nesting ( ) {
273
+ if result. is_err ( ) && parse_qualified {
265
274
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) ;
267
277
}
268
278
269
279
return Some ( result. map_err ( |e| ( e, self . input . slice_from ( start. position ( ) ) ) ) ) ;
270
280
}
271
- Ok ( & Token :: AtKeyword ( ref name) ) => {
281
+ Token :: AtKeyword ( ref name) => {
272
282
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 ) ) ;
274
284
}
275
- Ok ( token) => {
276
- let result = if self . parser . enable_nesting ( ) {
285
+ token => {
286
+ let result = if self . parser . parse_qualified ( ) {
277
287
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
+ )
281
296
} else {
282
297
let token = token. clone ( ) ;
283
298
self . input . parse_until_after ( Delimiter :: Semicolon , |_| {
@@ -286,66 +301,44 @@ where
286
301
} ;
287
302
return Some ( result. map_err ( |e| ( e, self . input . slice_from ( start. position ( ) ) ) ) ) ;
288
303
}
289
- Err ( ..) => return None ,
290
304
}
291
305
}
292
306
}
293
307
}
294
308
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.
298
312
pub input : & ' a mut Parser < ' i , ' t > ,
299
313
300
- /// The parser given to `RuleListParser::new`
301
- pub parser : P ,
314
+ /// The parser given.
315
+ pub parser : & ' a mut P ,
302
316
303
- is_stylesheet : bool ,
304
317
any_rule_so_far : bool ,
305
318
}
306
319
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 >
308
321
where
309
322
P : QualifiedRuleParser < ' i , QualifiedRule = R , Error = E >
310
323
+ AtRuleParser < ' i , AtRule = R , Error = E > ,
311
324
{
312
- /// Create a new `RuleListParser` for the given `input` at the top-level of a stylesheet
313
- /// and the given `parser`.
314
- ///
315
325
/// 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.
318
328
///
319
329
/// 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 {
324
333
input,
325
334
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 ,
342
335
any_rule_so_far : false ,
343
336
}
344
337
}
345
338
}
346
339
347
340
/// `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 >
349
342
where
350
343
P : QualifiedRuleParser < ' i , QualifiedRule = R , Error = E >
351
344
+ AtRuleParser < ' i , AtRule = R , Error = E > ,
@@ -354,13 +347,8 @@ where
354
347
355
348
fn next ( & mut self ) -> Option < Self :: Item > {
356
349
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 ( ) ;
362
351
let start = self . input . state ( ) ;
363
-
364
352
let at_keyword = match self . input . next_byte ( ) ? {
365
353
b'@' => match self . input . next_including_whitespace_and_comments ( ) {
366
354
Ok ( & Token :: AtKeyword ( ref name) ) => Some ( name. clone ( ) ) ,
@@ -373,7 +361,7 @@ where
373
361
} ;
374
362
375
363
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 ;
377
365
self . any_rule_so_far = true ;
378
366
if first_stylesheet_rule && name. eq_ignore_ascii_case ( "charset" ) {
379
367
let delimiters = Delimiter :: Semicolon | Delimiter :: CurlyBracketBlock ;
@@ -384,12 +372,17 @@ where
384
372
& start,
385
373
name. clone ( ) ,
386
374
self . input ,
387
- & mut self . parser ,
375
+ & mut * self . parser ,
388
376
) ) ;
389
377
}
390
378
} else {
391
379
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
+ ) ;
393
386
return Some ( result. map_err ( |e| ( e, self . input . slice_from ( start. position ( ) ) ) ) ) ;
394
387
}
395
388
}
@@ -441,7 +434,7 @@ where
441
434
if let Some ( name) = at_keyword {
442
435
parse_at_rule ( & start, name, input, parser) . map_err ( |e| e. 0 )
443
436
} else {
444
- parse_qualified_rule ( & start, input, parser)
437
+ parse_qualified_rule ( & start, input, parser, Delimiter :: CurlyBracketBlock )
445
438
}
446
439
} )
447
440
}
@@ -485,19 +478,14 @@ fn parse_qualified_rule<'i, 't, P, E>(
485
478
start : & ParserState ,
486
479
input : & mut Parser < ' i , ' t > ,
487
480
parser : & mut P ,
481
+ delimiters : Delimiters ,
488
482
) -> Result < <P as QualifiedRuleParser < ' i > >:: QualifiedRule , ParseError < ' i , E > >
489
483
where
490
484
P : QualifiedRuleParser < ' i , Error = E > ,
491
485
{
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) )
503
491
}
0 commit comments