Skip to content

Commit a01848b

Browse files
committed
[css-nesting] Make our nesting implementation match the new spec better.
This fixes issues that were found when enabling nesting by default on Nightly. It matches the spec (see new link) more closely. The places where we diverge (continuing rather than stopping when hitting right-curly, etc) are not really observable because of how our other APIs work (parse_nested_block in particular, for that case).
1 parent a3ebfb1 commit a01848b

File tree

1 file changed

+33
-28
lines changed

1 file changed

+33
-28
lines changed

src/rules_and_declarations.rs

+33-28
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
// https://drafts.csswg.org/css-syntax/#parsing
66

7-
use super::{BasicParseError, BasicParseErrorKind, Delimiter, Delimiters, ParseError, Parser, Token};
7+
use super::{
8+
BasicParseError, BasicParseErrorKind, Delimiter, Delimiters, ParseError, Parser, Token,
9+
};
810
use crate::cow_rc_str::CowRcStr;
911
use crate::parser::{parse_nested_block, parse_until_after, parse_until_before, ParserState};
1012

@@ -239,8 +241,7 @@ impl<'i, 't, 'a, P, I, E> RuleBodyParser<'i, 't, 'a, P, I, E> {
239241
}
240242
}
241243

242-
/// `DeclarationListParser` is an iterator that yields `Ok(_)` for a valid declaration or at-rule
243-
/// or `Err(())` for an invalid one.
244+
/// https://drafts.csswg.org/css-syntax/#consume-a-blocks-contents
244245
impl<'i, 't, 'a, I, P, E: 'i> Iterator for RuleBodyParser<'i, 't, 'a, P, I, E>
245246
where
246247
P: RuleBodyItemParser<'i, I, E>,
@@ -252,47 +253,51 @@ where
252253
self.input.skip_whitespace();
253254
let start = self.input.state();
254255
match self.input.next_including_whitespace_and_comments().ok()? {
256+
Token::CloseCurlyBracket |
257+
Token::WhiteSpace(..) |
258+
Token::Semicolon |
255259
Token::Comment(..) => continue,
256-
Token::Semicolon if self.parser.parse_declarations() => continue,
260+
Token::AtKeyword(ref name) => {
261+
let name = name.clone();
262+
return Some(parse_at_rule(&start, name, self.input, &mut *self.parser));
263+
}
264+
// https://drafts.csswg.org/css-syntax/#consume-a-declaration bails out just to
265+
// keep parsing as a qualified rule if the token is not an ident, so we implement
266+
// that in a slightly more straight-forward way
257267
Token::Ident(ref name) if self.parser.parse_declarations() => {
258268
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-
};
265-
let mut result = {
269+
let result = {
266270
let parser = &mut self.parser;
267-
parse_until_after(self.input, delimiters, |input| {
271+
parse_until_after(self.input, Delimiter::Semicolon, |input| {
268272
input.expect_colon()?;
269273
parser.parse_value(name, input)
270274
})
271275
};
272-
273-
if result.is_err() && parse_qualified {
276+
if result.is_err() && self.parser.parse_qualified() {
274277
self.input.reset(&start);
275-
result =
276-
parse_qualified_rule(&start, self.input, &mut *self.parser, delimiters);
278+
// We ignore the resulting error here. The property declaration parse error
279+
// is likely to be more relevant.
280+
if let Ok(qual) = parse_qualified_rule(
281+
&start,
282+
self.input,
283+
&mut *self.parser,
284+
Delimiter::Semicolon | Delimiter::CurlyBracketBlock,
285+
) {
286+
return Some(Ok(qual))
287+
}
277288
}
278289

279290
return Some(result.map_err(|e| (e, self.input.slice_from(start.position()))));
280291
}
281-
Token::AtKeyword(ref name) => {
282-
let name = name.clone();
283-
return Some(parse_at_rule(&start, name, self.input, &mut *self.parser));
284-
}
285292
token => {
286293
let result = if self.parser.parse_qualified() {
287294
self.input.reset(&start);
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-
)
295+
let delimiters = if self.parser.parse_declarations() {
296+
Delimiter::Semicolon | Delimiter::CurlyBracketBlock
297+
} else {
298+
Delimiter::CurlyBracketBlock
299+
};
300+
parse_qualified_rule(&start, self.input, &mut *self.parser, delimiters)
296301
} else {
297302
let token = token.clone();
298303
self.input.parse_until_after(Delimiter::Semicolon, |_| {

0 commit comments

Comments
 (0)