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 let rule = p.parse::<R>();
121 p.set_state(old_state);
122 match rule {
123 Ok(rule) => {
124 flush_decls!();
125 meta = meta.merge(rule.metadata());
126 rules.push(rule);
127 }
128 Err(_) => {
131 p.rewind(checkpoint);
132 p.set_state(State::Nested);
133 if let Ok(bad_decl) = p.parse::<BadDeclaration>() {
134 p.set_state(old_state);
135 decls.push(DeclarationOrBad::Bad(bad_decl));
136 }
137 }
138 }
139 } else if let Ok(Some(decl)) = p.try_parse_if_peek::<Declaration<'a, D, M>>() {
140 if decl.is_unknown() && !D::valid_declaration_name(p, decl.name.into()) {
157 p.rewind(checkpoint.clone());
158 if let Ok(rule) = p.parse::<R>()
159 && !rule.is_unknown()
160 {
161 flush_decls!();
163 p.set_state(old_state);
164 meta = meta.merge(rule.metadata());
165 rules.push(rule);
166 continue;
167 }
168 p.rewind(checkpoint);
170 p.parse::<Declaration<'a, D, M>>().ok();
171 }
172 p.set_state(old_state);
173 meta = meta.merge(decl.metadata());
174 declarations.push(decl);
175 } else {
176 let result = p.parse::<R>();
178 p.set_state(old_state);
179 match result {
180 Ok(rule) => {
181 flush_decls!();
182 meta = meta.merge(rule.metadata());
183 rules.push(rule);
184 }
185 Err(_) => {
186 p.rewind(checkpoint);
188 p.set_state(State::Nested);
189 if let Ok(bad_decl) = p.parse::<BadDeclaration>() {
190 p.set_state(old_state);
191 decls.push(DeclarationOrBad::Bad(bad_decl));
192 }
193 }
194 }
195 }
196 }
197
198 flush_decls!();
200 let close_curly = p.parse_if_peek::<T!['}']>()?;
201 Ok(Self { open_curly, declarations, rules, close_curly, meta })
202 }
203}
204
205impl<'a, D, R, M> ToCursors for Block<'a, D, R, M>
206where
207 D: DeclarationValue<'a, M> + ToCursors,
208 R: ToCursors,
209 M: NodeMetadata,
210{
211 fn to_cursors(&self, s: &mut impl CursorSink) {
212 ToCursors::to_cursors(&self.open_curly, s);
213 ToCursors::to_cursors(&self.declarations, s);
214 ToCursors::to_cursors(&self.rules, s);
215 ToCursors::to_cursors(&self.close_curly, s);
216 }
217}
218
219impl<'a, D, R, M> ToSpan for Block<'a, D, R, M>
220where
221 D: DeclarationValue<'a, M> + ToSpan,
222 R: ToSpan,
223 M: NodeMetadata,
224{
225 fn to_span(&self) -> Span {
226 self.open_curly.to_span()
227 + if self.close_curly.is_some() {
228 self.close_curly.to_span()
229 } else {
230 self.declarations.to_span() + self.rules.to_span() + self.close_curly.to_span()
231 }
232 }
233}
234
235impl<'a, D, R, M> SemanticEq for Block<'a, D, R, M>
236where
237 D: DeclarationValue<'a, M>,
238 R: SemanticEq,
239 M: NodeMetadata,
240{
241 fn semantic_eq(&self, other: &Self, source_text: &str) -> bool {
242 self.open_curly.semantic_eq(&other.open_curly, source_text)
243 && self.close_curly.semantic_eq(&other.close_curly, source_text)
244 && self.declarations.semantic_eq(&other.declarations, source_text)
245 && self.rules.semantic_eq(&other.rules, source_text)
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use crate::EmptyAtomSet;
253 use crate::{Cursor, test_helpers::*};
254
255 #[derive(Debug)]
256 struct Decl(T![Ident]);
257
258 impl<M: NodeMetadata> NodeWithMetadata<M> for Decl {
259 fn metadata(&self) -> M {
260 M::default()
261 }
262 }
263
264 impl<'a, M: NodeMetadata> DeclarationValue<'a, M> for Decl {
265 fn parse_specified_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _: Cursor) -> Result<Self>
266 where
267 Iter: Iterator<Item = crate::Cursor> + Clone,
268 {
269 p.parse::<T![Ident]>().map(Self)
270 }
271 }
272
273 impl ToCursors for Decl {
274 fn to_cursors(&self, s: &mut impl CursorSink) {
275 ToCursors::to_cursors(&self.0, s);
276 }
277 }
278
279 impl ToSpan for Decl {
280 fn to_span(&self) -> Span {
281 self.0.to_span()
282 }
283 }
284
285 impl SemanticEq for Decl {
286 fn semantic_eq(&self, other: &Self, source_text: &str) -> bool {
287 self.0.semantic_eq(&other.0, source_text)
288 }
289 }
290
291 impl NodeWithMetadata<()> for T![Ident] {
292 fn metadata(&self) {}
293 }
294
295 #[derive(Debug)]
296 struct Rule(T![Ident]);
297
298 impl<'a> Parse<'a> for Rule {
299 fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
300 where
301 I: Iterator<Item = Cursor> + Clone,
302 {
303 Ok(Self(p.parse::<T![Ident]>()?))
304 }
305 }
306
307 impl ToCursors for Rule {
308 fn to_cursors(&self, s: &mut impl CursorSink) {
309 ToCursors::to_cursors(&self.0, s);
310 }
311 }
312
313 impl ToSpan for Rule {
314 fn to_span(&self) -> Span {
315 self.0.to_span()
316 }
317 }
318
319 impl NodeWithMetadata<()> for Rule {
320 fn metadata(&self) {}
321 }
322
323 impl<'a> crate::RuleVariants<'a> for Rule {
324 type DeclarationValue = Decl;
325 type Metadata = ();
326 }
327
328 #[test]
329 fn test_writes() {
330 assert_parse!(EmptyAtomSet::ATOMS, Block<Decl, Rule, ()>, "{color:black}");
331 }
332
333 #[test]
334 fn test_bad_string_in_block_does_not_hang() {
335 let alloc = crate::Arena::new();
336 for src in
337 [":{\".\n", "am:{\"\n", "alm:{\"\n", "alm:{\";.\n", "alm:{\"; }.\n", "alm:s {\n \x16\x00\x00:\";\n }\n"]
338 {
339 let lexer = css_lexer::Lexer::new(&EmptyAtomSet::ATOMS, src);
340 let mut parser = crate::Parser::new(&alloc, src, lexer);
341 let _ = parser.parse::<Block<Decl, Rule, ()>>();
342 }
343 }
344
345 #[test]
346 fn test_trailing_error_kinds_do_not_oom() {
347 let alloc = crate::Arena::new();
348 for src in ["{)))))))))))))", "{))))))))))))))", "{\r)))))))))))))"] {
349 let lexer = css_lexer::Lexer::new(&EmptyAtomSet::ATOMS, src);
350 let mut parser = crate::Parser::new(&alloc, src, lexer);
351 let _ = parser.parse::<Block<Decl, Rule, ()>>();
352 }
353 }
354
355 #[test]
356 fn test_unparseable_at_rule_does_not_fail_the_block() {
357 let alloc = crate::Arena::new();
358 for src in ["{@x}", "{@x (}", "{a:b;@x (}", "{@x (", "{@x{a:b}}"] {
359 let lexer = css_lexer::Lexer::new(&EmptyAtomSet::ATOMS, src);
360 let mut parser = crate::Parser::new(&alloc, src, lexer);
361 assert!(parser.parse::<Block<Decl, Rule, ()>>().is_ok(), "{src:?} should parse as a Block");
362 }
363 }
364}