1use crate::{
2 BadDeclaration, Block, Cursor, CursorSink, DeclarationValue, Diagnostic, Kind, KindSet, Parse, Parser, Peek,
3 Result, Span, State, T, ToCursors, ToSpan,
4};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
8pub struct QualifiedRule<'a, P, D, R>
9where
10 D: DeclarationValue<'a>,
11{
12 pub prelude: P,
13 pub block: Block<'a, D, R>,
14}
15
16impl<'a, P, D, R> Peek<'a> for QualifiedRule<'a, P, D, R>
17where
18 P: Peek<'a>,
19 D: DeclarationValue<'a>,
20{
21 fn peek<Iter>(p: &Parser<'a, Iter>, c: Cursor) -> bool
22 where
23 Iter: Iterator<Item = crate::Cursor> + Clone,
24 {
25 <P>::peek(p, c)
26 }
27}
28
29impl<'a, P, D, R> Parse<'a> for QualifiedRule<'a, P, D, R>
33where
34 D: DeclarationValue<'a>,
35 P: Parse<'a>,
36 R: Parse<'a>,
37{
38 fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self>
39 where
40 Iter: Iterator<Item = crate::Cursor> + Clone,
41 {
42 let c = p.peek_n(1);
43 if p.at_end() {
51 Err(Diagnostic::new(p.peek_n(1), Diagnostic::unexpected_end))?
52 }
53
54 if p.is(State::Nested) && <T!['}']>::peek(p, c) {
57 Err(Diagnostic::new(c, Diagnostic::unexpected_close_curly))?;
58 }
59
60 let checkpoint = p.checkpoint();
63 if <T![DashedIdent]>::peek(p, c) {
64 p.parse::<T![DashedIdent]>().ok();
65 if <T![:]>::peek(p, p.peek_n(1)) {
66 if p.is(State::Nested) {
68 p.rewind(checkpoint.clone());
69 let start = p.peek_n(1);
70 p.parse::<BadDeclaration>()?;
71 let end = p.peek_n(0);
72 Err(Diagnostic::new(start, Diagnostic::bad_declaration).with_end_cursor(end))?
73 } else {
75 p.parse::<Block<'a, D, R>>()?;
81 let start = p.peek_n(1);
82 p.parse::<BadDeclaration>()?;
83 let end = p.peek_n(0);
84 Err(Diagnostic::new(start, Diagnostic::bad_declaration).with_end_cursor(end))?
85 }
86 }
87 p.rewind(checkpoint);
88 }
89
90 let old_stop = p.set_stop(KindSet::new(&[Kind::LeftCurly]));
92 let prelude = p.parse::<P>();
93 p.set_stop(old_stop);
94 let prelude = prelude?;
95
96 Ok(Self { prelude, block: p.parse::<Block<'a, D, R>>()? })
103 }
104}
105
106impl<'a, P, D, R> ToCursors for QualifiedRule<'a, P, D, R>
107where
108 D: DeclarationValue<'a> + ToCursors,
109 P: ToCursors,
110 R: ToCursors,
111{
112 fn to_cursors(&self, s: &mut impl CursorSink) {
113 ToCursors::to_cursors(&self.prelude, s);
114 ToCursors::to_cursors(&self.block, s);
115 }
116}
117
118impl<'a, P, D, R> ToSpan for QualifiedRule<'a, P, D, R>
119where
120 D: DeclarationValue<'a> + ToSpan,
121 P: ToSpan,
122 R: ToSpan,
123{
124 fn to_span(&self) -> Span {
125 self.prelude.to_span() + self.block.to_span()
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use crate::{EmptyAtomSet, test_helpers::*};
133
134 #[derive(Debug)]
135 struct Decl(T![Ident]);
136 impl<'a> DeclarationValue<'a> for Decl {
137 type ComputedValue = T![Eof];
138
139 fn is_initial(&self) -> bool {
140 false
141 }
142
143 fn is_inherit(&self) -> bool {
144 false
145 }
146
147 fn is_unset(&self) -> bool {
148 false
149 }
150
151 fn is_revert(&self) -> bool {
152 false
153 }
154
155 fn is_revert_layer(&self) -> bool {
156 false
157 }
158
159 fn needs_computing(&self) -> bool {
160 false
161 }
162
163 fn parse_specified_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _: Cursor) -> Result<Self>
164 where
165 Iter: Iterator<Item = crate::Cursor> + Clone,
166 {
167 p.parse::<T![Ident]>().map(Self)
168 }
169 }
170
171 impl ToCursors for Decl {
172 fn to_cursors(&self, s: &mut impl CursorSink) {
173 ToCursors::to_cursors(&self.0, s);
174 }
175 }
176
177 impl ToSpan for Decl {
178 fn to_span(&self) -> Span {
179 self.0.to_span()
180 }
181 }
182
183 #[test]
184 fn size_test() {
185 assert_eq!(std::mem::size_of::<QualifiedRule<T![Ident], Decl, T![Ident]>>(), 112);
186 }
187
188 #[test]
189 fn test_writes() {
190 assert_parse!(EmptyAtomSet::ATOMS, QualifiedRule<T![Ident], Decl, T![Ident]>, "body{color:black}");
191 }
192}