css_parse/syntax/
block.rs1use crate::{
2 CursorSink, DeclarationValue, Kind, KindSet, Parse, Parser, Peek, Result, Span, State, T, ToCursors, ToSpan,
3 token_macros,
4};
5use bumpalo::collections::Vec;
6
7use super::Declaration;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
23pub struct Block<'a, D, R>
24where
25 D: DeclarationValue<'a>,
26{
27 pub open_curly: token_macros::LeftCurly,
28 pub declarations: Vec<'a, Declaration<'a, D>>,
29 pub rules: Vec<'a, R>,
30 pub close_curly: Option<token_macros::RightCurly>,
31}
32
33impl<'a, D, R> Peek<'a> for Block<'a, D, R>
34where
35 D: DeclarationValue<'a>,
36{
37 const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly]);
38}
39
40impl<'a, D, R> Parse<'a> for Block<'a, D, R>
41where
42 D: DeclarationValue<'a>,
43 R: Parse<'a>,
44{
45 fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self>
46 where
47 Iter: Iterator<Item = crate::Cursor> + Clone,
48 {
49 let open_curly = p.parse::<T!['{']>()?;
50 let mut declarations = Vec::new_in(p.bump());
51 let mut rules = Vec::new_in(p.bump());
52 loop {
53 if p.parse_if_peek::<T![' ']>()?.is_some() || p.parse_if_peek::<T![;]>()?.is_some() {
57 continue;
58 }
59 if p.at_end() {
60 break;
61 }
62 let c = p.peek_n(1);
63 if <T!['}']>::peek(p, c) {
64 break;
65 }
66 let old_state = p.set_state(State::Nested);
67 if <T![AtKeyword]>::peek(p, c) {
68 let rule = p.parse::<R>();
69 p.set_state(old_state);
70 rules.push(rule?);
71 } else if let Ok(Some(decl)) = p.try_parse_if_peek::<Declaration<'a, D>>() {
72 p.set_state(old_state);
73 declarations.push(decl);
74 } else {
75 let rule = p.parse::<R>();
76 p.set_state(old_state);
77 rules.push(rule?);
78 }
79 }
80 let close_curly = p.parse_if_peek::<T!['}']>()?;
81 Ok(Self { open_curly, declarations, rules, close_curly })
82 }
83}
84
85impl<'a, D, R> ToCursors for Block<'a, D, R>
86where
87 D: DeclarationValue<'a> + ToCursors,
88 R: ToCursors,
89{
90 fn to_cursors(&self, s: &mut impl CursorSink) {
91 ToCursors::to_cursors(&self.open_curly, s);
92 ToCursors::to_cursors(&self.declarations, s);
93 ToCursors::to_cursors(&self.rules, s);
94 ToCursors::to_cursors(&self.close_curly, s);
95 }
96}
97
98impl<'a, D, R> ToSpan for Block<'a, D, R>
99where
100 D: DeclarationValue<'a> + ToSpan,
101 R: ToSpan,
102{
103 fn to_span(&self) -> Span {
104 self.open_curly.to_span()
105 + if self.close_curly.is_some() {
106 self.close_curly.to_span()
107 } else {
108 self.declarations.to_span() + self.rules.to_span() + self.close_curly.to_span()
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::EmptyAtomSet;
117 use crate::{Cursor, test_helpers::*};
118
119 #[derive(Debug)]
120 struct Decl(T![Ident]);
121 impl<'a> DeclarationValue<'a> for Decl {
122 type ComputedValue = T![Eof];
123
124 fn is_initial(&self) -> bool {
125 false
126 }
127
128 fn is_inherit(&self) -> bool {
129 false
130 }
131
132 fn is_unset(&self) -> bool {
133 false
134 }
135
136 fn is_revert(&self) -> bool {
137 false
138 }
139
140 fn is_revert_layer(&self) -> bool {
141 false
142 }
143
144 fn needs_computing(&self) -> bool {
145 false
146 }
147
148 fn parse_specified_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _: Cursor) -> Result<Self>
149 where
150 Iter: Iterator<Item = crate::Cursor> + Clone,
151 {
152 p.parse::<T![Ident]>().map(Self)
153 }
154 }
155
156 impl ToCursors for Decl {
157 fn to_cursors(&self, s: &mut impl CursorSink) {
158 ToCursors::to_cursors(&self.0, s);
159 }
160 }
161
162 impl ToSpan for Decl {
163 fn to_span(&self) -> Span {
164 self.0.to_span()
165 }
166 }
167
168 #[test]
169 fn size_test() {
170 assert_eq!(std::mem::size_of::<Block<Decl, T![Ident]>>(), 96);
171 }
172
173 #[test]
174 fn test_writes() {
175 assert_parse!(EmptyAtomSet::ATOMS, Block<Decl, T![Ident]>, "{color:black}");
176 }
177}