1use super::prelude::*;
2use crate::{BadDeclaration, Declaration, DeclarationGroup, DeclarationOrBad, RuleVariants, token_macros};
3
4#[node]
17#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize))]
19#[cfg_attr(feature = "serde", serde(bound(serialize = "D: serde::Serialize, R: serde::Serialize")))]
20pub struct Block<'a, D, R, M>
21where
22 D: DeclarationValue<'a, M>,
23 M: NodeMetadata,
24{
25 pub open_curly: token_macros::LeftCurly,
26 pub declarations: Vec<'a, Declaration<'a, D, M>>,
27 pub rules: Vec<'a, R>,
28 pub close_curly: Option<token_macros::RightCurly>,
29 #[cfg_attr(feature = "serde", serde(skip))]
30 pub meta: M,
31}
32
33impl<'a, D, R, M> NodeWithMetadata<M> for Block<'a, D, R, M>
34where
35 D: DeclarationValue<'a, M>,
36 M: NodeMetadata,
37{
38 fn metadata(&self) -> M {
39 self.meta
40 }
41}
42
43impl<'a, D, R, M> Peek<'a> for Block<'a, D, R, M>
44where
45 D: DeclarationValue<'a, M>,
46 M: NodeMetadata,
47{
48 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly]);
49}
50
51impl<'a, D, R, M> Parse<'a> for Block<'a, D, R, M>
52where
53 D: DeclarationValue<'a, M>,
54 R: Parse<'a> + NodeWithMetadata<M> + RuleVariants<'a, DeclarationValue = D, Metadata = M>,
55 M: NodeMetadata,
56{
57 fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self>
58 where
59 Iter: Iterator<Item = crate::Cursor> + Clone,
60 {
61 let nested = p.is(State::Nested);
62 let open_curly = p.parse::<T!['{']>()?;
63 let mut declarations = Vec::new_in(p.alloc());
64 let mut rules = Vec::new_in(p.alloc());
65 let mut meta = if nested { M::default().with_nested() } else { M::default() };
66
67 let mut decls: Vec<'a, DeclarationOrBad<'a, D, M>> = Vec::new_in(p.alloc());
70
71 macro_rules! flush_decls {
74 () => {
75 if !decls.is_empty() {
76 let group =
77 DeclarationGroup { declarations: std::mem::replace(&mut decls, Vec::new_in(p.alloc())) };
78 if let Some(rule) = R::from_declaration_group(group) {
79 meta = meta.merge(rule.metadata());
80 rules.push(rule);
81 }
82 }
83 };
84 }
85
86 loop {
87 p.consume_trivia_as_leading();
95 const ERROR_KINDS: KindSet = KindSet::new(&[
96 Kind::CdcOrCdo,
97 Kind::Semicolon,
98 Kind::RightParen,
99 Kind::RightSquare,
100 Kind::BadString,
101 Kind::BadUrl,
102 ]);
103 let c = p.peek_n(1);
104 if c == ERROR_KINDS {
105 let old_skip = p.set_skip(ERROR_KINDS);
106 p.consume_trivia_as_leading();
107 p.set_skip(old_skip);
108 continue;
109 }
110 if p.at_end() {
111 break;
112 }
113 let c = p.peek_n(1);
114 if <T!['}']>::peek(p, c) {
115 break;
116 }
117 let old_state = p.set_state(State::Nested);
118 let checkpoint = p.checkpoint();
119 if <T![AtKeyword]>::peek(p, c) {
120 flush_decls!();
122 let rule = p.parse::<R>();
123 p.set_state(old_state);
124 let rule = rule?;
125 meta = meta.merge(rule.metadata());
126 rules.push(rule);
127 } else if let Ok(Some(decl)) = p.try_parse_if_peek::<Declaration<'a, D, M>>() {
128 if decl.is_unknown() && !D::valid_declaration_name(p, decl.name.into()) {
145 p.rewind(checkpoint.clone());
146 if let Ok(rule) = p.parse::<R>()
147 && !rule.is_unknown()
148 {
149 flush_decls!();
151 p.set_state(old_state);
152 meta = meta.merge(rule.metadata());
153 rules.push(rule);
154 continue;
155 }
156 p.rewind(checkpoint);
158 p.parse::<Declaration<'a, D, M>>().ok();
159 }
160 p.set_state(old_state);
161 meta = meta.merge(decl.metadata());
162 declarations.push(decl);
163 } else {
164 let result = p.parse::<R>();
166 p.set_state(old_state);
167 match result {
168 Ok(rule) => {
169 flush_decls!();
170 meta = meta.merge(rule.metadata());
171 rules.push(rule);
172 }
173 Err(_) => {
174 p.rewind(checkpoint);
176 p.set_state(State::Nested);
177 if let Ok(bad_decl) = p.parse::<BadDeclaration>() {
178 p.set_state(old_state);
179 decls.push(DeclarationOrBad::Bad(bad_decl));
180 }
181 }
182 }
183 }
184 }
185
186 flush_decls!();
188 let close_curly = p.parse_if_peek::<T!['}']>()?;
189 Ok(Self { open_curly, declarations, rules, close_curly, meta })
190 }
191}
192
193impl<'a, D, R, M> ToCursors for Block<'a, D, R, M>
194where
195 D: DeclarationValue<'a, M> + ToCursors,
196 R: ToCursors,
197 M: NodeMetadata,
198{
199 fn to_cursors(&self, s: &mut impl CursorSink) {
200 ToCursors::to_cursors(&self.open_curly, s);
201 ToCursors::to_cursors(&self.declarations, s);
202 ToCursors::to_cursors(&self.rules, s);
203 ToCursors::to_cursors(&self.close_curly, s);
204 }
205}
206
207impl<'a, D, R, M> ToSpan for Block<'a, D, R, M>
208where
209 D: DeclarationValue<'a, M> + ToSpan,
210 R: ToSpan,
211 M: NodeMetadata,
212{
213 fn to_span(&self) -> Span {
214 self.open_curly.to_span()
215 + if self.close_curly.is_some() {
216 self.close_curly.to_span()
217 } else {
218 self.declarations.to_span() + self.rules.to_span() + self.close_curly.to_span()
219 }
220 }
221}
222
223impl<'a, D, R, M> SemanticEq for Block<'a, D, R, M>
224where
225 D: DeclarationValue<'a, M>,
226 R: SemanticEq,
227 M: NodeMetadata,
228{
229 fn semantic_eq(&self, other: &Self) -> bool {
230 self.open_curly.semantic_eq(&other.open_curly)
231 && self.close_curly.semantic_eq(&other.close_curly)
232 && self.declarations.semantic_eq(&other.declarations)
233 && self.rules.semantic_eq(&other.rules)
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::EmptyAtomSet;
241 use crate::{Cursor, test_helpers::*};
242
243 #[derive(Debug)]
244 struct Decl(T![Ident]);
245
246 impl<M: NodeMetadata> NodeWithMetadata<M> for Decl {
247 fn metadata(&self) -> M {
248 M::default()
249 }
250 }
251
252 impl<'a, M: NodeMetadata> DeclarationValue<'a, M> for Decl {
253 fn parse_specified_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _: Cursor) -> Result<Self>
254 where
255 Iter: Iterator<Item = crate::Cursor> + Clone,
256 {
257 p.parse::<T![Ident]>().map(Self)
258 }
259 }
260
261 impl ToCursors for Decl {
262 fn to_cursors(&self, s: &mut impl CursorSink) {
263 ToCursors::to_cursors(&self.0, s);
264 }
265 }
266
267 impl ToSpan for Decl {
268 fn to_span(&self) -> Span {
269 self.0.to_span()
270 }
271 }
272
273 impl SemanticEq for Decl {
274 fn semantic_eq(&self, other: &Self) -> bool {
275 self.0.semantic_eq(&other.0)
276 }
277 }
278
279 impl NodeWithMetadata<()> for T![Ident] {
280 fn metadata(&self) {}
281 }
282
283 #[derive(Debug)]
284 struct Rule(T![Ident]);
285
286 impl<'a> Parse<'a> for Rule {
287 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
288 where
289 I: Iterator<Item = Cursor> + Clone,
290 {
291 Ok(Self(p.parse::<T![Ident]>()?))
292 }
293 }
294
295 impl ToCursors for Rule {
296 fn to_cursors(&self, s: &mut impl CursorSink) {
297 ToCursors::to_cursors(&self.0, s);
298 }
299 }
300
301 impl ToSpan for Rule {
302 fn to_span(&self) -> Span {
303 self.0.to_span()
304 }
305 }
306
307 impl NodeWithMetadata<()> for Rule {
308 fn metadata(&self) {}
309 }
310
311 impl<'a> crate::RuleVariants<'a> for Rule {
312 type DeclarationValue = Decl;
313 type Metadata = ();
314 }
315
316 #[test]
317 fn test_writes() {
318 assert_parse!(EmptyAtomSet::ATOMS, Block<Decl, Rule, ()>, "{color:black}");
319 }
320
321 #[test]
322 fn test_bad_string_in_block_does_not_hang() {
323 let alloc = crate::Arena::new();
324 for src in
325 [":{\".\n", "am:{\"\n", "alm:{\"\n", "alm:{\";.\n", "alm:{\"; }.\n", "alm:s {\n \x16\x00\x00:\";\n }\n"]
326 {
327 let lexer = css_lexer::Lexer::new(&EmptyAtomSet::ATOMS, src);
328 let mut parser = crate::Parser::new(&alloc, src, lexer);
329 let _ = parser.parse::<Block<Decl, Rule, ()>>();
330 }
331 }
332
333 #[test]
334 fn test_trailing_error_kinds_do_not_oom() {
335 let alloc = crate::Arena::new();
336 for src in ["{)))))))))))))", "{))))))))))))))", "{\r)))))))))))))"] {
337 let lexer = css_lexer::Lexer::new(&EmptyAtomSet::ATOMS, src);
338 let mut parser = crate::Parser::new(&alloc, src, lexer);
339 let _ = parser.parse::<Block<Decl, Rule, ()>>();
340 }
341 }
342}