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(p: &mut Parser<'a>) -> Result<Self> {
46 let open_curly = p.parse::<T!['{']>()?;
47 let mut declarations = Vec::new_in(p.bump());
48 let mut rules = Vec::new_in(p.bump());
49 loop {
50 if p.parse_if_peek::<T![' ']>()?.is_some() || p.parse_if_peek::<T![;]>()?.is_some() {
54 continue;
55 }
56 if p.at_end() {
57 break;
58 }
59 if p.peek::<T!['}']>() {
60 break;
61 }
62 let old_state = p.set_state(State::Nested);
63 if p.peek::<T![AtKeyword]>() {
64 let rule = p.parse::<R>();
65 p.set_state(old_state);
66 rules.push(rule?);
67 } else if let Ok(Some(decl)) = p.try_parse_if_peek::<Declaration<'a, D>>() {
68 p.set_state(old_state);
69 declarations.push(decl);
70 } else {
71 let rule = p.parse::<R>();
72 p.set_state(old_state);
73 rules.push(rule?);
74 }
75 }
76 let close_curly = p.parse_if_peek::<T!['}']>()?;
77 Ok(Self { open_curly, declarations, rules, close_curly })
78 }
79}
80
81impl<'a, D, R> ToCursors for Block<'a, D, R>
82where
83 D: DeclarationValue<'a> + ToCursors,
84 R: ToCursors,
85{
86 fn to_cursors(&self, s: &mut impl CursorSink) {
87 ToCursors::to_cursors(&self.open_curly, s);
88 ToCursors::to_cursors(&self.declarations, s);
89 ToCursors::to_cursors(&self.rules, s);
90 ToCursors::to_cursors(&self.close_curly, s);
91 }
92}
93
94impl<'a, D, R> ToSpan for Block<'a, D, R>
95where
96 D: DeclarationValue<'a> + ToSpan,
97 R: ToSpan,
98{
99 fn to_span(&self) -> Span {
100 self.open_curly.to_span()
101 + if self.close_curly.is_some() {
102 self.close_curly.to_span()
103 } else {
104 self.declarations.to_span() + self.rules.to_span() + self.close_curly.to_span()
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::{Cursor, test_helpers::*};
113
114 #[derive(Debug)]
115 struct Decl(T![Ident]);
116 impl<'a> DeclarationValue<'a> for Decl {
117 type ComputedValue = T![Eof];
118
119 fn is_initial(&self) -> bool {
120 false
121 }
122
123 fn is_inherit(&self) -> bool {
124 false
125 }
126
127 fn is_unset(&self) -> bool {
128 false
129 }
130
131 fn is_revert(&self) -> bool {
132 false
133 }
134
135 fn is_revert_layer(&self) -> bool {
136 false
137 }
138
139 fn needs_computing(&self) -> bool {
140 false
141 }
142
143 fn parse_specified_declaration_value(p: &mut Parser<'a>, _: Cursor) -> Result<Self> {
144 p.parse::<T![Ident]>().map(Self)
145 }
146 }
147
148 impl ToCursors for Decl {
149 fn to_cursors(&self, s: &mut impl CursorSink) {
150 ToCursors::to_cursors(&self.0, s);
151 }
152 }
153
154 impl ToSpan for Decl {
155 fn to_span(&self) -> Span {
156 self.0.to_span()
157 }
158 }
159
160 #[test]
161 fn size_test() {
162 assert_eq!(std::mem::size_of::<Block<Decl, T![Ident]>>(), 96);
163 }
164
165 #[test]
166 fn test_writes() {
167 assert_parse!(Block<Decl, T![Ident]>, "{color:black}");
168 }
169}