1use crate::{
2 BadDeclaration, Block, Cursor, CursorSink, DeclarationValue, Kind, KindSet, Parse, Parser, Peek, Result, Span,
3 State, T, ToCursors, ToSpan, diagnostics,
4};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(tag = "type"))]
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(p: &Parser<'a>, c: Cursor) -> bool {
22 <P>::peek(p, c)
23 }
24}
25
26impl<'a, P, D, R> Parse<'a> for QualifiedRule<'a, P, D, R>
30where
31 D: DeclarationValue<'a>,
32 P: Parse<'a>,
33 R: Parse<'a>,
34{
35 fn parse(p: &mut Parser<'a>) -> Result<Self> {
36 if p.at_end() {
44 Err(diagnostics::UnexpectedEnd())?
45 }
46
47 if p.is(State::Nested) && p.peek::<T!['}']>() {
50 Err(diagnostics::UnexpectedCloseCurly(p.peek_n(1)))?;
51 }
52
53 let checkpoint = p.checkpoint();
56 if p.peek::<T![DashedIdent]>() {
57 p.parse::<T![DashedIdent]>().ok();
58 if p.peek::<T![:]>() {
59 if p.is(State::Nested) {
61 p.rewind(checkpoint);
62 let span = p.parse::<BadDeclaration>()?.to_span();
63 Err(diagnostics::BadDeclaration(span))?
64 } else {
66 p.parse::<Block<'a, D, R>>()?;
72 Err(diagnostics::BadDeclaration(checkpoint.to_span()))?
73 }
74 }
75 p.rewind(checkpoint);
76 }
77
78 let old_stop = p.set_stop(KindSet::new(&[Kind::LeftCurly]));
80 let prelude = p.parse::<P>();
81 p.set_stop(old_stop);
82 let prelude = prelude?;
83
84 Ok(Self { prelude, block: p.parse::<Block<'a, D, R>>()? })
91 }
92}
93
94impl<'a, P, D, R> ToCursors for QualifiedRule<'a, P, D, R>
95where
96 D: DeclarationValue<'a> + ToCursors,
97 P: ToCursors,
98 R: ToCursors,
99{
100 fn to_cursors(&self, s: &mut impl CursorSink) {
101 ToCursors::to_cursors(&self.prelude, s);
102 ToCursors::to_cursors(&self.block, s);
103 }
104}
105
106impl<'a, P, D, R> ToSpan for QualifiedRule<'a, P, D, R>
107where
108 D: DeclarationValue<'a> + ToSpan,
109 P: ToSpan,
110 R: ToSpan,
111{
112 fn to_span(&self) -> Span {
113 self.prelude.to_span() + self.block.to_span()
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120 use crate::test_helpers::*;
121
122 #[derive(Debug)]
123 struct Decl(T![Ident]);
124 impl<'a> DeclarationValue<'a> for Decl {
125 type ComputedValue = T![Eof];
126
127 fn is_initial(&self) -> bool {
128 false
129 }
130
131 fn is_inherit(&self) -> bool {
132 false
133 }
134
135 fn is_unset(&self) -> bool {
136 false
137 }
138
139 fn is_revert(&self) -> bool {
140 false
141 }
142
143 fn is_revert_layer(&self) -> bool {
144 false
145 }
146
147 fn needs_computing(&self) -> bool {
148 false
149 }
150
151 fn parse_specified_declaration_value(p: &mut Parser<'a>, _: Cursor) -> Result<Self> {
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::<QualifiedRule<T![Ident], Decl, T![Ident]>>(), 112);
171 }
172
173 #[test]
174 fn test_writes() {
175 assert_parse!(QualifiedRule<T![Ident], Decl, T![Ident]>, "body{color:black}");
176 }
177}