MCPcopy Create free account
hub / github.com/csskit/csskit / parse

Method parse

crates/css_parse/src/syntax/block.rs:60–191  ·  view source on GitHub ↗
(p: &mut Parser<'a, Iter>)

Source from the content-addressed store, hash-verified

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 }

Callers

nothing calls this directly

Calls 13

peek_nMethod · 0.80
set_skipMethod · 0.80
set_stateMethod · 0.80
cloneMethod · 0.80
okMethod · 0.80
bumpMethod · 0.45
at_endMethod · 0.45
checkpointMethod · 0.45
mergeMethod · 0.45
metadataMethod · 0.45
is_unknownMethod · 0.45

Tested by

no test coverage detected