(p: &mut Parser<'a, Iter>)
| 58 | M: NodeMetadata, |
| 59 | { |
| 60 | fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self> |
| 61 | where |
| 62 | Iter: Iterator<Item = crate::Cursor> + Clone, |
| 63 | { |
| 64 | let open_curly = p.parse::<T!['{']>()?; |
| 65 | let mut declarations = Vec::new_in(p.bump()); |
| 66 | let mut rules = Vec::new_in(p.bump()); |
| 67 | let mut meta = M::default(); |
| 68 | |
| 69 | // Per CSS Syntax spec: maintain a buffer of declarations to flush when we encounter rules. |
| 70 | // This enables proper interleaving of declarations and rules. |
| 71 | let mut decls: Vec<'a, DeclarationOrBad<'a, D, M>> = Vec::new_in(p.bump()); |
| 72 | |
| 73 | // Flush the decls buffer into the rules list as a DeclarationGroup. |
| 74 | // Per spec: "If decls is not empty, append it to rules, and set decls to a fresh empty list" |
| 75 | macro_rules! flush_decls { |
| 76 | () => { |
| 77 | if !decls.is_empty() { |
| 78 | let group = DeclarationGroup { declarations: std::mem::replace(&mut decls, Vec::new_in(p.bump())) }; |
| 79 | if let Some(rule) = R::from_declaration_group(group) { |
| 80 | meta = meta.merge(rule.metadata()); |
| 81 | rules.push(rule); |
| 82 | } |
| 83 | } |
| 84 | }; |
| 85 | } |
| 86 | |
| 87 | loop { |
| 88 | // While by default the parser will skip whitespace, the Declaration or Rule type may be a whitespace sensitive |
| 89 | // node, for example `ComponentValues`. As such whitespace needs to be consumed here, before Declarations and |
| 90 | // Rules are parsed. |
| 91 | // Additional tokens, such as CDC (`-->`) and CDO (`<!--`), Semicolon, RightParen, RightSquare are not valid |
| 92 | // component values and are not consumed by the declaration/rule/bad-declaration recovery paths below. Left |
| 93 | // unconsumed they cause a zero-progress loop and unbounded allocation. Per CSS Syntax they are only meaningful |
| 94 | // at the stylesheet top level, so discard them here, mirroring the stylesheet top-level loop. |
| 95 | p.consume_trivia_as_leading(); |
| 96 | const ERROR_KINDS: KindSet = KindSet::new(&[ |
| 97 | Kind::CdcOrCdo, |
| 98 | Kind::Semicolon, |
| 99 | Kind::RightParen, |
| 100 | Kind::RightSquare, |
| 101 | Kind::BadString, |
| 102 | Kind::BadUrl, |
| 103 | ]); |
| 104 | let c = p.peek_n(1); |
| 105 | if c == ERROR_KINDS { |
| 106 | let old_skip = p.set_skip(ERROR_KINDS); |
| 107 | p.consume_trivia_as_leading(); |
| 108 | p.set_skip(old_skip); |
| 109 | continue; |
| 110 | } |
| 111 | if p.at_end() { |
| 112 | break; |
| 113 | } |
| 114 | let c = p.peek_n(1); |
| 115 | if <T!['}']>::peek(p, c) { |
| 116 | break; |
| 117 | } |
nothing calls this directly
no test coverage detected